]> arthur.barton.de Git - netatalk.git/commitdiff
adouble:ea VFS stuff
authorFrank Lahm <franklahm@googlemail.com>
Fri, 20 Jan 2012 16:15:54 +0000 (17:15 +0100)
committerFrank Lahm <franklahm@googlemail.com>
Fri, 20 Jan 2012 16:15:54 +0000 (17:15 +0100)
include/atalk/unix.h
libatalk/adouble/ad_flush.c
libatalk/adouble/ad_open.c
libatalk/vfs/unix.c
libatalk/vfs/vfs.c

index f6d191ca6000d21f1613cad1a3fd6afb47083786..c7a2bc38cdd03edda656180547e434cc9ada7dd8 100644 (file)
@@ -23,6 +23,9 @@
 #include <sys/types.h>
 #include <dirent.h>
 
+#define NETATALK_DIOSZ_STACK 65536
+#define NETATALK_DIOSZ_HEAP  (1024*1024)
+
 /* vfs/unix.c */
 extern int netatalk_unlink(const char *name);
 extern int netatalk_unlinkat(int dirfd, const char *name);
@@ -39,4 +42,6 @@ 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(int sfd, const char *oldpath, int dfd, const char *newpath);
 extern int copy_file(int sfd, const char *src, const char *dst, mode_t mode);
+extern int copy_file_fd(int sfd, int dfd);
+extern int copy_ea(const char *ea, int sfd, const char *src, const char *dst, mode_t mode);
 #endif  /* ATALK_UNIX_H */
index e0321a398cd43e3edf855a0c3a15ffcaf70caac2..83febd0e84a02ef204025fa19abf7ebf6d84df21 100644 (file)
@@ -38,6 +38,7 @@
 #include <atalk/bstrlib.h>
 #include <atalk/bstradd.h>
 #include <atalk/errchk.h>
+#include <atalk/util.h>
 
 #include "ad_lock.h"
 
@@ -60,6 +61,8 @@ int ad_rebuild_adouble_header(struct adouble *ad)
     char        *buf, *nentp;
     int             len;
 
+    LOG(log_debug, logtype_default, "ad_rebuild_adouble_header");
+
     buf = ad->ad_data;
 
     temp = htonl( ad->ad_magic );
@@ -206,7 +209,9 @@ int ad_copy_header(struct adouble *add, struct adouble *ads)
 
 static int ad_flush_hf(struct adouble *ad)
 {
+    EC_INIT;
     int len;
+    int cwd = -1;
 
     LOG(log_debug, logtype_default, "ad_flush_hf(%s)", adflags2logstr(ad->ad_adflags));
 
@@ -224,7 +229,8 @@ static int ad_flush_hf(struct adouble *ad)
         return -1;
     }
 
