]> arthur.barton.de Git - netatalk.git/commitdiff
Merge branch 'nohex' into develop
authorFrank Lahm <franklahm@googlemail.com>
Fri, 30 Mar 2012 14:43:45 +0000 (16:43 +0200)
committerFrank Lahm <franklahm@googlemail.com>
Fri, 30 Mar 2012 14:43:45 +0000 (16:43 +0200)
15 files changed:
NEWS
bin/ad/ad_util.c
etc/afpd/enumerate.c
etc/afpd/filedir.c
etc/afpd/volume.c
etc/cnid_dbd/cmd_dbd_scanvol.c
include/atalk/adouble.h
include/atalk/volume.h
libatalk/adouble/Makefile.am
libatalk/adouble/ad_conv.c [new file with mode: 0644]
libatalk/adouble/ad_open.c
libatalk/unicode/charcnv.c
libatalk/util/netatalk_conf.c
libatalk/vfs/vfs.c
man/man5/afp.conf.5.tmpl

diff --git a/NEWS b/NEWS
index 47791c31c80faaa44d5a553718aef48d03098440..2b46166a9bc2e05ed490b7084c8b3db504dd7dea 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,7 +1,13 @@
 Changes in 3.0 alpha2
 =====================
 
+* UPD: afpd: Store '.' as is and '/' as ':' on the server, don't
+       CAP hexencode as "2e" and "2f" respectively
+* UPD: afdp: Automatic name conversion, renaming files and directories
+       containing CAP sequences to their not enscaped forms
+* UPD: dbd: -C option removes CAP encoding
 * UPD: Add graceful option to RedHat init script
+* REM: Volumes options "use dots" and "hex encoding"
 
 Changes in 3.0 alpha1
 =====================
index d994f74f56afa666fe8376d142c882fcf6a83aaa..682bc57c98190191bccdc5f6721315395b62d6d3 100644 (file)
@@ -216,15 +216,6 @@ int convert_dots_encoding(const afpvol_t *svol, const afpvol_t *dvol, char *path
         from = svol->vol->v_volcharset;
     }
 
