]> arthur.barton.de Git - netatalk.git/commitdiff
Add support for long filename mangling. Basically, tis code will take
authorjmarcus <jmarcus>
Wed, 29 May 2002 18:02:57 +0000 (18:02 +0000)
committerjmarcus <jmarcus>
Wed, 29 May 2002 18:02:57 +0000 (18:02 +0000)
filenames greater than MACFILELEN characters, and mangle them much like
DOS does.  The mangled filenames are stored in a Berkeley database per
volume.

NOTE: This code is _not_ tested, and may cause data loss.  Use at your own
risk.  To enable it, configure with --with-mangling.

15 files changed:
NEWS
acconfig.h
configure.in
etc/afpd/Makefile.am
etc/afpd/desktop.c
etc/afpd/mangle.c [new file with mode: 0644]
etc/afpd/mangle.h [new file with mode: 0644]
etc/afpd/ofork.c
include/atalk/cnid.h
libatalk/cnid/Makefile.am
libatalk/cnid/cnid_close.c
libatalk/cnid/cnid_mangle_add.c [new file with mode: 0644]
libatalk/cnid/cnid_mangle_get.c [new file with mode: 0644]
libatalk/cnid/cnid_open.c
libatalk/cnid/cnid_private.h

diff --git a/NEWS b/NEWS
index 4cccc98f7598e39e769966c8a77fd07c88e83f8f..876e283c36f2fa971d7b298c72e3ee3012eab772 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -3,6 +3,7 @@ Changes from 1.5.3
 
 * NEW: Add the ability to enable debugging at runtime by sending afpd a
        SIGUSR1.
+* NEW: Add support for long filename mangling.
 * NEW: Add a -noslp option to disable SLP per afpd instance.
 * NEW: Added -d option for pap to enable debugging at runtime rather than
        compile time.
index a200ec1cb40eaff428a5e48d0ee0ed88e89d7fb2..19bd4f5be884855623e2de7a392a900fc092c0f2 100644 (file)
@@ -5,6 +5,7 @@
 #undef AFS
 #undef BSD4_4
 #undef CNID_DB
+#undef FILE_MANGLING
 #undef DISABLE_LOGGER
 #undef LOGFILEPATH
 #undef DEBUG
index d15bc05c365732c9f1f337049dba59b04e0c10e6..9764e236828577726ec95f02a88dee6b021bad48 100644 (file)
@@ -1,4 +1,4 @@
-dnl $Id: configure.in,v 1.157 2002-04-29 06:23:57 morgana Exp $
+dnl $Id: configure.in,v 1.158 2002-05-29 18:02:57 jmarcus Exp $
 dnl configure.in for netatalk
 
 AC_INIT(bin/adv1tov2/adv1tov2.c)