-    if ((adf->adf_flags & O_RDWR)) {
+    if ((adf->adf_flags & O_RDWR)
+        || ((ad->ad_adflags & ADFLAGS_DIR) && (ad->ad_adflags & ADFLAGS_RDWR))) {
         if (ad_getentryoff(ad, ADEID_RFORK)) {
             if (ad->ad_rlen > 0xffffffff)
                 ad_setentrylen(ad, ADEID_RFORK, 0xffffffff);
@@ -243,10 +249,11 @@ static int ad_flush_hf(struct adouble *ad)
             break;
         case AD_VERSION_EA:
             if (AD_META_OPEN(ad)) {
-                if (sys_fsetxattr(ad_data_fileno(ad), AD_EA_META, ad->ad_data, AD_DATASZ_EA, 0) != 0) {
-                    LOG(log_error, logtype_afpd, "ad_flush: sys_fsetxattr error: %s",
-                        strerror(errno));
-                    return -1;
+                if (ad->ad_adflags & ADFLAGS_DIR) {
+                    EC_NEG1_LOG( cwd = open(".", O_RDONLY) );
+                    EC_ZERO_LOG( sys_lsetxattr(".", AD_EA_META, ad->ad_data, AD_DATASZ_EA, 0) );
+                } else {
+                    EC_ZERO_LOG( sys_fsetxattr(ad_data_fileno(ad), AD_EA_META, ad->ad_data, AD_DATASZ_EA, 0) );
                 }
             }
             break;
@@ -256,7 +263,14 @@ static int ad_flush_hf(struct adouble *ad)
         }
     }
 
-    return( 0 );
+EC_CLEANUP:
+    if (cwd != -1) {
+        if (fchdir(cwd) != 0) {
+            AFP_PANIC("ad_flush: cant fchdir");
+        }
+        close(cwd);
+    }
+    EC_EXIT;
 }
 
 /* Flush resofork adouble file if any (currently adouble:ea and #ifndef HAVE_EAFD eg Linux) */
index d3a4c6b3ace9e8a246a1b43e0e7591af28bbb0a4..71a495d5d864dd3efe831c207871fb885d4cc4d9 100644 (file)
@@ -944,7 +944,10 @@ static int ad_open_hf_ea(const char *path, int adflags, int mode, struct adouble
     } else {
         if (adflags & ADFLAGS_RDWR) {
             /* Fo a RDONLY adouble we just use sys_lgetxattr instead if sys_fgetxattr */
-            LOG(log_debug, logtype_default, "ad_open_hf_ea(\"%s\"): opening for base file for meta adouble EA", path);
+            if (adflags & ADFLAGS_DIR)
+                /* For directories we open the directory RDONYL so we can later fchdir()  */
+                oflags = (oflags & ~O_RDWR) | O_RDONLY;
+            LOG(log_debug, logtype_default, "ad_open_hf_ea(\"%s\"): opening base file for meta adouble EA", path);
             if ((ad_meta_fileno(ad) = open(path, oflags)) == -1)
                 goto error;
             ad->ad_mdp->adf_flags = oflags;
index 14a0f1647dec29ad31974533de1561c8bc9242c7..659cd41162d95a004eaaefbada06432b03147433 100644 (file)
@@ -23,6 +23,8 @@
 #include <atalk/unix.h>
 #include <atalk/acl.h>
 #include <atalk/compat.h>
+#include <atalk/errchk.h>
+#include <atalk/ea.h>
 
 /* -----------------------------
    a dropbox is a folder where w is set but not r eg:
@@ -150,6 +152,38 @@ int netatalk_unlink(const char *name)
  * *at semnatics support functions (like openat, renameat standard funcs)
  **************************************************************************/
 
+/* Copy all file data from one file fd to another */
+int copy_file_fd(int sfd, int dfd)
+{
+    EC_INIT;
+    ssize_t cc;
+    size_t  buflen;
+    char   filebuf[NETATALK_DIOSZ_STACK];
+
+    while ((cc = read(sfd, filebuf, sizeof(filebuf)))) {
+        if (cc < 0) {
+            if (errno == EINTR)
+                continue;
+            LOG(log_error, logtype_afpd, "copy_file_fd: %s", strerror(errno));
+            EC_FAIL;
+        }
+
+        buflen = cc;
+        while (buflen > 0) {
+            if ((cc = write(dfd, filebuf, buflen)) < 0) {
+                if (errno == EINTR)
+                    continue;
+                LOG(log_error, logtype_afpd, "copy_file_fd: %s", strerror(errno));
+                EC_FAIL;
+            }
+            buflen -= cc;
+        }
+    }
+
+EC_CLEANUP:
+    EC_EXIT;
+}
+
 /* 
  * Supports *at semantics if HAVE_ATFUNCS, pass dirfd=-1 to ignore this
  */
@@ -160,7 +194,7 @@ int copy_file(int dirfd, const char *src, const char *dst, mode_t mode)
     int    dfd = -1;
     ssize_t cc;
     size_t  buflen;
-    char   filebuf[8192];
+    char   filebuf[NETATALK_DIOSZ_STACK];
 
 #ifdef HAVE_ATFUNCS
     if (dirfd == -1)
@@ -182,29 +216,7 @@ int copy_file(int dirfd, const char *src, const char *dst, mode_t mode)
         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;
-        }
-
-        buflen = cc;
-        while (buflen > 0) {
-            if ((cc = write(dfd, filebuf, buflen)) < 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;
-            }
-            buflen -= cc;
-        }
-    }
+    ret = copy_file_fd(sfd, dfd);
 
 exit:
     if (sfd != -1)
@@ -225,6 +237,43 @@ exit:
     return ret;
 }
 