-    if ( (svol->vol->v_path)
-         && ! (svol->vol->v_flags & AFPVOL_USEDOTS)
-         && (dvol->vol->v_flags & AFPVOL_USEDOTS)) {
-        /* source is without dots, destination is with */
-        flags |= CONV_UNESCAPEHEX;
-    } else if (! (dvol->vol->v_flags & AFPVOL_USEDOTS)) {
-        flags |= CONV_ESCAPEDOTS;
-    }
-
     int len = convert_charset(from,
                               dvol->vol->v_volcharset,
                               dvol->vol->v_maccharset,
index 80759a439cf61bfed6f088b0641bf5e4c48a907a..f77d34a522a91ce702ff80599540791684586548 100644 (file)
@@ -347,13 +347,15 @@ static int enumerate(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_,
             continue;
         }
         memset(&s_path, 0, sizeof(s_path));
+
+        /* conversions on the fly */
+        const char *convname;
         s_path.u_name = sd.sd_last;
-        if (of_stat( &s_path) < 0 ) {
-            /*
-             * Somebody else plays with the dir, well it can be us with 
-            * "Empty Trash..."
-            */
+        if (ad_convert(sd.sd_last, &s_path.st, vol, &convname) == 0 && convname) {
+            s_path.u_name = (char *)convname;
+        }
 
+        if (of_stat( &s_path) < 0 ) {
             /* so the next time it won't try to stat it again
              * another solution would be to invalidate the cache with 
              * sd.sd_did = 0 but if it's not ENOENT error it will start again
@@ -364,12 +366,18 @@ static int enumerate(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_,
             continue;
         }
 
+        /* Fixup CNID db if ad_convert resulted in a rename (then convname != NULL) */
+        if (convname) {
+            s_path.id = cnid_lookup(vol->v_cdb, &s_path.st, curdir->d_did, sd.sd_last, strlen(sd.sd_last));
+            if (s_path.id != CNID_INVALID) {
+                if (cnid_update(vol->v_cdb, s_path.id, &s_path.st, curdir->d_did, convname, strlen(convname)) != 0)
+                    LOG(log_error, logtype_afpd, "enumerate: error updating CNID of \"%s\"", fullpathname(convname));
+            }
+        }
+
         sd.sd_last += len + 1;
         s_path.m_name = NULL;
 
-        /* Convert adouble:v2 to adouble:ea on the fly */
-        (void)ad_convert(s_path.u_name, &s_path.st, vol);
-
         /*
          * If a fil/dir is not a dir, it's a file. This is slightly
          * inaccurate, since that means /dev/null is a file, /dev/printer
index a04776fae35148b85735549221f22f0f2e479722..17473d19e7788adc542e8c95f8d66ed4b0e28e08 100644 (file)
@@ -203,9 +203,6 @@ int afp_setfildirparams(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf
 */
 int check_name(const struct vol *vol, char *name)
 {
-    if ((vol->v_flags & AFPVOL_NOHEX) && strchr(name, '/'))
-        return AFPERR_PARAM;
-
     if (!vol->vfs->vfs_validupath(vol, name)) {
         LOG(log_error, logtype_afpd, "check_name: illegal name: '%s'", name);
         return AFPERR_EXIST;
index 1d4081e29212e9dcd851e8e39efbaccfc7fe3273..61d744ca70cdc980d21b98734a06b25682e3e1d9 100644 (file)
@@ -321,7 +321,7 @@ static int getvolparams(const AFPObj *obj, uint16_t bitmap, struct vol *vol, str
      * .Parent file here if it doesn't exist. */
 
     /* Convert adouble:v2 to adouble:ea on the fly */
-    (void)ad_convert(vol->v_path, st, vol);
+    (void)ad_convert(vol->v_path, st, vol, NULL);
 
     ad_init(&ad, vol);
     if (ad_open(&ad, vol->v_path, ADFLAGS_HF | ADFLAGS_DIR | ADFLAGS_RDWR | ADFLAGS_CREATE, 0666) != 0 ) {
index 9685c3d219c341a81aa48de436abd2e3f3bb4ca0..cad6a944857f8369b2fe7bbddd88a9f9e119afb9 100644 (file)
@@ -124,11 +124,6 @@ static char *mtoupath(char *mpath)
     }
 
     /* set conversion flags */
-    if (!(myvol->v_flags & AFPVOL_NOHEX))
-        flags |= CONV_ESCAPEHEX;
-    if (!(myvol->v_flags & AFPVOL_USEDOTS))
-        flags |= CONV_ESCAPEDOTS;
-
     if ((myvol->v_casefold & AFPVOL_MTOUUPPER))
         flags |= CONV_TOUPPER;
     else if ((myvol->v_casefold & AFPVOL_MTOULOWER))
@@ -156,28 +151,6 @@ static char *mtoupath(char *mpath)
     return( upath );
 }
 
-/*
-  Check for wrong encoding e.g. "." at the beginning is not CAP encoded (:2e) although volume is default !AFPVOL_USEDOTS.
-  We do it by roundtripiping from volcharset to UTF8-MAC and back and then compare the result.
-*/
-static int check_name_encoding(char *uname)
-{
-    char *roundtripped;
-
-    roundtripped = mtoupath(utompath(uname));
-    if (!roundtripped) {
-        dbd_log( LOGSTD, "Error checking encoding for '%s/%s'", cwdbuf, uname);
-        return -1;
-    }
-
-    if ( STRCMP(uname, !=, roundtripped)) {
-        dbd_log( LOGSTD, "Bad encoding for '%s/%s'", cwdbuf, uname);
-        return -1;
-    }
-
-    return 0;
-}
-
 /*
   Check for netatalk special folders e.g. ".AppleDB" or ".AppleDesktop"
   Returns pointer to name or NULL.
@@ -208,20 +181,72 @@ static const char *check_special_dirs(const char *name)
     return NULL;
 }
 
+/*
+ * We unCAPed a name, update CNID db
+ */
+static int update_cnid(cnid_t did, const struct stat *sp, const char *oldname, const char *newname)
+{
+    int ret;
+    cnid_t id;
+
+    /* Prepare request data */
+    memset(&rqst, 0, sizeof(struct cnid_dbd_rqst));
+    memset(&rply, 0, sizeof(struct cnid_dbd_rply));
+    rqst.did = did;
+    rqst.cnid = 0;
+    if ( ! (myvol->v_flags & AFPVOL_NODEV))
+        rqst.dev = sp->st_dev;
+    rqst.ino = sp->st_ino;
+    rqst.type = S_ISDIR(sp->st_mode) ? 1 : 0;
+    rqst.name = (char *)oldname;
+    rqst.namelen = strlen(oldname);
+
+    /* Query the database */
+    ret = dbd_lookup(dbd, &rqst, &rply, (dbd_flags & DBD_FLAGS_SCAN) ? 1 : 0);
+    if (dbif_txn_close(dbd, ret) != 0)
+        return -1;
+    if (rply.result != CNID_DBD_RES_OK)
+        return 0;
+    id = rply.cnid;
+
+    /* Prepare request data */
+    memset(&rqst, 0, sizeof(struct cnid_dbd_rqst));
+    memset(&rply, 0, sizeof(struct cnid_dbd_rply));
+    rqst.did = did;
+    rqst.cnid = id;
+    if ( ! (myvol->v_flags & AFPVOL_NODEV))
+        rqst.dev = sp->st_dev;
+    rqst.ino = sp->st_ino;
+    rqst.type = S_ISDIR(sp->st_mode) ? 1 : 0;
+    rqst.name = (char *)newname;
+    rqst.namelen = strlen(newname);
+
+    /* Update the database */
+    ret = dbd_update(dbd, &rqst, &rply);
+    if (dbif_txn_close(dbd, ret) != 0)
+        return -1;
+    if (rply.result != CNID_DBD_RES_OK)
+        return -1;
+
+    return 0;
+}
+
 /*
   Check for .AppleDouble file, create if missing
 */
-static int check_adfile(const char *fname, const struct stat *st)
+static int check_adfile(const char *fname, const struct stat *st, const char **newname)
 {
     int ret;
     int adflags = ADFLAGS_HF;
     struct adouble ad;
     const char *adname;
 
+    *newname = NULL;
+
     if (myvol->v_adouble == AD_VERSION_EA) {
         if (!(dbd_flags & DBD_FLAGS_V2TOEA))
             return 0;
-        if (ad_convert(fname, st, myvol) != 0) {
+        if (ad_convert(fname, st, myvol, newname) != 0) {
             switch (errno) {
             case ENOENT:
                 break;
@@ -897,21 +922,21 @@ static int dbd_readdir(int volroot, cnid_t did)
            Tests
         **************************************************************************/
 
-        /* Check encoding */
-        if ( -1 == (encoding_ok = check_name_encoding(ep->d_name)) ) {
-            /* If its a file: skipp all other tests now ! */
-            /* For dirs we could try to get a CNID for it and recurse, but currently I prefer not to */
-            continue;
-        }
-
         /* Check for appledouble file, create if missing, but only if we have addir */
+        const char *name = NULL;
         adfile_ok = -1;
         if (ADDIR_OK)
-            adfile_ok = check_adfile(ep->d_name, &st);
+            adfile_ok = check_adfile(ep->d_name, &st, &name);
+
+        if (name == NULL) {
+            name = ep->d_name;
+        } else {
+            update_cnid(did, &st, ep->d_name, name);
+        }
 
         if ( ! nocniddb) {
             /* Check CNIDs */
-            cnid = check_cnid(ep->d_name, did, &st, adfile_ok);
+            cnid = check_cnid(name, did, &st, adfile_ok);
 
             /* Now add this object to our rebuild dbd */
             if (cnid && dbd_rebuild) {
@@ -922,7 +947,7 @@ static int dbd_readdir(int volroot, cnid_t did)
                     return -1;
                 if (rply.result != CNID_DBD_RES_OK) {
                     dbd_log( LOGSTD, "Fatal error adding CNID: %u for '%s/%s' to in-memory rebuild-db",
-                             cnid, cwdbuf, ep->d_name);
+                             cnid, cwdbuf, name);
                     return -1;
                 }
                 count++;
@@ -938,20 +963,20 @@ static int dbd_readdir(int volroot, cnid_t did)
 
         /* Check EA files */
         if (myvol->v_vfs_ea == AFPVOL_EA_AD)
-            check_eafiles(ep->d_name);
+            check_eafiles(name);
 
         /**************************************************************************
           Recursion
         **************************************************************************/
         if (S_ISDIR(st.st_mode) && (cnid || nocniddb)) { /* If we have no cnid for it we cant recur */
             strcat(cwdbuf, "/");
-            strcat(cwdbuf, ep->d_name);
+            strcat(cwdbuf, name);
             dbd_log( LOGDEBUG, "Entering directory: %s", cwdbuf);
             if (-1 == (cwd = open(".", O_RDONLY))) {
                 dbd_log( LOGSTD, "Cant open directory '%s': %s", cwdbuf, strerror(errno));
                 continue;
             }
-            if (0 != chdir(ep->d_name)) {
+            if (0 != chdir(name)) {
                 dbd_log( LOGSTD, "Cant chdir to directory '%s': %s", cwdbuf, strerror(errno));
                 close(cwd);
                 continue;
@@ -1002,7 +1027,7 @@ static int scanvol(struct vol *vol, dbd_flags_t flags)
     if ((myvol->v_adouble == AD_VERSION_EA) && (dbd_flags & DBD_FLAGS_V2TOEA)) {
         if (lstat(".", &st) != 0)
             return -1;
-        if (ad_convert(".", &st, vol) != 0) {
+        if (ad_convert(".", &st, vol, NULL) != 0) {
             switch (errno) {
             case ENOENT:
                 break;
index 5b276a5a27a2e8255266eb5bbf810e3c0b19c2b8..f95279d7aa7779ada385ea7642799aad682b832e 100644 (file)
@@ -403,8 +403,11 @@ extern int ad_stat        (const char *, struct stat *);
 extern int ad_metadata    (const char *, int, struct adouble *);
 extern int ad_metadataat  (int, const char *, int, struct adouble *);
 extern mode_t ad_hf_mode(mode_t mode);
-extern int ad_convert(const char *path, const struct stat *sp, const struct vol *vol);
 extern int ad_valid_header_osx(const char *path);
+
+/* ad_conv.c */
+extern int ad_convert(const char *path, const struct stat *sp, const struct vol *vol, const char **newpath);
+
 /* ad_read.c/ad_write.c */
 extern int     sys_ftruncate(int fd, off_t length);
 extern ssize_t ad_read(struct adouble *, uint32_t, off_t, char *, size_t);
index d8948500e8eb86d57df8fc95236d7790016fd0f0..f5e995d28319c2be8665d2896f422c70eab35342 100644 (file)
@@ -114,8 +114,6 @@ struct vol {
 #define AFPVOL_NOV2TOEACONV (1 << 5) /* no adouble:v2 to adouble:ea conversion */
 #define AFPVOL_UNIX_CTXT (1 << 6)   /* volume created by getvolbypath ie UNIX access, not afpd AFP user session */
 #define AFPVOL_RO        (1 << 8)   /* read-only volume */
-#define AFPVOL_NOHEX     (1 << 10)  /* don't do :hex translation */
-#define AFPVOL_USEDOTS   (1 << 11)  /* use real dots */
 #define AFPVOL_NOSTAT    (1 << 16)  /* advertise the volume even if we can't stat() it
                                      * maybe because it will be mounted later in preexec */
 #define AFPVOL_UNIX_PRIV (1 << 17)  /* support unix privileges */
index 6602926b6328986453cb395bbb9c476bdf582aca..49144a2aa62831042f33efff428316378d724b60 100644 (file)
@@ -2,7 +2,17 @@
 
 noinst_LTLIBRARIES = libadouble.la
 
-libadouble_la_SOURCES = ad_open.c ad_flush.c ad_read.c ad_write.c ad_size.c \
-       ad_mmap.c ad_lock.c ad_date.c ad_attr.c ad_sendfile.c
+libadouble_la_SOURCES = \
+       ad_attr.c \
+       ad_conv.c \
+       ad_date.c \
+       ad_flush.c \
+       ad_lock.c \
+       ad_mmap.c \
+       ad_open.c \
+       ad_read.c \
+       ad_sendfile.c \
+       ad_size.c \
+       ad_write.c
 
 noinst_HEADERS = ad_lock.h
diff --git a/libatalk/adouble/ad_conv.c b/libatalk/adouble/ad_conv.c
new file mode 100644 (file)
index 0000000..10284db
--- /dev/null
@@ -0,0 +1,247 @@
+/*
+ * Copyright (c) 2012 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.
+ */
+
+/*!
+ * @file
+ * Part of Netatalk's AppleDouble implementatation
+ * @sa include/atalk/adouble.h
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include <errno.h>
+#include <sys/param.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <arpa/inet.h>
+
+#include <atalk/logger.h>
+#include <atalk/adouble.h>
+#include <atalk/util.h>
+#include <atalk/unix.h>
+#include <atalk/ea.h>
+#include <atalk/bstrlib.h>
+#include <atalk/bstradd.h>
+#include <atalk/compat.h>
+#include <atalk/errchk.h>
+#include <atalk/volume.h>
+
+#include "ad_lock.h"
+
+static char emptyfilad[32] = {0,0,0,0,0,0,0,0,
+                              0,0,0,0,0,0,0,0,
+                              0,0,0,0,0,0,0,0,
+                              0,0,0,0,0,0,0,0};
+
+static char emptydirad[32] = {0,0,0,0,0,0,0,0,
+                              0,0,0,0,0,0,1,0,
+                              0,0,0,0,0,0,0,0,
+                              0,0,0,0,0,0,0,0};
+
+static int ad_conv_v22ea_hf(const char *path, const struct stat *sp, const struct vol *vol)
+{
+    EC_INIT;
+    struct adouble adv2;
+    struct adouble adea;
+    const char *adpath;
+    int adflags;
+    uint32_t ctime, mtime, afpinfo = 0;
+    char *emptyad;
+
+    LOG(log_debug, logtype_default,"ad_conv_v22ea_hf(\"%s\"): BEGIN", fullpathname(path));
+
+    ad_init(&adea, vol);
+    ad_init_old(&adv2, AD_VERSION2, adea.ad_options);
+    adflags = S_ISDIR(sp->st_mode) ? ADFLAGS_DIR : 0;
+
+    /* Open and lock adouble:v2 file */
+    EC_ZERO( ad_open(&adv2, path, adflags | ADFLAGS_HF | ADFLAGS_RDWR) );
+
+    EC_NEG1_LOG( ad_tmplock(&adv2, ADEID_RFORK, ADLOCK_WR | ADLOCK_FILELOCK, 0, 0, 0) );
+    EC_NEG1_LOG( adv2.ad_ops->ad_header_read(path, &adv2, sp) );
+
+    /* Check if it's a non-empty header */
+    if (S_ISREG(sp->st_mode))
+        emptyad = &emptyfilad[0];
+    else
+        emptyad = &emptydirad[0];
+
+    if (ad_getentrylen(&adv2, ADEID_COMMENT) != 0)
+        goto copy;
+    if (ad_getentryoff(&adv2, ADEID_FINDERI)
+        && (ad_getentrylen(&adv2, ADEID_FINDERI) == ADEDLEN_FINDERI)
+        && (memcmp(ad_entry(&adv2, ADEID_FINDERI), emptyad, ADEDLEN_FINDERI) != 0))
+        goto copy;
+    if (ad_getentryoff(&adv2, ADEID_FILEDATESI)) {
+        EC_ZERO_LOG( ad_getdate(&adv2, AD_DATE_CREATE | AD_DATE_UNIX, &ctime) );
+        EC_ZERO_LOG( ad_getdate(&adv2, AD_DATE_MODIFY | AD_DATE_UNIX, &mtime) );
+        if ((ctime != mtime) || (mtime != sp->st_mtime))
+            goto copy;
+    }
+    if (ad_getentryoff(&adv2, ADEID_AFPFILEI)) {
+        if (memcmp(ad_entry(&adv2, ADEID_AFPFILEI), &afpinfo, ADEDLEN_AFPFILEI) != 0)
+            goto copy;
+    }
+
+    LOG(log_debug, logtype_default,"ad_conv_v22ea_hf(\"%s\"): default adouble", fullpathname(path), ret);
+    goto EC_CLEANUP;
+
+copy:
+    /* Create a adouble:ea meta EA */
+    LOG(log_debug, logtype_default,"ad_conv_v22ea_hf(\"%s\"): copying adouble", fullpathname(path), ret);
+    EC_ZERO_LOG( ad_open(&adea, path, adflags | ADFLAGS_HF | ADFLAGS_RDWR | ADFLAGS_CREATE) );
+    EC_ZERO_LOG( ad_copy_header(&adea, &adv2) );
+    ad_flush(&adea);
+
+EC_CLEANUP:
+    EC_ZERO_LOG( ad_close(&adv2, ADFLAGS_HF | ADFLAGS_SETSHRMD) );
+    EC_ZERO_LOG( ad_close(&adea, ADFLAGS_HF | ADFLAGS_SETSHRMD) );
+    LOG(log_debug, logtype_default,"ad_conv_v22ea_hf(\"%s\"): END: %d", fullpathname(path), ret);
+    EC_EXIT;
+}
+
+static int ad_conv_v22ea_rf(const char *path, const struct stat *sp, const struct vol *vol)
+{
+    EC_INIT;
+    struct adouble adv2;
+    struct adouble adea;
+
+    LOG(log_debug, logtype_default,"ad_conv_v22ea_rf(\"%s\"): BEGIN", fullpathname(path));
+
+    if (S_ISDIR(sp->st_mode))
+        return 0;
+
+    ad_init(&adea, vol);
+    ad_init_old(&adv2, AD_VERSION2, adea.ad_options);
+
+    /* Open and lock adouble:v2 file */
+    EC_ZERO( ad_open(&adv2, path, ADFLAGS_HF | ADFLAGS_RF | ADFLAGS_RDWR) );
+
+    if (adv2.ad_rlen > 0) {
+        EC_NEG1_LOG( ad_tmplock(&adv2, ADEID_RFORK, ADLOCK_WR | ADLOCK_FILELOCK, 0, 0, 0) );
+
+        /* Create a adouble:ea resource fork */
+        EC_ZERO_LOG( ad_open(&adea, path, ADFLAGS_HF | ADFLAGS_RF | ADFLAGS_RDWR | ADFLAGS_CREATE, 0666) );
+
+        EC_ZERO_LOG( copy_fork(ADEID_RFORK, &adea, &adv2) );
+        adea.ad_rlen = adv2.ad_rlen;
+        ad_flush(&adea);
+    }
+
+EC_CLEANUP:
+    EC_ZERO_LOG( ad_close(&adv2, ADFLAGS_HF | ADFLAGS_RF) );
+    EC_ZERO_LOG( ad_close(&adea, ADFLAGS_HF | ADFLAGS_RF) );
+    LOG(log_debug, logtype_default,"ad_conv_v22ea_rf(\"%s\"): END: %d", fullpathname(path), ret);
+    EC_EXIT;
+}
+
+static int ad_conv_v22ea(const char *path, const struct stat *sp, const struct vol *vol)
+{
+    EC_INIT;
+    const char *adpath;
+    int adflags = S_ISDIR(sp->st_mode) ? ADFLAGS_DIR : 0;
+
+    EC_ZERO( ad_conv_v22ea_hf(path, sp, vol) );
+    EC_ZERO( ad_conv_v22ea_rf(path, sp, vol) );
+
+    EC_NULL( adpath = ad_path(path, adflags) );
+    LOG(log_debug, logtype_default,"ad_conv_v22ea_hf(\"%s\"): deleting adouble:v2 file: \"%s\"",
+        path, fullpathname(adpath));
+
+    become_root();
+    EC_ZERO_LOG( unlink(adpath) );
+    unbecome_root();
+
+EC_CLEANUP:
+    if (errno == ENOENT)
+        EC_STATUS(0);
+    EC_EXIT;
+}
+
+/*!
+ * Remove hexencoded dots and slashes (":2e" and ":2f")
+ */
+static int ad_conv_dehex(const char *path, const struct stat *sp, const struct vol *vol, const char **newpathp)
+{
+    EC_INIT;
+    static char buf[MAXPATHLEN];
+    const char *adpath, *p;
+    int adflags = S_ISDIR(sp->st_mode) ? ADFLAGS_DIR : 0;
+    bstring newpath = NULL;
+
+    LOG(log_debug, logtype_default,"ad_conv_dehex(\"%s\"): BEGIN", fullpathname(path));
+
+    *newpathp = NULL;
+
+    if ((p = strchr(path, ':')) == NULL)
+        goto EC_CLEANUP;
+
+    EC_NULL( newpath = bfromcstr(path) );
+
+    EC_ZERO( bfindreplace(newpath, bfromcstr(":2e"), bfromcstr("."), 0) );
+    EC_ZERO( bfindreplace(newpath, bfromcstr(":2f"), bfromcstr(":"), 0) );
+    
+    become_root();
+    if (adflags != ADFLAGS_DIR)
+        rename(vol->ad_path(path, 0), vol->ad_path(bdata(newpath), 0));
+    rename(path, bdata(newpath));
+    unbecome_root();
+
+    strlcpy(buf, bdata(newpath), sizeof(buf));
+    *newpathp = buf;
+
+EC_CLEANUP:
+    if (newpath)
+        bdestroy(newpath);
+    EC_EXIT;
+}
+
+/*!
+ * AppleDouble and encoding conversion on the fly
+ *
+ * @param path      (r) path to file or directory
+ * @param sp        (r) stat(path)
+ * @param vol       (r) volume handle
+ * @param newpath   (w) if encoding changed, new name. Can be NULL.
+ *
+ * @returns         -1 on internal error, otherwise 0. newpath is NULL if no character conversion was done,
+ *                  otherwise newpath points to a static string with the converted name
+ */
+int ad_convert(const char *path, const struct stat *sp, const struct vol *vol, const char **newpath)
+{
+    EC_INIT;
+    const char *p;
+
+    LOG(log_debug, logtype_default,"ad_convert(\"%s\"): BEGIN", fullpathname(path));
+
+    if (newpath)
+        *newpath = NULL;
+
+    if ((vol->v_adouble == AD_VERSION_EA) && !(vol->v_flags & AFPVOL_NOV2TOEACONV))
+        EC_ZERO( ad_conv_v22ea(path, sp, vol) );
+
+    if (vol->v_adouble == AD_VERSION_EA) {
+        EC_ZERO( ad_conv_dehex(path, sp, vol, &p) );
+        if (p && newpath)
+            *newpath = p;
+    }
+
+EC_CLEANUP:
+    LOG(log_debug, logtype_default,"ad_convert(\"%s\"): END: %d", fullpathname(path), ret);
+    EC_EXIT;
+}
+
index 196053ee31ab288601b4c365f56da42600c00263..79016b5feac43e1d6fed2110e2d5e320610470e9 100644 (file)
@@ -809,111 +809,6 @@ static int ad2openflags(const struct adouble *ad, int adfile, int adflags)
     return oflags;
 }
 
-static char emptyfilad[32] = {0,0,0,0,0,0,0,0,
-                              0,0,0,0,0,0,0,0,
-                              0,0,0,0,0,0,0,0,
-                              0,0,0,0,0,0,0,0};
-
-static char emptydirad[32] = {0,0,0,0,0,0,0,0,
-                              0,0,0,0,0,0,1,0,
-                              0,0,0,0,0,0,0,0,
-                              0,0,0,0,0,0,0,0};
-
-static int ad_conv_v22ea_hf(const char *path, const struct stat *sp, const struct vol *vol)
-{
-    EC_INIT;
-    struct adouble adv2;
-    struct adouble adea;
-    const char *adpath;
-    int adflags;
-    uint32_t ctime, mtime, afpinfo = 0;
-    char *emptyad;
-
-    LOG(log_debug, logtype_default,"ad_conv_v22ea_hf(\"%s\"): BEGIN", fullpathname(path));
-
-    ad_init(&adea, vol);
-    ad_init_old(&adv2, AD_VERSION2, adea.ad_options);
-    adflags = S_ISDIR(sp->st_mode) ? ADFLAGS_DIR : 0;
-
-    /* Open and lock adouble:v2 file */
-    EC_ZERO( ad_open(&adv2, path, adflags | ADFLAGS_HF | ADFLAGS_RDWR) );
-    EC_NEG1_LOG( ad_tmplock(&adv2, ADEID_RFORK, ADLOCK_WR | ADLOCK_FILELOCK, 0, 0, 0) );
-    EC_NEG1_LOG( adv2.ad_ops->ad_header_read(path, &adv2, sp) );
-
-    /* Check if it's a non-empty header */
-    if (S_ISREG(sp->st_mode))
-        emptyad = &emptyfilad[0];
-    else
-        emptyad = &emptydirad[0];
-
-    if (ad_getentrylen(&adv2, ADEID_COMMENT) != 0)
-        goto copy;
-    if (ad_getentryoff(&adv2, ADEID_FINDERI)
-        && (ad_getentrylen(&adv2, ADEID_FINDERI) == ADEDLEN_FINDERI)
-        && (memcmp(ad_entry(&adv2, ADEID_FINDERI), emptyad, ADEDLEN_FINDERI) != 0))
-        goto copy;
-    if (ad_getentryoff(&adv2, ADEID_FILEDATESI)) {
-        EC_ZERO_LOG( ad_getdate(&adv2, AD_DATE_CREATE | AD_DATE_UNIX, &ctime) );
-        EC_ZERO_LOG( ad_getdate(&adv2, AD_DATE_MODIFY | AD_DATE_UNIX, &mtime) );
-        if ((ctime != mtime) || (mtime != sp->st_mtime))
-            goto copy;
-    }
-    if (ad_getentryoff(&adv2, ADEID_AFPFILEI)) {
-        if (memcmp(ad_entry(&adv2, ADEID_AFPFILEI), &afpinfo, ADEDLEN_AFPFILEI) != 0)
-            goto copy;
-    }
-
-    LOG(log_debug, logtype_default,"ad_conv_v22ea_hf(\"%s\"): default adouble", fullpathname(path), ret);
-    goto EC_CLEANUP;
-
-copy:
-    /* Create a adouble:ea meta EA */
-    LOG(log_debug, logtype_default,"ad_conv_v22ea_hf(\"%s\"): copying adouble", fullpathname(path), ret);
-    EC_ZERO_LOG( ad_open(&adea, path, adflags | ADFLAGS_HF | ADFLAGS_RDWR | ADFLAGS_CREATE) );
-    EC_ZERO_LOG( ad_copy_header(&adea, &adv2) );
-    ad_flush(&adea);
-
-EC_CLEANUP:
-    EC_ZERO_LOG( ad_close(&adv2, ADFLAGS_HF | ADFLAGS_SETSHRMD) );
-    EC_ZERO_LOG( ad_close(&adea, ADFLAGS_HF | ADFLAGS_SETSHRMD) );
-    LOG(log_debug, logtype_default,"ad_conv_v22ea_hf(\"%s\"): END: %d", fullpathname(path), ret);
-    EC_EXIT;
-}
-
-static int ad_conv_v22ea_rf(const char *path, const struct stat *sp, const struct vol *vol)
-{
-    EC_INIT;
-    struct adouble adv2;
-    struct adouble adea;
-
-    LOG(log_debug, logtype_default,"ad_conv_v22ea_rf(\"%s\"): BEGIN", fullpathname(path));
-
-    if (S_ISDIR(sp->st_mode))
-        return 0;
-
-    ad_init(&adea, vol);
-    ad_init_old(&adv2, AD_VERSION2, adea.ad_options);
-
-    /* Open and lock adouble:v2 file */
-    EC_ZERO( ad_open(&adv2, path, ADFLAGS_HF | ADFLAGS_RF | ADFLAGS_RDWR) );
-    if (adv2.ad_rlen > 0) {
-        EC_NEG1_LOG( ad_tmplock(&adv2, ADEID_RFORK, ADLOCK_WR | ADLOCK_FILELOCK, 0, 0, 0) );
-
-        /* Create a adouble:ea resource fork */
-        EC_ZERO_LOG( ad_open(&adea, path, ADFLAGS_HF | ADFLAGS_RF | ADFLAGS_RDWR | ADFLAGS_CREATE, 0666) );
-
-        EC_ZERO_LOG( copy_fork(ADEID_RFORK, &adea, &adv2) );
-        adea.ad_rlen = adv2.ad_rlen;
-        ad_flush(&adea);
-    }
-
-EC_CLEANUP:
-    EC_ZERO_LOG( ad_close(&adv2, ADFLAGS_HF | ADFLAGS_RF) );
-    EC_ZERO_LOG( ad_close(&adea, ADFLAGS_HF | ADFLAGS_RF) );
-    LOG(log_debug, logtype_default,"ad_conv_v22ea_rf(\"%s\"): END: %d", fullpathname(path), ret);
-    EC_EXIT;
-}
-
 static int ad_open_df(const char *path, int adflags, mode_t mode, struct adouble *ad)
 {
     EC_INIT;
@@ -1929,33 +1824,6 @@ EC_CLEANUP:
     return ret;
 }
 
-int ad_convert(const char *path, const struct stat *sp, const struct vol *vol)
-{
-    EC_INIT;
-    const char *adpath;
-    int adflags = S_ISDIR(sp->st_mode) ? ADFLAGS_DIR : 0;
-
-    LOG(log_debug, logtype_default,"ad_convert(\"%s\"): BEGIN", fullpathname(path));
-
-    if (!(vol->v_adouble == AD_VERSION_EA) || (vol->v_flags & AFPVOL_NOV2TOEACONV))
-        goto EC_CLEANUP;
-
-    EC_ZERO( ad_conv_v22ea_hf(path, sp, vol) );
-    EC_ZERO( ad_conv_v22ea_rf(path, sp, vol) );
-
-    EC_NULL( adpath = ad_path(path, adflags) );
-    LOG(log_debug, logtype_default,"ad_conv_v22ea_hf(\"%s\"): deleting adouble:v2 file: \"%s\"",
-        path, fullpathname(adpath));
-
-    become_root();
-    EC_ZERO_LOG( unlink(adpath) );
-    unbecome_root();
-
-EC_CLEANUP:
-    LOG(log_debug, logtype_default,"ad_convert(\"%s\"): END: %d", fullpathname(path), ret);
-    EC_EXIT;
-}
-
 /* build a resource fork mode from the data fork mode:
  * remove X mode and extend header to RW if R or W (W if R for locking),
  */
index fe33a21784f3eeb0125c33c99d0282c4f43f3665..455a72622ef9fb0f2aa7543aec6bfe6feb651c57 100644 (file)
@@ -772,13 +772,11 @@ static size_t pull_charset_flags (charset_t from_set, charset_t cap_set, const c
     o_len=destlen;
 
     while (i_len > 0) {
-        if ((option & CONV_UNESCAPEHEX)) {
-            for (j = 0; j < i_len; ++j) {
-                if (inbuf[j] == ':') break;
-            }
-            j = i_len - j;
-            i_len -= j;
-        }
+        for (j = 0; j < i_len; ++j)
+            if (inbuf[j] == ':')
+                break;
+        j = i_len - j;
+        i_len -= j;
 
         if (i_len > 0 &&
             atalk_iconv(descriptor, &inbuf, &i_len, &outbuf, &o_len) == (size_t)-1) {
@@ -806,36 +804,48 @@ static size_t pull_charset_flags (charset_t from_set, charset_t cap_set, const c
         }
 
         if (j) {
-            /* we're at the start on an hex encoded ucs2 char */
-            char h[MAXPATHLEN];
-            size_t hlen = 0;
-
+            /* we have a ':' */
             i_len = j, j = 0;
-            while (i_len >= 3 && inbuf[0] == ':' &&
-                   isxdigit(inbuf[1]) && isxdigit(inbuf[2])) {
-                h[hlen++] = (hextoint(inbuf[1]) << 4) | hextoint(inbuf[2]);
-                inbuf += 3;
-                i_len -= 3;
-            }
-            if (hlen) {
-                const char *h_buf = h;
-                if (atalk_iconv(descriptor_cap, &h_buf, &hlen, &outbuf, &o_len) == (size_t)-1) {
-                    i_len += hlen * 3;
-                    inbuf -= hlen * 3;
-                    if (errno == EILSEQ && (option & CONV_IGNORE)) {
+
+            if ((option & CONV_UNESCAPEHEX)) {
+                /* treat it as a CAP hex encoded char */
+                char h[MAXPATHLEN];
+                size_t hlen = 0;
+
+                while (i_len >= 3 && inbuf[0] == ':' &&
+                       isxdigit(inbuf[1]) && isxdigit(inbuf[2])) {
+                    h[hlen++] = (hextoint(inbuf[1]) << 4) | hextoint(inbuf[2]);
+                    inbuf += 3;
+                    i_len -= 3;
+                }
+                if (hlen) {
+                    const char *h_buf = h;
+                    if (atalk_iconv(descriptor_cap, &h_buf, &hlen, &outbuf, &o_len) == (size_t)-1) {
+                        i_len += hlen * 3;
+                        inbuf -= hlen * 3;
+                        if (errno == EILSEQ && (option & CONV_IGNORE)) {
+                            *flags |= CONV_REQMANGLE;
+                            return destlen - o_len;
+                        }
+                        goto end;
+                    }
+                } else {
+                    /* We have an invalid :xx sequence */
+                    errno = EILSEQ;
+                    if ((option & CONV_IGNORE)) {
                         *flags |= CONV_REQMANGLE;
                         return destlen - o_len;
                     }
                     goto end;
                 }
             } else {
-                /* We have an invalid :xx sequence */
-                errno = EILSEQ;
-                if ((option & CONV_IGNORE)) {
-                    *flags |= CONV_REQMANGLE;
-                    return destlen - o_len;
-                }
-                goto end;
+                /* a ':' that we just convert to a '/' */
+                ucs2_t slash = 0x002f;
+                memcpy(outbuf, &slash, sizeof(ucs2_t));
+                outbuf += 2;
+                o_len -= 2;
+                inbuf++;
+                i_len--;
             }
         }
     }
@@ -897,25 +907,23 @@ static size_t push_charset_flags (charset_t to_set, charset_t cap_set, char* src
     }
 
     while (i_len >= 2) {
-        if ((option & CONV_ESCAPEHEX)) {
-            for (i = 0; i < i_len; i += 2) {
-                ucs2_t c = SVAL(inbuf, i);
-                switch (c) {
-                case 0x003a: /* 0x003a = ':' */
-                    if ( ! (option & CONV_ALLOW_COLON)) {
-                        errno = EILSEQ;
-                        goto end;
-                    }
-                    escch = c;
-                    j = i_len - i;
-                    i_len = i;
-                    break;
-                case 0x002f: /* 0x002f = '/' */
-                    escch = c;
-                    j = i_len - i;
-                    i_len = i;
-                    break;
+        for (i = 0; i < i_len; i += 2) {
+            ucs2_t c = SVAL(inbuf, i);
+            switch (c) {
+            case 0x003a: /* 0x003a = ':' */
+                if ( ! (option & CONV_ALLOW_COLON)) {
+                    errno = EILSEQ;
+                    goto end;
                 }
+                escch = c;
+                j = i_len - i;
+                i_len = i;
+                break;
+            case 0x002f: /* 0x002f = '/' */
+                escch = c;
+                j = i_len - i;
+                i_len = i;
+                break;
             }
         }
         while (i_len > 0 &&
@@ -968,35 +976,53 @@ static size_t push_charset_flags (charset_t to_set, charset_t cap_set, char* src
         }
 
         if (j) {
+            /* we have a ':' or '/' */
             i_len = j, j = 0;
-            if (o_len < 3) {
-                errno = E2BIG;
-                goto end;
-            }
-            switch (escch) {
-            case '/':
-                *outbuf++ = ':';
-                *outbuf++ = '2';
-                *outbuf++ = 'f';
-                break;
-            case ':':
-                *outbuf++ = ':';
-                *outbuf++ = '3';
-                *outbuf++ = 'a';
-                break;
-            default:
-                /*
-                 *  THIS SHOULD NEVER BE REACHED !!!
-                 *  As a safety net I put in a ' ' here
-                 */
-                *outbuf++ = ':';
-                *outbuf++ = '2';
-                *outbuf++ = '0';
-                break;
+
+            if ((option & CONV_ESCAPEHEX)) {
+                /* CAP hex encode it */
+                if (o_len < 3) {
+                    errno = E2BIG;
+                    goto end;
+                }
+                switch (escch) {
+                case '/':
+                    *outbuf++ = ':';
+                    *outbuf++ = '2';
+                    *outbuf++ = 'f';
+                    break;
+                case ':':
+                    *outbuf++ = ':';
+                    *outbuf++ = '3';
+                    *outbuf++ = 'a';
+                    break;
+                default:
+                    /*
+                     *  THIS SHOULD NEVER BE REACHED !!!
+                     *  As a safety net I put in a ' ' here
+                     */
+                    *outbuf++ = ':';
+                    *outbuf++ = '2';
+                    *outbuf++ = '0';
+                    break;
+                }
+                o_len -= 3;
+                inbuf += 2;
+                i_len -= 2;
+            } else {
+                switch (escch) {
+                case '/':
+                case ':':
+                    *outbuf++ = ':';
+                    break;
+                default: /* should never be reached */
+                    *outbuf++ = ' ';
+                    break;
+                }
+                o_len--;
+                inbuf += 2;
+                i_len -= 2;
             }
-            o_len -= 3;
-            inbuf += 2;
-            i_len -= 2;
         }
     }
     if (i_len > 0) errno = EINVAL;
index af5a21ae8625c02407f93d9d9566748b63c30b18..d06be264051bdd9de82934deddfa753bd4ec32ea 100644 (file)
@@ -719,10 +719,6 @@ static struct vol *creatvol(AFPObj *obj,
 
     if (getoption_bool(obj->iniconfig, section, "read only", preset, 0))
         volume->v_flags |= AFPVOL_RO;
-    if (!getoption_bool(obj->iniconfig, section, "hex encoding", preset, 1))
-        volume->v_flags |= AFPVOL_NOHEX;
-    if (getoption_bool(obj->iniconfig, section, "use dots", preset, 1))
-        volume->v_flags |= AFPVOL_USEDOTS;
     if (getoption_bool(obj->iniconfig, section, "invisible dots", preset, 0))
         volume->v_flags |= AFPVOL_INV_DOTS;
     if (!getoption_bool(obj->iniconfig, section, "stat vol", preset, 1))
@@ -771,10 +767,6 @@ static struct vol *creatvol(AFPObj *obj,
         volume->v_ad_options |= ADVOL_INVDOTS;
 
     /* Mac to Unix conversion flags*/
-    if (!(volume->v_flags & AFPVOL_NOHEX))
-        volume->v_mtou_flags |= CONV_ESCAPEHEX;
-    if (!(volume->v_flags & AFPVOL_USEDOTS))
-        volume->v_mtou_flags |= CONV_ESCAPEDOTS;
     if ((volume->v_flags & AFPVOL_EILSEQ))
         volume->v_mtou_flags |= CONV__EILSEQ;
 
@@ -784,7 +776,7 @@ static struct vol *creatvol(AFPObj *obj,
         volume->v_mtou_flags |= CONV_TOLOWER;
 
     /* Unix to Mac conversion flags*/
-    volume->v_utom_flags = CONV_IGNORE | CONV_UNESCAPEHEX;
+    volume->v_utom_flags = CONV_IGNORE;
     if ((volume->v_casefold & AFPVOL_UTOMUPPER))
         volume->v_utom_flags |= CONV_TOUPPER;
     else if ((volume->v_casefold & AFPVOL_UTOMLOWER))
index 738e3b837851abc278296f05ebe6d038559dcbc6..8495d8c22fba19dd88789b82c6822bfb4a4fb3d6 100644 (file)
@@ -103,9 +103,6 @@ static int validupath_adouble(VFS_FUNC_ARGS_VALIDUPATH)
     if (name[0] != '.')
         return 1;
     
-    if (!(vol->v_flags & AFPVOL_USEDOTS))
-        return 0;
-        
     return netatalk_name(name) && strcmp(name,".AppleDouble") && strcasecmp(name,".Parent");
 }                                           
 
@@ -467,9 +464,6 @@ static int validupath_ea(VFS_FUNC_ARGS_VALIDUPATH)
     if (name[0] != '.')
         return 1;
     
-    if (!(vol->v_flags & AFPVOL_USEDOTS))
-        return 0;
-
 #ifndef HAVE_EAFD
     if (name[1] == '_')
         return ad_valid_header_osx(name);
index 0506a802aff7d6a015dbf6ff330aa36393ad804c..c96eddb828d95ab0c585d260245112ec3f1a9cc8 100644 (file)
@@ -942,17 +942,9 @@ is performed when accessing filesystems from clients\&. This is generally useful
 on volumes and do the conversion with that\&. Then this option can be set to no\&.
 .RE
 .PP
-hex encoding = \fIBOOLEAN\fR (default: \fIyes\fR) \fB(V)\fR
-.RS 4
-Whether :hex encoding is done for file and directory names containing the character
-/\&. Setting this option to no makes the
-/
-character illegal\&.
-.RE
-.PP
 invisible dots = \fIBOOLEAN\fR (default: \fIno\fR) \fB(V)\fR
 .RS 4
-make dot files invisible\&. If "\fBuse dots = no\fR", this parameter is not unnecessary\&.
+make dot files invisible\&.
 .RE
 .PP
 network ids = \fIBOOLEAN\fR (default: \fIyes\fR) \fB(V)\fR
@@ -1003,12 +995,6 @@ Whether to use AFP3 UNIX privileges\&. This should be set for OS X clients\&. Se
 and
 \fBumask\fR\&.
 .RE
-.PP
-use dots = \fIBOOLEAN\fR (default: \fIyes\fR) \fB(V)\fR
-.RS 4
-Whether to do :hex translation for dot files\&. See also
-\fBinvisible dots\fR\&.
-.RE
 .SH "CNID BACKENDS"
 .PP
 The AFP protocol mostly refers to files and directories by ID and not by name\&. Netatalk needs a way to store these ID\'s in a persistent way, to achieve this several different CNID backends are available\&. The CNID Databases are by default located in the