@@ -208,7 +208,6 @@ AC_ARG_ENABLE(force-uidgid,
 dnl Don't use DB3 unless it's needed
 db3_required=no
 
-
 dnl Determine DID scheme
 AC_MSG_CHECKING([for DID scheme to use])
 AC_ARG_WITH(did,
@@ -234,6 +233,20 @@ else
 fi
 AM_CONDITIONAL(COMPILE_CNID, test "x$did_scheme" = "xcnid")
 
+dnl Determine whether or not to use filename mangling
+AC_MSG_CHECKING([whether or not to use filename mangling])
+AC_ARG_WITH(mangling,
+       [ --with-mangling       enable filename mangling],
+       if test "$withval" = "yes"; then
+           if test "x$did_scheme" != "xcnid"; then
+               AC_MSG_ERROR([DID scheme must be CNID to use filename mangling])
+           else
+               AC_DEFINE(FILE_MANGLING, 1)
+               AC_MSG_RESULT([yes])
+           fi
+       fi
+)
+
 dnl Check for Berkeley DB3 library
 if test "x$db3_required" = "xyes"; then
        AC_PATH_DB3(, [AC_MSG_ERROR([Berkeley DB3 library not found!])])
index 1f13c62d493f62aea7b4fcc03fc32c82f02adbc7..03282b55e10921088252ad62ac84d8887c994611 100644 (file)
@@ -11,9 +11,9 @@ bin_PROGRAMS = test_parse_mtab
 
 afpd_SOURCES = unix.c ofork.c main.c switch.c auth.c volume.c directory.c \
         file.c enumerate.c desktop.c filedir.c fork.c appl.c gettok.c \
-        status.c afp_options.c afp_asp.c afp_dsi.c messages.c afp_config.c \
-        nfsquota.c codepage.c quota.c uam.c afs.c uid.c parse_mtab.c \
-        afp_util.c
+        mangle.c status.c afp_options.c afp_asp.c afp_dsi.c messages.c  \
+        afp_config.c nfsquota.c codepage.c quota.c uam.c afs.c uid.c  \
+        parse_mtab.c afp_util.c
 
 test_parse_mtab_SOURCES = test_parse_mtab.c parse_mtab.c
 test_parse_mtab_LDADD = $(top_builddir)/libatalk/libatalk.la
@@ -22,8 +22,8 @@ afpd_LDADD = $(top_builddir)/libatalk/libatalk.la
 afpd_LDFLAGS = -export-dynamic
 
 noinst_HEADERS = auth.h codepage.h afp_config.h desktop.h directory.h file.h \
-        filedir.h fork.h globals.h icon.h misc.h status.h switch.h uam_auth.h \
-        uid.h unix.h volume.h parse_mtab.h
+        filedir.h fork.h globals.h icon.h mangle.h misc.h status.h switch.h \
+        uam_auth.h uid.h unix.h volume.h parse_mtab.h
 
 LIBS = @LIBS@ @AFPD_LIBS@ @QUOTA_LIBS@ @SLP_LIBS@
 
index 344eb08bf9d916d3da401d1d0ed1ee3a2900945d..864cf26aa66cd478c5ece445031654120be9df79 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: desktop.c,v 1.12 2002-03-24 01:23:40 sibaz Exp $
+ * $Id: desktop.c,v 1.13 2002-05-29 18:02:59 jmarcus Exp $
  *
  * See COPYRIGHT.
  */
@@ -40,6 +40,9 @@
 #include "fork.h"
 #include "globals.h"
 #include "desktop.h"
+#ifdef FILE_MANGLING
+#include "mangle.h"
+#endif /* CNID_DB */
 
 int afp_opendt(obj, ibuf, ibuflen, rbuf, rbuflen )
 AFPObj      *obj;
@@ -611,6 +614,10 @@ char *mtoupath(const struct vol *vol, char *mpath)
         return( "." );
     }
 
+#ifdef FILE_MANGLING
+    mpath = demangle(vol, mpath);
+#endif /* FILE_MANGLING */
+
     m = mpath;
     u = upath;
     while ( *m != '\0' ) {
@@ -663,6 +670,10 @@ char *utompath(const struct vol *vol, char *upath)
     char        *m, *u;
     int          h;
 
+#ifdef FILE_MANGLING
+    upath = mangle(vol, upath);
+#endif /* FILE_MANGLING */
+
     /* do the hex conversion */
     u = upath;
     m = mpath;
diff --git a/etc/afpd/mangle.c b/etc/afpd/mangle.c
new file mode 100644 (file)
index 0000000..0a6146d
--- /dev/null
@@ -0,0 +1,115 @@
+/* 
+ * $Id: mangle.c,v 1.1 2002-05-29 18:02:59 jmarcus Exp $ 
+ *
+ * Copyright (c) 2002. Joe Marcus Clarke (marcus@marcuscom.com)
+ * All Rights Reserved.  See COPYRIGHT.
+ *
+ * mangle, demangle (filename):
+ * mangle or demangle filenames if they are greater than the max allowed
+ * characters for a given version of AFP.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#ifdef FILE_MANGLING
+#include "mangle.h"
+
+char *
+demangle(const struct vol *vol, char *mfilename) {
+       char *filename = NULL;
+       char *ext = NULL;
+       char dir[MAXPATHLEN+1];
+       char *mangle;
+
+       /* Is this really a mangled file? */
+       mangle = strstr(mfilename, MANGLE_CHAR);
+       if (!mangle) {
+           return mfilename;
+       }
+
+       ext = strrchr(mfilename, '.');
+       if (strlen(mangle) != strlen(MANGLE_CHAR) + MANGLE_LENGTH + strlen(ext)) {
+           return mfilename;
+       }
+
+       getcwd(dir, MAXPATHLEN);
+
+       if (strlen(dir) > MAXPATHLEN - strlen(mfilename) - 1) {
+           LOG(log_error, logtype_default, "demangle: Path is too large");
+           return mfilename;
+       }
+
+       strcat(dir, "/");
+       strcat(dir, mfilename);
+
+       filename = cnid_mangle_get(vol->v_db, dir);
+
+       /* No unmangled filename was found. */
+       if (filename == NULL) {
+           LOG(log_debug, logtype_default, "demangle: Unable to lookup %s in the mangle database", dir);
+           return mfilename;
+       }
+
+       return filename;
+}
+char *
+mangle(const struct vol *vol, char *filename) {
+    char *ext = NULL;
+    char mfilename[MAX_LENGTH+1];
+    char mangle_suffix[MANGLE_LENGTH+1];
+    char dir[MAXPATHLEN+1];
+    char tmp[MAXPATHLEN+1];
+    int mangle_suffix_int = 0;
+
+    /* Do we really need to mangle this filename? */
+    if (strlen(filename) <= MAX_LENGTH) {
+       return filename;
+    }
+
+    /* First, attmept to locate a file extension. */
+    ext = strrchr(filename, '.');
+
+    getcwd(dir, MAXPATHLEN);
+
+    if (strlen(dir) > MAXPATHLEN - strlen(filename) - 1) {
+       LOG(log_error, logtype_default, "mangle: path is too large");
+       return filename;
+    }
+
+    /* Check to see if we already have a mangled filename by this name. */
+    while (1) {
+       strcpy(tmp, dir);
+       strncpy(mfilename, filename, MAX_LENGTH - strlen(MANGLE_CHAR) - MANGLE_LENGTH - ((ext != NULL)?strlen(ext):0));
+       strcat(mfilename, MANGLE_CHAR);
+       (void)sprintf(mangle_suffix, "%03d", mangle_suffix_int);
+       strcat(mfilename, mangle_suffix);
+
+       if (ext) {
+               strcat(mfilename, ext);
+       }
+       
+       strcat(tmp, "/");
+       strcat(tmp, mfilename);
+
+       if (!cnid_mangle_get(vol->v_db, tmp)) {
+           break;
+       }
+       else {
+           if (++mangle_suffix_int > MAX_MANGLE_SUFFIX_LENGTH) {
+               LOG(log_error, logtype_default, "mangle: Failed to find a free mangle suffix; returning original filename");
+               return filename;
+           }
+       }
+    }
+
+    if (cnid_mangle_add(vol->v_db, mfilename, tmp) < 0) {
+       return filename;
+    }
+
+    filename = mfilename;
+
+    return filename;
+}
+#endif /* FILE_MANGLING */
diff --git a/etc/afpd/mangle.h b/etc/afpd/mangle.h
new file mode 100644 (file)
index 0000000..6010c44
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * $Id: mangle.h,v 1.1 2002-05-29 18:02:59 jmarcus Exp $
+ *
+ */
+
+#ifndef AFPD_MANGLE_H 
+#define AFPD_MANGLE_H 1
+
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#ifdef CNID_DB
+#include <atalk/cnid.h>
+#endif /* CNID_DB */
+#include <atalk/logger.h>
+
+#include "globals.h"
+#include "volume.h"
+#include "directory.h"
+
+#define MANGLE_CHAR "~"
+#define MANGLE_LENGTH 3 /* XXX This really can't be changed. */
+#define MAX_MANGLE_SUFFIX_LENGTH 999
+#define MAX_LENGTH 31
+
+extern char *mangle __P((const struct vol *, char *));
+extern char *demangle __P((const struct vol *, char *));
+
+#endif /* AFPD_MANGLE_H */
index d30d1af90104436c291aab28261400af58685987..ef2c85832a7cccae43e5dfc3a454f71ae907ac46 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: ofork.c,v 1.14 2002-05-13 04:59:36 jmarcus Exp $
+ * $Id: ofork.c,v 1.15 2002-05-29 18:02:59 jmarcus Exp $
  *
  * Copyright (c) 1996 Regents of The University of Michigan.
  * All Rights Reserved.  See COPYRIGHT.
@@ -230,7 +230,7 @@ struct adouble      *ad;
     /* here's the deal: we allocate enough for the standard mac file length.
      * in the future, we'll reallocate in fairly large jumps in case
      * of long unicode names */
-    if (( of->of_name =(char *)malloc(MACFILELEN + 1)) ==
+    if (( of->of_name =(char *)malloc(255 + 1)) ==
             NULL ) {
         LOG(log_error, logtype_afpd, "of_alloc: malloc: %s", strerror(errno) );
         if (!ad)
@@ -239,7 +239,7 @@ struct adouble      *ad;
         oforks[ of_refnum ] = NULL;
         return NULL;
     }
-    strncpy( of->of_name, path, of->of_namelen = MACFILELEN + 1);
+    strncpy( of->of_name, path, of->of_namelen = 255 + 1);
     *ofrefnum = refnum;
     of->of_refnum = refnum;
     of_hash(of);
index d96e8a858053a602f3f2602ca968f03e4019e146..d112eeef3946565273f85dc764fe3629a4e97e22 100644 (file)
@@ -48,4 +48,8 @@ extern int cnid_delete __P((void *, const cnid_t));
 /* cnid_nextid.c */
 extern cnid_t cnid_nextid __P((void *));
 
+/* cnid_mangle_* */
+extern int cnid_mangle_add __P((void *, char *, char *));
+extern char *cnid_mangle_get __P((void *, char *));
+
 #endif /* include/atalk/cnid.h */
index 91875f0e67760438605acb1356aaa61a9af63400..2d04daaaba31bd6405eff157c3943dfdcb0acaf2 100644 (file)
@@ -5,7 +5,7 @@ LIBS = @LIBS@ @DB3_LIBS@
 
 noinst_LTLIBRARIES = libcnid.la
 
-libcnid_la_SOURCES = cnid_add.c cnid_close.c cnid_delete.c cnid_get.c cnid_lookup.c cnid_open.c cnid_resolve.c cnid_update.c
+libcnid_la_SOURCES = cnid_add.c cnid_close.c cnid_delete.c cnid_get.c cnid_lookup.c cnid_mangle_add.c cnid_mangle_get.c cnid_open.c cnid_resolve.c cnid_update.c
 
 noinst_HEADERS = cnid_meta.h cnid_private.h 
 
index 882cd838c4744f620fc1018b9dd280adc6ed100e..2d649cfc403f9682f120b7760603449d01a4e7e0 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: cnid_close.c,v 1.22 2002-02-01 19:51:09 jmarcus Exp $
+ * $Id: cnid_close.c,v 1.23 2002-05-29 18:02:59 jmarcus Exp $
  */
 
 #ifdef HAVE_CONFIG_H
@@ -75,6 +75,9 @@ void cnid_close(void *CNID) {
     db->db_didname->close(db->db_didname, 0);
     db->db_devino->close(db->db_devino, 0);
     db->db_cnid->close(db->db_cnid, 0);
+#ifdef FILE_MANGLING
+    db->db_mangle->close(db->db_mangle, 0);
+#endif /* FILE_MANGLING */
     db->dbenv->close(db->dbenv, 0);
 
     if (db->lockfd > -1) {
diff --git a/libatalk/cnid/cnid_mangle_add.c b/libatalk/cnid/cnid_mangle_add.c
new file mode 100644 (file)
index 0000000..bc88d56
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * $Id: cnid_mangle_add.c,v 1.1 2002-05-29 18:02:59 jmarcus Exp $
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#ifdef FILE_MANGLING
+#include <stdio.h>
+#include <string.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <atalk/logger.h>
+#include <errno.h>
+
+#include <db.h>
+#include <netatalk/endian.h>
+#include <atalk/adouble.h>
+#include <atalk/cnid.h>
+
+#include "cnid_private.h"
+
+/* Add a mangled filename. */
+int
+cnid_mangle_add(void *CNID, char *mfilename, char *filename)
+{
+    CNID_private *db;
+    DBT key, data;
+    DB_TXN *tid;
+    cnid_t id;
+    struct stat st;
+    int rc, ret;
+
+    if (!(db = CNID)) {
+        return -1;
+    }
+
+    memset(&key, 0, sizeof(key));
+    memset(&data, 0, sizeof(data));
+
+    key.data = mfilename;
+    key.size = strlen(mfilename) + 1;
+    data.data = filename;
+    data.size = strlen(filename) + 1;
+
+retry:
+    if ((rc = txn_begin(db->dbenv, NULL, &tid, 0)) != 0) {
+       LOG(log_error, logtype_default, "cnid_mangle_add: Failed to begin transaction: %s", db_strerror(rc));
+       return -1;
+    }
+
+    if ((rc = db->db_mangle->put(db->db_mangle, tid, &key, &data, 0))) {
+       if ((ret = txn_abort(tid)) != 0) {
+           LOG(log_error, logtype_default, "cnid_mangle_add: txn_abort: %s", db_strerror(ret));
+           return -1;
+       }
+       switch (rc) {
+           case DB_LOCK_DEADLOCK:
+               goto retry;
+           default:
+               LOG(log_error, logtype_default, "cnid_mangle_add: Failed to add mangled filename to the database: %s", db_strerror(rc));
+               return -1;
+       }
+    }
+
+    return 0;
+}
+#endif /* FILE_MANGLING */
diff --git a/libatalk/cnid/cnid_mangle_get.c b/libatalk/cnid/cnid_mangle_get.c
new file mode 100644 (file)
index 0000000..6f80189
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * $Id: cnid_mangle_get.c,v 1.1 2002-05-29 18:02:59 jmarcus Exp $
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#ifdef FILE_MANGLING
+#include <stdio.h>
+#include <string.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <atalk/logger.h>
+#include <errno.h>
+
+#include <db.h>
+#include <netatalk/endian.h>
+#include <atalk/adouble.h>
+#include <atalk/cnid.h>
+
+#include "cnid_private.h"
+
+/* Find a mangled filename entry. */
+char *
+cnid_mangle_get(void *CNID, char *mfilename)
+{
+    CNID_private *db;
+    DBT key, data;
+    DB_TXN *tid;
+    cnid_t id;
+    struct stat st;
+    char *filename;
+    int rc;
+
+    if (!(db = CNID)) {
+        return NULL;
+    }
+
+    memset(&key, 0, sizeof(key));
+    memset(&data, 0, sizeof(data));
+
+    key.data = mfilename;
+    key.size = strlen(mfilename) + 1;
+
+    while ((rc = db->db_didname->get(db->db_mangle, NULL, &key, &data, 0))) {
+        if (rc == DB_LOCK_DEADLOCK) {
+            continue;
+        }
+
+        if (rc == DB_NOTFOUND) {
+           return NULL;
+
+        }
+
+        return NULL;
+    }
+
+    filename = strrchr(data.data, '/');
+    filename++; /* Skip the leading '/' */
+
+    if (stat(data.data, &st) < 0) {
+       if (errno == ENOENT) {
+           /* The file no longer exists.  Purge it from the database. */
+/*retry:
+           if ((rc = txn_begin(db->dbenv, NULL, &tid, 0)) != 0) {
+               LOG(log_error, logtype_default, "cnid_mangle_get: Failed to begin transaction: %s", db_strerror(rc));
+               return filename;
+           }
+
+           if ((rc = db->db_mangle->del(db->db_mangle, tid, &key, 0))) {
+               int ret;
+               if ((ret = txn_abort(tid)) != 0) {
+                   LOG(log_error, logtype_default, "cnid_mangle_get: txn_abort: %s", db_strerror(ret));
+                   return filename;
+               }
+               switch (rc) {
+                   case DB_LOCK_DEADLOCK:
+                       goto retry;
+                   default:
+                       LOG(log_error, logtype_default, "cnid_mangle_get: Unable to delete mangled file entry: %s", mfilename);
+                       return filename;
+               }
+           }*/
+           return NULL;
+       }
+    }
+
+    return filename;
+}
+#endif /* FILE_MANGLING */
index 15e07707cd8616619630e5d4c3a8545bbc2c2920..7f24b51d478bdcb5aa6806ee12bd091bd5d800b3 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: cnid_open.c,v 1.38 2002-02-01 19:51:09 jmarcus Exp $
+ * $Id: cnid_open.c,v 1.39 2002-05-29 18:02:59 jmarcus Exp $
  *
  * Copyright (c) 1999. Adrian Sun (asun@zoology.washington.edu)
  * All Rights Reserved. See COPYRIGHT.
@@ -73,6 +73,7 @@
 #define DBDIDNAME     "didname.db"   /* did/full name mapping */
 #define DBSHORTNAME   "shortname.db" /* did/8+3 mapping */
 #define DBMACNAME     "macname.db"   /* did/31 mapping */
+#define DBMANGLE      "mangle.db"    /* filename mangling */
 #define DBLONGNAME    "longname.db"  /* did/unicode mapping */
 #define DBLOCKFILE    "cnid.lock"
 #define DBRECOVERFILE "cnid.dbrecover"
@@ -508,6 +509,35 @@ dbversion_retry:
         goto fail_appinit;
     }
 
+#ifdef FILE_MANGLING
+    /* filename mangling database.  Use a hash for this one. */
+    if ((rc = db_create(&db->db_mangle, db->dbenv, 0)) != 0) {
+        LOG(log_error, logtype_default, "cnid_open: Failed to create mangle database: %s", db_strerror(rc));
+        db->db_didname->close(db->db_didname, 0);
+        db->db_devino->close(db->db_devino, 0);
+        db->db_cnid->close(db->db_cnid, 0);
+#ifdef EXTENDED_DB
+        db->db_macname->close(db->db_macname, 0);
+        db->db_shortname->close(db->db_shortname, 0);
+        db->db_longname->close(db->db_longname, 0);
+#endif /* EXTENDED_DB */
+        goto fail_appinit;
+    }
+
+    if ((rc = db->db_mangle->open(db->db_mangle, DBMANGLE, NULL, DB_HASH, open_flag, 0666)) != 0) {
+        LOG(log_error, logtype_default, "cnid_open: Failed to open mangle database: %s", db_strerror(rc));
+        db->db_didname->close(db->db_didname, 0);
+        db->db_devino->close(db->db_devino, 0);
+        db->db_cnid->close(db->db_cnid, 0);
+#ifdef EXTENDED_DB
+        db->db_macname->close(db->db_macname, 0);
+        db->db_shortname->close(db->db_shortname, 0);
+        db->db_longname->close(db->db_longname, 0);
+#endif /* EXTENDED_DB */
+        goto fail_appinit;
+    }
+#endif /* FILE_MANGLING */
+
     /* Print out the version of DB3 we're linked against. */
     LOG(log_info, logtype_default, "CNID DB initialized using %s",
         db_version(NULL, NULL, NULL));
index cf1c3d4f8fde70f2559ef68943918230f1542275..b7f7683da0c21d78102268ea00fb05b6c8121e13 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: cnid_private.h,v 1.9 2002-02-02 19:12:31 jmarcus Exp $
+ * $Id: cnid_private.h,v 1.10 2002-05-29 18:02:59 jmarcus Exp $
  */
 
 #ifndef LIBATALK_CNID_PRIVATE_H
@@ -39,6 +39,7 @@ typedef struct CNID_private {
     DB *db_cnid;
     DB *db_didname;
     DB *db_devino;
+    DB *db_mangle;
 #ifdef EXTENDED_DB
     DB *db_shortname;
     DB *db_macname;