+/*!
+ * Copy an EA from one file to another
+ *
+ * Supports *at semantics if HAVE_ATFUNCS, pass dirfd=-1 to ignore this
+ */
+int copy_ea(const char *ea, int dirfd, const char *src, const char *dst, mode_t mode)
+{
+    EC_INIT;
+    int    sfd = -1;
+    int    dfd = -1;
+    size_t easize;
+    char   *eabuf = NULL;
+
+#ifdef HAVE_ATFUNCS
+    if (dirfd == -1)
+        dirfd = AT_FDCWD;
+    EC_NEG1_LOG( sfd = openat(dirfd, src, O_RDONLY) );
+#else
+    EC_NEG1_LOG( sfd = open(src, O_RDONLY) );
+#endif
+    EC_NEG1_LOG( dfd = open(dst, O_WRONLY, mode) );
+
+    if ((easize = sys_fgetxattr(sfd, ea, NULL, 0)) > 0) {
+        EC_NULL_LOG( eabuf = malloc(easize));
+        EC_NEG1_LOG( easize = sys_fgetxattr(sfd, ea, eabuf, easize) );
+        EC_NEG1_LOG( easize = sys_fsetxattr(dfd, ea, eabuf, easize, 0) );
+    }
+
+EC_CLEANUP:
+    if (sfd != -1)
+        close(sfd);
+    if (dfd != -1)
+        close(dfd);
+    free(eabuf);
+    EC_EXIT;
+}
+
 /* 
  * at wrapper for netatalk_unlink
  */
index 75f461efab106660cd6555e3cb08b77ebda00011..044000922796b6eab4fb3a4d69f2877aa6021148 100644 (file)
@@ -140,7 +140,7 @@ static int deletecurdir_adouble_loop(struct dirent *de, char *name, void *data _
     /* bail if the file exists in the current directory.
      * note: this will not fail with dangling symlinks */
     
-    if (stat(de->d_name, &st) == 0)
+    if (lstat(de->d_name, &st) == 0)
         return AFPERR_DIRNEMPT;
 
     if ((err = netatalk_unlink(name)))
@@ -515,6 +515,9 @@ static int validupath_ea(VFS_FUNC_ARGS_VALIDUPATH)
 /* ----------------- */
 static int RF_chown_ea(VFS_FUNC_ARGS_CHOWN)
 {
+#ifndef HAVE_EAFD
+    return chown(vol->ad_path(path, ADFLAGS_HF ), uid, gid);
+#endif
     return 0;
 }
 
@@ -524,95 +527,182 @@ static int RF_renamedir_ea(VFS_FUNC_ARGS_RENAMEDIR)
     return 0;
 }
 
+/* Returns 1 if the entry is NOT an ._ file */
+static int deletecurdir_ea_osx_chkifempty_loop(struct dirent *de, char *name, void *data _U_, int flag _U_, mode_t v_umask _U_)
+{
+    if (de->d_name[0] != '.' || de->d_name[0] == '_')
+        return 1;
+
+    return 0;
+}
+
+static int deletecurdir_ea_osx_loop(struct dirent *de, char *name, void *data _U_, int flag _U_, mode_t v_umask _U_)
+{
+    int ret;
+    
+    if ((ret = netatalk_unlink(name)) != 0)
+        return ret;
+
+    return 0;
+}
+
 /* ---------------- */
 static int RF_deletecurdir_ea(VFS_FUNC_ARGS_DELETECURDIR)
 {
+#ifndef HAVE_EAFD
+    int err;
+    /* delete stray ._AppleDouble files */
+
+    /* first check if there's really no other file besides files starting with ._ */
+    if ((err = for_each_adouble("deletecurdir_ea_osx", ".",
+                                deletecurdir_ea_osx_chkifempty_loop,
+                                NULL, 0, 0)) != 0) {
+        if (err == 1)
+            return AFPERR_DIRNEMPT;
+        return AFPERR_MISC;
+    }
+
+    /* Now delete orphaned ._ files */
+    if ((err = for_each_adouble("deletecurdir_ea_osx", ".",
+                                deletecurdir_ea_osx_loop,
+                                NULL, 0, 0)) != 0)
+        return err;
+
+#endif
     return 0;
 }
 
 /* ---------------- */
 static int RF_setdirunixmode_ea(VFS_FUNC_ARGS_SETDIRUNIXMODE)
 {
+#ifndef HAVE_EAFD
+#endif
     return 0;
 }
 
 static int RF_setfilmode_ea(VFS_FUNC_ARGS_SETFILEMODE)
 {
+#ifndef HAVE_EAFD
+    return adouble_setfilmode(vol->ad_path(name, ADFLAGS_HF ), mode, st, vol->v_umask);
+#endif
     return 0;
 }
 
 /* ---------------- */
 static int RF_setdirmode_ea(VFS_FUNC_ARGS_SETDIRMODE)
 {
+#ifndef HAVE_EAFD
+#endif
     return 0;
 }
 
 /* ---------------- */
 static int RF_setdirowner_ea(VFS_FUNC_ARGS_SETDIROWNER)
 {
+#ifndef HAVE_EAFD
+#endif
        return 0;
 }
 
 static int RF_deletefile_ea(VFS_FUNC_ARGS_DELETEFILE)
 {
+#ifndef HAVE_EAFD
+       return netatalk_unlinkat(dirfd, vol->ad_path(file, ADFLAGS_HF));
+#endif
     return 0;
 }
 static int RF_copyfile_ea(VFS_FUNC_ARGS_COPYFILE)
 {
-    return 0;
-}
+    EC_INIT;
 
-/* ---------------- */
-static int RF_renamefile_ea(VFS_FUNC_ARGS_RENAMEFILE)
-{
-    return 0;
-}
+    /* copy meta EA */
+    if (copy_ea(AD_EA_META, sfd, src, dst, 0666) != 0)
+        return AFPERR_MISC;
 
-#if 0
-/*************************************************************************
- * osx adouble format 
- ************************************************************************/
-static int validupath_osx(VFS_FUNC_ARGS_VALIDUPATH)
-{
-    return strncmp(name,"._", 2) && (
-      (vol->v_flags & AFPVOL_USEDOTS) ? netatalk_name(name): name[0] != '.');
-}             
+    /* copy reso */
+#ifdef HAVE_EAFD
+    int sfile = -1, dfile = -1, sea = -1, dea = -1;
 
-/* ---------------- */
-static int RF_renamedir_osx(VFS_FUNC_ARGS_RENAMEDIR)
-{
-    /* We simply move the corresponding ad file as well */
-    char   tempbuf[258]="._";
-    return unix_rename(dirfd, vol->ad_path(oldpath,0), -1, strcat(tempbuf,newpath));
-}
+    if ((sfile = openat(sfd, src, O_RDONLY)) == -1) {
+        ret = AFPERR_MISC;
+        goto copyresoerr;
+    }
 
-/* ---------------- */
-static int RF_deletecurdir_osx(VFS_FUNC_ARGS_DELETECURDIR)
-{
-    return netatalk_unlink( vol->ad_path(".",0) );
-}
+    if ((dfile = open(dts, O_WRONLY)) == -1) {
+        ret = AFPERR_MISC;
+        goto copyresoerr;
+    }
 
-/* ---------------- */
-static int RF_setdirunixmode_osx(VFS_FUNC_ARGS_SETDIRUNIXMODE)
-{
-    return adouble_setfilmode(vol->ad_path(name, ADFLAGS_DIR ), mode, st, vol->v_umask);
-}
+    if ((sea = openat(sfile, AD_EA_RESO, O_RDONLY | O_XATTR)) == -1) {
+        ret = AFPERR_MISC;
+        goto copyresoerr;
+    }
 
-/* ---------------- */
-static int RF_setdirmode_osx(VFS_FUNC_ARGS_SETDIRMODE)
-{
-    return 0;
-}
+    if ((dea = openat(dfile, AD_EA_RESO, O_RDWR | O_CREAT | O_XATTR)) == -1) {
+        ret = AFPERR_MISC;
+        goto copyresoerr;
+    }
 
-/* ---------------- */
-static int RF_setdirowner_osx(VFS_FUNC_ARGS_SETDIROWNER)
-{
-       return 0;
+    ret = copy_file_fd(sea, dea);
+
+copyresoerr:
+    if (sfile != -1) close(sfile);
+    if (dfile != -1) close(dfile);
+    if (sea != -1) close(sea);
+    if (dea != -1) close(dea);
+    if (ret != 0)
+        return ret;
+
+EC_CLEANUP:
+#else
+    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;
+
+    /* get basename */
+
+    /* build src path to ._ 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, "/._"));
+    EC_ZERO(bcatcstr(s, name));
+
+    /* build dst path to ._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, "/._"));
+    EC_ZERO(bcatcstr(d, name));
+
+    EC_ZERO(copy_file(sfd, cfrombstr(s), cfrombstr(d), 0666));
+
+EC_CLEANUP:
+    bdestroy(s);
+    bdestroy(d);
+    free(dup1);
+    free(dup2);
+    free(dup3);
+    free(dup4);
+#endif
+out:
+    EC_EXIT;
 }
 
 /* ---------------- */
-static int RF_renamefile_osx(VFS_FUNC_ARGS_RENAMEFILE)
+static int RF_renamefile_ea(VFS_FUNC_ARGS_RENAMEFILE)
 {
+#ifndef HAVE_EAFD
     char  adsrc[ MAXPATHLEN + 1];
     int   err = 0;
 
@@ -628,8 +718,9 @@ static int RF_renamefile_osx(VFS_FUNC_ARGS_RENAMEFILE)
         return -1;
     }
     return 0;
-}
 #endif
+    return 0;
+}
 
 /********************************************************************************************
  * VFS chaining