]> arthur.barton.de Git - netatalk.git/commitdiff
big merge for db frontend and unicode.
authordidg <didg>
Tue, 9 Sep 2003 16:42:19 +0000 (16:42 +0000)
committerdidg <didg>
Tue, 9 Sep 2003 16:42:19 +0000 (16:42 +0000)
164 files changed:
bin/cnid/Makefile.am
configure.in
etc/Makefile.am
etc/afpd/Makefile.am
etc/afpd/afp_asp.c
etc/afpd/afp_dsi.c
etc/afpd/afp_options.c
etc/afpd/afprun.c
etc/afpd/catsearch.c
etc/afpd/desktop.c
etc/afpd/desktop.h
etc/afpd/directory.c
etc/afpd/enumerate.c
etc/afpd/file.c
etc/afpd/file.h
etc/afpd/filedir.c
etc/afpd/fork.c
etc/afpd/globals.h
etc/afpd/main.c
etc/afpd/mangle.c
etc/afpd/mangle.h
etc/afpd/messages.c
etc/afpd/ofork.c
etc/afpd/status.c
etc/afpd/uid.c
etc/afpd/volume.c
etc/afpd/volume.h
etc/cnid_dbd/Makefile.am [new file with mode: 0644]
etc/cnid_dbd/README [new file with mode: 0644]
etc/cnid_dbd/cnid_metad.c [new file with mode: 0644]
etc/cnid_dbd/comm.c [new file with mode: 0644]
etc/cnid_dbd/comm.h [new file with mode: 0644]
etc/cnid_dbd/db_param.c [new file with mode: 0644]
etc/cnid_dbd/db_param.h [new file with mode: 0644]
etc/cnid_dbd/dbd.h [new file with mode: 0644]
etc/cnid_dbd/dbd_add.c [new file with mode: 0644]
etc/cnid_dbd/dbd_delete.c [new file with mode: 0644]
etc/cnid_dbd/dbd_get.c [new file with mode: 0644]
etc/cnid_dbd/dbd_lookup.c [new file with mode: 0644]
etc/cnid_dbd/dbd_resolve.c [new file with mode: 0644]
etc/cnid_dbd/dbd_update.c [new file with mode: 0644]
etc/cnid_dbd/dbif.c [new file with mode: 0644]
etc/cnid_dbd/dbif.h [new file with mode: 0644]
etc/cnid_dbd/main.c [new file with mode: 0644]
etc/cnid_dbd/pack.c [new file with mode: 0644]
etc/cnid_dbd/pack.h [new file with mode: 0644]
etc/cnid_dbd/usockfd.c [new file with mode: 0644]
etc/cnid_dbd/usockfd.h [new file with mode: 0644]
etc/papd/Makefile.am
etc/uams/Makefile.am
etc/uams/uams_dhx_pam.c
etc/uams/uams_gss.c [new file with mode: 0644]
etc/uams/uams_pam.c
include/atalk/Makefile.am
include/atalk/adouble.h
include/atalk/cnid.h
include/atalk/cnid_dbd_private.h [new file with mode: 0644]
include/atalk/list.h [new file with mode: 0644]
include/atalk/tdb.h [new file with mode: 0644]
include/atalk/unicode.h
include/atalk/util.h
libatalk/Makefile.am
libatalk/adouble/ad_attr.c
libatalk/adouble/ad_flush.c
libatalk/adouble/ad_open.c
libatalk/cnid/Makefile.am
libatalk/cnid/README
libatalk/cnid/cdb/Makefile.am [new file with mode: 0644]
libatalk/cnid/cdb/README [new file with mode: 0644]
libatalk/cnid/cdb/cnid_cdb.h [new file with mode: 0644]
libatalk/cnid/cdb/cnid_cdb_add.c [new file with mode: 0644]
libatalk/cnid/cdb/cnid_cdb_close.c [new file with mode: 0644]
libatalk/cnid/cdb/cnid_cdb_delete.c [new file with mode: 0644]
libatalk/cnid/cdb/cnid_cdb_get.c [new file with mode: 0644]
libatalk/cnid/cdb/cnid_cdb_lookup.c [new file with mode: 0644]
libatalk/cnid/cdb/cnid_cdb_meta.c [new file with mode: 0644]
libatalk/cnid/cdb/cnid_cdb_meta.h [new file with mode: 0644]
libatalk/cnid/cdb/cnid_cdb_nextid.c [new file with mode: 0644]
libatalk/cnid/cdb/cnid_cdb_open.c [new file with mode: 0644]
libatalk/cnid/cdb/cnid_cdb_private.h [new file with mode: 0644]
libatalk/cnid/cdb/cnid_cdb_resolve.c [new file with mode: 0644]
libatalk/cnid/cdb/cnid_cdb_update.c [new file with mode: 0644]
libatalk/cnid/cnid.c [new file with mode: 0644]
libatalk/cnid/cnid_init.c [new file with mode: 0644]
libatalk/cnid/db3/Makefile.am [new file with mode: 0644]
libatalk/cnid/db3/README [new file with mode: 0644]
libatalk/cnid/db3/cnid_db3.h [new file with mode: 0644]
libatalk/cnid/db3/cnid_db3_add.c [new file with mode: 0644]
libatalk/cnid/db3/cnid_db3_close.c [new file with mode: 0644]
libatalk/cnid/db3/cnid_db3_delete.c [new file with mode: 0644]
libatalk/cnid/db3/cnid_db3_get.c [new file with mode: 0644]
libatalk/cnid/db3/cnid_db3_lookup.c [new file with mode: 0644]
libatalk/cnid/db3/cnid_db3_meta.c [new file with mode: 0644]
libatalk/cnid/db3/cnid_db3_meta.h [new file with mode: 0644]
libatalk/cnid/db3/cnid_db3_nextid.c [new file with mode: 0644]
libatalk/cnid/db3/cnid_db3_open.c [new file with mode: 0644]
libatalk/cnid/db3/cnid_db3_private.h [new file with mode: 0644]
libatalk/cnid/db3/cnid_db3_resolve.c [new file with mode: 0644]
libatalk/cnid/db3/cnid_db3_update.c [new file with mode: 0644]
libatalk/cnid/dbd/Makefile.am [new file with mode: 0644]
libatalk/cnid/dbd/cnid_dbd.c [new file with mode: 0644]
libatalk/cnid/dbd/cnid_dbd.h [new file with mode: 0644]
libatalk/cnid/hash/Makefile.am [new file with mode: 0644]
libatalk/cnid/hash/README [new file with mode: 0644]
libatalk/cnid/hash/cnid_hash.h [new file with mode: 0644]
libatalk/cnid/hash/cnid_hash_add.c [new file with mode: 0644]
libatalk/cnid/hash/cnid_hash_close.c [new file with mode: 0644]
libatalk/cnid/hash/cnid_hash_delete.c [new file with mode: 0644]
libatalk/cnid/hash/cnid_hash_get.c [new file with mode: 0644]
libatalk/cnid/hash/cnid_hash_lookup.c [new file with mode: 0644]
libatalk/cnid/hash/cnid_hash_nextid.c [new file with mode: 0644]
libatalk/cnid/hash/cnid_hash_open.c [new file with mode: 0644]
libatalk/cnid/hash/cnid_hash_resolve.c [new file with mode: 0644]
libatalk/cnid/hash/cnid_hash_update.c [new file with mode: 0644]
libatalk/cnid/last/Makefile.am [new file with mode: 0644]
libatalk/cnid/last/README [new file with mode: 0644]
libatalk/cnid/last/cnid_last.c [new file with mode: 0644]
libatalk/cnid/last/cnid_last.h [new file with mode: 0644]
libatalk/cnid/mtab/Makefile.am [new file with mode: 0644]
libatalk/cnid/mtab/README [new file with mode: 0644]
libatalk/cnid/mtab/cnid_mtab.c [new file with mode: 0644]
libatalk/cnid/mtab/cnid_mtab.h [new file with mode: 0644]
libatalk/cnid/tdb/Makefile.am [new file with mode: 0644]
libatalk/cnid/tdb/README [new file with mode: 0644]
libatalk/cnid/tdb/cnid_tdb.h [new file with mode: 0644]
libatalk/cnid/tdb/cnid_tdb_add.c [new file with mode: 0644]
libatalk/cnid/tdb/cnid_tdb_close.c [new file with mode: 0644]
libatalk/cnid/tdb/cnid_tdb_delete.c [new file with mode: 0644]
libatalk/cnid/tdb/cnid_tdb_get.c [new file with mode: 0644]
libatalk/cnid/tdb/cnid_tdb_lookup.c [new file with mode: 0644]
libatalk/cnid/tdb/cnid_tdb_nextid.c [new file with mode: 0644]
libatalk/cnid/tdb/cnid_tdb_open.c [new file with mode: 0644]
libatalk/cnid/tdb/cnid_tdb_resolve.c [new file with mode: 0644]
libatalk/cnid/tdb/cnid_tdb_update.c [new file with mode: 0644]
libatalk/dsi/Makefile.am
libatalk/dsi/dsi_tcp.c
libatalk/unicode/Makefile.am
libatalk/unicode/charcnv.c
libatalk/unicode/charsets/Makefile.am [new file with mode: 0644]
libatalk/unicode/charsets/generic_mb.c [new file with mode: 0644]
libatalk/unicode/charsets/generic_mb.h [new file with mode: 0644]
libatalk/unicode/charsets/mac_centraleurope.c [new file with mode: 0644]
libatalk/unicode/charsets/mac_centraleurope.h [new file with mode: 0644]
libatalk/unicode/charsets/mac_cyrillic.c [new file with mode: 0644]
libatalk/unicode/charsets/mac_cyrillic.h [new file with mode: 0644]
libatalk/unicode/charsets/mac_hebrew.c [new file with mode: 0644]
libatalk/unicode/charsets/mac_hebrew.h [new file with mode: 0644]
libatalk/unicode/charsets/mac_roman.c [new file with mode: 0644]
libatalk/unicode/charsets/mac_roman.h [new file with mode: 0644]
libatalk/unicode/charsets/mac_turkish.c [new file with mode: 0644]
libatalk/unicode/charsets/mac_turkish.h [new file with mode: 0644]
libatalk/unicode/iconv.c
libatalk/unicode/utf8.c [new file with mode: 0644]
libatalk/unicode/util_unistr.c
libatalk/util/Makefile.am
libatalk/util/fault.c [new file with mode: 0644]
libatalk/util/logger.c
macros/gssapi-check.m4 [new file with mode: 0644]
macros/iconv.m4
macros/ssl-check.m4
macros/tcp-wrappers.m4 [new file with mode: 0644]
macros/util.m4 [new file with mode: 0644]
man/man8/Makefile.am
man/man8/afpd.8.tmpl

index c318a3b11a39b6bde81a55ac651773eae13efb30..519068ea4cd5c477435afb7559c13e139229112e 100644 (file)
@@ -2,8 +2,8 @@
 
 EXTRA_DIST = cnid_maint.in
 
-if COMPILE_CNID
+#if COMPILE_CNID
 bin_SCRIPTS = cnid_maint
-else
-bin_SCRIPTS = 
-endif
+#else
+#bin_SCRIPTS = 
+#endif
index 8733954ba0b812b153db47cc2dd4ac2bcee1fd13..d6b48cd23a0673f80a8020c059e6bd254a585fcd 100644 (file)
@@ -1,4 +1,4 @@
-dnl $Id: configure.in,v 1.179.2.3 2003-06-23 10:25:07 didg Exp $
+dnl $Id: configure.in,v 1.179.2.3.2.1 2003-09-09 16:42:19 didg Exp $
 dnl configure.in for netatalk
 
 AC_INIT(bin/adv1tov2/adv1tov2.c)
@@ -27,43 +27,50 @@ dnl FIXME! FIXME! These should be selectable properly, and should produce
 dnl the proper flags and defines...
 dnl *********************************************************************
 
+############################################
+# we need dlopen/dlclose/dlsym/dlerror for PAM, the password database plugins and the plugin loading code
+#AC_SEARCH_LIBS(dlopen, [dl])
+# dlopen/dlclose/dlsym/dlerror will be checked again later and defines will be set then
+
 dnl Checks for libraries.
 dnl Replace `main' with a function in -labs:
-AC_CHECK_LIB(abs, main)
+dnl AC_CHECK_LIB(abs, main)
 dnl Replace `main' with a function in -laudit:
-AC_CHECK_LIB(audit, main)
+dnl AC_CHECK_LIB(audit, main)
 dnl Replace `main' with a function in -lauth:
-AC_CHECK_LIB(auth, main)
+dnl AC_CHECK_LIB(auth, main)
 dnl Replace `main' with a function in -lcmd:
-AC_CHECK_LIB(cmd, main)
+dnl AC_CHECK_LIB(cmd, main)
 dnl Replace `main' with a function in -lcrypt:
-AC_CHECK_LIB(crypt, main)
+dnl AC_CHECK_LIB(crypt, main)
 dnl Replace `main' with a function in -ld:
-AC_CHECK_LIB(d, main)
+dnl AC_CHECK_LIB(d, main)
 dnl Replace `main' with a function in -ldl:
-AC_CHECK_LIB(dl, main)
+AC_CHECK_LIB(dl, dlopen)
 dnl Replace `main' with a function in -lkauth:
-AC_CHECK_LIB(kauth, main)
+dnl AC_CHECK_LIB(kauth, main)
 dnl Replace `main' with a function in -lkrb:
-AC_CHECK_LIB(krb, main)
+dnl AC_CHECK_LIB(krb, main)
 dnl Replace `main' with a function in -llwp:
-AC_CHECK_LIB(lwp, main)
+dnl AC_CHECK_LIB(lwp, main)
 dnl Replace `main' with a function in -ln:
-AC_CHECK_LIB(n, main)
+dnl AC_CHECK_LIB(n, main)
 dnl Replace `main' with a function in -lnsl:
-AC_CHECK_LIB(nsl, main)
+AC_CHECK_LIB(nsl, socket)
 dnl Replace `main' with a function in -lprot:
-AC_CHECK_LIB(prot, main)
+dnl AC_CHECK_LIB(prot, main)
 dnl Replace `main' with a function in -lrx:
-AC_CHECK_LIB(rx, main)
+dnl AC_CHECK_LIB(rx, main)
 dnl Replace `main' with a function in -lrxkad:
-AC_CHECK_LIB(rxkad, main)
+dnl AC_CHECK_LIB(rxkad, main)
 dnl Replace `main' with a function in -lsocket:
-AC_CHECK_LIB(socket, main)
+AC_CHECK_LIB(socket, socket)
 dnl Replace `main' with a function in -lsys:
-AC_CHECK_LIB(sys, main)
+dnl AC_CHECK_LIB(sys, main)
 dnl Replace `main' with a function in -lubik:
-AC_CHECK_LIB(ubik, main)
+dnl AC_CHECK_LIB(ubik, main)
+
+AC_MSG_RESULT([    LIBS = $LIBS])
 
 #
 # Check presence of some functions
@@ -84,6 +91,7 @@ AC_CHECK_HEADER(sys/cdefs.h,,
        AC_MSG_RESULT([enabling generic cdefs.h from tree])
        CFLAGS="-I\$(top_srcdir)/sys/generic $CFLAGS"
 )
+AC_CHECK_HEADERS(langinfo.h locale.h)
 
 dnl Checks for typedefs, structures, and compiler characteristics.
 AC_C_CONST
@@ -108,9 +116,14 @@ AC_FUNC_UTIME_NULL
 AC_FUNC_WAIT3
 AC_CHECK_FUNCS(getcwd gethostname gettimeofday getusershell mkdir rmdir select socket strdup strcasestr strstr strtoul setpgrp strchr memcpy)
 AC_FUNC_SETPGRP
+AC_CHECK_FUNCS(backtrace_symbols)
+AC_CHECK_FUNCS(setlocale nl_langinfo)
+AC_CHECK_FUNCS(dlopen dlclose dlsym dlerror waitpid getcwd strdup strndup strnlen strtoul strerror chown fchown chmod fchmod chroot link mknod mknod64)
+
 
 dnl Checks for (v)snprintf
 NETATALK_SNPRINTF_CHECK
+AC_MSG_RESULT([    LIBS = $LIBS])
 
 dnl --------------------------------------------------------------------------
 dnl specific configuration comes in here:
@@ -200,6 +213,7 @@ if test "$afp3" = "yes"; then
        AM_ICONV
         AC_SYS_LARGEFILE
 fi
+NETATALK_GSSAPI_CHECK
 
 
 dnl ----------- A NOTE ABOUT DROPKLUDGE
@@ -228,83 +242,213 @@ AC_ARG_ENABLE(force-uidgid,
 dnl Don't use BDB unless it's needed
 bdb_required=no
 
-dnl Determine DID scheme
-AC_MSG_CHECKING([for DID scheme to use])
-AC_ARG_WITH(did,
-       [  --with-did=SCHEME       set DID scheme (cnid,last,hash)],
-       [ did_scheme="$withval" ],
-       [ did_scheme="cnid" ]
-)
-
-if test "x$did_scheme" = "xlast"; then
-       AC_DEFINE(USE_LASTDID, 1, [Define if the last DID scheme should be used])
-       AC_MSG_RESULT([last])
-elif test "x$did_scheme" = "xhash"; then
-       AC_DEFINE(USE_HASHDID, 1, [Define if the hash DID scheme should be used, only one dev])
-       AC_MSG_RESULT([hash])
-elif test "x$did_scheme" = "xcnid"; then
-       bdb_required="yes"
-       AC_DEFINE(CNID_DB, 1, [Define if the CNID DB DID scheme should be used])
-       AC_MSG_RESULT([enabling build with CNID DB support])
-else
-       AC_MSG_ERROR([unknown DID scheme])
-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 "x$withval" = "xyes"; then
-                       if test "x$did_scheme" != "xcnid"; then
-                               AC_MSG_ERROR([DID scheme must be CNID to use filename mangling])
+dnl Determine whether or not to use DB3 Concurrent Data Store
+AC_MSG_CHECKING([whether or not to use DB3 Concurrent Data Store])
+AC_ARG_WITH(cnid-cdb-backend,
+       [  --with-cnid-cdb-backend      enable CNID with Concurrent DB3 Data Store],
+       if test x"$withval" = x"no"; then
+           use_cdb_backend=no
                        else
-                               AC_DEFINE(FILE_MANGLING, 1, [Define if file name mangling should be used])
+           use_cdb_backend=yes
+       fi
+       ,use_cdb_backend=yes
+)
+
+if test $use_cdb_backend = yes; then
                                AC_MSG_RESULT([yes])
+    AC_DEFINE(CNID_BACKEND_CDB, 1, [Define if CNID Concurrent DB3 backend should be compiled.])            
+    DEFAULT_CNID_SCHEME=cdb
+    bdb_required=yes
+else
+    AC_MSG_RESULT([no])
                        fi
+
+dnl Determine whether or not to use Database Daemon CNID backend
+AC_MSG_CHECKING([whether or not to use Database Daemon CNID backend])
+AC_ARG_WITH(cnid-dbd-backend,
+       [  --with-cnid-dbd-backend      enable CNID with Database Daemon Data Store],
+       if test x"$withval" = x"no"; then
+           AC_MSG_RESULT([no])
+           use_dbd_backend=no
                else
+           use_dbd_backend=yes
+           AC_MSG_RESULT([yes])
+       fi
+       ,use_dbd_backend=no
+        AC_MSG_RESULT([no])
+)
+
+dnl Determine whether or not to use with transaction support in Database Daemon
+AC_MSG_CHECKING([whether or not to use Database Daemon with transaction support])
+AC_ARG_WITH(cnid-dbd-txn,
+        [  --with-cnid-dbd-txn          enable transaction support for dbd backend],
+       if test x"$withval" = x"no"; then
+           AC_MSG_RESULT([no])
+           use_dbd_txn=no
+       else
+           use_dbd_txn=yes
+           AC_MSG_RESULT([yes])
+       fi
+       ,use_dbd_txn=no
                        AC_MSG_RESULT([no])
+)
+
+if test $use_dbd_txn = yes; then
+    use_dbd_backend=yes
+    AC_DEFINE(CNID_BACKEND_DBD_TXN, 1, [Define if CNID Database Daemon backend has transaction support])
+else
+    if test x"$use_dbd_backend" = x; then    
+        use_dbd_backend=no
+    fi
+fi
+
+if test $use_dbd_backend = yes; then
+    AC_DEFINE(CNID_BACKEND_DBD, 1, [Define if CNID Database Daemon backend should be compiled.])
+    if test x"$DEFAULT_CNID_SCHEME" = x; then
+        DEFAULT_CNID_SCHEME=dbd
+    fi
+    bdb_required=yes
+fi
+
+dnl Determine whether or not to use DB3 transactional data store
+AC_MSG_CHECKING([whether or not to use DB3 transactional DB store])
+AC_ARG_WITH(cnid-db3-backend,
+        [  --with-cnid-db3-backend     enable CNID with transactional DB3 Data Store],
+       if test x"$withval" = x"no"; then
+           use_db3_backend=no
+       else
+           use_db3_backend=yes
                fi
-       ], [
-               if test "x$did_scheme" = "xcnid"; then
-                       AC_DEFINE(FILE_MANGLING, 1, [Define if file name mangling should be used])
+       ,use_db3_backend=no
+)
+
+if test $use_db3_backend = yes; then
                        AC_MSG_RESULT([yes])
+    AC_DEFINE(CNID_BACKEND_DB3, 1, [Define if CNID transactional DB3 backend should be compiled.])
+    if test x"$DEFAULT_CNID_SCHEME" = x; then
+       DEFAULT_CNID_SCHEME=db3
+    fi
+    bdb_required=yes
                else
                        AC_MSG_RESULT([no])
                fi
-       ]
+
+dnl Determine whether or not to use LAST DID scheme
+AC_MSG_CHECKING([whether or not to use LAST DID scheme])
+AC_ARG_WITH(cnid-last-backend,
+       [  --with-cnid-last-backend     enable LAST CNID scheme],
+       if test x"$withval" = x"no"; then
+           use_last_backend=no
+       else
+           use_last_backend=yes
+       fi
+       ,use_last_backend=no
 )
 
-if test "$did_scheme" = "cnid"; then
-    USE_CDB="yes"
+if test $use_last_backend = yes; then
+    AC_MSG_RESULT([yes])
+    AC_DEFINE(CNID_BACKEND_LAST, 1, [Define if CNID LAST scheme backend should be compiled.])
+    if test x"$DEFAULT_CNID_SCHEME" = x; then
+       DEFAULT_CNID_SCHEME=last
+    fi
 else
-    USE_CDB="no"
+    AC_MSG_RESULT([no])
 fi
 
-dnl Determine whether or not to use CDB or transactional DB store
-AC_MSG_CHECKING([whether or not to use CNID with Concurrent Data Store])
-AC_ARG_WITH(cdb,
-       [  --with-cdb              enable CNID with Concurrent Data Store],
-       if test "$withval" = "no"; then
-           if test "x$did_scheme" != "xcnid"; then
-               USE_CDB="no"
-               AC_MSG_ERROR([DID scheme must be CNID to use CDB])
+dnl Determine whether or not to use HASH DID scheme
+AC_MSG_CHECKING([whether or not to use HASH DID scheme])
+AC_ARG_WITH(cnid-hash-backend,
+       [  --with-cnid-hash-backend     enable HASH CNID scheme],
+       if test x"$withval" = x"no"; then
+           use_hash_backend=no
+       else
+           use_hash_backend=yes
+       fi
+       ,use_hash_backend=no
+)
+
+if test $use_hash_backend = yes; then
+    AC_MSG_RESULT([yes])
+    AC_DEFINE(CNID_BACKEND_HASH, 1, [Define if CNID HASH scheme backend should be compiled.])
+    if test x"$DEFAULT_CNID_SCHEME" = x; then
+       DEFAULT_CNID_SCHEME=hash
+    fi
            else
-               USE_CDB="no"
                AC_MSG_RESULT([no])
            fi
+
+dnl Determine whether or not to use TDB DID scheme
+AC_MSG_CHECKING([whether or not to use TDB DID scheme])
+AC_ARG_WITH(cnid-tdb-backend,
+       [  --with-cnid-tdb-backend      enable DID CNID scheme],
+       if test x"$withval" = x"no"; then
+           use_tdb_backend=no
        else
-           USE_CDB="yes"
+           use_tdb_backend=yes
+       fi
+       ,use_tdb_backend=no
+)
+
+if test $use_tdb_backend = yes; then
            AC_MSG_RESULT([yes])
+    AC_DEFINE(CNID_BACKEND_TDB, 1, [Define if CNID TDB scheme backend should be compiled.])
+    if test x"$DEFAULT_TDB_SCHEME" = x; then
+       DEFAULT_TDB_SCHEME=tdb
        fi
-       , AC_MSG_RESULT([yes])
+else
+    AC_MSG_RESULT([no])
+fi
+
+dnl Determine whether or not to use MTAB DID scheme
+AC_MSG_CHECKING([whether or not to use MTAB DID scheme])
+AC_ARG_WITH(cnid-mtab-backend,
+       [  --with-cnid-mtab-backend     enable MTAB CNID scheme],
+       if test x"$withval" = x"no"; then
+           use_mtab_backend=no
+       else
+           use_mtab_backend=yes
+       fi
+       ,use_mtab_backend=no
 )
 
-if test "$USE_CDB" = "yes"; then
-    AC_DEFINE(CNID_DB_CDB, 1, [Define if CNID should be used with Concurrent Data Store])
+if test $use_mtab_backend = yes; then
+    AC_MSG_RESULT([yes])
+    AC_DEFINE(CNID_BACKEND_MTAB, 1, [Define if CNID MTAB scheme backend should be compiled.])
+    if test x"$DEFAULT_CNID_SCHEME" = x; then
+       DEFAULT_CNID_SCHEME=mtab
+fi
+else           
+    AC_MSG_RESULT([no])
 fi
 
+dnl Set default DID scheme
+AC_MSG_CHECKING([default DID scheme])
+AC_ARG_WITH(cnid-default-backend,
+       [  --with-cnid-default-backend=val      set default DID scheme],
+       if test x"$withval" = x; then
+           AC_MSG_RESULT([ignored])
+       else
+           DEFAULT_CNID_SCHEME=$withval
+           AC_MSG_RESULT($DEFAULT_CNID_SCHEME)
+       fi
+       ,AC_MSG_RESULT($DEFAULT_CNID_SCHEME)
+)
+
+if test x"$DEFAULT_CNID_SCHEME" = x; then
+    AC_MSG_ERROR([No DID schemes compiled in ])
+fi
+
+#eval "default_scheme_selected=\$use_$DEFAULT_CNID_SCHEME_backend"
+#echo "default_scheme_selected=[$default_scheme_selected]"
+#if test x"$default_scheme_selected" = xyes; then
+#   AC_MSG_CHECKING([Checking whether default CNID scheme has been activated])
+#   AC_MSG_RESULT([yes])
+#else
+#   AC_MSG_ERROR([Default CNID scheme is disabled ! Enable it or select other as default.])
+#fi
+
+AC_DEFINE_UNQUOTED(DEFAULT_CNID_SCHEME, "$DEFAULT_CNID_SCHEME", [Default CNID scheme to be used])
+
 dnl Check for Berkeley DB library
 if test "x$bdb_required" = "xyes"; then
        AC_PATH_BDB(, [AC_MSG_ERROR([Berkeley DB library not found!])])
@@ -316,6 +460,7 @@ AC_CHECK_QUOTA
 dnl Check for optional server location protocol support (used by MacOS X)
 NETATALK_SRVLOC
 
+AC_MSG_RESULT([    LIBS = $LIBS])
 dnl Check for PAM libs
 AC_PATH_PAM([
        PAPD_LIBS="$PAPD_LIBS $PAM_LIBS"
@@ -344,14 +489,16 @@ AC_ARG_ENABLE(shell-check,
        fi
 )
 
-AC_ARG_WITH(tcp-wrappers,
-       [  --with-tcp-wrappers     enable TCP wrappers support],
-       AC_CHECK_LIB(wrap, tcpd_warn,
-               AC_DEFINE(TCPWRAP, 1, [Define if TCP wrappers should be used])
-               AFPD_LIBS="$AFPD_LIBS -lwrap"
-               AC_MSG_RESULT([enabling TCP wrappers support])
-       )
-)
+#AC_ARG_WITH(tcp-wrappers,
+#      [  --with-tcp-wrappers     enable TCP wrappers support],[
+#      AC_CHECK_HEADERS(tcpd.h)
+#      AC_CHECK_LIB(wrap, tcpd_warn,
+#              AC_DEFINE(TCPWRAP, 1, [Define if TCP wrappers should be used])
+#              AFPD_LIBS="$AFPD_LIBS -lwrap"
+#              AC_MSG_RESULT([enabling TCP wrappers support])
+#      )
+#])
+NETATALK_TCP_WRAPPERS
 
 AC_ARG_ENABLE(redhat,
        [  --enable-redhat         use redhat-style sysv configuration ],
@@ -636,6 +783,7 @@ if test x"$this_os" = "xtru64"; then
 fi
 
 dnl -- look for openssl
+AC_MSG_RESULT([    LIBS = $LIBS])
 AC_PATH_SSL
 
 dnl --------------------- check for building PGP UAM module
@@ -736,6 +884,7 @@ AC_OUTPUT([Makefile
        etc/afpd/Makefile
        etc/afpd/nls/Makefile
        etc/atalkd/Makefile
+       etc/cnid_dbd/Makefile
        etc/uams/Makefile
        etc/uams/uams_krb4/Makefile
        etc/papd/Makefile
@@ -747,12 +896,21 @@ AC_OUTPUT([Makefile
        libatalk/asp/Makefile
        libatalk/atp/Makefile
        libatalk/cnid/Makefile
+       libatalk/cnid/db3/Makefile
+       libatalk/cnid/cdb/Makefile
+       libatalk/cnid/last/Makefile
+       libatalk/cnid/mtab/Makefile
+       libatalk/cnid/dbd/Makefile
+       libatalk/cnid/hash/Makefile
+       libatalk/cnid/tdb/Makefile
        libatalk/compat/Makefile
        libatalk/dsi/Makefile
        libatalk/nbp/Makefile
        libatalk/netddp/Makefile
        libatalk/util/Makefile
+       libatalk/tdb/Makefile
        libatalk/unicode/Makefile
+       libatalk/unicode/charsets/Makefile
        macros/Makefile
        man/Makefile
        man/man1/Makefile
@@ -774,3 +932,17 @@ AC_OUTPUT([Makefile
        [chmod a+x distrib/config/netatalk-config contrib/shell_utils/apple_*]
 )
 
+
+#################################################
+# Display summary of libraries detected
+
+AC_MSG_RESULT([Using libraries:])
+AC_MSG_RESULT([    LIBS = $LIBS])
+AC_MSG_RESULT([    SSL_LIBS = $SSL_LIBS])
+AC_MSG_RESULT([    GSSAPI_LIBS = $GSSAPI_LIBS])
+AC_MSG_RESULT([    BDB_LIBS = $BDB_LIBS])
+AC_MSG_RESULT([    AFPD_LIBS= $AFPD_LIBS])
+AC_MSG_RESULT([    PAPD_LIBS= $PAPD_LIBS])
+AC_MSG_RESULT([    CFLAGS = $CFLAGS])
+
+
index 83a4d085f852d83281eb9e9ffa77ba395e857264..7ed56ed6612fc957a815944cf3eaf610e0727de5 100644 (file)
@@ -1,3 +1,3 @@
 # Makefile.am for etc/
 
-SUBDIRS = afpd atalkd papd psf uams
+SUBDIRS = afpd cnid_dbd atalkd papd psf uams
index 01b6c2e2b74037bd24418e34eec2804f4693a5bb..e8418e08710194838c64a4e520d31ece70576f39 100644 (file)
@@ -20,7 +20,9 @@ noinst_HEADERS = auth.h codepage.h afp_config.h desktop.h directory.h file.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
 
-LIBS = @LIBS@ @AFPD_LIBS@ @QUOTA_LIBS@ @SLP_LIBS@
+#LIBS = @LIBS@ @AFPD_LIBS@ @QUOTA_LIBS@ @SLP_LIBS@
+LIBS = @LIBS@ @PAM_LIBS@ @QUOTA_LIBS@ @SLP_LIBS@
+#LIBS = @LIBS@ @QUOTA_LIBS@ @SLP_LIBS@
 
 CFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/sys \
         @CFLAGS@ @SLP_CFLAGS@ \
index e822a89ed37b2e47a2eab3774d7f391b4607bca9..477217f1a778e5d95b18738ecd716c0ce0c6a59d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: afp_asp.c,v 1.18 2002-12-04 10:59:36 didg Exp $
+ * $Id: afp_asp.c,v 1.18.6.1 2003-09-09 16:42:19 didg Exp $
  *
  * Copyright (c) 1997 Adrian Sun (asun@zoology.washington.edu)
  * Copyright (c) 1990,1993 Regents of The University of Michigan.
@@ -53,6 +53,7 @@ static __inline__ void afp_asp_close(AFPObj *obj)
 {
     ASP asp = obj->handle;
 
+    close_all_vol();
     if (obj->options.authprintdir) afp_authprint_remove(obj);
 
     if (obj->logout)
@@ -175,6 +176,16 @@ static void afp_asp_timedown()
     }
 }
 
+/* ---------------------- */
+#ifdef SERVERTEXT
+static void afp_asp_getmesg (int sig)
+{
+    readmessage(child);
+    asp_attention(child->handle, AFPATTN_MESG | AFPATTN_TIME(5));
+}
+#endif /* SERVERTEXT */
+
+
 void afp_over_asp(AFPObj *obj)
 {
     ASP asp;
@@ -205,6 +216,19 @@ void afp_over_asp(AFPObj *obj)
         afp_asp_die(1);
     }
 
+#ifdef SERVERTEXT
+    /* Added for server message support */
+    action.sa_handler = afp_asp_getmesg;
+    sigemptyset( &action.sa_mask );
+    sigaddset(&action.sa_mask, SIGUSR2);
+    action.sa_flags = SA_RESTART;
+    if ( sigaction( SIGUSR2, &action, 0) < 0 ) {
+        LOG(log_error, logtype_afpd, "afp_over_asp: sigaction: %s", strerror(errno) );
+        afp_asp_die(1);
+    }
+#endif /* SERVERTEXT */
+
+
     LOG(log_info, logtype_afpd, "session from %u.%u:%u on %u.%u:%u",
         ntohs( asp->asp_sat.sat_addr.s_net ),
         asp->asp_sat.sat_addr.s_node, asp->asp_sat.sat_port,
index 24d73511c42e70b56ee82bce1b541d28eaf95acb..bccc826f2cace9731791b271a7458ad25a00a3d7 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: afp_dsi.c,v 1.27.2.3 2003-07-21 05:50:53 didg Exp $
+ * $Id: afp_dsi.c,v 1.27.2.3.2.1 2003-09-09 16:42:19 didg Exp $
  *
  * Copyright (c) 1999 Adrian Sun (asun@zoology.washington.edu)
  * Copyright (c) 1990,1993 Regents of The University of Michigan.
@@ -60,6 +60,7 @@ static __inline__ void afp_dsi_close(AFPObj *obj)
 {
     DSI *dsi = obj->handle;
 
+    close_all_vol();
     if (obj->logout)
         (*obj->logout)();
 
@@ -156,7 +157,7 @@ static void afp_dsi_reload()
 #ifdef SERVERTEXT
 static void afp_dsi_getmesg (int sig)
 {
-    readmessage();
+    readmessage(child.obj);
     dsi_attention(child.obj->handle, AFPATTN_MESG | AFPATTN_TIME(5));
 }
 #endif /* SERVERTEXT */
@@ -276,6 +277,8 @@ void afp_over_dsi(AFPObj *obj)
         afp_dsi_die(1);
     }
 
+    fault_setup((void (*)(void *))afp_dsi_die);
+
     /* get stuck here until the end */
     while ((cmd = dsi_receive(dsi))) {
         child.tickle = 0;
index 31c923f05fc5a25997c28529a320d897a85a7c23..e95cf9087c373750674150d9268d73a3fcf3ff78 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: afp_options.c,v 1.30.2.2 2003-07-21 05:50:53 didg Exp $
+ * $Id: afp_options.c,v 1.30.2.2.2.1 2003-09-09 16:42:19 didg Exp $
  *
  * Copyright (c) 1997 Adrian Sun (asun@zoology.washington.edu)
  * Copyright (c) 1990,1993 Regents of The University of Michigan.
@@ -61,6 +61,10 @@ char *strchr (), *strrchr ();
 #define MIN(a, b)  ((a) < (b) ? (a) : (b))
 #endif /* MIN */
 
+/* FIXME CNID */
+char             *Cnid_srv;
+int              Cnid_port;
+
 #define OPTIONS "dn:f:s:uc:g:P:ptDS:TL:F:U:Ivm:"
 #define LENGTH 512
 
@@ -139,6 +143,12 @@ void afp_options_free(struct afp_options *opt,
        free(opt->k5service);
     if (opt->k5realm && (opt->k5realm != save->k5realm))
        free(opt->k5realm);
+    if (opt->k5keytab && (opt->k5keytab != save->k5keytab))
+       free(opt->k5keytab);
+    if (opt->unixcodepage && (opt->unixcodepage != save->unixcodepage))
+       free(opt->unixcodepage);
+    if (opt->maccodepage && (opt->maccodepage != save->maccodepage))
+       free(opt->maccodepage);
 }
 
 /* initialize options */
@@ -169,6 +179,11 @@ void afp_options_init(struct afp_options *options)
 #endif /* ADMIN_GRP */
     options->k5service = NULL;
     options->k5realm = NULL;
+    options->k5keytab = NULL;
+    options->unixcharset = CH_UNIX;
+    options->unixcodepage = "LOCALE";
+    options->maccharset = CH_MAC;
+    options->maccodepage = "MAC_ROMAN";
 }
 
 /* parse an afpd.conf line. i'm doing it this way because it's
@@ -403,8 +418,15 @@ int afp_options_parseline(char *buf, struct afp_options *options)
        options->k5service = opt;
     if ((c = getoption(buf, "-k5realm")) && (opt = strdup(c)))
        options->k5realm = opt;
-    if ((c = getoption(buf, "-k5keytab")))
-       setenv( "KRB5_KTNAME", c, 1 );
+    if ((c = getoption(buf, "-k5keytab"))) {
+       if ( NULL == (options->k5keytab = (char *) malloc(sizeof(char)*(strlen(c)+14)) )) {
+               LOG(log_error, logtype_afpd, "malloc failed");
+               exit(-1);
+       }
+       snprintf(options->k5keytab, strlen(c)+14, "KRB5_KTNAME=%s", c);
+       putenv(options->k5keytab);
+       /* setenv( "KRB5_KTNAME", c, 1 ); */
+    }
     if ((c = getoption(buf, "-authprintdir")) && (opt = strdup(c)))
         options->authprintdir = opt;
     if ((c = getoption(buf, "-uampath")) && (opt = strdup(c)))
@@ -423,6 +445,16 @@ int afp_options_parseline(char *buf, struct afp_options *options)
         }
     }
 
+    /* FIXME CNID */
+    if ((c = getoption(buf, "-cnidserver"))) {
+        char *p;
+        
+        Cnid_srv = strdup(c);
+        p = strchr(Cnid_srv, ':');
+        *p = 0;
+        Cnid_port = atoi(p +1);
+    }
+
     if ((c = getoption(buf, "-port")))
         options->port = atoi(c);
     if ((c = getoption(buf, "-ddpaddr")))
@@ -443,6 +475,23 @@ int afp_options_parseline(char *buf, struct afp_options *options)
         }
     }
 
+    if ((c = getoption(buf, "-unixcodepage"))) {
+       options->unixcodepage = c;
+       if ( 0 == ( options->unixcharset = add_charset(options->unixcodepage)) ) {
+               options->unixcodepage= "LOCALE";
+               options->unixcharset = CH_UNIX;
+       }
+    }
+       
+    if ((c = getoption(buf, "-maccodepage"))) {
+       options->maccodepage = c;
+       if ( 0 == ( options->maccharset = add_charset(options->maccodepage)) ) {
+               options->maccodepage= "Mac_Roman";
+               options->maccharset = CH_MAC;
+       }
+       LOG(log_debug, logtype_afpd, "Setting Mac Codepage to '%s'", options->maccodepage);
+    }
+
     return 1;
 }
 
index 8bafcea97fc50062c2d010f4d3db7fae1f763e9a..4517d6094b47cb7abb2dbd274fabca587ecd8198 100644 (file)
 #include <stdlib.h>
 
 #include <sys/types.h>
+#define __USE_GNU 1
 #include <unistd.h>
+
 #include <errno.h>
+
+#ifdef HAVE_SYS_WAIT_H 
 #include <sys/wait.h>
+#endif
+
 #include <sys/param.h>  
 #include <string.h>
 
index 1d8785f9259ccebeec8f99c5483ef396d46920f6..165ad61c7d5fd857d3143159a7fe21fe444d8b11 100644 (file)
@@ -242,8 +242,10 @@ static int resolve_dir(struct vol *vol, int cidx)
        return 1;
 } /* resolve_dir */
 
-/* Looks up for an opened adouble structure, opens resource fork of selected file. */
-static struct adouble *adl_lkup(struct path *path)
+/* Looks up for an opened adouble structure, opens resource fork of selected file. 
+ * FIXME What about noadouble?
+*/
+static struct adouble *adl_lkup(struct vol *vol, struct path *path)
 {
        static struct adouble ad;
        struct adouble *adp;
@@ -253,7 +255,7 @@ static struct adouble *adl_lkup(struct path *path)
        if (!isdir && (of = of_findname(path))) {
                adp = of->of_ad;
        } else {
-               memset(&ad, 0, sizeof(ad));
+               ad_init(&ad, vol->v_adouble);
                adp = &ad;
        } 
 
@@ -273,12 +275,11 @@ static struct adouble *adl_lkup(struct path *path)
  */
 static int crit_check(struct vol *vol, struct path *path, int cidx) {
        int r = 0;
-       u_int16_t attr;
+       u_int16_t attr, flags = CONV_PRECOMPOSE;
        struct finderinfo *finfo = NULL, finderinfo;
        struct adouble *adp = NULL;
        time_t c_date, b_date;
        static char convbuf[512];
-       static char convbuf2[512];
        size_t len;
 
        if (S_ISDIR(path->st.st_mode)) {
@@ -297,6 +298,9 @@ static int crit_check(struct vol *vol, struct path *path, int cidx) {
 
        /* Check for filename */
        if (c1.rbitmap & (1<<DIRPBIT_LNAME)) { 
+#ifdef DEBUG
+               LOG(log_debug, logtype_afpd, "Crit check: comparing %s/%s to %s", path->m_name, path->u_name, c1.lname);
+#endif
                if ( (size_t)(-1) == (len = convert_string(vol->v_maccharset, CH_UCS2, path->m_name, strlen(path->m_name), convbuf, 512)) )
                        goto crit_check_ret;
                convbuf[len] = 0; 
@@ -309,9 +313,10 @@ static int crit_check(struct vol *vol, struct path *path, int cidx) {
        } /* if (c1.rbitmap & ... */
        
        if ((c1.rbitmap & (1<<FILPBIT_PDINFO))) { 
-               if ( (size_t)(-1) == (len = utf8_precompose( path->m_name, strlen(path->m_name), convbuf2, 512)) )
-                       goto crit_check_ret;
-               if ( (size_t)(-1) == (len = convert_string( CH_UTF8, CH_UCS2, convbuf2, len, convbuf, 512)) )
+#ifdef DEBUG
+               LOG(log_debug, logtype_afpd, "Crit check: comparing %s to %s", path->m_name, c1.utf8name);
+#endif
+               if ( (size_t)(-1) == (len = convert_charset( CH_UTF8_MAC, CH_UCS2, path->m_name, strlen(path->m_name), convbuf, 512, &flags)) )
                        goto crit_check_ret;
                convbuf[len] = 0; 
                if (c1.rbitmap & (1<<CATPBIT_PARTIAL)) {
@@ -339,7 +344,7 @@ static int crit_check(struct vol *vol, struct path *path, int cidx) {
 
        /* Check for creation date... */
        if (c1.rbitmap & (1<<DIRPBIT_CDATE)) {
-               if (adp || (adp = adl_lkup(path))) {
+               if (adp || (adp = adl_lkup(vol, path))) {
                        if (ad_getdate(adp, AD_DATE_CREATE, (u_int32_t*)&c_date) >= 0)
                                c_date = AD_DATE_TO_UNIX(c_date);
                        else c_date = path->st.st_mtime;
@@ -350,7 +355,7 @@ static int crit_check(struct vol *vol, struct path *path, int cidx) {
 
        /* Check for backup date... */
        if (c1.rbitmap & (1<<DIRPBIT_BDATE)) {
-               if (adp || (adp == adl_lkup(path))) {
+               if (adp || (adp == adl_lkup(vol, path))) {
                        if (ad_getdate(adp, AD_DATE_BACKUP, (u_int32_t*)&b_date) >= 0)
                                b_date = AD_DATE_TO_UNIX(b_date);
                        else b_date = path->st.st_mtime;
@@ -361,7 +366,7 @@ static int crit_check(struct vol *vol, struct path *path, int cidx) {
                                
        /* Check attributes */
        if ((c1.rbitmap & (1<<DIRPBIT_ATTR)) && c2.attr != 0) {
-               if (adp || (adp = adl_lkup(path))) {
+               if (adp || (adp = adl_lkup(vol, path))) {
                        ad_getattr(adp, &attr);
                        if ((attr & c2.attr) != c1.attr)
                                goto crit_check_ret;
@@ -371,7 +376,7 @@ static int crit_check(struct vol *vol, struct path *path, int cidx) {
         /* Check file type ID */
        if ((c1.rbitmap & (1<<DIRPBIT_FINFO)) && c2.finfo.f_type != 0) {
                if (!adp)
-                       adp = adl_lkup(path);
+                       adp = adl_lkup(vol, path);
                finfo = get_finderinfo(path->m_name, adp, &finderinfo);
                if (finfo->f_type != c1.finfo.f_type)
                        goto crit_check_ret;
@@ -381,7 +386,7 @@ static int crit_check(struct vol *vol, struct path *path, int cidx) {
        if ((c1.rbitmap & (1<<DIRPBIT_FINFO)) && c2.finfo.creator != 0) {
                if (!finfo) {
                        if (!adp)
-                               adp = adl_lkup(path);
+                               adp = adl_lkup(vol, path);
                        finfo = get_finderinfo(path->m_name, adp, &finderinfo);
                }
                if (finfo->creator != c1.finfo.creator)
@@ -392,7 +397,7 @@ static int crit_check(struct vol *vol, struct path *path, int cidx) {
        if ((c1.rbitmap & (1<<DIRPBIT_FINFO)) && c2.finfo.attrs != 0) {
                u_int8_t attrs = 0;
 
-               if (adp || (adp = adl_lkup(path))) {
+               if (adp || (adp = adl_lkup(vol, path))) {
                        finfo = (struct finderinfo*)ad_entry(adp, ADEID_FINDERI);
                        attrs = finfo->attrs;
                }
@@ -406,7 +411,7 @@ static int crit_check(struct vol *vol, struct path *path, int cidx) {
        
        /* Check label */
        if ((c1.rbitmap & (1<<DIRPBIT_FINFO)) && c2.finfo.label != 0) {
-               if (adp || (adp = adl_lkup(path))) {
+               if (adp || (adp = adl_lkup(vol, path))) {
                        finfo = (struct finderinfo*)ad_entry(adp, ADEID_FINDERI);
                        if ((finfo->label & c2.finfo.label) != c1.finfo.label)
                                goto crit_check_ret;
@@ -603,6 +608,14 @@ static int catsearch(struct vol *vol, struct dir *dir,
                        if (!(fname = path.m_name = check_dirent(vol, entry->d_name)))
                           continue;
 
+                       if (NULL == (fname = path.m_name = utompath(vol, entry->d_name, 0, utf8_encoding())))
+                          continue;
+
+                      /* now check against too big a file */
+                       if (strlen(path.m_name) > vol->max_filename)
+                          continue;
+
+
                        path.u_name = entry->d_name;
                        if (of_stat(&path) != 0) {
                                switch (errno) {
@@ -702,6 +715,10 @@ int catsearch_afp(AFPObj *obj, char *ibuf, int ibuflen,
     int ret, rsize;
     u_int32_t nrecs = 0;
     unsigned char *spec1, *spec2, *bspec1, *bspec2;
+    size_t     len;
+    u_int16_t  namelen;
+    u_int16_t  flags;
+    char       tmppath[256];
 
     memset(&c1, 0, sizeof(c1));
     memset(&c2, 0, sizeof(c2));
@@ -833,11 +850,7 @@ int catsearch_afp(AFPObj *obj, char *ibuf, int ibuflen,
 
     /* Long name */
     if (c1.rbitmap & (1 << FILPBIT_LNAME)) {
-       char            tmppath[256];
-       size_t          len;
         /* Get the long filename */    
-/*     memcpy(c1.lname, bspec1 + spec1[1] + 1, (bspec1 + spec1[1])[0]);
-       c1.lname[(bspec1 + spec1[1])[0]]= 0;*/
        memcpy(tmppath, bspec1 + spec1[1] + 1, (bspec1 + spec1[1])[0]);
        tmppath[(bspec1 + spec1[1])[0]]= 0;
        len = convert_string ( vol->v_maccharset, CH_UCS2, tmppath, strlen(tmppath), c1.lname, 64);
@@ -845,24 +858,14 @@ int catsearch_afp(AFPObj *obj, char *ibuf, int ibuflen,
             return AFPERR_PARAM;
        c1.lname[len] = 0;
 
-       
 #if 0  
-       for (i = 0; c1.lname[i] != 0; i++)
-               c1.lname[i] = tolower(c1.lname[i]);
-#endif         
        /* FIXME: do we need it ? It's always null ! */
        memcpy(c2.lname, bspec2 + spec2[1] + 1, (bspec2 + spec2[1])[0]);
        c2.lname[(bspec2 + spec2[1])[0]]= 0;
-#if 0
-       for (i = 0; c2.lname[i] != 0; i++)
-               c2.lname[i] = tolower(c2.lname[i]);
 #endif
     }
         /* UTF8 Name */
     if (c1.rbitmap & (1 << FILPBIT_PDINFO)) {
-       char            tmppath[256];
-       size_t          len;
-       u_int16_t       namelen;
 
        /* offset */
        memcpy(&namelen, spec1, sizeof(namelen));
@@ -880,8 +883,8 @@ int catsearch_afp(AFPObj *obj, char *ibuf, int ibuflen,
        c1.utf8name[(namelen+1)] =0;
 
        /* convert charset */
-       len = utf8_precompose( c1.utf8name, namelen, tmppath, 256); 
-       len = convert_string(CH_UTF8, CH_UCS2, tmppath, namelen, c1.utf8name, 512);
+       flags = CONV_PRECOMPOSE;
+       len = convert_charset(CH_UTF8_MAC, CH_UCS2, c1.utf8name, namelen, c1.utf8name, 512, &flags);
         if (len == (size_t)(-1))
             return AFPERR_PARAM;
        c1.utf8name[len]=0;
index a6375e4eb7df2e08fb5542fdaae8ecbb860119a3..daa2ae8e9b96d2b3ccc8420627ba3dbdbd52213a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: desktop.c,v 1.26.2.4 2003-07-21 05:50:54 didg Exp $
+ * $Id: desktop.c,v 1.26.2.4.2.1 2003-09-09 16:42:19 didg Exp $
  *
  * See COPYRIGHT.
  *
@@ -46,9 +46,7 @@
 #include "globals.h"
 #include "desktop.h"
 
-#ifdef FILE_MANGLING
 #include "mangle.h"
-#endif /* CNID_DB */
 
 #ifdef AFP3x
 #include <iconv.h>
@@ -622,248 +620,105 @@ static char  upath[ MAXPATHLEN + 1];
 static char  mpath[ MAXPATHLEN + 1];
 static char  ucs2[ MAXPATHLEN + 1];
 
-static char *old_mtoupath(const struct vol *vol, char *mpath)
-{
-    char       *m, *u;
-    int                 i = 0;
-    int          changed = 0;
-        
-    m = mpath;
-    u = upath;
-    if ((vol->v_casefold & (AFPVOL_MTOUUPPER| AFPVOL_MTOULOWER))) {
-        changed = 1;
-    }
-    while ( *m != '\0' ) {
-        /* handle case conversion first */
-        if (vol->v_casefold & AFPVOL_MTOUUPPER)
-            *m = diatoupper( *m );
-        else if (vol->v_casefold & AFPVOL_MTOULOWER)
-            *m = diatolower( *m );
-
-        /* we have a code page. we only use the ascii range
-         * if we have map ascii specified. */
-        if (vol->v_mtoupage && ((*m & 0x80) ||
-                                vol->v_flags & AFPVOL_MAPASCII)) {
-            *u = vol->v_mtoupage->map[(unsigned char) *m].value;
-            changed = 1;
-            if (!*u && *m) {
-                /* if conversion failed, encode in hex
-                 * to prevent silly truncation
-                 * H.P. Jansen <hpj@urpla.net> */
-#ifdef DEBUG
-                LOG(log_debug, logtype_afpd, "mtoupath: hex encode: 0x%x", (unsigned char) *m);
-#endif
-                *u++ = ':';
-                *u++ = hexdig[ ( *m & 0xf0 ) >> 4 ];
-                *u = hexdig[ *m & 0x0f ];
-            }
-        } else {
-#if AD_VERSION == AD_VERSION1
-            if ((((vol->v_flags & AFPVOL_NOHEX) == 0) &&
-                    (!isascii(*m) || *m == '/')) ||
-                    (((vol->v_flags & AFPVOL_USEDOTS) == 0) &&
-                     ( i == 0 && (*m == '.' )))) {
-#else 
-            if ((((vol->v_flags & AFPVOL_NOHEX) == 0) &&
-                    (!isprint(*m) || *m == '/')) ||
-                    (((vol->v_flags & AFPVOL_USEDOTS) == 0) &&
-                     ( i == 0 && (*m == '.' )))) {
-#endif
-                /* do hex conversion. */
-                *u++ = ':';
-                *u++ = hexdig[ ( *m & 0xf0 ) >> 4 ];
-                *u = hexdig[ *m & 0x0f ];
-                changed = 1;
-            } else
-                *u = *m;
-        }
-        u++;
-        i++;
-        m++;
-    }
-    *u = '\0';
-
-#ifdef DEBUG
-    LOG(log_debug, logtype_afpd, "mtoupath: '%s':'%s'", mpath, upath);
-#endif /* DEBUG */
-
-    return( (changed)?upath:mpath );
-}
-
-/* ---------------------------- */
-#define hextoint( c )  ( isdigit( c ) ? c - '0' : c + 10 - 'a' )
-#define islxdigit(x)   (!isupper(x)&&isxdigit(x))
-
-static char *old_utompath(const struct vol *vol, char *upath)
-{
-    char        *m, *u;
-    int          h;
-    int          changed = 0;
-
-    /* do the hex conversion */
-    u = upath;
-    m = mpath;
-    if ((vol->v_casefold & (AFPVOL_MTOUUPPER| AFPVOL_MTOULOWER))) {
-        changed = 1;
-    }
-    while ( *u != '\0' ) {
-        /* we have a code page */
-        if (vol->v_utompage && ((*u & 0x80) ||
-                                (vol->v_flags & AFPVOL_MAPASCII))) {
-            *m = vol->v_utompage->map[(unsigned char) *u].value;
-            changed = 1;
-        } else
-            if ( *u == ':' && *(u+1) != '\0' && islxdigit( *(u+1)) &&
-                    *(u+2) != '\0' && islxdigit( *(u+2))) {
-                ++u;
-                h = hextoint( *u ) << 4;
-                ++u;
-                h |= hextoint( *u );
-                *m = h;
-                changed = 1;
-            } else
-                *m = *u;
-
-        /* handle case conversion */
-        if (vol->v_casefold & AFPVOL_UTOMLOWER)
-            *m = diatolower( *m );
-        else if (vol->v_casefold & AFPVOL_UTOMUPPER)
-            *m = diatoupper( *m );
-
-        u++;
-        m++;
-    }
-    *m = '\0';
-    m = mpath;
-
-#ifdef FILE_MANGLING
-    m = mangle(vol, mpath, upath, 0);
-    if (m != mpath) {
-        changed = 1;
-    }
-#endif /* FILE_MANGLING */
-
-#ifdef DEBUG
-    LOG(log_debug, logtype_afpd, "utompath: '%s':'%s'", upath, mpath);
-#endif /* DEBUG */
-
-    return((changed)? m:upath );
-}
-
-/* --------------------------- */
 char *mtoupath(const struct vol *vol, char *mpath, int utf8)
 {
-    char       *m, *u, *r;
-    int                 i = 0;
+    char       *m, *u;
     size_t       inplen;
     size_t       outlen;
+    u_int16_t   flags = 0;
         
     if ( *mpath == '\0' ) {
         return( "." );
     }
 
-#ifdef FILE_MANGLING
     m = demangle(vol, mpath);
     if (m != mpath) {
         return m;
     }
-#endif /* FILE_MANGLING */
-
-    if (!vol_utf8(vol))
-       return old_mtoupath(vol, mpath);
 
     m = mpath;
     u = upath;
-    while ( *m != '\0' ) {
-        if ( (!(vol->v_flags & AFPVOL_NOHEX) && *m == '/') ||
-             (!(vol->v_flags & AFPVOL_USEDOTS) && i == 0 && *m == '.') 
-        ) {
-          /* do hex conversion. */
-          *u++ = ':';
-          *u++ = hexdig[ ( *m & 0xf0 ) >> 4 ];
-          *u = hexdig[ *m & 0x0f ];
-        } else
-           *u = *m;
-        u++;
-        i++;
-        m++;
-    }
-    *u = '\0';
-    u = upath;
-#ifdef AFP3x
-    inplen = strlen(u);
+
+    inplen = strlen(m);
     outlen = MAXPATHLEN;
-    r = ucs2;
-    if (!utf8) {
-        /* assume precompose */
-        if ((size_t)(-1) == (outlen = convert_string ( vol->v_maccharset, CH_UTF8, u, inplen, r, outlen)) )
-            return NULL;
-        u = ucs2;
-    }
-    else { 
 
-       r = upath;
+    /* set conversion flags */
+    if (!(vol->v_flags & AFPVOL_NOHEX))
+        flags |= CONV_ESCAPEHEX;
+    if (!(vol->v_flags & AFPVOL_USEDOTS))
+        flags |= CONV_ESCAPEDOTS;
+
+    if ((vol->v_casefold & AFPVOL_MTOUUPPER))
+        flags |= CONV_TOUPPER;
+    else if ((vol->v_casefold & AFPVOL_MTOULOWER))
+        flags |= CONV_TOLOWER;
        
-        if ((size_t)(-1) == (outlen = utf8_precompose(  u, inplen, r, outlen)) )
+    if ((size_t)-1 == (outlen = convert_charset ( (utf8)?CH_UTF8_MAC:vol->v_maccharset, vol->v_volcharset, m, inplen, u, outlen, &flags)) ) {
+        LOG(log_error, logtype_afpd, "conversion from %s to %s for %s failed.", (utf8)?"UTF8-MAC":vol->v_maccodepage, vol->v_volcodepage, mpath);
            return NULL;
+    }
+    upath[outlen] = 0;
 
-        u = upath; 
+    /* convert to old cap format */
+    u=ucs2;
+    if ((size_t)-1 == (outlen = encode_cap ( vol->v_maccharset, upath, outlen, u, MAXPATHLEN)) ) {
+        LOG(log_error, logtype_afpd, "cap encode '%s' failed.", upath);
+        return NULL;
     }
     u[outlen] = 0;
-#endif
+
 #ifdef DEBUG
-    LOG(log_debug, logtype_afpd, "mtoupath: '%s':'%s'", mpath, upath);
+    LOG(log_debug, logtype_afpd, "mtoupath: '%s':'%s'", mpath, u);
 #endif /* DEBUG */
     return( u );
 }
 
 /* --------------- */
-char *utompath(const struct vol *vol, char *upath, int utf8)
+char *utompath(const struct vol *vol, char *upath, cnid_t id, int utf8)
 {
     char        *m, *u;
-    int          h;
-    int          mangleflag = 0;
+    u_int16_t    flags = CONV_IGNORE | CONV_UNESCAPEHEX;
     size_t       outlen;
 
-    if (!vol_utf8(vol))
-       return old_utompath(vol, upath);
-    /* do the hex conversion */
-    u = upath;
     m = mpath;
-    while ( *u != '\0' ) {
-        if ( *u == ':' && islxdigit( *(u+1)) && islxdigit( *(u+2))) {
-            ++u;
-            h = hextoint( *u ) << 4;
-            ++u;
-            h |= hextoint( *u );
-            *m = h;
-        } else
-            *m = *u;
-        u++;
-        m++;
+    outlen = strlen(upath);
+
+    u=ucs2;
+    if ((size_t)-1 == (outlen = decode_cap(vol->v_maccharset, upath, outlen, u, MAXPATHLEN, &flags)) ) {
+        LOG(log_error, logtype_afpd, "cap_decode failed for '%s'", upath);
+       goto utompath_error;
     }
-    *m = '\0';
-    m = mpath;
-#ifdef AFP3x    
-    if (utf8) {
-       if ((size_t)(-1) == ( outlen = utf8_decompose ( mpath, strlen (mpath), mpath, MAXPATHLEN)) )
-          return NULL;
+    u[outlen] = 0;
+
+    if (vol->v_casefold & AFPVOL_UTOMUPPER)
+        flags |= CONV_TOUPPER;
+    else if (vol->v_casefold & AFPVOL_UTOMLOWER)
+        flags |= CONV_TOLOWER;
+
+    /* convert charsets */
+    if ((size_t)-1 == ( outlen = convert_charset ( vol->v_volcharset, (utf8)?CH_UTF8_MAC:vol->v_maccharset,  u, outlen, mpath, MAXPATHLEN, &flags)) ) { 
+        LOG(log_error, logtype_afpd, "Conversion from %s to %s for %s (%u) failed.", vol->v_volcodepage, vol->v_maccodepage, u, ntohl(id));
+       goto utompath_error;
     }
+
+    mpath[outlen] = 0; 
+    if (!(flags & CONV_REQMANGLE)) 
+        flags = 0;
     else {
-        if ((size_t)(-1) == ( outlen = utf8_to_mac_charset ( vol->v_maccharset,  mpath, strlen(mpath), mpath, MAXPATHLEN, &mangleflag)) ) 
-               return NULL;
+       if (NULL != (u = strrchr(mpath, '.')) ) 
+               mpath[u-mpath] = 0;
    }
-   mpath[outlen] = 0; 
 
-#endif
-#ifdef FILE_MANGLING
-    m = mangle(vol, mpath, upath, mangleflag);
-#else
-    if (mangleflag)
-        return NULL;
-    m = mpath;
-#endif /* FILE_MANGLING */
+    m = mangle(vol, mpath, upath, id, flags);
+
+#ifdef DEBUG
+    LOG(log_debug, logtype_afpd, "utompath: '%s':'%s':'%2.2X'", upath, m, ntohl(id));
+#endif /* DEBUG */
+    return(m);
 
+utompath_error:
+    u = "unconvertable";
+    m = mangle(vol, u, upath, id, 1);
     return(m);
 }
 
@@ -917,7 +772,7 @@ int         ibuflen, *rbuflen;
 
     isadir = path_isadir(path);
     if (isadir || !(of = of_findname(path))) {
-        memset(&ad, 0, sizeof(ad));
+        ad_init(&ad, vol->v_adouble);
         adp = &ad;
     } else
         adp = of->of_ad;
@@ -983,7 +838,7 @@ int         ibuflen, *rbuflen;
     upath = s_path->u_name;
     isadir = path_isadir(s_path);
     if (isadir || !(of = of_findname(s_path))) {
-        memset(&ad, 0, sizeof(ad));
+        ad_init(&ad, vol->v_adouble);
         adp = &ad;
     } else
         adp = of->of_ad;
@@ -1053,7 +908,7 @@ int                ibuflen, *rbuflen;
 
     isadir = path_isadir(s_path);
     if (isadir || !(of = of_findname(s_path))) {
-        memset(&ad, 0, sizeof(ad));
+        ad_init(&ad, vol->v_adouble);
         adp = &ad;
     } else
         adp = of->of_ad;
index f766c7579c8290d5bdb4f2177acde7e9bad2588f..fd932a4e577461898bfc2d61e647a063b4b944b9 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: desktop.h,v 1.3 2003-03-09 19:55:33 didg Exp $
+ * $Id: desktop.h,v 1.3.6.1 2003-09-09 16:42:20 didg Exp $
  *
  * Copyright (c) 1990,1991 Regents of The University of Michigan.
  * All Rights Reserved.
@@ -47,7 +47,7 @@ typedef unsigned char CreatorType[4];
 
 extern char    *dtfile __P((const struct vol *, u_char [], char *));
 extern char    *mtoupath __P((const struct vol *, char *, int utf8));
-extern char    *utompath __P((const struct vol *, char *, int utf8));
+extern char    *utompath __P((const struct vol *, char *, cnid_t, int utf8));
 extern u_char  ucreator[];
 
 #define validupath(vol, name) ((((vol)->v_flags & AFPVOL_USEDOTS) ? \
index c6e7e015875bc4186b4797dcf8eede368b679d6a..f8b0a61e0b122fef1a1dbd8a0351fdc36c318042 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: directory.c,v 1.71.2.4 2003-07-21 05:50:54 didg Exp $
+ * $Id: directory.c,v 1.71.2.4.2.1 2003-09-09 16:42:20 didg Exp $
  *
  * Copyright (c) 1990,1993 Regents of The University of Michigan.
  * All Rights Reserved.  See COPYRIGHT.
@@ -22,9 +22,7 @@
 #include <atalk/adouble.h>
 #include <atalk/afp.h>
 #include <atalk/util.h>
-#ifdef CNID_DB
 #include <atalk/cnid.h>
-#endif /* CNID_DB */
 #include <utime.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -59,6 +57,8 @@ char *strchr (), *strrchr ();
 #include "globals.h"
 #include "unix.h"
 
+#include "mangle.h"
+
 struct dir     *curdir;
 int             afp_errno;
 
@@ -173,10 +173,9 @@ struct dir *
             const struct vol   *vol;
 u_int32_t      did;
 {
-#ifdef CNID_DB
     struct dir   *ret;
     char        *upath;
-    u_int32_t   id;
+    cnid_t      id, cnid;
     static char  path[MAXPATHLEN + 1];
     size_t len,  pathlen;
     char         *ptr;
@@ -193,12 +192,12 @@ u_int32_t did;
     utf8 = utf8_encoding();
     maxpath = (utf8)?MAXPATHLEN -7:255;
     id = did;
-    if (NULL == (upath = cnid_resolve(vol->v_db, &id, buffer, buflen)) ) {
+    if (NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, buflen)) ) {
         afp_errno = AFPERR_NOOBJ;
         return NULL;
     }
     ptr = path + MAXPATHLEN;
-    if (NULL == ( mpath = utompath(vol, upath, utf8) ) ) {
+    if (NULL == ( mpath = utompath(vol, upath, did, utf8) ) ) {
         afp_errno = AFPERR_NOOBJ;
         return NULL;
     }
@@ -212,9 +211,10 @@ u_int32_t  did;
         if (ret != NULL) {
             break;
         }
-        if ( NULL == (upath = cnid_resolve(vol->v_db, &id, buffer, buflen))
+        cnid = id;
+        if ( NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, buflen))
              ||
-             NULL == (mpath = utompath(vol, upath, utf8))
+             NULL == (mpath = utompath(vol, upath, cnid, utf8))
         ) {
             afp_errno = AFPERR_NOOBJ;
             return NULL;
@@ -254,7 +254,7 @@ u_int32_t   did;
     /* cname is not efficient */
     if (cname( vol, ret, &ptr ) == NULL )
         return NULL;
-#endif
+       
     return dirsearch(vol, did);
 }
 
@@ -564,7 +564,9 @@ struct vol  *vol;
 struct dir     *dir;
 struct path *path;
 {
+    if ( path->u_name == NULL) {
     path->u_name = mtoupath(vol, path->m_name, utf8_encoding() );
+    }
     path->dir = NULL;
 
     if ( path->u_name == NULL) {
@@ -1044,7 +1046,7 @@ char      **cpath;
                ret.dir = dir;
             }               
             return &ret;
-        }
+        } /* if (len == 0) */
 
         if (*data == sep ) {
             data++;
@@ -1079,6 +1081,20 @@ char     **cpath;
         *p = '\0';
 
         if ( p != path ) { /* we got something */
+            char *t;
+            ret.u_name = NULL;
+            /* check for mangled filename :( */
+            if (afp_version >= 30) {
+                t = demangle(vol, path);
+                if (t != path) {
+                    /* should we check id is cdir->d_did ? */
+                    ret.u_name = t;
+                    if ( (t = utompath(vol, ret.u_name, 0, utf8_encoding())) ) {
+                         /* at last got our mac name */
+                         strcpy(path,t);
+                    }
+                }
+            }
             if ( !extend ) {
                 cdir = dir->d_child;
                 while (cdir) {
@@ -1112,7 +1128,7 @@ char      **cpath;
 
             } else {
                 cdir = extenddir( vol, dir, &ret );
-            }
+            } /* if (!extend) */
 
             if ( cdir == NULL ) {
 
@@ -1124,8 +1140,8 @@ char      **cpath;
                 dir = cdir;    
                 *path = '\0';
             }
-        }
-    }
+        } /* if (p != path) */
+    } /* for (;;) */
 }
 
 /*
@@ -1259,7 +1275,8 @@ int getdirparams(const struct vol *vol,
                   (1 << DIRPBIT_MDATE) |
                   (1 << DIRPBIT_BDATE) |
                   (1 << DIRPBIT_FINFO)))) {
-        memset(&ad, 0, sizeof(ad));
+
+        ad_init(&ad, vol->v_adouble);
        if ( !ad_open( upath, ADFLAGS_HF|ADFLAGS_DIR, O_RDONLY,
                   DIRBITS | 0777, &ad)) {
             isad = 1;
@@ -1454,12 +1471,12 @@ int getdirparams(const struct vol *vol,
     if ( l_nameoff ) {
         ashort = htons( data - buf );
         memcpy( l_nameoff, &ashort, sizeof( ashort ));
-        data = set_name(vol, data, dir->d_m_name, 0);
+        data = set_name(vol, data, dir->d_m_name, dir->d_did, 0);
     }
     if ( utf_nameoff ) {
         ashort = htons( data - buf );
         memcpy( utf_nameoff, &ashort, sizeof( ashort ));
-        data = set_name(vol, data, dir->d_m_name, utf8);
+        data = set_name(vol, data, dir->d_m_name, dir->d_did, utf8);
     }
     if ( isad ) {
         ad_close( &ad, ADFLAGS_HF );
@@ -1570,7 +1587,7 @@ int setdirparams(const struct vol *vol,
     int                 newdate = 0;
 
     upath = path->u_name;
-    memset(&ad, 0, sizeof(ad));
+    ad_init(&ad, vol->v_adouble);
 
     if (ad_open( upath, vol_noadouble(vol)|ADFLAGS_HF|ADFLAGS_DIR,
                  O_RDWR|O_CREAT, 0666, &ad) < 0) {
@@ -1887,6 +1904,10 @@ setdirparam_done:
     }
 
     if ( isad ) {
+        if (path->st_valid && !path->st_errno) {
+            ad_setid(&ad, &path->st, curdir->d_did, vol->v_stamp);
+        }
+    
         ad_flush( &ad, ADFLAGS_HF );
         ad_close( &ad, ADFLAGS_HF );
     }
@@ -1968,7 +1989,7 @@ int               ibuflen, *rbuflen;
         return( AFPERR_PARAM );
     }
 
-    memset(&ad, 0, sizeof(ad));
+    ad_init(&ad, vol->v_adouble);
     if (ad_open( ".", vol_noadouble(vol)|ADFLAGS_HF|ADFLAGS_DIR,
                  O_RDWR|O_CREAT, 0666, &ad ) < 0)  {
         if (vol_noadouble(vol))
@@ -1979,6 +2000,7 @@ int               ibuflen, *rbuflen;
     ad_setentrylen( &ad, ADEID_NAME, strlen( s_path->m_name ));
     memcpy( ad_entry( &ad, ADEID_NAME ), s_path->m_name,
             ad_getentrylen( &ad, ADEID_NAME ));
+    ad_setid( &ad, &s_path->st, dir->d_did, vol->v_stamp);
     ad_flush( &ad, ADFLAGS_HF );
     ad_close( &ad, ADFLAGS_HF );
 
@@ -2032,7 +2054,8 @@ const int noadouble;
         }
     }
 
-    memset(&ad, 0, sizeof(ad));
+    ad_init(&ad, 0);    /* FIXME */
+
     len = strlen( newname );
     /* rename() succeeded so we need to update our tree even if we can't open
      * .Parent
@@ -2103,7 +2126,7 @@ int pathlen;
 
     fdir = curdir;
 
-    memset(&ad, 0, sizeof(ad));
+    ad_init(&ad, vol->v_adouble);
     if ( ad_open( ".", ADFLAGS_HF|ADFLAGS_DIR, O_RDONLY,
                   DIRBITS | 0777, &ad) == 0 ) {
 
@@ -2170,9 +2193,7 @@ int pathlen;
 
     if ( !(err = netatalk_rmdir(fdir->d_u_name))) {
         dirchildremove(curdir, fdir);
-#ifdef CNID_DB
-        cnid_delete(vol->v_db, fdir->d_did);
-#endif /* CNID_DB */
+        cnid_delete(vol->v_cdb, fdir->d_did);
         dir_remove( vol, fdir );
         err = AFP_OK;
     }
index 4c8abb6c85e4819fdf389862503dfdd97e01cbcb..5875cc8fd130e144a7c83dcf69770d89cc5e312e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: enumerate.c,v 1.39.2.2 2003-05-26 11:17:25 didg Exp $
+ * $Id: enumerate.c,v 1.39.2.2.2.1 2003-09-09 16:42:20 didg Exp $
  *
  * Copyright (c) 1990,1993 Regents of The University of Michigan.
  * All Rights Reserved.  See COPYRIGHT.
@@ -23,9 +23,7 @@
 #include <netatalk/endian.h>
 #include <atalk/afp.h>
 #include <atalk/adouble.h>
-#ifdef CNID_DB
 #include <atalk/cnid.h>
-#endif /* CNID_DB */
 #include "desktop.h"
 #include "directory.h"
 #include "volume.h"
@@ -49,19 +47,26 @@ struct path     *path;
     char        *upath;
     struct stat *st;
     int         deleted;
+    cnid_t      id;
 
     upath = path->u_name;
-    name  = path->m_name;    
     st    = &path->st;
     upathlen = strlen(upath);
+
+    id = get_id(vol, NULL, st, dir->d_did, upath, upathlen);
+    if (id == 0) {
+        return NULL;
+    }
+    if (!path->m_name && !(path->m_name = utompath(vol, upath, id , utf8_encoding()))) {
+        return NULL;
+    }
+    name  = path->m_name;    
     if ((cdir = dirnew(name, upath)) == NULL) {
         LOG(log_error, logtype_afpd, "adddir: malloc: %s", strerror(errno) );
         return NULL;
     }
 
-    cdir->d_did = get_id(vol, NULL, st, dir->d_did, upath, upathlen);
-    if (cdir->d_did == 0) 
-        return NULL;
+    cdir->d_did = id;
 
     if ((edir = dirinsert( vol, cdir ))) {
         /* it's not possible with LASTDID
@@ -117,8 +122,7 @@ static int enumerate_loop(struct dirent *de, char *mname, void *data)
     end = sd->sd_buf + sd->sd_buflen;
     len = strlen(de->d_name);
     *(sd->sd_last)++ = len;
-    lenm = strlen(mname);
-
+    lenm = 0; /* strlen(mname);*/
     if ( sd->sd_last + len +lenm + 4 > end ) {
         char *buf;
 
@@ -137,11 +141,11 @@ static int enumerate_loop(struct dirent *de, char *mname, void *data)
 
     memcpy( sd->sd_last, de->d_name, len + 1 );
     sd->sd_last += len + 1;
-
+#if 0
     *(sd->sd_last)++ = lenm;
     memcpy( sd->sd_last, mname, lenm + 1 );
     sd->sd_last += lenm + 1;
-    
+#endif    
     return 0;
 }
 
@@ -161,7 +165,6 @@ static int enumerate_loop(struct dirent *de, char *mname, void *data)
 */
 char *check_dirent(const struct vol *vol, char *name)
 {
-    char *m_name = NULL;
 
     if (!strcmp(name, "..") || !strcmp(name, "."))
         return NULL;
@@ -172,14 +175,17 @@ char *check_dirent(const struct vol *vol, char *name)
     /* check for vetoed filenames */
     if (veto_file(vol->v_veto, name))
         return NULL;
-    if (NULL == (m_name = utompath(vol, name, utf8_encoding()))) 
+#if 0
+    char *m_name = NULL;
+
+    if (NULL == (m_name = utompath(vol, name, 0, utf8_encoding()))) 
         return NULL;    
 
     /* now check against too big a file */
     if (strlen(m_name) > vol->max_filename)
         return NULL;
-
-    return m_name;
+#endif
+    return name;
 }
 
 /* ----------------------------- */
@@ -371,8 +377,6 @@ int     ext;
             return( AFPERR_NOOBJ );
         }
         sd.sd_last += len + 1;
-        len = *(sd.sd_last)++;
-        sd.sd_last += len + 1;
         sd.sd_sindex++;
     }
 
@@ -394,8 +398,6 @@ int     ext;
         if (*sd.sd_last == 0) {
             /* stat() already failed on this one */
             sd.sd_last += len + 1;
-            len = *(sd.sd_last)++;
-            sd.sd_last += len + 1;
             continue;
         }
         s_path.u_name = sd.sd_last;
@@ -411,16 +413,12 @@ int     ext;
              */
             *sd.sd_last = 0;
             sd.sd_last += len + 1;
-            len = *(sd.sd_last)++;
-            sd.sd_last += len + 1;
             curdir->offcnt--;          /* a little lie */
             continue;
         }
 
         sd.sd_last += len + 1;
-        len = *(sd.sd_last)++;
-        s_path.m_name = sd.sd_last;
-        sd.sd_last += len + 1;
+        s_path.m_name = NULL;
         /*
          * 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
@@ -431,14 +429,9 @@ int     ext;
                 continue;
             }
             dir = dirsearch_byname(curdir, s_path.u_name);
-            if (!dir) {
-                if (s_path.m_name == NULL || (dir = adddir( vol, curdir, &s_path)) == NULL) {
+            if (!dir && NULL == (dir = adddir( vol, curdir, &s_path) ) ) {
                     return AFPERR_MISC;
                 }
-            }
-            else {
-                s_path.m_name = NULL;
-            }
             if (AFP_OK != ( ret = getdirparams(vol, dbitmap, &s_path, dir,
                                      data + header , &esz ))) {
                 return( ret );
@@ -448,9 +441,6 @@ int     ext;
             if ( fbitmap == 0 ) {
                 continue;
             }
-            if (s_path.m_name == NULL ) {
-                return AFPERR_MISC;
-            }
             if (AFP_OK != ( ret = getfilparams(vol, fbitmap, &s_path, curdir, 
                                      data + header , &esz )) ) {
                 return( ret );
index 8a7fe25448b5e0f27f063cd299a3e99e764e5423..acfbd5a7780ea41f4e1bf1eaea78c80cca6a2f0b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: file.c,v 1.92.2.2 2003-07-21 05:50:54 didg Exp $
+ * $Id: file.c,v 1.92.2.2.2.1 2003-09-09 16:42:20 didg Exp $
  *
  * Copyright (c) 1990,1993 Regents of The University of Michigan.
  * All Rights Reserved.  See COPYRIGHT.
@@ -48,9 +48,7 @@ char *strchr (), *strrchr ();
 #include <atalk/adouble.h>
 #include <atalk/afp.h>
 #include <atalk/util.h>
-#ifdef CNID_DB
 #include <atalk/cnid.h>
-#endif /* CNID_DB */
 #include "directory.h"
 #include "desktop.h"
 #include "volume.h"
@@ -90,9 +88,10 @@ const u_char ufinderi[] = {
 void *get_finderinfo(const char *mpath, struct adouble *adp, void *data)
 {
     struct extmap      *em;
+    void                *ad_finder;
 
-    if (adp) {
-        memcpy(data, ad_entry(adp, ADEID_FINDERI), 32);
+    if (adp && (ad_finder = ad_entry(adp, ADEID_FINDERI))) {
+        memcpy(data, ad_finder, 32);
     }
     else {
         memcpy(data, ufinderi, 32);
@@ -109,7 +108,7 @@ void *get_finderinfo(const char *mpath, struct adouble *adp, void *data)
 
 /* ---------------------
 */
-char *set_name(const struct vol *vol, char *data, char *name, u_int32_t utf8) 
+char *set_name(const struct vol *vol, char *data, char *name, cnid_t id, u_int32_t utf8) 
 {
     u_int32_t   aint;
     char        *tp = NULL;
@@ -124,7 +123,7 @@ char *set_name(const struct vol *vol, char *data, char *name, u_int32_t utf8)
            
             /* global static variable... */
             tp = strdup(name);
-            if (!(u = mtoupath(vol, name, 1)) || !(m = utompath(vol, u, 0))) {
+            if (!(u = mtoupath(vol, name, 1)) || !(m = utompath(vol, u, id, 0))) {
                aint = 0;
             }
             else {
@@ -143,7 +142,7 @@ char *set_name(const struct vol *vol, char *data, char *name, u_int32_t utf8)
         if (aint > 255)  /* FIXME safeguard, anyway if no ascii char it's game over*/
            aint = 255;
 
-        utf8 = 0;         /* htonl(utf8) */
+        utf8 = htonl(vol->v_mac->kTextEncoding);         /* htonl(utf8) */
         memcpy(data, &utf8, sizeof(utf8));
         data += sizeof(utf8);
         
@@ -179,9 +178,30 @@ u_int32_t get_id(struct vol *vol, struct adouble *adp,  const struct stat *st,
 {
 u_int32_t aint = 0;
 
-#ifdef CNID_DB
-
-    aint = cnid_add(vol->v_db, st, did, upath, len, aint);
+#if AD_VERSION > AD_VERSION1
+dev_t  dev;
+ino_t  ino;
+char   stamp[ADEDLEN_PRIVSYN];
+    /* look in AD v2 header 
+     * note inode and device are opaques and not in network order
+    */
+    if (adp && sizeof(dev_t) == ad_getentrylen(adp, ADEID_PRIVDEV)) {
+        memcpy(&dev, ad_entry(adp, ADEID_PRIVDEV), sizeof(dev_t));
+        if ( sizeof(ino_t) == ad_getentrylen(adp,ADEID_PRIVINO)) {
+            memcpy(&ino, ad_entry(adp, ADEID_PRIVINO), sizeof(ino_t));
+            if (sizeof(stamp) == ad_getentrylen(adp,ADEID_PRIVSYN)) {
+                memcpy(stamp, ad_entry(adp, ADEID_PRIVSYN), sizeof(stamp));
+
+                if (dev == st->st_dev && ino == st->st_ino && !memcmp(vol->v_stamp, stamp, sizeof(stamp))) {
+                    memcpy(&aint, ad_entry(adp, ADEID_DID), sizeof(aint));
+                    return aint;
+                }
+            }
+        }
+    }
+#endif
+    if (vol->v_cdb != NULL) {
+           aint = cnid_add(vol->v_cdb, st, did, upath, len, aint);
     /* Throw errors if cnid_add fails. */
     if (aint == CNID_INVALID) {
         switch (errno) {
@@ -199,53 +219,17 @@ u_int32_t aint = 0;
             return CNID_INVALID;
         }
     }
-#endif /* CNID_DB */
-
-    if (aint == 0) {
-        /*
-         * First thing:  DID and FNUMs are
-         * in the same space for purposes of enumerate (and several
-         * other wierd places).  While we consider this Apple's bug,
-         * this is the work-around:  In order to maintain constant and
-         * unique DIDs and FNUMs, we monotonically generate the DIDs
-         * during the session, and derive the FNUMs from the filesystem.
-         * Since the DIDs are small, we insure that the FNUMs are fairly
-         * large by setting thier high bits to the device number.
-         *
-         * AFS already does something very similar to this for the
-         * inode number, so we don't repeat the procedure.
-         *
-         * new algorithm:
-         * due to complaints over did's being non-persistent,
-         * here's the current hack to provide semi-persistent
-         * did's:
-         *      1) we reserve the first bit for file ids.
-         *      2) the next 7 bits are for the device.
-         *      3) the remaining 24 bits are for the inode.
-         *
-         * both the inode and device information are actually hashes
-         * that are then truncated to the requisite bit length.
-         *
-         * it should be okay to use lstat to deal with symlinks.
+#if AD_VERSION > AD_VERSION1
+            else if (adp && sizeof(dev_t) == ADEDLEN_PRIVDEV && sizeof(ino_t) == ADEDLEN_PRIVINO) {
+                /* update the ressource fork
+                 * for a folder adp is always null
          */
-#ifdef USE_LASTDID
-        if ( S_ISDIR(st->st_mode)) {
-            aint = htonl( vol->v_lastdid++ );
+                 ad_setid(adp, st, aint, vol->v_stamp);
+                 ad_flush(adp, ADFLAGS_HF);
         }
-        else
-        {
-            aint = htonl(( st->st_dev << 16 ) | (st->st_ino & 0x0000ffff));
+#endif    
         }
-#else /* USE_LASTDID */
-        {
-            struct stat        lst;
-            const struct stat *lstp;
 
-            lstp = lstat(upath, &lst) < 0 ? st : &lst;
-            aint = htonl(CNID(lstp, 1));
-        }
-#endif /* USE_LASTDID */
-    }
     return aint;
 }
              
@@ -259,6 +243,7 @@ int getmetadata(struct vol *vol,
     char                *utf_nameoff = NULL;
     int                        bit = 0;
     u_int32_t          aint;
+    cnid_t              id = 0;
     u_int16_t          ashort;
     u_char              achar, fdType[4];
     u_int32_t           utf8 = 0;
@@ -273,6 +258,18 @@ int getmetadata(struct vol *vol,
     st = &path->st;
 
     data = buf;
+
+    if ( ((bitmap & ( (1 << FILPBIT_FINFO)|(1 << FILPBIT_LNAME)|(1 <<FILPBIT_PDINFO) ) ) && !path->m_name)
+         || (bitmap & ( (1 << FILPBIT_LNAME) ) && utf8_encoding()) /* FIXME should be m_name utf8 filename */
+         || (bitmap & (1 << FILPBIT_FNUM))) {
+         
+        id = get_id(vol, adp, st, dir->d_did, upath, strlen(upath));
+        if (id == 0)
+            return afp_errno;
+        if (!path->m_name) {
+            path->m_name = utompath(vol, upath, id, utf8_encoding());
+        }
+    }
     while ( bitmap != 0 ) {
         while (( bitmap & 1 ) == 0 ) {
             bitmap = bitmap>>1;
@@ -358,11 +355,8 @@ int getmetadata(struct vol *vol,
             break;
 
         case FILPBIT_FNUM :
-            aint = get_id(vol, adp, st, dir->d_did, upath, strlen(upath));
-            if (aint == 0)
-                return afp_errno;
-            memcpy(data, &aint, sizeof( aint ));
-            data += sizeof( aint );
+            memcpy(data, &id, sizeof( id ));
+            data += sizeof( id );
             break;
 
         case FILPBIT_DFLEN :
@@ -492,12 +486,12 @@ int getmetadata(struct vol *vol,
     if ( l_nameoff ) {
         ashort = htons( data - buf );
         memcpy(l_nameoff, &ashort, sizeof( ashort ));
-        data = set_name(vol, data, path->m_name, 0);
+        data = set_name(vol, data, path->m_name, id, 0);
     }
     if ( utf_nameoff ) {
         ashort = htons( data - buf );
         memcpy(utf_nameoff, &ashort, sizeof( ashort ));
-        data = set_name(vol, data, path->m_name, utf8);
+        data = set_name(vol, data, path->m_name, id, utf8);
     }
     *buflen = data - buf;
     return (AFP_OK);
@@ -529,7 +523,7 @@ int getfilparams(struct vol *vol,
            attrbits = ((of->of_ad->ad_df.adf_refcount > 0) ? ATTRBIT_DOPEN : 0);
            attrbits |= ((of->of_ad->ad_hf.adf_refcount > of->of_ad->ad_df.adf_refcount)? ATTRBIT_ROPEN : 0);
         } else {
-            memset(&ad, 0, sizeof(ad));
+            ad_init(&ad, vol->v_adouble);
             adp = &ad;
         }
 
@@ -619,7 +613,7 @@ int         ibuflen, *rbuflen;
     if ((of = of_findname(s_path))) {
         adp = of->of_ad;
     } else {
-        memset(&ad, 0, sizeof(ad));
+        ad_init(&ad, vol->v_adouble);
         adp = &ad;
     }
     if ( creatf) {
@@ -788,7 +782,7 @@ int setfilparams(struct vol *vol,
     if ((of = of_findname(path))) {
         adp = of->of_ad;
     } else {
-        memset(&ad, 0, sizeof(ad));
+        ad_init(&ad, vol->v_adouble);
         adp = &ad;
     }
 
@@ -1016,7 +1010,7 @@ struct adouble    *adp;
              * create .AppleDouble if the file is already opened, so we
              * use a diff one, it's not a pb,ie it's not the same file, yet.
              */
-            memset(&ad, 0, sizeof(ad));
+            ad_init(&ad, AD_VERSION); /* FIXME */
             if (!ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, &ad)) {
                ad_close(&ad, ADFLAGS_HF);
                if (!unix_rename( adsrc, ad_path( dst, 0 )) ) 
@@ -1322,8 +1316,8 @@ const int   noadouble;
     LOG(log_info, logtype_afpd, "begin copyfile:");
 #endif /* DEBUG */
 
-    memset(&ads, 0, sizeof(ads));
-    memset(&add, 0, sizeof(add));
+    ad_init(&ads, 0); /* OK */
+    ad_init(&add, 0); /* FIXME */
     adflags = ADFLAGS_DF;
     if (newname) {
         adflags |= ADFLAGS_HF;
@@ -1418,7 +1412,7 @@ int         checkAttrib;
     /* try to open both forks at once */
     adflags = ADFLAGS_DF|ADFLAGS_HF;
     while(1) {
-        memset(&ad, 0, sizeof(ad));
+        ad_init(&ad, 0);  /* OK */
         if ( ad_open( file, adflags, O_RDONLY, 0, &ad ) < 0 ) {
             switch (errno) {
             case ENOENT:
@@ -1473,13 +1467,11 @@ int         checkAttrib;
     }
     else if (!(err = netatalk_unlink( ad_path( file, ADFLAGS_HF)) ) &&
              !(err = netatalk_unlink( file )) ) {
-#ifdef CNID_DB /* get rid of entry */
         cnid_t id;
-        if (vol && (id = cnid_get(vol->v_db, curdir->d_did, file, strlen(file)))) 
+        if (vol && (id = cnid_get(vol->v_cdb, curdir->d_did, file, strlen(file)))) 
         {
-            cnid_delete(vol->v_db, id);
+            cnid_delete(vol->v_cdb, id);
         }
-#endif /* CNID_DB */
 
     }
     ad_close( &ad, adflags );  /* ad_close removes locks if any */
@@ -1492,7 +1484,6 @@ int         checkAttrib;
 }
 
 /* ------------------------------------ */
-#ifdef CNID_DB
 /* return a file id */
 int afp_createid(obj, ibuf, ibuflen, rbuf, rbuflen )
 AFPObj      *obj;
@@ -1523,7 +1514,7 @@ int               ibuflen, *rbuflen;
         return( AFPERR_PARAM);
     }
 
-    if (vol->v_db == NULL) {
+    if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
         return AFPERR_NOOP;
     }
 
@@ -1558,7 +1549,7 @@ int               ibuflen, *rbuflen;
             return AFPERR_PARAM;
     }
     st = &s_path->st;
-    if ((id = cnid_lookup(vol->v_db, st, did, upath, len = strlen(upath)))) {
+    if ((id = cnid_lookup(vol->v_cdb, st, did, upath, len = strlen(upath)))) {
         memcpy(rbuf, &id, sizeof(id));
         *rbuflen = sizeof(id);
         return AFPERR_EXISTID;
@@ -1588,7 +1579,7 @@ int               ibuflen, *rbuflen;
     char               *upath;
     struct path         path;
     int                 err, buflen;
-    cnid_t             id;
+    cnid_t             id, cnid;
     u_int16_t          vid, bitmap;
 
     static char buffer[12 + MAXPATHLEN + 1];
@@ -1608,14 +1599,15 @@ int             ibuflen, *rbuflen;
         return( AFPERR_PARAM);
     }
 
-    if (vol->v_db == NULL) {
+    if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
         return AFPERR_NOOP;
     }
 
     memcpy(&id, ibuf, sizeof( id ));
     ibuf += sizeof(id);
+    cnid = id;
 
-    if (NULL == (upath = cnid_resolve(vol->v_db, &id, buffer, len)) ) {
+    if (NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, len)) ) {
         return AFPERR_NOID; /* was AFPERR_BADID, but help older Macs */
     }
 
@@ -1640,7 +1632,7 @@ int               ibuflen, *rbuflen;
 
     memcpy(&bitmap, ibuf, sizeof(bitmap));
     bitmap = ntohs( bitmap );
-    if (NULL == (path.m_name = utompath(vol, upath, utf8_encoding()))) {
+    if (NULL == (path.m_name = utompath(vol, upath, cnid, utf8_encoding()))) {
         return AFPERR_NOID;
     }
     if (AFP_OK != (err = getfilparams(vol, bitmap, &path , curdir, 
@@ -1688,7 +1680,7 @@ int               ibuflen, *rbuflen;
         return( AFPERR_PARAM);
     }
 
-    if (vol->v_db == NULL) {
+    if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
         return AFPERR_NOOP;
     }
 
@@ -1699,7 +1691,7 @@ int               ibuflen, *rbuflen;
     ibuf += sizeof(id);
     fileid = id;
 
-    if (NULL == (upath = cnid_resolve(vol->v_db, &id, buffer, len)) ) {
+    if (NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, len)) ) {
         return AFPERR_NOID;
     }
 
@@ -1724,7 +1716,7 @@ int               ibuflen, *rbuflen;
     else if (S_ISDIR(st.st_mode)) /* directories are bad */
         return AFPERR_BADTYPE;
 
-    if (cnid_delete(vol->v_db, fileid)) {
+    if (cnid_delete(vol->v_cdb, fileid)) {
         switch (errno) {
         case EROFS:
             return AFPERR_VLOCK;
@@ -1742,7 +1734,6 @@ int               ibuflen, *rbuflen;
 
     return err;
 }
-#endif /* CNID_DB */
 
 #define APPLETEMP ".AppleTempXXXXXX"
 
@@ -1766,9 +1757,7 @@ int               ibuflen, *rbuflen;
     struct ofork       *d_of;
     int                 crossdev;
     
-#ifdef CNID_DB
     int                 slen, dlen;
-#endif /* CNID_DB */
     u_int32_t          sid, did;
     u_int16_t          vid;
 
@@ -1820,7 +1809,7 @@ int               ibuflen, *rbuflen;
         default:
             return AFPERR_PARAM;
     }
-    memset(&ads, 0, sizeof(ads));
+    ad_init(&ads, vol->v_adouble);
     adsp = &ads;
     if ((s_of = of_findname(path))) {
             /* reuse struct adouble so it won't break locks */
@@ -1841,10 +1830,7 @@ int              ibuflen, *rbuflen;
 
     /* look for the source cnid. if it doesn't exist, don't worry about
      * it. */
-#ifdef CNID_DB
-    sid = cnid_lookup(vol->v_db, &srcst, sdir->d_did, supath,
-                      slen = strlen(supath));
-#endif /* CNID_DB */
+    sid = cnid_lookup(vol->v_cdb, &srcst, sdir->d_did, supath,slen = strlen(supath));
 
     if (NULL == ( dir = dirlookup( vol, did )) ) {
         return afp_errno; /* was AFPERR_PARAM */
@@ -1874,7 +1860,7 @@ int               ibuflen, *rbuflen;
         default:
             return AFPERR_PARAM;
     }
-    memset(&add, 0, sizeof(add));
+    ad_init(&add, vol->v_adouble);
     addp = &add;
     if ((d_of = of_findname( path))) {
             /* reuse struct adouble so it won't break locks */
@@ -1889,11 +1875,8 @@ int              ibuflen, *rbuflen;
         return AFPERR_MISC;
     
     upath = path->u_name;
-#ifdef CNID_DB
     /* look for destination id. */
-    did = cnid_lookup(vol->v_db, &destst, curdir->d_did, upath,
-                      dlen = strlen(upath));
-#endif /* CNID_DB */
+    did = cnid_lookup(vol->v_cdb, &destst, curdir->d_did, upath, dlen = strlen(upath));
 
     /* construct a temp name.
      * NOTE: the temp file will be in the dest file's directory. it
@@ -1917,21 +1900,20 @@ int             ibuflen, *rbuflen;
         goto err_dest_to_src;
     of_rename(vol, s_of, curdir, temp, curdir, path->m_name);
 
-#ifdef CNID_DB
     /* id's need switching. src -> dest and dest -> src. 
      * we need to re-stat() if it was a cross device copy.
     */
     if (sid) {
-       cnid_delete(vol->v_db, sid);
+       cnid_delete(vol->v_cdb, sid);
     }
     if (did) {
-       cnid_delete(vol->v_db, did);
+       cnid_delete(vol->v_cdb, did);
     }
     if ((did && ( (crossdev && stat( upath, &srcst) < 0) || 
-                cnid_update(vol->v_db, did, &srcst, curdir->d_did,upath, dlen) < 0))
+                cnid_update(vol->v_cdb, did, &srcst, curdir->d_did,upath, dlen) < 0))
        ||
        (sid && ( (crossdev && stat(p, &destst) < 0) ||
-                cnid_update(vol->v_db, sid, &destst, sdir->d_did,supath, slen) < 0))
+                cnid_update(vol->v_cdb, sid, &destst, sdir->d_did,supath, slen) < 0))
     ) {
         switch (errno) {
         case EPERM:
@@ -1943,7 +1925,6 @@ int               ibuflen, *rbuflen;
         }
         goto err_temp_to_dest;
     }
-#endif /* CNID_DB */
 
 #ifdef DEBUG
     LOG(log_info, logtype_afpd, "ending afp_exchangefiles:");
@@ -1954,9 +1935,7 @@ int               ibuflen, *rbuflen;
 
     /* all this stuff is so that we can unwind a failed operation
      * properly. */
-#ifdef CNID_DB
 err_temp_to_dest:
-#endif
     /* rename dest to temp */
     renamefile(upath, temp, temp, vol_noadouble(vol), adsp);
     of_rename(vol, s_of, curdir, upath, curdir, temp);
index b3179db45d4d0285833817ccf1f8a5718489b2a8..3c82d51567862e3eb99994bd1ede7517d1ae2f3f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: file.h,v 1.16.2.2 2003-07-21 05:50:54 didg Exp $
+ * $Id: file.h,v 1.16.2.2.2.1 2003-09-09 16:42:20 didg Exp $
  *
  * Copyright (c) 1990,1991 Regents of The University of Michigan.
  * All Rights Reserved.
@@ -120,7 +120,7 @@ typedef enum {
   kTextEncodingMacKeyboardGlyphs = 41,
 } kTextEncoding_t;
 
-extern char *set_name   __P((const struct vol *, char *, char *, u_int32_t ) );
+extern char *set_name   __P((const struct vol *, char *, char *, cnid_t, u_int32_t ) );
 
 extern struct extmap   *getextmap __P((const char *));
 extern struct extmap   *getdefextmap __P((void));
@@ -144,14 +144,8 @@ extern int      afp_exchangefiles __P((AFPObj *, char *, int, char *, int *));
 extern int     afp_setfilparams __P((AFPObj *, char *, int, char *, int *));
 extern int     afp_copyfile __P((AFPObj *, char *, int, char *, int *));
 extern int     afp_createfile __P((AFPObj *, char *, int, char *, int *));
-#ifdef CNID_DB
 extern int      afp_createid __P((AFPObj *, char *, int, char *, int *));
 extern int      afp_resolveid __P((AFPObj *, char *, int, char *, int *));
 extern int      afp_deleteid __P((AFPObj *, char *, int, char *, int *));
-#else /* CNID_DB */
-#define afp_createid      afp_null
-#define afp_resolveid     afp_null
-#define afp_deleteid      afp_null
-#endif /* AD_VERSION > AD_VERSION1 */
 
 #endif
index 24e1e1572fe41ed58d83ca034a61c62bc861eb9b..3edf77bdec3f949482900a04f19d217d13d8d011 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: filedir.c,v 1.45.2.2 2003-07-21 05:50:54 didg Exp $
+ * $Id: filedir.c,v 1.45.2.2.2.1 2003-09-09 16:42:20 didg Exp $
  *
  * Copyright (c) 1990,1993 Regents of The University of Michigan.
  * All Rights Reserved.  See COPYRIGHT.
@@ -18,9 +18,7 @@
 #include <atalk/adouble.h>
 #include <atalk/afp.h>
 #include <atalk/util.h>
-#ifdef CNID_DB
 #include <atalk/cnid.h>
-#endif /* CNID_DB */
 #include <stdio.h>
 #include <stdlib.h>
 #ifdef HAVE_FCNTL_H
@@ -351,22 +349,18 @@ int         isdir;
     struct adouble     *adp;
     struct ofork       *opened = NULL;
     struct path         path;
-#ifdef CNID_DB
     cnid_t      id;
-#endif /* CNID_DB */
 
-    memset(&ad, 0, sizeof(ad));
+    ad_init(&ad, vol->v_adouble);
     adp = &ad;
     adflags = 0;
     
     if (!isdir) {
-#ifdef CNID_DB
         p = mtoupath(vol, oldname, utf8_encoding());
         if (!p) { 
             return AFPERR_PARAM; /* can't convert */
         }
-        id = cnid_get(vol->v_db, sdir->d_did, p, strlen(p));
-#endif /* CNID_DB */
+        id = cnid_get(vol->v_cdb, sdir->d_did, p, strlen(p));
         p = ctoupath( vol, sdir, oldname );
         if (!p) { 
             return AFPERR_PARAM; /* pathname too long */
@@ -379,9 +373,7 @@ int         isdir;
         }
     }
     else {
-#ifdef CNID_DB
         id = sdir->d_did; /* we already have the CNID */
-#endif /* CNID_DB */
         p = ctoupath( vol, sdir->d_parent, oldname );
         if (!p) {
             return AFPERR_PARAM;
@@ -437,15 +429,13 @@ int         isdir;
     } else {
         rc = renamedir(p, upath, sdir, curdir, newname, vol_noadouble(vol));
     }
-    if ( rc == AFP_OK ) {
-#ifdef CNID_DB
+    if ( rc == AFP_OK && id ) {
         /* renaming may have moved the file/dir across a filesystem */
         if (stat(upath, st) < 0)
             return AFPERR_MISC;
 
         /* fix up the catalog entry */
-        cnid_update(vol->v_db, id, st, curdir->d_did, upath, strlen(upath));
-#endif /* CNID_DB */
+        cnid_update(vol->v_cdb, id, st, curdir->d_did, upath, strlen(upath));
     }
 
     return rc;
index a1d35ee40cbda213fef1ae1844896f14dab4a5df..1221534f8e14d604e316deb3dc7b61f24578048a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: fork.c,v 1.51.2.2 2003-08-24 14:00:43 didg Exp $
+ * $Id: fork.c,v 1.51.2.2.2.1 2003-09-09 16:42:20 didg Exp $
  *
  * Copyright (c) 1990,1993 Regents of The University of Michigan.
  * All Rights Reserved.  See COPYRIGHT.
@@ -36,9 +36,7 @@
 #include <atalk/afp.h>
 #include <atalk/adouble.h>
 #include <atalk/util.h>
-#ifdef CNID_DB
 #include <atalk/cnid.h>
-#endif
 
 #include "fork.h"
 #include "file.h"
index 9cb09f4a7bd44221e8a15773cfd74e57a0c3497d..458c1a3e556e31279a4260694cede749da817586 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: globals.h,v 1.18.2.2 2003-07-21 05:50:54 didg Exp $
+ * $Id: globals.h,v 1.18.2.2.2.1 2003-09-09 16:42:20 didg Exp $
  *
  * Copyright (c) 1990,1993 Regents of The University of Michigan.
  * All Rights Reserved.  See COPYRIGHT.
@@ -23,6 +23,7 @@
 #include <netatalk/at.h>
 #include <atalk/afp.h>
 #include <atalk/compat.h>
+#include <atalk/unicode.h>
 
 /* test for inline */
 #ifndef __inline__
@@ -69,7 +70,9 @@ struct afp_options {
     char *uamlist;
     char *authprintdir;
     char *signature;
-    char *k5service, *k5realm;
+    char *k5service, *k5realm, *k5keytab;
+    char *unixcodepage,*maccodepage;
+    charset_t maccharset, unixcharset; 
     mode_t umask;
     mode_t save_mask;
     int    sleep;
@@ -106,6 +109,10 @@ extern unsigned char       nologin;
 extern struct dir      *curdir;
 extern char            getwdbuf[];
 
+/* FIXME CNID */
+extern char             *Cnid_srv;
+extern int              Cnid_port;
+
 extern int  get_afp_errno   __P((const int param));
 extern void afp_options_init __P((struct afp_options *));
 extern int afp_options_parse __P((int, char **, struct afp_options *));
@@ -113,7 +120,7 @@ extern int afp_options_parseline __P((char *, struct afp_options *));
 extern void afp_options_free __P((struct afp_options *,
                                       const struct afp_options *));
 extern void setmessage __P((const char *));
-extern void readmessage __P((void));
+extern void readmessage __P((AFPObj *));
 
 /* gettok.c */
 extern void initline   __P((int, char *));
index c6446141e1c84819f909da73193e1e34bbd6ccab..74396115d790679781aec56bc63b6c57b76674ca 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: main.c,v 1.20.4.2 2003-07-21 05:50:54 didg Exp $
+ * $Id: main.c,v 1.20.4.2.2.1 2003-09-09 16:42:20 didg Exp $
  *
  * Copyright (c) 1990,1993 Regents of The University of Michigan.
  * All Rights Reserved.  See COPYRIGHT.
@@ -172,6 +172,7 @@ char        **av;
     argv = av;
     set_auth_parameters( ac, av );
 #endif /* TRU64 */
+    fault_setup(NULL);
 
     afp_options_init(&default_options);
     if (!afp_options_parse(ac, av, &default_options))
@@ -191,6 +192,9 @@ char        **av;
         exit(0);
     }
 
+    /* Register CNID  */
+    cnid_init();
+
     /* install child handler for asp and dsi. we do this before afp_goaway
      * as afp_goaway references stuff from here. 
      * XXX: this should really be setup after the initial connections. */
index fda4e5868482dbb6bf6dc4efee2eaeb2aa7a681d..8ec4d17daf478396a2c9a1b131054097c17bc8ef 100644 (file)
@@ -1,5 +1,5 @@
 /* 
- * $Id: mangle.c,v 1.16.2.1 2003-06-23 10:25:08 didg Exp $ 
+ * $Id: mangle.c,v 1.16.2.1.2.1 2003-09-09 16:42:20 didg Exp $ 
  *
  * Copyright (c) 2002. Joe Marcus Clarke (marcus@marcuscom.com)
  * All Rights Reserved.  See COPYRIGHT.
 #include "config.h"
 #endif /* HAVE_CONFIG_H */
 
-#ifdef FILE_MANGLING
+#include <stdio.h>
+#include <ctype.h>
 #include "mangle.h"
 
-#ifndef MIN
-#define MIN(a, b) ((a) < (b) ? (a) : (b))
-#endif /* ! MIN */
-
+#define hextoint( c )   ( isdigit( c ) ? c - '0' : c + 10 - 'A' )
+#define isuxdigit(x)    (isdigit(x) || (isupper(x) && isxdigit(x)))
 
 char *
 demangle(const struct vol *vol, char *mfilename) {
-       char *filename = NULL;
-       char *ext = NULL;
-       size_t ext_len = 0;
-       char *mangle;
+    char *t;
+    char *u_name;
+    u_int32_t id = 0;
+    static char buffer[12 + MAXPATHLEN + 1];
+    int len = 12 + MAXPATHLEN + 1;
+    struct dir *dir;
+
 
-       /* Is this really a mangled file? */
-       mangle = strstr(mfilename, MANGLE_CHAR);
-       if (!mangle) {
+    t = strchr(mfilename, MANGLE_CHAR);
+    if (t == NULL) {
            return mfilename;
        }
-
-       if (NULL != (ext = strrchr(mfilename, '.')) ) {
-           ext_len = strlen(ext);
+    /* may be a mangled filename */
+    t++;
+    if (*t == '0') { /* can't start with a 0 */
+        return mfilename;
        }
-       if (strlen(mangle) != strlen(MANGLE_CHAR) + MANGLE_LENGTH + ext_len) {
+    while(isuxdigit(*t)) {
+        id = (id *16) + hextoint(*t);
+        t++;
+    }
+    if ((*t != 0 && *t != '.') || strlen(t) > MAX_EXT_LENGTH || id == 0) {
            return mfilename;
        }
 
-       filename = cnid_mangle_get(vol->v_db, mfilename);
-
-       /* No unmangled filename was found. */
-       if (filename == NULL) {
-#ifdef DEBUG
-           LOG(log_debug, logtype_afpd, "demangle: Unable to lookup %s in the mangle database", mfilename);
-#endif
-           return mfilename;
+    id = htonl(id);
+    /* is it a dir?*/
+    if (NULL != (dir = dirsearch(vol, id))) {
+        return dir->d_u_name;
        }
-       return filename;
+    if (NULL != (u_name = cnid_resolve(vol->v_cdb, &id, buffer, len)) ) {
+        return u_name;
+    }
+    return mfilename;
 }
 
 /* -----------------------
    with utf8 filename not always round trip
    filename   mac filename too long or with unmatchable utf8 replaced with _
    uname      unix filename 
+   id         file/folder ID or 0
+   
 */
 char *
-mangle(const struct vol *vol, char *filename, char *uname, int flags) {
+mangle(const struct vol *vol, char *filename, char *uname, cnid_t id, int flags) {
     char *ext = NULL;
-    char *tf = NULL;
     char *m = NULL;
     static char mfilename[MAX_LENGTH + 1];
     char mangle_suffix[MANGLE_LENGTH + 1];
     size_t ext_len = 0;
-    int mangle_suffix_int = 0;
+    int k;
 
     /* Do we really need to mangle this filename? */
     if (!flags && strlen(filename) <= vol->max_filename) {
        return filename;
     }
     /* First, attempt to locate a file extension. */
-    if (NULL != (ext = strrchr(filename, '.')) ) {
+    if (NULL != (ext = strrchr(uname, '.')) ) {
        ext_len = strlen(ext);
        if (ext_len > MAX_EXT_LENGTH) {
            /* Do some bounds checking to prevent an extension overflow. */
            ext_len = MAX_EXT_LENGTH;
        }
     }
-
-    /* Check to see if we already have a mangled filename by this name. */
-    while (1) {
        m = mfilename;
-       strncpy(m, filename, MIN(MAX_LENGTH - strlen(MANGLE_CHAR) - MANGLE_LENGTH - ext_len, strlen(filename)-ext_len));
-       m[MIN(MAX_LENGTH - strlen(MANGLE_CHAR) - MANGLE_LENGTH - ext_len, strlen(filename)-ext_len)] = '\0';
+    memset(m, 0, MAX_LENGTH + 1);
+    k = sprintf(mangle_suffix, "%c%X", MANGLE_CHAR, ntohl(id));
 
-       strcat(m, MANGLE_CHAR);
-       (void)sprintf(mangle_suffix, "%03d", mangle_suffix_int);
+    strncpy(m, filename, MAX_LENGTH - k - ext_len);
        strcat(m, mangle_suffix);
-
-       if (ext) {
                strncat(m, ext, ext_len);
-       }
-
-       tf = cnid_mangle_get(vol->v_db, m);
-       if (tf == NULL || (strcmp(tf, uname)) == 0) {
-           break;
-       }
-       else {
-           if (++mangle_suffix_int > MAX_MANGLE_SUFFIX_LENGTH) {
-               LOG(log_error, logtype_afpd, "mangle: Failed to find a free mangle suffix; returning original filename");
-               return filename;
-           }
-       }
-    }
-
-    if (cnid_mangle_add(vol->v_db, m, uname) < 0) {
-       return filename;
-    }
 
     return m;
 }
-#endif /* FILE_MANGLING */
index f541b5fc81249872c166a0243dcec4c9e99adf6c..d878d8ad114c40041241db348e73779102d3c3aa 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: mangle.h,v 1.4.2.1 2003-06-23 10:25:08 didg Exp $
+ * $Id: mangle.h,v 1.4.2.1.2.1 2003-09-09 16:42:20 didg Exp $
  *
  */
 
@@ -9,25 +9,22 @@
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
- #include <stdio.h>
 
 #include <atalk/adouble.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 MANGLE_CHAR '#'
 #define MAX_MANGLE_SUFFIX_LENGTH 999
-#define MAX_EXT_LENGTH 4 /* XXX This cannot be greater than 27 */
+#define MAX_EXT_LENGTH 5 /* XXX This cannot be greater than 27 */
+#define MANGLE_LENGTH  9 /* #ffffffff This really can't be changed. */
 #define MAX_LENGTH MACFILELEN 
 
-extern char *mangle __P((const struct vol *, char *, char *, int));
+extern char *mangle __P((const struct vol *, char *, char *, cnid_t, int));
 extern char *demangle __P((const struct vol *, char *));
 
 #endif /* AFPD_MANGLE_H */
index 45e6be67726af2a3c6df716d4fa080ee348e3692..91ef8fff1629decdce3a3d413fa47cb2571973ef 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: messages.c,v 1.16.6.1 2003-06-23 10:25:08 didg Exp $
+ * $Id: messages.c,v 1.16.6.1.2.1 2003-09-09 16:42:20 didg Exp $
  *
  * Copyright (c) 1997 Adrian Sun (asun@zoology.washington.edu)
  * All Rights Reserved.  See COPYRIGHT.
 #include <stdio.h>
 #include <string.h>
 #include <errno.h>
+#include <stdlib.h>
 #include <atalk/afp.h>
+#include <atalk/dsi.h>
 #include <atalk/logger.h>
 #ifdef HAVE_UNISTD_H
 #include <unistd.h>
 #endif /* HAVE_UNISTD_H */
+#include <atalk/unicode.h>
 #include "globals.h"
 #include "misc.h"
 
+#ifndef MAX
+#define MAX(a,b)     ((a) > (b) ? (a) : (b))
+#endif /* ! MAX */
+
 #define MAXMESGSIZE 199
 
 /* this is only used by afpd children, so it's okay. */
-static char servermesg[MAXMESGSIZE] = "";
+static char servermesg[MAXPATHLEN] = "";
+static char localized_message[MAXPATHLEN] = "";
 
 void setmessage(const char *message)
 {
     strncpy(servermesg, message, MAXMESGSIZE);
 }
 
-void readmessage(void)
+void readmessage(obj)
+AFPObj *obj;
 {
     /* Read server message from file defined as SERVERTEXT */
 #ifdef SERVERTEXT
     FILE *message;
     char * filename;
-    int i, rc;
+    unsigned int i; 
+    int rc;
     static int c;
     uid_t euid;
+    u_int32_t maxmsgsize;
+
+    maxmsgsize = (obj->proto == AFPPROTO_DSI)?MIN(MAX(((DSI*)obj->handle)->attn_quantum, MAXMESGSIZE),MAXPATHLEN):MAXMESGSIZE;
 
     i=0;
     /* Construct file name SERVERTEXT/message.[pid] */
@@ -63,7 +76,7 @@ void readmessage(void)
     /* if either message.pid or message exists */
     if (message!=NULL) {
         /* added while loop to get characters and put in servermesg */
-        while ((( c=fgetc(message)) != EOF) && (i < (MAXMESGSIZE - 1))) {
+        while ((( c=fgetc(message)) != EOF) && (i < (maxmsgsize - 1))) {
             if ( c == '\n')  c = ' ';
             servermesg[i++] = c;
         }
@@ -80,7 +93,8 @@ void readmessage(void)
                                strerror(errno));
         }
 
-        rc = unlink(filename);
+        if ( 0 < (rc = unlink(filename)) )
+           LOG(log_error, logtype_afpd, "File '%s' could not be deleted", strerror(errno));
 
         /* Drop privs again, failing this is very bad */
         if (seteuid(euid) < 0) {
@@ -109,6 +123,10 @@ int ibuflen, *rbuflen;
 {
     char *message;
     u_int16_t type, bitmap;
+    u_int32_t msgsize;
+    size_t outlen;
+
+    msgsize = (obj->proto == AFPPROTO_DSI)?MAX(((DSI*)obj->handle)->attn_quantum, MAXMESGSIZE):MAXMESGSIZE;
 
     memcpy(&type, ibuf + 2, sizeof(type));
     memcpy(&bitmap, ibuf + 4, sizeof(bitmap));
@@ -136,10 +154,23 @@ int ibuflen, *rbuflen;
     memcpy(rbuf, &bitmap, sizeof(bitmap));
     rbuf += sizeof(bitmap);
     *rbuflen = strlen(message);
+#if 0
     if (*rbuflen > MAXMESGSIZE)
         *rbuflen = MAXMESGSIZE;
+#endif
+    if (*rbuflen > msgsize)
+        *rbuflen = msgsize;
     *rbuf++ = *rbuflen;
-    memcpy(rbuf, message, *rbuflen);
+
+    /* Convert the message to the macs codepage 
+     * according to AFP 3.1 specs page 200 
+     * bit 1 set in bitmap means Unicode ?= utf8
+     * Never saw this in the wild yet             */   
+
+    if ( (size_t)-1 == (outlen = convert_charset(obj->options.unixcharset, ((ntohs(bitmap)) & 2)?CH_UTF8_MAC:obj->options.maccharset, message, *rbuflen, localized_message, msgsize, 0)) )
+       memcpy(rbuf, message, *rbuflen); /*FIXME*/
+    else
+       memcpy(rbuf, localized_message, outlen);
 
     *rbuflen += 5;
 
index abfa5ec03c3c321de33407024719a886326c946f..5e3354ce17ca380dcfb9253d51f81fb4f2ebd208 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: ofork.c,v 1.20 2002-10-11 14:18:34 didg Exp $
+ * $Id: ofork.c,v 1.20.6.1 2003-09-09 16:42:20 didg Exp $
  *
  * Copyright (c) 1996 Regents of The University of Michigan.
  * All Rights Reserved.  See COPYRIGHT.
@@ -215,7 +215,7 @@ struct stat     *st;
 
         /* initialize to zero. This is important to ensure that
            ad_open really does reinitialize the structure. */
-        memset( ad, 0, sizeof( struct adouble ) );
+        ad_init(ad, vol->v_adouble);
     } else {
         /* Increase the refcount on this struct adouble. This is
            decremented again in oforc_dealloc. */
index e9a1f49bf15b699a6d22e0f859dfb4d11f678164..57da01de915a82dc3d2e10cc0b8dd89b2de7cb20 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: status.c,v 1.13 2003-04-21 22:39:40 samnoble Exp $
+ * $Id: status.c,v 1.13.6.1 2003-09-09 16:42:20 didg Exp $
  *
  * Copyright (c) 1990,1993 Regents of The University of Michigan.
  * All Rights Reserved.  See COPYRIGHT.
@@ -131,7 +131,7 @@ static u_int16_t status_signature(char *data, int *servoffset, DSI *dsi,
                                   const struct afp_options *options)
 {
     char                 *status;
-    char                *usersign, *ifaddr;
+    char                *usersign;
     int                  i;
     u_int16_t            offset, sigoff;
     long                 hostid;
@@ -342,7 +342,7 @@ static int status_utf8servername(char *data, int *nameoffset,
                                 const DSI *dsi,
                                 const struct afp_options *options)
 {
-    u_int16_t namelen, len;
+   /* u_int16_t namelen, len;*/
     char *begin = data;
     u_int16_t offset;
     memcpy(&offset, data + *nameoffset, sizeof(offset));
index 0a3a135a5c594a20daeb347961f86997e5bc6e9e..c4b74236e0e62c06f129769fc53cfe37fdb0270e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: uid.c,v 1.13 2002-08-30 19:32:41 didg Exp $
+ * $Id: uid.c,v 1.13.8.1 2003-09-09 16:42:20 didg Exp $
  * code: jeff@univrel.pr.uconn.edu
  *
  * These functions are abstracted here, so that all calls for resolving
@@ -40,7 +40,8 @@ uidgidset *pair;
 void restore_uidgid ( pair )
 uidgidset *pair;
 {
-    int                uid, gid;   
+    uid_t uid
+    gid_t gid;   
     
     uid = geteuid ();
     gid = getegid ();
index db0f5017c1acc4f20b44746dba1e7ac0db272099..35d4e1eeb5eec8d621f3079955355ac048f2860e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: volume.c,v 1.51.2.7 2003-07-21 05:50:54 didg Exp $
+ * $Id: volume.c,v 1.51.2.7.2.1 2003-09-09 16:42:20 didg Exp $
  *
  * Copyright (c) 1990,1993 Regents of The University of Michigan.
  * All Rights Reserved.  See COPYRIGHT.
@@ -79,9 +79,7 @@ extern int afprun(int root, char *cmd, int *outfd);
 
 static struct vol *Volumes = NULL;
 static int             lastvid = 0;
-#ifndef CNID_DB
 static char            *Trash = "\02\024Network Trash Folder";
-#endif /* CNID_DB */
 
 static struct extmap   *Extmap = NULL, *Defextmap = NULL;
 static int              Extmap_cnt;
@@ -114,15 +112,18 @@ m=u -> map both ways
 #define VOLOPT_ROOTPOSTEXEC  14  /* root postexec command */
 
 #define VOLOPT_ENCODING      15  /* mac encoding (pre OSX)*/
+#define VOLOPT_MACCHARSET    16
+#define VOLOPT_CNIDSCHEME    17
+#define VOLOPT_ADOUBLE       18  /* adouble version */
 #ifdef FORCE_UIDGID
 #warning UIDGID
 #include "uid.h"
 
-#define VOLOPT_FORCEUID  16  /* force uid for username x */
-#define VOLOPT_FORCEGID  17  /* force gid for group x */
-#define VOLOPT_UMASK     18
+#define VOLOPT_FORCEUID  19  /* force uid for username x */
+#define VOLOPT_FORCEGID  20  /* force gid for group x */
+#define VOLOPT_UMASK     21
 #else 
-#define VOLOPT_UMASK     16
+#define VOLOPT_UMASK     19
 #endif /* FORCE_UIDGID */
 
 #define VOLOPT_MAX       (VOLOPT_UMASK +1)
@@ -251,7 +252,7 @@ static char *volxlate(AFPObj *obj, char *dest, size_t destlen,
             if (path) {
                 struct adouble ad;
 
-                memset(&ad, 0, sizeof(ad));
+               ad_init(&ad, 0);
                 if (ad_open(path, ADFLAGS_HF, O_RDONLY, 0, &ad) < 0)
                     goto no_volname;
 
@@ -376,10 +377,14 @@ static void volset(struct vol_option *options, struct vol_option *save,
             free(options[VOLOPT_CODEPAGE].c_value);
         }
         options[VOLOPT_CODEPAGE].c_value = get_codepage_path(nlspath, val + 1);
-    } else if (optionok(tmp, "encoding:", val)) {
+    } else if (optionok(tmp, "volcharset:", val)) {
         setoption(options, save, VOLOPT_ENCODING, val);
+    } else if (optionok(tmp, "maccharset:", val)) {
+        setoption(options, save, VOLOPT_MACCHARSET, val);
     } else if (optionok(tmp, "veto:", val)) {
         setoption(options, save, VOLOPT_VETO, val);
+    } else if (optionok(tmp, "cnidscheme:", val)) {
+        setoption(options, save, VOLOPT_CNIDSCHEME, val);
     } else if (optionok(tmp, "casefold:", val)) {
         if (strcasecmp(val + 1, "tolower") == 0)
             options[VOLOPT_CASEFOLD].i_value = AFPVOL_UMLOWER;
@@ -389,7 +394,13 @@ static void volset(struct vol_option *options, struct vol_option *save,
             options[VOLOPT_CASEFOLD].i_value = AFPVOL_UUPPERMLOWER;
         else if (strcasecmp(val + 1, "xlateupper") == 0)
             options[VOLOPT_CASEFOLD].i_value = AFPVOL_ULOWERMUPPER;
-
+    } else if (optionok(tmp, "adouble:", val)) {
+        if (strcasecmp(val + 1, "v1") == 0)
+            options[VOLOPT_ADOUBLE].i_value = AD_VERSION1;
+#if AD_VERSION == AD_VERSION2            
+        else if (strcasecmp(val + 1, "v2") == 0)
+            options[VOLOPT_ADOUBLE].i_value = AD_VERSION2;
+#endif
     } else if (optionok(tmp, "options:", val)) {
         char *p;
 
@@ -424,8 +435,6 @@ static void volset(struct vol_option *options, struct vol_option *save,
                 options[VOLOPT_FLAGS].i_value |= AFPVOL_DROPBOX;
             else if (strcasecmp(p, "nofileid") == 0)
                 options[VOLOPT_FLAGS].i_value |= AFPVOL_NOFILEID;
-            else if (strcasecmp(p, "utf8") == 0)
-                options[VOLOPT_FLAGS].i_value |= AFPVOL_UTF8;
             else if (strcasecmp(p, "nostat") == 0)
                 options[VOLOPT_FLAGS].i_value |= AFPVOL_NOSTAT;
             else if (strcasecmp(p, "preexec_close") == 0)
@@ -438,11 +447,8 @@ static void volset(struct vol_option *options, struct vol_option *save,
             p = strtok(NULL, ",");
         }
 
-#ifdef CNID_DB
-
     } else if (optionok(tmp, "dbpath:", val)) {
         setoption(options, save, VOLOPT_DBPATH, val);
-#endif /* CNID_DB */
 
     } else if (optionok(tmp, "umask:", val)) {
        options[VOLOPT_UMASK].i_value = (int)strtol(val, (char **)NULL, 8);
@@ -553,7 +559,6 @@ static int creatvol(AFPObj *obj, struct passwd *pwd,
     volume->v_qfd = -1;
 #endif /* __svr4__ */
     volume->v_vid = lastvid++;
-    volume->v_lastdid = 17;
 
     /* handle options */
     if (options) {
@@ -574,15 +579,24 @@ static int creatvol(AFPObj *obj, struct passwd *pwd,
             volume->v_veto = strdup(options[VOLOPT_VETO].c_value);
 
         if (options[VOLOPT_ENCODING].c_value)
-            volume->v_encoding = strdup(options[VOLOPT_ENCODING].c_value);
-#ifdef CNID_DB
+            volume->v_volcodepage = strdup(options[VOLOPT_ENCODING].c_value);
+
+        if (options[VOLOPT_MACCHARSET].c_value)
+            volume->v_maccodepage = strdup(options[VOLOPT_MACCHARSET].c_value);
+
         if (options[VOLOPT_DBPATH].c_value)
             volume->v_dbpath = volxlate(obj, NULL, MAXPATHLEN, options[VOLOPT_DBPATH].c_value, pwd, path);
-#endif
+
+       if (options[VOLOPT_CNIDSCHEME].c_value)
+           volume->v_cnidscheme = strdup(options[VOLOPT_CNIDSCHEME].c_value);
 
        if (options[VOLOPT_UMASK].i_value)
            volume->v_umask = (mode_t)options[VOLOPT_UMASK].i_value;
 
+       if (options[VOLOPT_ADOUBLE].i_value)
+           volume->v_adouble = options[VOLOPT_ADOUBLE].i_value;
+       else 
+           volume->v_adouble = AD_VERSION;
 #ifdef FORCE_UIDGID
         if (options[VOLOPT_FORCEUID].c_value) {
             volume->v_forceuid = strdup(options[VOLOPT_FORCEUID].c_value);
@@ -657,6 +671,18 @@ FILE       *fp;
  *      0: list exists, but name isn't in it
  *      1: in list
  */
+
+#ifndef NO_REAL_USER_NAME
+/* authentication is case insensitive 
+ * FIXME should we do the same with group name?
+*/
+#define access_strcmp strcasecmp
+
+#else
+#define access_strcmp strcmp
+
+#endif
+
 static int accessvol(args, name)
 const char *args;
 const char *name;
@@ -675,7 +701,7 @@ const char *name;
         if (*p == '@') { /* it's a group */
             if ((gr = getgrnam(p + 1)) && gmem(gr->gr_gid))
                 return 1;
-        } else if (strcmp(p, name) == 0) /* it's a user name */
+        } else if (access_strcmp(p, name) == 0) /* it's a user name */
             return 1;
         p = strtok(NULL, ",");
     }
@@ -976,10 +1002,9 @@ static void volume_free(struct vol *vol)
     codepage_free(vol);
     free(vol->v_password);
     free(vol->v_veto);
-    free(vol->v_encoding);
-#ifdef CNID_DB
+    free(vol->v_volcodepage);
+    free(vol->v_maccodepage);
     free(vol->v_dbpath);
-#endif /* CNID_DB */
 #ifdef FORCE_UIDGID
     free(vol->v_forceuid);
     free(vol->v_forcegid);
@@ -1120,7 +1145,7 @@ int               *buflen;
      * For MacOS8.x support we need to create the
      * .Parent file here if it doesn't exist. */
 
-    memset(&ad, 0, sizeof(ad));
+    ad_init(&ad, vol->v_adouble);
     if ( ad_open( vol->v_path, vol_noadouble(vol) |
                   ADFLAGS_HF|ADFLAGS_DIR, O_RDWR | O_CREAT,
                   0666, &ad) < 0 ) {
@@ -1162,11 +1187,10 @@ int             *buflen;
         switch ( bit ) {
         case VOLPBIT_ATTR :
             ashort = 0;
-#ifdef CNID_DB
-            if (0 == (vol->v_flags & AFPVOL_NOFILEID) && vol->v_db != NULL) {
+            if (0 == (vol->v_flags & AFPVOL_NOFILEID) && vol->v_cdb != NULL &&
+                           (vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
                 ashort = VOLPBIT_ATTR_FILEID;
             }
-#endif /* CNID_DB */
             /* check for read-only.
              * NOTE: we don't actually set the read-only flag unless
              *       it's passed in that way as it's possible to mount
@@ -1441,9 +1465,7 @@ int               ibuflen, *rbuflen;
 {
     struct stat        st;
     char       *volname;
-#ifndef CNID_DB
     char        *p;
-#endif
     struct vol *volume;
     struct dir *dir;
     int                len, ret;
@@ -1503,9 +1525,6 @@ int               ibuflen, *rbuflen;
         volume->max_filename = MACFILELEN;
     }
 
-#ifdef CNID_DB
-    volume->v_db = NULL;
-#endif
     volume->v_dir = volume->v_root = NULL;
 
     /* FIXME unix name != mac name */
@@ -1519,6 +1538,7 @@ int               ibuflen, *rbuflen;
     dir->d_color = DIRTREE_COLOR_BLACK; /* root node is black */
     volume->v_dir = volume->v_root = dir;
     volume->v_flags |= AFPVOL_OPEN;
+    volume->v_cdb = NULL;  
 
     if (volume->v_root_preexec) {
        if ((ret = afprun(1, volume->v_root_preexec, NULL)) && volume->v_root_preexec_close) {
@@ -1550,37 +1570,76 @@ int             ibuflen, *rbuflen;
         goto openvol_err;
     }
     curdir = volume->v_dir;
-
-#ifdef CNID_DB
+    if (volume->v_cnidscheme == NULL) {
+        volume->v_cnidscheme = strdup(DEFAULT_CNID_SCHEME);
+        LOG(log_warning, logtype_afpd, "Warning: No CNID scheme for volume %s. Using default.",
+               volume->v_path);
+    }
     if (volume->v_dbpath)
-        volume->v_db = cnid_open (volume->v_dbpath, volume->v_umask);
-    if (volume->v_db == NULL)
-        volume->v_db = cnid_open (volume->v_path, volume->v_umask);
-    if (volume->v_db == NULL) {
-        /* FIXME config option? 
-         * - mount the volume readonly
-         * - return an error
-         * - read/write with other scheme
-         */
+        volume->v_cdb = cnid_open (volume->v_dbpath, volume->v_umask, volume->v_cnidscheme);
+    if (volume->v_cdb == NULL)
+        volume->v_cdb = cnid_open (volume->v_path, volume->v_umask, volume->v_cnidscheme);
+    if (volume->v_cdb == NULL) {
+        volume->v_cdb = cnid_open (volume->v_path, volume->v_umask, DEFAULT_CNID_SCHEME);
+        LOG(log_error, logtype_afpd, "Error: invalid CNID backend for %s: %s", volume->v_path,
+            volume->v_cnidscheme);
+    }
+    if (volume->v_cdb == NULL) {
+        LOG(log_error, logtype_afpd, "Fatal error: cannot open CNID for %s", volume->v_path);
+        ret = AFPERR_MISC;
+        goto openvol_err;
     }
-#endif
 
-    if ( 0 == ( volume->v_maccharset = add_charset(volume->v_encoding?volume->v_encoding:"MAC")) )
-       volume->v_maccharset = CH_MAC;
+    /* Codepages */
+
+    if (!volume->v_volcodepage)
+       volume->v_volcodepage = strdup("UTF8");
+
+    if ( (charset_t) -1 == ( volume->v_volcharset = add_charset(volume->v_volcodepage)) ) {
+       LOG (log_error, logtype_afpd, "Setting codepage %s as volume codepage failed", volume->v_volcodepage);
+       ret = AFPERR_MISC;
+       goto openvol_err;
+    }
+
+    if ( NULL == ( volume->v_vol = find_charset_functions(volume->v_volcodepage)) || volume->v_vol->flags & CHARSET_ICONV ) {
+       LOG (log_warning, logtype_afpd, "WARNING: volume encoding %s is *not* supported by netatalk, expect problems !!!!", volume->v_volcodepage);
+    }  
+
+    if (!volume->v_maccodepage)
+       volume->v_maccodepage = strdup(obj->options.maccodepage);
+
+    if ( (charset_t) -1 == ( volume->v_maccharset = add_charset(volume->v_maccodepage)) ) {
+       LOG (log_error, logtype_afpd, "Setting codepage %s as mac codepage failed", volume->v_maccodepage);
+       ret = AFPERR_MISC;
+       goto openvol_err;
+    }
+
+    if ( NULL == ( volume->v_mac = find_charset_functions(volume->v_maccodepage)) || ! (volume->v_mac->flags & CHARSET_CLIENT) ) {
+       LOG (log_error, logtype_afpd, "Fatal error: mac charset %s not supported", volume->v_maccodepage);
+       ret = AFPERR_MISC;
+       goto openvol_err;
+    }  
 
     ret  = stat_vol(bitmap, volume, rbuf, rbuflen);
     if (ret == AFP_OK) {
-#ifndef CNID_DB
         /*
          * If you mount a volume twice, the second time the trash appears on
          * the desk-top.  That's because the Mac remembers the DID for the
          * trash (even for volumes in different zones, on different servers).
          * Just so this works better, we prime the DID cache with the trash,
          * fixing the trash at DID 17.
+         * FIXME (RL): should it be done inside a CNID backend ? (always returning Trash DID when asked) ?
          */
+        if ((volume->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
+
+            /* FIXME find db time stamp */
+            if (!cnid_getstamp(volume->v_cdb, volume->v_stamp, sizeof(volume->v_stamp)) ) {
+                LOG(log_error, logtype_afpd, "stamp %x", *(unsigned *)volume->v_stamp);
+            
+            }
         p = Trash;
         cname( volume, volume->v_dir, &p );
-#endif
+        }
         return( AFP_OK );
     }
 
@@ -1591,13 +1650,10 @@ openvol_err:
     }
 
     volume->v_flags &= ~AFPVOL_OPEN;
-
-#ifdef CNID_DB
-    if (volume->v_db != NULL) {
-        cnid_close(volume->v_db);
-        volume->v_db = NULL;
+    if (volume->v_cdb != NULL) {
+        cnid_close(volume->v_cdb);
+        volume->v_cdb = NULL;
     }
-#endif
     *rbuflen = 0;
     return ret;
 }
@@ -1610,10 +1666,10 @@ static void closevol(struct vol *vol)
 
     dirfree( vol->v_root );
     vol->v_dir = NULL;
-#ifdef CNID_DB
-    cnid_close(vol->v_db);
-    vol->v_db = NULL;
-#endif /* CNID_DB */
+    if (vol->v_cdb != NULL) {
+        cnid_close(vol->v_cdb);
+        vol->v_cdb = NULL;
+    }
 
     if (vol->v_postexec) {
        afprun(0, vol->v_postexec, NULL);
@@ -1843,7 +1899,7 @@ int               ibuflen, *rbuflen;
     if (bitmap != (1 << VOLPBIT_BDATE))
         return AFPERR_BITMAP;
 
-    memset(&ad, 0, sizeof(ad));
+    ad_init(&ad, vol->v_adouble);
     if ( ad_open( vol->v_path, ADFLAGS_HF|ADFLAGS_DIR, O_RDWR,
                   0666, &ad) < 0 ) {
         if (errno == EROFS)
index debca3774db100535a1d2357f029c02e8ad38882..82cd29eb05ab7aa67b8b924469773ee14f452d24 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: volume.h,v 1.19.2.5 2003-07-21 05:50:54 didg Exp $
+ * $Id: volume.h,v 1.19.2.5.2.1 2003-09-09 16:42:20 didg Exp $
  *
  * Copyright (c) 1990,1994 Regents of The University of Michigan.
  * All Rights Reserved.  See COPYRIGHT.
@@ -21,6 +21,8 @@
 
 #define AFPVOL_NAMELEN   27
 
+#include <atalk/cnid.h>
+
 struct codepage_hash {
     unsigned char *from, *to;
     struct codepage_hash *next, *prev;
@@ -49,7 +51,6 @@ struct vol {
 #endif /*__svr4__*/
     char               *v_gvs;
     time_t             v_time;
-    int                        v_lastdid;
     u_int16_t          v_vid;
     void                *v_nfsclient;
     int                 v_nfs;
@@ -61,10 +62,10 @@ struct vol {
     char                *v_password;
     char                *v_veto;
 
-#ifdef CNID_DB
-    void                *v_db;
+    char                *v_cnidscheme;
     char                *v_dbpath;
-#endif 
+    struct _cnid_db     *v_cdb;
+    char                v_stamp[ADEDLEN_PRIVSYN];
     mode_t             v_umask;
 
 #ifdef FORCE_UIDGID
@@ -72,11 +73,16 @@ struct vol {
     char               *v_forcegid;
 #endif 
 
-    char                *v_encoding;
+    char                *v_volcodepage;
+    charset_t          v_volcharset;   
+    struct charset_functions   *v_vol;
+    char               *v_maccodepage;
     charset_t          v_maccharset;
+    struct charset_functions   *v_mac;
 
     int                 v_deleted;  /* volume open but deleted in new config file */
     int                 v_hide;     /* new volume wait open volume */
+    int                 v_adouble;  /* default adouble format */
 
     char                *v_root_preexec;
     char                *v_preexec;
@@ -116,9 +122,8 @@ this is going away. */
 #define AFPVOL_MAPASCII  (1 << 13)  /* map the ascii range as well */
 #define AFPVOL_DROPBOX   (1 << 14)  /* dropkludge dropbox support */
 #define AFPVOL_NOFILEID  (1 << 15)  /* don't advertise createid resolveid and deleteid calls */
-#define AFPVOL_UTF8      (1 << 16)  /* unix name are in UTF8 */
-#define AFPVOL_NOSTAT    (1 << 17)  /* unix name are in UTF8 */
-#define AFPVOL_UNIX_PRIV (1 << 18)  /* support unix privileges */
+#define AFPVOL_NOSTAT    (1 << 16)  /* unix name are in UTF8 */
+#define AFPVOL_UNIX_PRIV (1 << 17)  /* support unix privileges */
 
 /* FPGetSrvrParms options */
 #define AFPSRVR_CONFIGINFO     (1 << 0)
@@ -171,12 +176,9 @@ int wincheck(const struct vol *vol, const char *path);
 
 #define vol_noadouble(vol) (((vol)->v_flags & AFPVOL_NOADOUBLE) ? \
                            ADFLAGS_NOADOUBLE : 0)
-
 #ifdef AFP3x
-#define vol_utf8(vol) ((vol)->v_flags & AFPVOL_UTF8)
 #define utf8_encoding() (afp_version >= 30)
 #else
-#define vol_utf8(vol) (0)
 #define utf8_encoding() (0)
 #endif
 #define vol_unix_priv(vol) (afp_version >= 30 && ((vol)->v_flags & AFPVOL_UNIX_PRIV))
diff --git a/etc/cnid_dbd/Makefile.am b/etc/cnid_dbd/Makefile.am
new file mode 100644 (file)
index 0000000..1758166
--- /dev/null
@@ -0,0 +1,22 @@
+# Makefile.am for etc/cnid_dbd/
+
+sbin_PROGRAMS = cnid_dbd cnid_metad
+
+cnid_dbd_SOURCES = dbif.c pack.c comm.c usockfd.c db_param.c main.c \
+                   dbd_add.c dbd_get.c dbd_resolve.c dbd_lookup.c \
+                   dbd_update.c dbd_delete.c
+
+cnid_dbd_LDADD = $(top_builddir)/libatalk/libatalk.la
+
+cnid_metad_SOURCES = cnid_metad.c usockfd.c db_param.c
+
+cnid_metad_LDADD = $(top_builddir)/libatalk/libatalk.la
+
+noinst_HEADERS = dbif.h pack.h db_param.h dbd.h usockfd.h comm.h
+
+EXTRA_DIST = README
+
+LIBS = @LIBS@ @BDB_LIBS@
+
+
+CFLAGS = -I$(top_srcdir)/include @CFLAGS@ @BDB_CFLAGS@ 
diff --git a/etc/cnid_dbd/README b/etc/cnid_dbd/README
new file mode 100644 (file)
index 0000000..106a08b
--- /dev/null
@@ -0,0 +1,196 @@
+This is a reimplementation of the netatalk CNID database support that
+attempts to put all current functionality into a separate daemon
+called cnid_dbd. There is one such daemon per netatalk volume. The
+underlying database structure is still based on Berkeley DB and the
+database format is the same as in the current CNID implementation, so
+this can be used as a drop-in replacement.
+
+Advantages: 
+
+- No locking issues or leftover locks due to crashed afpd daemons any
+  more. Since there is only one thread of control accessing the
+  database, no locking is needed and changes appear atomic.
+
+- Berkeley DB transactions are difficult to get right with several
+  processes attempting to access the CNID database simultanously. This 
+  is much easier with a single process and the database can be made nearly 
+  crashproof this way (at a performance cost).
+
+- No problems with user permissions and access to underlying database
+  files, the cnid_dbd process runs under a configurable user
+  ID that normally also owns the underlying database
+  and can be contacted by whatever afpd daemon accesses a volume.
+
+- If an afpd process crashes, the CNID database is unaffected. If the
+  process was making changes to the database at the time of the crash,
+  those changes will either be completed (no transactions) or rolled
+  back entirely (transactions). If the process was not using the
+  database at the time of the crash, no corrective action is
+  necessary. In both cases, database consistency is assured.
+
+Disadvantages:
+
+- Performance in an environment of processes sharing the database
+  (files) is potentially better for two reasons:
+
+  i)  IPC overhead.
+  ii) r/o access to database pages is possible by more than one
+      process at once, r/w access is possible for nonoverlapping regions.
+
+  The current implementation of cnid_dbd uses unix domain sockets as
+  the IPC mechanism. While this is not the fastest possible method, it
+  is very portable and the cnid_dbd IPC mechanisms can be extended to
+  use faster IPC (like mmap) on architectures where it is
+  supported. As a ballpark figure, 20000 requests/replies to the cnid_dbd
+  daemon take about 0.6 seconds on a Pentium III 733 Mhz running Linux
+  Kernel 2.4.18 using unix domain sockets. The requests are "empty"
+  (no database lookups/changes), so this is just the IPC
+  overhead.
+  
+  I have not measured the effects of the advantages of simultanous
+  database access.
+
+
+Installation and configuration
+
+cnid_dbd is now part of a new CNID framework whereby various CNID
+backends (including the ones present so far) can be selected for afpd
+as a runtime option for a given volume. The default is to compile
+support for all these backends, so normally there is no need to
+specify other options to configure. The only exception is
+transactional support, which is enabled as the default. If you want to
+turn it off use --with-cnid-dbd-txn=no.
+
+In order to turn on cnid_dbd backend support for a given volume, set
+the option -cnidscheme:dbd in your AppleVolumes.default file or
+equivalent. The default for this parameter is -cnidscheme:cdb.
+
+There are two executeables that will be built in etc/cnid_dbd and 
+installed into the systems binaries directories of netatalk
+(e.g. /usr/local/netatalk/sbin or whatever you specify with 
+--sbindir to configure): cnid_metad and cnid_dbd. cnid_metad should
+run all the time with root permissions. It will be notified when an
+instance of afpd starts up and will in turn make sure that a cnid_dbd
+daemon is started for the volume that afpd wishes to access. The
+daemon runs forever and services any other instances of afpd that
+access the volume. You can safely kill it with SIGTERM, it will be
+restarted automatically by cnid_metad as soon as the volume is
+accessed again. 
+
+cnid_metad needs one command line argument, the name of the cnid_dbd
+executeable. You can either specify "cnid_dbd" if it is in the path
+for cnid_metad or otherwise use the fully qualified pathname to
+cnid_dbd, e.g. /usr/local/netatalk/sbin/cnid_dbd. cnid_metad also uses
+a unix domain socket to receive requests from afpd. The pathname for
+that socket is /tmp/cnid_meta. It should not be deleted while
+cnid_metad runs.
+
+
+cnid_dbd changes to the Berkeley DB directory on startup and sets
+effective UID and GID to owner and group of that directory. Database and
+supporting files should therefore be writeable by that user/group. cnid_dbd
+reads configuration information from the file db_param in the database
+directory on startup. If the file does not exist, suitable default
+values for all parameters are used. The format for a single parameter
+is the parameter name, followed by one or more spaces, followed by the
+parameter value, followed by a newline. The following parameters are
+currently recognized:
+
+Name               Default
+
+backlog            20
+cachesize          1024
+nosync             0
+flush_frequency    100
+flush_interval     30
+usock_file         <databasedirectory>/usock
+fd_table_size      16
+
+
+"backlog" specifies the maximum number of connection requests that can
+be pending on the unix domain socket cnid_dbd uses. listen(2) has more
+information about this value on your system.
+
+"cachesize" determines the size of the Berkeley DB cache in
+kilobytes. Each cnid_dbd process grabs that much memory on top of its
+normal memory footprint. It can be used to tune database
+performance. The db_stat utility with the "-m" option that comes with
+Berkely DB can help you determine wether you need to change this
+value. The default is pretty conservative so that a large percentage
+of requests should be satisfied from the cache directly. If memory is
+not a bottleneck on your system you might want to leave it at that
+value. The Berkeley DB Tutorial and Reference Guide has a section
+"Selecting a cache size" that gives more detailed information.
+
+"nosync" is only valid if transactional support is enabled. If it is
+set to 1, transactional changes to the database are not synchronously
+written to disk when the transaction completes. This will increase
+performance considerably at the risk of recent changes getting
+lost in case of a crash. The database will still be consistent,
+though. See "Transaction throughput" in the Berkeley DB Tutorial for
+more information.
+
+"flush_frequency" and "flush_interval" control how often changes to
+the database are written to the underlying database files if no
+transactions are used or how often the transaction system is
+checkpointed for transactions. Both of these operations are
+performed if either i) more than flush_frequency requests have been
+received or ii) more than flush_interval seconds have elapsed since
+the last save/checkpoint. If you use transactions with nosync set to
+zero these parameters only influence how long recovery takes after
+a crash, there should never be any lost data. If nosync is 1, changes
+might be lost, but only since the last checkpoint. Be careful to check
+your harddisk configuration for on disk cache settings. Many IDE disks
+just cache writes as the default behaviour, so even flushing database
+files to disk will not have the desired effect.
+
+"usock_file" gives the pathname of the unix domain socket file that
+that instance of cnid_dbd will use for receiving requests. You might
+have to use another value if the total length of the default pathname
+exceeds the limits for unix domain socket files on your system,
+usually this is something like 100 bytes.
+
+"fd_table_size" is the maximum number of connections (filedescriptors)
+that can be open for afpd client processes in cnid_dbd. If this number
+is exceeded, one of the existing connections is closed and reused. The
+affected afpd process will transparently reconnect later, which causes
+slight overhead. On the other hand, setting this parameter too high
+could affect performance in cnid_dbd since all descriptors have to be
+checked in a select() system call, or worse, you might exceed the per
+process limit of open file descriptors on your system. It is safe to
+set the value to 1 on volumes where only one afpd client process
+is expected to run, e.g. home directories.
+
+"idle_timeout" is the number of seconds of inactivity before an idle
+cnid_dbd exits. Set this to 0 to disable the timeout.
+
+Current shortcomings:
+
+- The implementation for cnid_dbd doubles code from libatalk/cnid,
+making it more difficult to keep changes to the library interface and
+the semantics of database requests in sync.  If cnid_dbd takes over
+the world, this problem will eventually disappear, otherwise it should
+be possible to merge things again, if transactional support is
+eliminated from libatalk/cnid. I do not think it can work relieably in
+the current form anyway.
+
+- It would be more flexible to have transaction support as a run time
+option as well.
+
+- mmap for IPC would be nice as an alternative.
+
+- The parameter file parsing of db_param is very simpleminded. It is
+easy to cause buffer overruns and the like.
+Also, there is no support for blanks (or weird characters) in
+filenames for the usock_file parameter.
+
+- There is no protection against a malicious user connecting to the
+cnid_dbd socket and changing the database. I will adress this problem
+soon.
+
+Please feel free to grep the source in etc/cnid_dbd and the file
+libatalk/cnid/dbd/cnid_dbd.c for the string TODO, which indicates
+comments that adress other, less important points.
+
+
+Joerg Lenneis, lenneis@wu-wien.ac.at
diff --git a/etc/cnid_dbd/cnid_metad.c b/etc/cnid_dbd/cnid_metad.c
new file mode 100644 (file)
index 0000000..ed2532c
--- /dev/null
@@ -0,0 +1,469 @@
+/*
+ * $Id: cnid_metad.c,v 1.1.4.1 2003-09-09 16:42:20 didg Exp $
+ *
+ * Copyright (C) Joerg Lenneis 2003
+ * All Rights Reserved.  See COPYRIGHT.
+ *
+ */
+
+/* cnid_dbd metadaemon to start up cnid_dbd upon request from afpd */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include <stdlib.h>
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#include <sys/param.h>
+#include <errno.h>
+#include <string.h>
+#include <signal.h>
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#ifdef HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#endif
+#include <sys/un.h>
+#include <sys/socket.h>
+#include <stdio.h>
+#include <time.h>
+
+#ifndef WEXITSTATUS 
+#define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
+#endif /* ! WEXITSTATUS */
+#ifndef WIFEXITED
+#define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
+#endif /* ! WIFEXITED */
+#ifndef WIFSTOPPED
+#define WIFSTOPPED(status) (((status) & 0xff) == 0x7f)
+#endif
+
+#ifndef WIFSIGNALED
+#define WIFSIGNALED(status) (!WIFSTOPPED(status) && !WIFEXITED(status))
+#endif
+#ifndef WTERMSIG
+#define WTERMSIG(status)      ((status) & 0x7f)
+#endif
+
+#ifdef ATACC
+#define fork aTaC_fork
+#endif
+
+/* functions for username and group */
+#include <pwd.h>
+#include <grp.h>
+
+#include <atalk/logger.h>
+#include <atalk/cnid_dbd_private.h>
+
+#include "db_param.h"
+#include "usockfd.h"
+
+#define DBHOME        ".AppleDB"
+#define DBHOMELEN    8      
+
+static int srvfd;
+static int rqstfd;
+
+#define MAXSRV 20
+
+#define MAXSPAWN   3                   /* Max times respawned in.. */
+#define TESTTIME   20                  /* this much seconds */
+
+struct server {
+    char  *name;
+    pid_t pid;
+    time_t tm;                    /* When respawned last */
+    int count;                    /* Times respawned in the last TESTTIME secondes */
+    int   sv[2];
+};
+
+static struct server srv[MAXSRV +1];
+
+static struct server *test_usockfn(char *dir, char *fn)
+{
+int i;
+    for (i = 1; i <= MAXSRV; i++) {
+        if (srv[i].name && !strcmp(srv[i].name, dir)) {
+            return &srv[i];
+        }
+    }
+    return NULL;
+}
+
+/* -------------------- */
+static int send_cred(int socket, int fd)
+{
+   int ret;
+   struct msghdr msgh; 
+   struct iovec iov[1];
+   struct cmsghdr *cmsgp = NULL;
+   char buf[CMSG_SPACE(sizeof fd)];
+   int er=0;
+
+   memset(&msgh,0,sizeof (msgh));
+   memset(buf,0,sizeof (buf));
+
+   msgh.msg_name = NULL;
+   msgh.msg_namelen = 0;
+
+   msgh.msg_iov = iov;
+   msgh.msg_iovlen = 1;
+
+   iov[0].iov_base = &er;
+   iov[0].iov_len = sizeof(er);
+
+   msgh.msg_control = buf;
+   msgh.msg_controllen = sizeof(buf);
+
+   cmsgp = CMSG_FIRSTHDR(&msgh);
+   cmsgp->cmsg_level = SOL_SOCKET;
+   cmsgp->cmsg_type = SCM_RIGHTS;
+   cmsgp->cmsg_len = CMSG_LEN(sizeof(fd));
+
+   *((int *)CMSG_DATA(cmsgp)) = fd;
+   msgh.msg_controllen = cmsgp->cmsg_len;
+
+   do  {
+       ret = sendmsg(socket,&msgh, 0);
+   } while ( ret == -1 && errno == EINTR );
+   if (ret == -1) {
+       LOG(log_error, logtype_cnid, "error in sendmsg: %s", strerror(errno));
+       return -1;
+   }
+   return 0;
+}
+
+/* -------------------- */
+static int maybe_start_dbd(char *dbdpn, char *dbdir, char *usockfn)
+{
+    pid_t pid;
+    struct server *up;
+    int i;
+    time_t t;
+
+    up = test_usockfn(dbdir, usockfn);
+    if (up && up->pid) {
+       /* we already have a process, send our fd */
+       if (send_cred(up->sv[0], rqstfd) < 0) {
+           /* FIXME */
+           return -1;
+       }
+       return 0;
+    }
+
+    time(&t);
+    if (!up) {
+        /* find an empty slot */
+        for (i = 1; i <= MAXSRV; i++) {
+            if (!srv[i].pid && srv[i].tm + TESTTIME < t) {
+                up = &srv[i];
+                free(up->name);
+                up->tm = t;
+                up->count = 0;
+                /* copy name */
+                up->name = strdup(dbdir);
+                break;
+            }
+        }
+        if (!up) {
+           LOG(log_error, logtype_cnid, "no free slot");
+           return -1;
+        }
+    }
+    else {
+        /* we have a slot but no process, check for respawn too fast */
+        if (up->tm + TESTTIME > t) {
+            up->count++;
+        } else {
+            up->count = 0;
+            up->tm = t;
+        }
+        if (up->count >= MAXSPAWN) {
+            up->tm = t;
+           LOG(log_error, logtype_cnid, "respawn too fast %s", up->name);
+           /* FIXME should we sleep a little ? */
+           return -1;
+        }
+        
+    }
+    /* create socketpair for comm between parent and child 
+     * FIXME Do we really need a permanent pipe between them ?
+     */
+    if (socketpair(PF_UNIX, SOCK_STREAM, 0, up->sv) < 0) {
+       LOG(log_error, logtype_cnid, "error in fork: %s", strerror(errno));
+       return -1;
+    }
+        
+    if ((pid = fork()) < 0) {
+       LOG(log_error, logtype_cnid, "error in fork: %s", strerror(errno));
+       return -1;
+    }    
+    if (pid == 0) {
+       /*
+        *  Child. Close descriptors and start the daemon. If it fails
+        *  just log it. The client process will fail connecting
+        *  afterwards anyway.
+        */
+       close(0);
+       close(1);
+       close(srvfd);
+       dup2(up->sv[1], 0);
+       dup2(rqstfd, 1);
+
+       close(up->sv[0]);
+       close(up->sv[1]);
+       close(rqstfd);
+       if (execlp(dbdpn, dbdpn, dbdir, NULL) < 0) {
+           LOG(log_error, logtype_cnid, "Fatal error in exec: %s", strerror(errno));
+           exit(0);
+       }
+    }
+    /*
+     *  Parent.
+     */
+    up->pid = pid;
+    return 0;
+}
+
+/* ------------------ */
+static int set_dbdir(char *dbdir, int len)
+{
+   struct stat st;
+
+    if (!len)
+        return -1;
+
+    if (stat(dbdir, &st) < 0 && mkdir(dbdir, 0755) < 0) {
+        LOG(log_error, logtype_cnid, "set_dbdir: mkdir failed for %s", dbdir);
+        return -1;
+    }
+
+    if (dbdir[len - 1] != '/') {
+         strcat(dbdir, "/");
+         len++;
+    }
+    strcpy(dbdir + len, DBHOME);
+    if (stat(dbdir, &st) < 0 && mkdir(dbdir, 0755 ) < 0) {
+        LOG(log_error, logtype_cnid, "set_dbdir: mkdir failed for %s", dbdir);
+        return -1;
+    }
+    return 0;   
+}
+
+/* ------------------ */
+uid_t user_to_uid ( username )
+char    *username;
+{
+    struct passwd *this_passwd;
+    /* check for anything */
+    if ( !username || strlen ( username ) < 1 ) return 0;
+    /* grab the /etc/passwd record relating to username */
+    this_passwd = getpwnam ( username );
+    /* return false if there is no structure returned */
+    if (this_passwd == NULL) return 0;
+    /* return proper uid */
+    return this_passwd->pw_uid;
+} 
+
+/* ------------------ */
+gid_t group_to_gid ( group )
+char    *group;
+{
+    struct group *this_group;
+    /* check for anything */
+    if ( !group || strlen ( group ) < 1 ) return 0;
+    /* grab the /etc/groups record relating to group */
+    this_group = getgrnam ( group );
+    /* return false if there is no structure returned */
+    if (this_group == NULL) return 0;
+    /* return proper gid */
+    return this_group->gr_gid;
+}
+
+/* ------------------ */
+int main(int argc, char *argv[])
+{
+    char  dbdir[MAXPATHLEN + 1];
+    int   len;
+    pid_t pid;
+    int   status;
+    char  *dbdpn = NULL;
+    char  *host = NULL;
+    int   port = 0;
+    struct db_param *dbp;
+    int    i;
+    int    cc;
+    uid_t  uid = 0;
+    gid_t  gid = 0;
+    int    err = 0;
+    int    debug = 0;
+    
+    while (( cc = getopt( argc, argv, "ds:p:h:u:g:")) != -1 ) {
+        switch (cc) {
+        case 'd':
+            debug = 1;
+            break;
+        case 'h':
+            host = strdup(optarg);  
+            break;
+        case 'u':
+            uid = user_to_uid (optarg);
+            if (!uid) {
+                LOG(log_error, logtype_cnid, "main: bad user %s", optarg);
+                err++;
+            }
+            break;
+        case 'g':
+            gid =group_to_gid (optarg);
+            if (!gid) {
+                LOG(log_error, logtype_cnid, "main: bad group %s", optarg);
+                err++;
+            }
+            break;
+        case 'p':
+            port = atoi(optarg);
+            break;
+        case 's':
+            dbdpn = strdup(optarg);
+            break;
+        default:
+            err++;
+            break;
+        }
+    }
+    
+    if (err || !host || !port || !dbdpn) {
+        LOG(log_error, logtype_cnid, "main: bad arguments");
+        exit(1);
+    }
+    
+    if (!debug) {
+        switch (fork()) {
+        case 0 :
+            fclose(stdin);
+            fclose(stdout);
+            fclose(stderr);
+
+#ifdef TIOCNOTTY
+            {
+               int i;
+                if (( i = open( "/dev/tty", O_RDWR )) >= 0 ) {
+                    (void)ioctl( i, TIOCNOTTY, 0 );
+                    setpgid( 0, getpid());
+                    (void) close(i);
+                }
+            }
+#else
+            setpgid( 0, getpid());
+#endif
+           break;
+        case -1 :  /* error */
+            LOG(log_error, logtype_cnid, "detach from terminal: %s", strerror(errno));
+            exit(1);
+        default :  /* server */
+            exit(0);
+        }
+    }
+
+    if ((srvfd = tsockfd_create(host, port, 10)) < 0)
+        exit(1);
+    /* switch uid/gid */
+    if (uid || gid) {
+
+        LOG(log_info, logtype_cnid, "Setting uid/gid to %i/%i", uid, gid);
+        if (gid) {
+            if (setresgid(gid,gid,gid) < 0 || setgid(gid) < 0) {
+                LOG(log_info, logtype_cnid, "unable to switch to group %d", gid);
+                exit(1);
+            }
+        }
+        if (uid) {
+            if (setresuid(uid,uid,uid) < 0 || setuid(uid) < 0) {
+                LOG(log_info, logtype_cnid, "unable to switch to user %d", uid);
+                exit(1);
+            }
+        }
+    }
+
+    signal(SIGPIPE, SIG_IGN);
+
+    while (1) {
+       /* Collect zombie processes and log what happened to them */       
+        while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
+           for (i = 1; i <= MAXSRV; i++) {
+               if (srv[i].pid == pid) {
+                   srv[i].pid = 0;
+#if 0                   
+                   free(srv[i].name);
+#endif                   
+                   close(srv[i].sv[0]);
+                   close(srv[i].sv[1]);
+                   break;
+               }
+            }
+           if (WIFEXITED(status)) {
+               LOG(log_info, logtype_cnid, "cnid_dbd pid %i exited with exit code %i", 
+                   pid, WEXITSTATUS(status));
+           }
+           else if (WIFSIGNALED(status)) {
+               LOG(log_info, logtype_cnid, "cnid_dbd pid %i exited with signal %i", 
+                   pid, WTERMSIG(status));
+           }
+           /* FIXME should */
+           
+       }
+        if ((rqstfd = usockfd_check(srvfd, 10000000)) <= 0)
+            continue;
+        /* TODO: Check out read errors, broken pipe etc. in libatalk. Is
+           SIGIPE ignored there? Answer: Ignored for dsi, but not for asp ... */
+        if (read(rqstfd, &len, sizeof(int)) != sizeof(int)) {
+            LOG(log_error, logtype_cnid, "error/short read: %s", strerror(errno));
+            goto loop_end;
+        }
+        /*
+         *  checks for buffer overruns. The client libatalk side does it too 
+         *  before handing the dir path over but who trusts clients?
+         */
+        if (!len || len +DBHOMELEN +2 > MAXPATHLEN) {
+            LOG(log_error, logtype_cnid, "wrong len parameter: %d", len);
+            goto loop_end;
+        }
+        if (read(rqstfd, dbdir, len) != len) {
+            LOG(log_error, logtype_cnid, "error/short read (dir): %s", strerror(errno));
+            goto loop_end;
+        }
+        dbdir[len] = '\0';
+        
+        if (set_dbdir(dbdir, len) < 0) {
+            goto loop_end;
+        }
+        
+        if ((dbp = db_param_read(dbdir)) == NULL) {
+            LOG(log_error, logtype_cnid, "Error reading config file");
+            goto loop_end;
+        }
+       maybe_start_dbd(dbdpn, dbdir, dbp->usock_file);
+
+    loop_end:
+        close(rqstfd);
+    }
+}
diff --git a/etc/cnid_dbd/comm.c b/etc/cnid_dbd/comm.c
new file mode 100644 (file)
index 0000000..b343ffe
--- /dev/null
@@ -0,0 +1,280 @@
+/*
+ * $Id: comm.c,v 1.1.4.1 2003-09-09 16:42:20 didg Exp $
+ *
+ * Copyright (C) Joerg Lenneis 2003
+ * All Rights Reserved.  See COPYRIGHT.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#include <sys/param.h>
+#include <sys/socket.h>
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif /* HAVE_SYS_TYPES_H */
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif /* HAVE_SYS_TIME_H */
+
+#include <assert.h>
+#include <time.h>
+
+#include <atalk/logger.h>
+#include <atalk/cnid_dbd_private.h>
+
+#include "db_param.h"
+#include "usockfd.h"
+#include "comm.h"
+
+struct connection {
+    time_t tm;                    /* When respawned last */
+    int    fd;
+};
+
+static int   usock_fd;
+static int   cur_fd;
+static struct connection *fd_table;
+static int  fd_table_size;
+static int  fds_in_use = 0;
+
+
+static void invalidate_fd(int fd)
+{
+    int i;
+
+    if (fd == usock_fd)
+        return;
+    for (i = 0; i != fds_in_use; i++) 
+       if (fd_table[i].fd == fd)
+           break;
+    
+    assert(i < fds_in_use);
+
+    fds_in_use--;
+    fd_table[i] = fd_table[fds_in_use];
+    fd_table[fds_in_use].fd = -1;
+    close(fd);    
+    return;
+}
+
+static int recv_cred(int fd)
+{
+int ret;
+struct msghdr msgh; 
+struct iovec iov[1];
+struct cmsghdr *cmsgp = NULL;
+char buf[CMSG_SPACE(sizeof(int))];
+char dbuf[80];
+
+    memset(&msgh,0,sizeof(msgh));
+    memset(buf,0,sizeof(buf));
+
+    msgh.msg_name = NULL;
+    msgh.msg_namelen = 0;
+
+    msgh.msg_iov = iov;
+    msgh.msg_iovlen = 1;
+
+    iov[0].iov_base = dbuf;
+    iov[0].iov_len = sizeof(dbuf);
+
+    msgh.msg_control = buf;
+    msgh.msg_controllen = sizeof(buf);
+
+    do  {
+          ret = recvmsg(fd ,&msgh,0);
+    } while ( ret == -1 && errno == EINTR );
+
+    if ( ret == -1 ) {
+        return -1;
+    }
+      
+    for ( cmsgp = CMSG_FIRSTHDR(&msgh); cmsgp != NULL; cmsgp = CMSG_NXTHDR(&msgh,cmsgp) ) {
+        if ( cmsgp->cmsg_level == SOL_SOCKET && cmsgp->cmsg_type == SCM_RIGHTS ) {
+              return *(int *) CMSG_DATA(cmsgp);
+        }
+    }
+
+    if ( ret == sizeof (int) )
+       errno = *(int *)dbuf; /* Rcvd errno */
+    else
+       errno = ENOENT;    /* Default errno */
+   
+    return -1;
+}
+
+/*
+ *  Check for client requests. We keep up to fd_table_size open descriptors in
+ *  fd_table. If the table is full and we get a request for a new descriptor via
+ *  usock_fd, we close a random decriptor in the table to make space. The
+ *  affected client will automatically reconnect. For an EOF (descriptor is
+ *  closed by the client, so a read here returns 0) comm_rcv will take care of
+ *  things and clean up fd_table. The same happens for any read/write errors.
+ */
+
+static int check_fd()
+{
+    int fd;
+    fd_set readfds;
+    struct timeval tv;
+    int ret;
+    int i;
+    int maxfd = usock_fd;
+    time_t t;
+    
+    FD_ZERO(&readfds);
+    FD_SET(usock_fd, &readfds);
+    
+    for (i = 0; i != fds_in_use; i++) {
+       FD_SET(fd_table[i].fd, &readfds);
+       if (maxfd < fd_table[i].fd)
+           maxfd = fd_table[i].fd;
+    }
+
+    tv.tv_usec = 0;
+    tv.tv_sec  = 1;
+    if ((ret = select(maxfd + 1, &readfds, NULL, NULL, &tv)) < 0) {
+        if (errno == EINTR)
+            return 0;
+        LOG(log_error, logtype_cnid, "error in select: %s",strerror(errno));
+        return -1;
+    }
+
+    if (!ret)
+       return 0;
+
+    time(&t);
+
+    if (FD_ISSET(usock_fd, &readfds)) {
+       int    l = 0;
+       
+        fd = recv_cred(usock_fd);
+        if (fd < 0) {
+            return -1;
+        }
+       if (fds_in_use < fd_table_size) {
+           fd_table[fds_in_use].fd = fd;
+           fd_table[fds_in_use].tm = t;
+           fds_in_use++;
+       } else {
+           time_t older = t;
+            
+           for (i = 0; i != fds_in_use; i++) {
+               if (older <= fd_table[i].tm) {
+                   older = fd_table[i].tm;
+                   l = i;
+               }
+           }
+           close(fd_table[l].fd);
+           fd_table[l].fd = fd;
+           fd_table[l].tm = t;
+       }
+       return 0;
+    }
+
+    for (i = 0; i != fds_in_use; i++) {
+       if (FD_ISSET(fd_table[i].fd, &readfds)) {
+           fd_table[i].tm = t;
+           return fd_table[i].fd;
+       }
+    }      
+    /* We should never get here */
+    return 0;
+}
+
+int comm_init(struct db_param *dbp)
+{
+    int i;
+
+    fds_in_use = 0;
+    fd_table_size = dbp->fd_table_size;
+    
+    if ((fd_table = malloc(fd_table_size * sizeof(struct connection))) == NULL) {
+        LOG(log_error, logtype_cnid, "Out of memory");
+       return -1;
+    }
+    for (i = 0; i != fd_table_size; i++)
+       fd_table[i].fd = -1;
+    /* from dup2 */
+    usock_fd = 0;
+#if 0
+    int b = 1;
+    /* this one dump core in recvmsg, great */
+    if ( setsockopt(usock_fd, SOL_SOCKET, SO_PASSCRED, &b, sizeof (b)) < 0) {
+        LOG(log_error, logtype_cnid, "setsockopt SO_PASSCRED %s",  strerror(errno));
+       return -1;
+    }
+#endif
+    /* push the first from dup2 */
+    fd_table[fds_in_use].fd = 1;
+    fds_in_use++;
+    
+    return 0;
+}
+
+/* ------------ 
+   nbe of clients
+*/
+int comm_nbe(void)
+{
+    return fds_in_use;
+}
+
+/* ------------ */
+int comm_rcv(struct cnid_dbd_rqst *rqst)
+{
+    char *nametmp;
+    int b;
+
+    if ((cur_fd = check_fd()) < 0)
+        return -1;
+
+    if (!cur_fd)
+        return 0;
+    nametmp = rqst->name;
+    if ((b = read(cur_fd, rqst, sizeof(struct cnid_dbd_rqst))) != sizeof(struct cnid_dbd_rqst)) {
+       if (b)
+           LOG(log_error, logtype_cnid, "error reading message header: %s", strerror(errno));
+        invalidate_fd(cur_fd);
+        rqst->name = nametmp;
+        return 0;
+    }
+    rqst->name = nametmp;
+    if (rqst->namelen && read(cur_fd, rqst->name, rqst->namelen) != rqst->namelen) {
+        LOG(log_error, logtype_cnid, "error reading message name: %s", strerror(errno));
+        invalidate_fd(cur_fd);
+        return 0;
+    }
+    /* We set this to make life easier for logging. None of the other stuff
+       needs zero terminated strings. */
+    rqst->name[rqst->namelen] = '\0';
+        
+    return 1;
+}
+
+
+int comm_snd(struct cnid_dbd_rply *rply)
+{
+    if (write(cur_fd, rply, sizeof(struct cnid_dbd_rply)) != sizeof(struct cnid_dbd_rply)) {
+        LOG(log_error, logtype_cnid, "error writing message header: %s", strerror(errno));
+        invalidate_fd(cur_fd);
+        return 0;
+    }
+    if (rply->namelen && write(cur_fd, rply->name, rply->namelen) != rply->namelen) {
+        LOG(log_error, logtype_cnid, "error writing message name: %s", strerror(errno));
+        invalidate_fd(cur_fd);
+        return 0;
+    }
+    return 1;
+}
+
+
diff --git a/etc/cnid_dbd/comm.h b/etc/cnid_dbd/comm.h
new file mode 100644 (file)
index 0000000..304ac2e
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * $Id: comm.h,v 1.1.4.1 2003-09-09 16:42:20 didg Exp $
+ *
+ * Copyright (C) Joerg Lenneis 2003
+ * All Rights Reserved.  See COPYRIGHT.
+ */
+
+#ifndef CNID_DBD_COMM_H
+#define CNID_DBD_COMM_H 1
+
+
+#include <atalk/cnid_dbd_private.h>
+
+
+extern int      comm_init  __P((struct db_param *));
+extern int      comm_rcv  __P((struct cnid_dbd_rqst *));
+extern int      comm_snd  __P((struct cnid_dbd_rply *));
+extern int      comm_nbe  __P((void));
+
+
+
+
+#endif /* CNID_DBD_COMM_H */
+
+
+
+
+
+
diff --git a/etc/cnid_dbd/db_param.c b/etc/cnid_dbd/db_param.c
new file mode 100644 (file)
index 0000000..25bfb93
--- /dev/null
@@ -0,0 +1,180 @@
+/*
+ * $Id: db_param.c,v 1.1.4.1 2003-09-09 16:42:20 didg Exp $
+ *
+ * Copyright (C) Joerg Lenneis 2003
+ * All Rights Reserved.  See COPYRIGHT.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/param.h>
+#include <sys/un.h>
+
+
+#include <atalk/logger.h>
+
+#include "db_param.h"
+
+
+#define DB_PARAM_FN       "db_param"
+#define MAXKEYLEN         64
+
+#define DEFAULT_BACKLOG            20   
+#define DEFAULT_CACHESIZE          1024 * 4 
+#define DEFAULT_NOSYNC             0    
+#define DEFAULT_FLUSH_FREQUENCY    100  
+#define DEFAULT_FLUSH_INTERVAL     30   
+#define DEFAULT_USOCK_FILE         "usock"
+#define DEFAULT_FD_TABLE_SIZE      16
+#define DEFAULT_IDLE_TIMEOUT       600
+
+static struct db_param params;
+static int parse_err;
+
+static int usock_maxlen()
+{
+    struct sockaddr_un addr;
+
+    return sizeof(addr.sun_path) - 1;
+}
+
+static int make_pathname(char *path, char *dir, char *fn, int maxlen)
+{
+    size_t len;
+
+    if (fn[0] != '/') {
+        len = strlen(dir);
+        if (len + 1 + strlen(fn) > maxlen)
+            return -1;      
+        strcpy(path, dir);
+        if (path[len - 1] != '/')
+            strcat(path, "/");
+        strcat(path, fn);
+    } else {
+        if (strlen(fn) > maxlen)
+            return -1;
+        strcpy(path, fn);
+    }
+    return 0;
+}
+
+static void default_params(struct db_param *dbp, char *dir)
+{        
+    dbp->backlog             = DEFAULT_BACKLOG;
+    dbp->cachesize           = DEFAULT_CACHESIZE;
+    dbp->nosync              = DEFAULT_NOSYNC;
+    dbp->flush_frequency     = DEFAULT_FLUSH_FREQUENCY;
+    dbp->flush_interval      = DEFAULT_FLUSH_INTERVAL;
+    if (make_pathname(dbp->usock_file, dir, DEFAULT_USOCK_FILE, usock_maxlen()) < 0)
+        /* Not an error yet, it might be set in the config file */
+        dbp->usock_file[0] = '\0';
+    dbp->fd_table_size       = DEFAULT_FD_TABLE_SIZE;
+    dbp->idle_timeout        = DEFAULT_IDLE_TIMEOUT;
+    return;
+}
+
+static int parse_int(char *val)
+{
+    char *tmp;
+    int   result = 0;
+
+    result = strtol(val, &tmp, 10);
+    if (tmp[0] != '\0') {
+        LOG(log_error, logtype_cnid, "invalid characters in token %s", val);
+        parse_err++;
+    }
+    return result;
+}
+
+
+/* TODO: This configuration file reading routine is neither very robust (%s
+   buffer overflow) nor elegant, we need to add support for whitespace in
+   filenames as well. */
+
+struct db_param *db_param_read(char *dir)
+{
+    FILE *fp;
+    static char key[MAXKEYLEN + 1];
+    static char val[MAXPATHLEN + 1];
+    static char pfn[MAXPATHLEN + 1];
+    int    items;
+    
+    default_params(&params, dir);
+    
+    if (make_pathname(pfn, dir, DB_PARAM_FN, MAXPATHLEN) < 0) {
+        LOG(log_error, logtype_cnid, "Parameter filename too long");
+        return NULL;
+    }
+
+    if ((fp = fopen(pfn, "r")) == NULL) {
+        if (errno == ENOENT) {
+            if (strlen(params.usock_file) == 0) {
+                LOG(log_error, logtype_cnid, "default usock filename too long");
+                return NULL;
+            } else {
+                return &params;
+            }
+        } else {
+            LOG(log_error, logtype_cnid, "error opening %s: %s", pfn, strerror(errno));
+            return NULL;
+        }
+    }
+    parse_err = 0;
+
+    while ((items = fscanf(fp, " %s %s", key, val)) != EOF) {
+        if (items != 2) {
+            LOG(log_error, logtype_cnid, "error parsing config file");
+            parse_err++;
+            break;
+        }
+        
+        if (! strcmp(key, "backlog")) 
+            params.backlog = parse_int(val);
+        else if (! strcmp(key, "cachesize"))
+            params.cachesize = parse_int(val);
+        else if (! strcmp(key, "nosync"))
+            params.nosync = parse_int(val);
+        else if (! strcmp(key, "flush_frequency"))
+            params.flush_frequency = parse_int(val);
+        else if (! strcmp(key, "flush_interval"))
+            params.flush_interval = parse_int(val);
+        else if (! strcmp(key, "usock_file")) {
+            if (make_pathname(params.usock_file, dir, val, usock_maxlen()) < 0) {
+                LOG(log_error, logtype_cnid, "usock filename %s too long", val);
+                parse_err++;
+            }
+        } else if (! strcmp(key, "fd_table_size"))
+            params.fd_table_size = parse_int(val);
+       else if (! strcmp(key, "idle_timeout"))
+            params.idle_timeout = parse_int(val);
+       else {
+            LOG(log_error, logtype_cnid, "error parsing %s -> %s in config file", key, val);
+            parse_err++;
+        }
+        if(parse_err)
+            break;
+    }
+    
+    if (strlen(params.usock_file) == 0) {
+        LOG(log_error, logtype_cnid, "default usock filename too long");
+        parse_err++;
+    }
+
+    fclose(fp);
+    if (! parse_err)
+        return &params;
+    else
+        return NULL;
+}
+
+
+
diff --git a/etc/cnid_dbd/db_param.h b/etc/cnid_dbd/db_param.h
new file mode 100644 (file)
index 0000000..16a518c
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * $Id: db_param.h,v 1.1.4.1 2003-09-09 16:42:20 didg Exp $
+ *
+ * Copyright (C) Joerg Lenneis 2003
+ * All Rights Reserved.  See COPYRIGHT.
+ */
+
+#ifndef CNID_DBD_DB_PARAM_H
+#define CNID_DBD_DB_PARAM_H 1
+
+#include <sys/param.h>
+
+
+struct db_param {
+    int backlog;
+    int cachesize;
+    int nosync;
+    int flush_frequency;
+    int flush_interval;
+    char usock_file[MAXPATHLEN + 1];    
+    int fd_table_size;
+    int idle_timeout;
+};
+
+extern struct db_param *      db_param_read  __P((char *));
+
+
+#endif /* CNID_DBD_DB_PARAM_H */
+
diff --git a/etc/cnid_dbd/dbd.h b/etc/cnid_dbd/dbd.h
new file mode 100644 (file)
index 0000000..8e3669b
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * $Id: dbd.h,v 1.1.4.1 2003-09-09 16:42:20 didg Exp $
+ *
+ * Copyright (C) Joerg Lenneis 2003
+ * All Rights Reserved.  See COPYRIGHT.
+ */
+
+#ifndef CNID_DBD_DBD_H
+#define CNID_DBD_DBD_H 1
+
+
+#include <atalk/cnid_dbd_private.h>
+
+extern int      dbd_stamp __P((void));
+extern int      dbd_add  __P((struct cnid_dbd_rqst *, struct cnid_dbd_rply *));
+extern int      dbd_get  __P((struct cnid_dbd_rqst *, struct cnid_dbd_rply *));
+extern int      dbd_resolve  __P((struct cnid_dbd_rqst *, struct cnid_dbd_rply *));
+extern int      dbd_lookup  __P((struct cnid_dbd_rqst *, struct cnid_dbd_rply *));
+extern int      dbd_update  __P((struct cnid_dbd_rqst *, struct cnid_dbd_rply *));
+extern int      dbd_delete  __P((struct cnid_dbd_rqst *, struct cnid_dbd_rply *));
+
+#endif /* CNID_DBD_DBD_H */
diff --git a/etc/cnid_dbd/dbd_add.c b/etc/cnid_dbd/dbd_add.c
new file mode 100644 (file)
index 0000000..2c5f220
--- /dev/null
@@ -0,0 +1,206 @@
+/*
+ * $Id: dbd_add.c,v 1.1.4.1 2003-09-09 16:42:20 didg Exp $
+ *
+ * Copyright (C) Joerg Lenneis 2003
+ * All Rights Reserved.  See COPYRIGHT.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include <string.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif /* HAVE_FCNTL_H */
+#include <errno.h>
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif /* HAVE_SYS_TIME_H */
+
+#include <atalk/logger.h>
+#include <atalk/cnid_dbd_private.h>
+#include <atalk/cnid.h>
+#include <db.h>
+
+#include "dbif.h"
+#include "pack.h"
+#include "dbd.h"
+
+/* FIXME assume dev_t == ino_t == 8 */
+/*                         cnid   - dev        - inode     - type  - did  - name */
+#define ROOTINFO_DATA    "\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\0RootInfo"
+#define ROOTINFO_DATALEN (3*4 +2*8  +9)
+#define CNID_START        17 /*  0x80000000L */
+
+static int add_cnid(struct cnid_dbd_rqst *rqst, struct cnid_dbd_rply *rply)
+{
+    DBT key, data;
+    int rc;
+
+    memset(&key, 0, sizeof(key));
+    memset(&data, 0, sizeof(data));
+
+    key.data = &rply->cnid;
+    key.size = sizeof(rply->cnid);
+
+    data.data = pack_cnid_data(rqst);
+    data.size = CNID_HEADER_LEN + rqst->namelen + 1;
+    memcpy(data.data, &rply->cnid, sizeof(rply->cnid));
+
+    /* main database */
+    if ((rc = dbif_put(DBIF_IDX_CNID, &key, &data, DB_NOOVERWRITE))) {
+        /* This could indicate a database error or that the key already exists
+         (because of DB_NOOVERWRITE). In that case we still look at some sort of
+         database corruption since that is not supposed to happen. */
+        
+        switch (rc) {
+        case 1:
+            rply->result = CNID_DBD_RES_ERR_DUPLCNID;
+            break;
+        case -1:
+            LOG(log_error, logtype_cnid, "add_cnid: duplicate %x %s", rply->cnid
+             , data.data + CNID_NAME_OFS);
+            
+            rqst->cnid = rply->cnid;
+            rc = dbd_update(rqst, rply);
+            if (rc < 0) {
+                rply->result = CNID_DBD_RES_ERR_DB;
+                return -1;
+            }
+            else 
+               return 0;
+            break;
+        }
+        return -1;
+    }
+
+    return 0;
+}
+
+/* ---------------------- */
+static int get_cnid(struct cnid_dbd_rply *rply)
+{
+    DBT rootinfo_key, rootinfo_data;
+    int rc;
+    cnid_t hint, id;
+     
+    memset(&rootinfo_key, 0, sizeof(rootinfo_key));
+    memset(&rootinfo_data, 0, sizeof(rootinfo_data));
+    rootinfo_key.data = ROOTINFO_KEY;
+    rootinfo_key.size = ROOTINFO_KEYLEN;
+
+    if ((rc = dbif_get(DBIF_IDX_CNID, &rootinfo_key, &rootinfo_data, 0)) <= 0) {
+        rply->result = CNID_DBD_RES_ERR_DB;
+        return -1;
+    }
+    memcpy(&hint, (char *)rootinfo_data.data +CNID_TYPE_OFS, sizeof(hint));
+    id = ntohl(hint);
+    /* If we've hit the max CNID allowed, we return an error. CNID
+     * needs to be recycled before proceding. */
+    if (++id == CNID_INVALID) {
+        rply->result = CNID_DBD_RES_ERR_MAX;
+        return -1;
+    }
+
+#if 0
+    memcpy(buf, ROOTINFO_DATA, ROOTINFO_DATALEN);
+#endif    
+    rootinfo_data.size = ROOTINFO_DATALEN;
+    hint = htonl(id);
+    memcpy((char *)rootinfo_data.data +CNID_TYPE_OFS, &hint, sizeof(hint));
+
+    if (dbif_put(DBIF_IDX_CNID, &rootinfo_key, &rootinfo_data, 0) < 0) {
+        rply->result = CNID_DBD_RES_ERR_DB;
+        return -1;
+    }
+    rply->cnid = hint;
+    return 0;
+}
+
+/* --------------- 
+*/
+int dbd_stamp(void) 
+{
+    DBT rootinfo_key, rootinfo_data;
+    cnid_t hint, id;
+    int rc;
+    char buf[ROOTINFO_DATALEN];
+    char stamp[CNID_DEV_LEN];
+     
+    memset(&rootinfo_key, 0, sizeof(rootinfo_key));
+    memset(&rootinfo_data, 0, sizeof(rootinfo_data));
+    rootinfo_key.data = ROOTINFO_KEY;
+    rootinfo_key.size = ROOTINFO_KEYLEN;
+
+    switch (dbif_get(DBIF_IDX_CNID, &rootinfo_key, &rootinfo_data, 0)) {
+    case 0:
+        hint = htonl(CNID_START);
+        memcpy(buf, ROOTINFO_DATA, ROOTINFO_DATALEN);
+        rootinfo_data.data = buf;
+        rootinfo_data.size = ROOTINFO_DATALEN;
+        if (dbif_stamp(stamp, CNID_DEV_LEN) < 0) {
+            return -1;
+        }
+        memcpy((char *)rootinfo_data.data +CNID_TYPE_OFS, &hint, sizeof(hint));
+        memcpy((char *)rootinfo_data.data +CNID_DEV_OFS, stamp, sizeof(stamp));
+        if (dbif_put(DBIF_IDX_CNID, &rootinfo_key, &rootinfo_data, 0) < 0) {
+            return -1;
+        }
+        return 0;
+    
+    case 1: /* we already have one */
+        return 0;
+    default:
+        return -1;
+    }
+    return -1;
+}
+
+/* ------------------------ */
+int dbd_add(struct cnid_dbd_rqst *rqst, struct cnid_dbd_rply *rply)
+{
+    rply->namelen = 0;
+
+    /* See if we have an entry already and return it if yes */
+    if (dbd_lookup(rqst, rply) < 0)
+        return -1;
+
+    if (rply->result == CNID_DBD_RES_OK) {
+        /* Found it. rply->cnid is the correct CNID now. */
+#ifdef DEBUG
+        LOG(log_info, logtype_cnid, "dbd_add: Looked up did %u, name %s as %u", ntohl(rqst->did), rqst->name, ntohl(rply->cnid));
+#endif
+        return 1;
+    }
+
+    if (get_cnid(rply) < 0) {
+        if (rply->result == CNID_DBD_RES_ERR_MAX) {
+            LOG(log_error, logtype_cnid, "dbd_add: FATAL: CNID database has reached its limit.");
+            /* This will cause an abort/rollback if transactions are used */
+            return 0;
+        } else {
+            LOG(log_error, logtype_cnid, "dbd_add: Failed to compute CNID for %s, error reading/updating Rootkey", rqst->name);
+            return -1;
+        }
+    }
+    
+    if (add_cnid(rqst, rply) < 0) {
+        if (rply->result == CNID_DBD_RES_ERR_DUPLCNID) {
+            LOG(log_error, logtype_cnid, "dbd_add: Cannot add CNID %u. Corrupt/invalid Rootkey?.", ntohl(rply->cnid));
+            /* abort/rollback, see above */
+            return 0;
+        } else {
+            LOG(log_error, logtype_cnid, "dbd_add: Failed to add CNID for %s to database", rqst->name);
+            return -1;
+        }
+    }
+#ifdef DEBUG
+    LOG(log_info, logtype_cnid, "dbd_add: Returned CNID for did %u, name %s as %u", ntohl(rqst->did), rqst->name, ntohl(rply->cnid));
+#endif
+    rply->result = CNID_DBD_RES_OK;
+    return 1;
+}
diff --git a/etc/cnid_dbd/dbd_delete.c b/etc/cnid_dbd/dbd_delete.c
new file mode 100644 (file)
index 0000000..0c0f56d
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * $Id: dbd_delete.c,v 1.1.4.1 2003-09-09 16:42:20 didg Exp $
+ *
+ * Copyright (C) Joerg Lenneis 2003
+ * All Rights Reserved.  See COPYRIGHT.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include <string.h>
+#include <errno.h>
+#include <atalk/logger.h>
+
+#include <db.h>
+#include <netatalk/endian.h>
+#include <atalk/cnid_dbd_private.h>
+
+#include "dbif.h"
+#include "dbd.h"
+#include "pack.h"
+
+int dbd_delete(struct cnid_dbd_rqst *rqst, struct cnid_dbd_rply *rply)
+{
+    DBT key;
+    int rc;
+
+    memset(&key, 0, sizeof(key));
+
+    rply->namelen = 0;
+
+    key.data = (void *) &rqst->cnid;
+    key.size = sizeof(rqst->cnid);
+
+    if ((rc = dbif_del(DBIF_IDX_CNID, &key, 0)) < 0) {
+        LOG(log_error, logtype_cnid, "dbd_delete: Unable to delete entry for CNID %u", ntohl(rqst->cnid));
+        rply->result = CNID_DBD_RES_ERR_DB;
+        return -1;
+    }
+    else {
+#ifdef DEBUG
+        LOG(log_info, logtype_cnid, "cnid_delete: CNID %u not in database",
+            ntohl(rqst->cnid));
+#endif
+        rply->result = CNID_DBD_RES_NOTFOUND;
+    }
+    return 1;
+}
diff --git a/etc/cnid_dbd/dbd_get.c b/etc/cnid_dbd/dbd_get.c
new file mode 100644 (file)
index 0000000..6f0353a
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * $Id: dbd_get.c,v 1.1.4.1 2003-09-09 16:42:20 didg Exp $
+ *
+ * Copyright (C) Joerg Lenneis 2003
+ * All Rights Reserved.  See COPYRIGHT.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include <string.h>
+#include <sys/param.h>
+#include <atalk/logger.h>
+#include <errno.h>
+
+#include <db.h>
+#include <netatalk/endian.h>
+#include <atalk/cnid_dbd_private.h>
+
+
+#include "dbif.h"
+#include "dbd.h"
+#include "pack.h"
+
+
+/* Return CNID for a given did/name. */
+
+int dbd_get(struct cnid_dbd_rqst *rqst, struct cnid_dbd_rply *rply)
+{
+    char start[CNID_DID_LEN + MAXPATHLEN + 1], *buf;
+    DBT key, data;
+    int rc;
+
+    memset(&key, 0, sizeof(key));
+    memset(&data, 0, sizeof(data));
+
+    rply->namelen = 0;
+
+    buf = start;
+    memcpy(buf, &rqst->did, sizeof(rqst->did));
+    buf += sizeof(rqst->did);
+    memcpy(buf, rqst->name, rqst->namelen);
+    *(buf + rqst->namelen) = '\0'; /* Make it a C-string. */
+    key.data = start;
+    key.size = CNID_DID_LEN + rqst->namelen + 1;
+
+    if ((rc = dbif_get(DBIF_IDX_DIDNAME, &key, &data, 0)) < 0) {
+        LOG(log_error, logtype_cnid, "dbd_get: Unable to get CNID %u, name %s", ntohl(rqst->did), rqst->name);
+        rply->result = CNID_DBD_RES_ERR_DB;
+        return -1;
+    }
+
+    if (rc == 0) {
+        rply->result = CNID_DBD_RES_NOTFOUND;
+        return 1;
+    }
+
+    memcpy(&rply->cnid, data.data, sizeof(rply->cnid));
+#ifdef DEBUG
+    LOG(log_info, logtype_cnid, "cnid_get: Returning CNID for %u, name %s as %u",
+        ntohl(rqst->did), rqst->name, ntohl(rply->cnid));
+#endif
+    rply->result = CNID_DBD_RES_OK;
+    return 1;
+}
diff --git a/etc/cnid_dbd/dbd_lookup.c b/etc/cnid_dbd/dbd_lookup.c
new file mode 100644 (file)
index 0000000..ff5cda8
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+ * $Id: dbd_lookup.c,v 1.1.4.1 2003-09-09 16:42:20 didg Exp $
+ *
+ * Copyright (C) Joerg Lenneis 2003
+ * All Rights Reserved.  See COPYRIGHT.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/param.h>
+#include <atalk/logger.h>
+#include <errno.h>
+
+#include <db.h>
+#include <netatalk/endian.h>
+#include <atalk/cnid_dbd_private.h>
+
+#include "pack.h"
+#include "dbif.h"
+#include "dbd.h"
+
+/*
+ *  This returns the CNID corresponding to a particular file.  It will also fix
+ *  up the database if there's a problem.
+ */
+
+int dbd_lookup(struct cnid_dbd_rqst *rqst, struct cnid_dbd_rply *rply)
+{
+    char *buf;
+    DBT key, devdata, diddata;
+    dev_t  dev;
+    ino_t  ino;
+    int devino = 1, didname = 1; 
+    int rc;
+    cnid_t id_devino, id_didname;
+    u_int32_t type_devino  = (unsigned)-1;
+    u_int32_t type_didname = (unsigned)-1;
+    int update = 0;
+    
+    
+    memset(&key, 0, sizeof(key));
+    memset(&diddata, 0, sizeof(diddata));
+    memset(&devdata, 0, sizeof(devdata));
+
+    rply->namelen = 0;
+    rply->cnid = 0;
+    
+    buf = pack_cnid_data(rqst); 
+    memcpy(&dev, buf + CNID_DEV_OFS, sizeof(dev));
+    memcpy(&ino, buf + CNID_INO_OFS, sizeof(ino));
+
+    /* Look for a CNID.  We have two options: dev/ino or did/name.  If we
+       only get a match in one of them, that means a file has moved. */
+    key.data = buf +CNID_DEVINO_OFS;
+    key.size = CNID_DEVINO_LEN;
+
+    if ((rc = dbif_get(DBIF_IDX_DEVINO, &key, &devdata, 0))  < 0) {
+        LOG(log_error, logtype_cnid, "dbd_lookup: Unable to get CNID %u, name %s",
+                ntohl(rqst->did), rqst->name);
+        rply->result = CNID_DBD_RES_ERR_DB;
+        return -1;
+    }
+    if (rc == 0) {
+        devino = 0;
+    }
+    else {
+        memcpy(&id_devino, devdata.data, sizeof(rply->cnid));
+        memcpy(&type_devino, devdata.data +CNID_TYPE_OFS, sizeof(type_devino));
+        type_devino = ntohl(type_devino);
+    }
+    
+    buf = pack_cnid_data(rqst); 
+    key.data = buf +CNID_DID_OFS;
+    key.size = CNID_DID_LEN + rqst->namelen + 1;
+
+    if ((rc = dbif_get(DBIF_IDX_DIDNAME, &key, &diddata, 0))  < 0) {
+        LOG(log_error, logtype_cnid, "dbd_lookup: Unable to get CNID %u, name %s",
+                ntohl(rqst->did), rqst->name);
+        rply->result = CNID_DBD_RES_ERR_DB;
+        return -1;
+    }
+    if (rc == 0) {
+        didname = 0;
+    }
+    else {
+        memcpy(&id_didname, diddata.data, sizeof(rply->cnid));
+        memcpy(&type_didname, diddata.data +CNID_TYPE_OFS, sizeof(type_didname));
+        type_didname = ntohl(type_didname);
+    }
+    
+    if (!devino && !didname) {  
+        /* not found */
+        rply->result = CNID_DBD_RES_NOTFOUND;
+        return 1;
+    }
+
+    if (devino && didname && id_devino == id_didname && type_devino == rqst->type) {
+        /* the same */
+        rply->cnid = id_didname;
+        rply->result = CNID_DBD_RES_OK;
+        return 1;
+    }
+    
+    if (didname) {
+        rqst->cnid = id_didname;
+        /* we have a did:name 
+         * if it's the same dev or not the same type
+         * just delete it
+        */
+        if (!memcmp(&dev, (char *)diddata.data + CNID_DEV_OFS, sizeof(dev)) ||
+                   type_didname != rqst->type) {
+            if (dbd_delete(rqst, rply) < 0) {
+                return -1;
+            }
+        }
+        else {
+            update = 1;
+        }
+    }
+
+    if (devino) {
+        rqst->cnid = id_devino;
+        if (type_devino != rqst->type) {
+            /* same dev:inode but not same type one is a folder the other 
+             * is a file,it's an inode reused, delete the record
+            */
+            if (dbd_delete(rqst, rply) < 0) {
+                return -1;
+            }
+        }
+        else {
+            update = 1;
+        }
+    }
+    if (!update) {
+        rply->result = CNID_DBD_RES_NOTFOUND;
+        return 1;
+    }
+    /* Fix up the database. assume it was a file move and rename */
+    rc = dbd_update(rqst, rply);
+    if (rc >0) {
+        rply->cnid = rqst->cnid;
+    }
+#ifdef DEBUG
+    LOG(log_info, logtype_cnid, "cnid_lookup: Looked up did %u, name %s, as %u (needed update)", 
+    ntohl(rqst->did), rqst->name, ntohl(rply->cnid));
+#endif
+    return rc;
+}
diff --git a/etc/cnid_dbd/dbd_resolve.c b/etc/cnid_dbd/dbd_resolve.c
new file mode 100644 (file)
index 0000000..e809709
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * $Id: dbd_resolve.c,v 1.1.4.1 2003-09-09 16:42:20 didg Exp $
+ *
+ * Copyright (C) Joerg Lenneis 2003
+ * All Rights Reserved.  See COPYRIGHT.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include <string.h>
+#include <atalk/logger.h>
+#include <errno.h>
+
+#include <db.h>
+#include <netatalk/endian.h>
+#include <atalk/cnid_dbd_private.h>
+
+#include "dbif.h"
+#include "dbd.h"
+#include "pack.h"
+
+/* Return the did/name pair corresponding to a CNID. */
+
+int dbd_resolve(struct cnid_dbd_rqst *rqst, struct cnid_dbd_rply *rply)
+{
+    DBT key, data;
+    int rc;
+
+    memset(&key, 0, sizeof(key));
+    memset(&data, 0, sizeof(data));
+
+    rply->namelen = 0;
+
+    key.data = (void *) &rqst->cnid;
+    key.size = sizeof(cnid_t);
+
+    if ((rc = dbif_get(DBIF_IDX_CNID, &key, &data, 0)) < 0) {
+        LOG(log_error, logtype_cnid, "dbd_resolve: Unable to get did/name %u/%s", ntohl(rqst->did), rqst->name);
+        rply->result = CNID_DBD_RES_ERR_DB;
+        return -1;
+    }
+     
+    if (rc == 0) {
+        rply->result = CNID_DBD_RES_NOTFOUND;
+        return 1;
+    }
+    /* FIXME hack */
+    if (!rqst->cnid) {
+       memcpy(&rply->did, (char *) data.data + CNID_DEV_OFS, sizeof(cnid_t));
+    }
+    else {
+       memcpy(&rply->did, (char *) data.data + CNID_DID_OFS, sizeof(cnid_t));
+    }
+    rply->namelen = data.size - CNID_NAME_OFS;
+    rply->name = data.data + CNID_NAME_OFS;
+
+#ifdef DEBUG
+    LOG(log_info, logtype_cnid, "cnid_resolve: Returning id = %u, did/name = %s",
+        ntohl(rply->did), (char *)data.data + CNID_NAME_OFS);
+#endif
+    rply->result = CNID_DBD_RES_OK;
+    return 1;
+}
diff --git a/etc/cnid_dbd/dbd_update.c b/etc/cnid_dbd/dbd_update.c
new file mode 100644 (file)
index 0000000..e9628a2
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * $Id: dbd_update.c,v 1.1.4.1 2003-09-09 16:42:20 didg Exp $
+ *
+ * Copyright (C) Joerg Lenneis 2003
+ * All Rights Reserved.  See COPYRIGHT.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include <string.h>
+#include <errno.h>
+#include <atalk/logger.h>
+
+#include <db.h>
+#include <netatalk/endian.h>
+#include <atalk/cnid_dbd_private.h>
+
+
+#include "pack.h"
+#include "dbif.h"
+#include "dbd.h"
+
+
+/* cnid_update: takes the given cnid and updates the metadata. */
+
+int dbd_update(struct cnid_dbd_rqst *rqst, struct cnid_dbd_rply *rply)
+{
+    DBT key, data;
+    int rc;
+    char *buf;                                                                                               
+    int notfound = 0;
+    
+    memset(&key, 0, sizeof(key));
+
+    rply->namelen = 0;
+
+    buf = pack_cnid_data(rqst);
+    key.data = buf +CNID_DEVINO_OFS;
+    key.size = CNID_DEVINO_LEN;
+
+    if ((rc = dbif_del(DBIF_IDX_DEVINO, &key, 0) < 0) ) {
+        goto err_db;
+    }
+    if (!rc) {
+       notfound = 1;
+    }
+
+    buf = pack_cnid_data(rqst);
+    key.data = buf + CNID_DID_OFS;
+    key.size = CNID_DID_LEN + rqst->namelen +1;
+
+    if ((rc = dbif_del(DBIF_IDX_DIDNAME, &key, 0) < 0)) {
+        goto err_db;
+    }
+    if (!rc) {
+       notfound |= 2;
+    }
+
+    memset(&key, 0, sizeof(key));
+    key.data = (cnid_t *) &rqst->cnid;
+    key.size = sizeof(rqst->cnid);
+
+    memset(&data, 0, sizeof(data));
+    /* Make a new entry. */
+    data.data = pack_cnid_data(rqst);
+    memcpy(data.data, &rqst->cnid, sizeof(rqst->cnid));
+    data.size = CNID_HEADER_LEN + rqst->namelen + 1;
+
+    if (dbif_put(DBIF_IDX_CNID, &key, &data, 0) < 0)
+        goto err_db;
+
+    rply->result = CNID_DBD_RES_OK;
+    return 1;
+
+err_db:
+    LOG(log_error, logtype_cnid, "dbd_update: Unable to update CNID %u",
+        ntohl(rqst->cnid));
+    rply->result = CNID_DBD_RES_ERR_DB;
+    return -1;
+}
diff --git a/etc/cnid_dbd/dbif.c b/etc/cnid_dbd/dbif.c
new file mode 100644 (file)
index 0000000..7b8f206
--- /dev/null
@@ -0,0 +1,411 @@
+/*
+ * $Id: dbif.c,v 1.1.4.1 2003-09-09 16:42:20 didg Exp $
+ *
+ * Copyright (C) Joerg Lenneis 2003
+ * All Rights Reserved.  See COPYRIGHT.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include <stdio.h>
+#include <errno.h>
+
+#include <db.h>
+#include <atalk/logger.h>
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif /* HAVE_SYS_TYPES_H */
+
+#include <string.h>
+#include "db_param.h"
+#include "dbif.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#define DB_ERRLOGFILE "db_errlog"
+
+
+static DB_ENV *db_env = NULL;
+static DB_TXN *db_txn = NULL;
+static FILE   *db_errlog = NULL;
+
+#ifdef CNID_BACKEND_DBD_TXN
+#define DBOPTIONS    (DB_CREATE | DB_INIT_LOCK | DB_INIT_LOG | DB_INIT_MPOOL | DB_INIT_TXN)
+#else
+#define DBOPTIONS    (DB_CREATE | DB_INIT_CDB | DB_INIT_MPOOL) 
+#endif
+
+static struct db_table {
+     char            *name;
+     DB              *db;
+     u_int32_t       general_flags;
+     DBTYPE          type;
+} db_table[] =
+{
+     { "cnid2.db",       NULL,      0, DB_HASH},
+     { "devino.db",      NULL,      0, DB_HASH},
+     { "didname.db",     NULL,      0, DB_HASH},
+};
+
+/*
+ *  We assume our current directory is already the BDB homedir. Otherwise
+ *  opening the databases will not work as expected.
+ */
+
+extern int didname(DB *dbp, const DBT *pkey, const DBT *pdata, DBT *skey);
+extern int devino(DB *dbp, const DBT *pkey, const DBT *pdata, DBT *skey);
+
+static int env_init(struct db_param *dbp)
+{
+    int ret;
+
+    if ((ret = db_env_create(&db_env, 0))) {
+        LOG(log_error, logtype_cnid, "error creating DB environment: %s", 
+            db_strerror(ret));
+        return -1;
+    }    
+#ifdef CNID_BACKEND_DBD_TXN
+    if (db_errlog != NULL)
+        db_env->set_errfile(db_env, db_errlog); 
+    db_env->set_verbose(db_env, DB_VERB_RECOVERY, 1);
+    db_env->set_verbose(db_env, DB_VERB_CHKPOINT, 1);
+    if (ret = db_env->open(db_env, ".", DB_CREATE | DB_INIT_LOCK | DB_INIT_LOG | 
+                           DB_INIT_MPOOL | DB_INIT_TXN | DB_PRIVATE | DB_RECOVER, 0)) {
+        LOG(log_error, logtype_cnid, "error opening DB environment: %s", 
+            db_strerror(ret));
+        db_env->close(db_env, 0);
+        return -1;
+    }
+
+    if (db_errlog != NULL)
+        fflush(db_errlog);
+
+    if (ret = db_env->close(db_env, 0)) {
+        LOG(log_error, logtype_cnid, "error closining DB environment after recovery: %s", 
+            db_strerror(ret));
+        return -1;
+    }
+#endif
+    if ((ret = db_env_create(&db_env, 0))) {
+        LOG(log_error, logtype_cnid, "error creating DB environment after recovery: %s",
+            db_strerror(ret));
+        return -1;
+    }
+    if ((ret = db_env->set_cachesize(db_env, 0, 1024 * dbp->cachesize, 0))) {
+        LOG(log_error, logtype_cnid, "error settining DB environment cachesize to %i: %s",
+            dbp->cachesize, db_strerror(ret));
+        db_env->close(db_env, 0);
+        return -1;
+    }
+    
+    if (db_errlog != NULL)
+        db_env->set_errfile(db_env, db_errlog);
+    if ((ret = db_env->open(db_env, ".", DBOPTIONS , 0))) {
+        LOG(log_error, logtype_cnid, "error opening DB environment after recovery: %s",
+            db_strerror(ret));
+        db_env->close(db_env, 0);
+        return -1;      
+    }
+
+#ifdef CNID_BACKEND_DBD_TXN
+    if (dbp->nosync && (ret = db_env->set_flags(db_env, DB_TXN_NOSYNC, 1))) {
+        LOG(log_error, logtype_cnid, "error setting TXN_NOSYNC flag: %s",
+            db_strerror(ret));
+        db_env->close(db_env, 0);
+        return -1;      
+    }
+#endif
+    return 0;
+}
+
+/* --------------- */
+static int  db_compat_associate (DB *p, DB *s,
+                   int (*callback)(DB *, const DBT *,const DBT *, DBT *),
+                   u_int32_t flags)
+{
+#if DB_VERSION_MAJOR > 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 1)
+    return p->associate(p, NULL, s, callback, flags);
+#else
+    return p->associate(p,       s, callback, flags);
+#endif
+}
+
+/* --------------- */
+static int db_compat_open(DB *db, char *file, char *name, DBTYPE type, int mode)
+{
+    int ret;
+
+#if DB_VERSION_MAJOR > 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 1)
+#ifdef CNID_BACKEND_DBD_TXN
+    ret = db->open(db, NULL, file, name, type, DB_CREATE | DB_AUTO_COMMIT, mode); 
+#else 
+    ret = db->open(db, NULL, file, name, type, DB_CREATE                 , mode); 
+#endif
+#else
+    ret = db->open(db,       file, name, type, DB_CREATE                 , mode); 
+#endif
+
+    if (ret) {
+        LOG(log_error, logtype_cnid, "error opening database %s: %s", name, db_strerror(ret));
+        return -1;
+    } else {
+        return 0;
+    }
+}
+
+/* --------------- */
+int dbif_stamp(void *buffer, int size)
+{
+    struct stat st;
+    int         rc;
+
+    if (size < 8)
+        return -1;
+
+    if ((rc = stat(db_table[0].name, &st)) < 0) {
+        LOG(log_error, logtype_cnid, "error stating database %s: %s", db_table[0].name, db_strerror(rc));
+        return -1;
+    }
+    memset(buffer, 0, size);
+    memcpy(buffer, &st.st_ctime, sizeof(st.st_ctime));
+
+    return 0;
+}
+
+/* --------------- */
+int dbif_open(struct db_param *dbp)
+{
+    int ret;
+    int i;
+
+    if ((db_errlog = fopen(DB_ERRLOGFILE, "a")) == NULL)
+        LOG(log_warning, logtype_cnid, "error creating/opening DB errlogfile: %s", strerror(errno));
+
+    if (env_init(dbp) < 0)
+        return -1;
+
+    /* db_env will point to a valid environment handle from here onwards if
+       transactions are used or to NULL otherwise */
+
+    for (i = 0; i != DBIF_DB_CNT; i++) {
+        if ((ret = db_create(&(db_table[i].db), db_env, 0))) {
+            LOG(log_error, logtype_cnid, "error creating handle for database %s: %s", 
+                db_table[i].name, db_strerror(ret));
+            return -1;
+        }
+        if (db_table[i].general_flags) { 
+            if ((ret = db_table[i].db->set_flags(db_table[i].db, db_table[i].general_flags))) {
+                LOG(log_error, logtype_cnid, "error setting flags for database %s: %s", 
+                    db_table[i].name, db_strerror(ret));
+                return -1;
+            }
+        }
+#if 0
+#ifndef CNID_BACKEND_DBD_TXN
+        if ((ret = db_table[i].db->set_cachesize(db_table[i].db, 0, 1024 * dbp->cachesize, 0))) {
+            LOG(log_error, logtype_cnid, "error setting DB cachesize to %i for database %s: %s",
+                dbp->cachesize, db_table[i].name, db_strerror(ret));
+            return -1;
+        }
+#endif /* CNID_BACKEND_DBD_TXN */
+#endif
+        if (db_compat_open(db_table[i].db, db_table[0].name, db_table[i].name, db_table[i].type, 0664) < 0)
+            return -1;
+        if (db_errlog != NULL)
+            db_table[i].db->set_errfile(db_table[i].db, db_errlog);
+    }     
+    
+    /* TODO: Implement CNID DB versioning info on new databases. */
+    /* TODO: Make transaction support a runtime option. */
+    /* Associate the secondary with the primary. */
+    if ((ret = db_compat_associate(db_table[0].db, db_table[DBIF_IDX_DIDNAME].db, didname, 0)) != 0) {
+        LOG(log_error, logtype_cnid, "Failed to associate didname database: %s",db_strerror(ret));
+        return -1;
+    }
+    if ((ret = db_compat_associate(db_table[0].db, db_table[DBIF_IDX_DEVINO].db, devino, 0)) != 0) {
+        LOG(log_error, logtype_cnid, "Failed to associate devino database: %s",db_strerror(ret));
+       return -1;
+    }
+    return 0;
+}
+
+/* ------------------------ */
+int dbif_close()
+{
+    int i;
+    int ret;
+    int err = 0;
+     
+    for (i = DBIF_DB_CNT -1; i >= 0; i--) {
+        if (db_table[i].db != NULL && (ret = db_table[i].db->close(db_table[i].db, 0))) {
+            LOG(log_error, logtype_cnid, "error closing database %s: %s", db_table[i].name, db_strerror(ret));
+            err++;
+        }
+    }
+    if (db_env != NULL && (ret = db_env->close(db_env, 0))) { 
+        LOG(log_error, logtype_cnid, "error closing DB environment: %s", db_strerror(ret));
+        err++;
+    }
+    if (db_errlog != NULL && fclose(db_errlog) == EOF) {
+        LOG(log_error, logtype_cnid, "error closing DB logfile: %s", strerror(errno));
+        err++;
+    }
+    if (err)
+        return -1;
+    else
+        return 0;
+}
+
+/*
+ *  The following three functions are wrappers for DB->get(), DB->put() and
+ *  DB->del(). We define them here because we want access to the db_txn
+ *  transaction handle and the database handles limited to the functions in this
+ *  file. A consequence is that there is always only one transaction in
+ *  progress. For nontransactional access db_txn is NULL. All three return -1 on
+ *  error. dbif_get()/dbif_del return 1 if the key was found and 0
+ *  otherwise. dbif_put() returns 0 if key/val was successfully updated and 1 if
+ *  the DB_NOOVERWRITE flag was specified and the key already exists.
+ *  
+ *  All return codes other than DB_NOTFOUND and DB_KEYEXIST from the DB->()
+ *  functions are not expected and therefore error conditions.
+ */
+
+int dbif_get(const int dbi, DBT *key, DBT *val, u_int32_t flags)
+{
+    int ret;
+    DB *db = db_table[dbi].db;
+
+    ret = db->get(db, db_txn, key, val, flags);
+     
+    if (ret == DB_NOTFOUND)
+        return 0;
+    if (ret) {
+        LOG(log_error, logtype_cnid, "error retrieving value from %s: %s", db_table[dbi].name, db_strerror(errno));
+        return -1;
+    } else 
+        return 1;
+}
+
+int dbif_put(const int dbi, DBT *key, DBT *val, u_int32_t flags)
+{
+    int ret;
+    DB *db = db_table[dbi].db;
+
+    ret = db->put(db, db_txn, key, val, flags);
+     
+    if (ret) {
+        if ((flags & DB_NOOVERWRITE) && ret == DB_KEYEXIST) {
+            return 1;
+        } else {
+            LOG(log_error, logtype_cnid, "error setting key/value in %s: %s", db_table[dbi].name, db_strerror(errno));
+            return -1;
+        }
+    } else
+        return 0;
+}
+
+int dbif_del(const int dbi, DBT *key, u_int32_t flags)
+{
+    int ret;
+    DB *db = db_table[dbi].db;
+
+    ret = db->del(db, db_txn, key, flags);
+
+    if (ret == DB_NOTFOUND || ret == DB_SECONDARY_BAD)
+        return 0;
+    if (ret) {
+        LOG(log_error, logtype_cnid, "error deleting key/value from %s: %s", db_table[dbi].name, db_strerror(errno));
+        return -1;
+    } else
+        return 1;
+}
+
+#ifdef CNID_BACKEND_DBD_TXN
+
+int dbif_txn_begin()
+{
+    int ret;
+#if DB_VERSION_MAJOR >= 4
+    ret = db_env->txn_begin(db_env, NULL, &db_txn, 0);
+#else     
+    ret = txn_begin(db_env, NULL, &db_txn, 0);
+#endif
+    if (ret) {
+        LOG(log_error, logtype_cnid, "error starting transaction: %s", db_strerror(errno));
+        return -1;
+    } else 
+        return 0;
+}
+
+int dbif_txn_commit()
+{
+    int ret;
+#if DB_VERSION_MAJOR >= 4
+    ret = db_txn->commit(db_txn, 0);
+#else
+    ret = txn_commit(db_txn, 0);
+#endif
+    if (ret) {
+        LOG(log_error, logtype_cnid, "error committing transaction: %s", db_strerror(errno));
+        return -1;
+    } else 
+        return 0;
+}
+
+int dbif_txn_abort()
+{
+    int ret;
+#if DB_VERSION_MAJOR >= 4
+    ret = db_txn->abort(db_txn);
+#else
+    ret = txn_abort(db_txn);
+#endif
+    if (ret) {
+        LOG(log_error, logtype_cnid, "error aborting transaction: %s", db_strerror(errno));
+        return -1;
+    } else
+        return 0;
+}
+
+int dbif_txn_checkpoint(u_int32_t kbyte, u_int32_t min, u_int32_t flags)
+{
+    int ret;
+#if DB_VERSION_MAJOR >= 4
+    ret = db_env->txn_checkpoint(db_env, kbyte, min, flags);
+#else 
+    ret = txn_checkpoint(db_env, kbyte, min, flags);
+#endif
+    if (ret) {
+        LOG(log_error, logtype_cnid, "error checkpointing transaction susystem: %s", db_strerror(errno));
+        return -1;
+    } else 
+        return 0;
+}
+
+#else
+
+int dbif_sync()
+{
+    int i;
+    int ret;
+    int err = 0;
+     
+    for (i = 0; i != /* DBIF_DB_CNT*/ 1; i++) {
+        if ((ret = db_table[i].db->sync(db_table[i].db, 0))) {
+            LOG(log_error, logtype_cnid, "error syncing database %s: %s", db_table[i].name, db_strerror(ret));
+            err++;
+        }
+    }
+    if (err)
+        return -1;
+    else
+        return 0;
+}
+
+#endif /* CNID_BACKEND_DBD_TXN */
+
diff --git a/etc/cnid_dbd/dbif.h b/etc/cnid_dbd/dbif.h
new file mode 100644 (file)
index 0000000..6e005e5
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * $Id: dbif.h,v 1.1.4.1 2003-09-09 16:42:20 didg Exp $
+ *
+ * Copyright (C) Joerg Lenneis 2003
+ * All Rights Reserved.  See COPYRIGHT.
+ */
+
+#ifndef CNID_DBD_DBIF_H
+#define CNID_DBD_DBIF_H 1
+
+#include <db.h>
+#include "db_param.h"
+
+#define DBIF_DB_CNT 3
+
+#define DBIF_IDX_CNID      0
+#define DBIF_IDX_DEVINO    1
+#define DBIF_IDX_DIDNAME   2
+
+extern int        dbif_stamp  __P((void *, int));
+extern int        dbif_open  __P((struct db_param *));
+extern int        dbif_close __P((void));
+extern int        dbif_get __P((const int, DBT *, DBT *, u_int32_t));
+extern int        dbif_put __P((const int, DBT *, DBT *, u_int32_t));
+extern int        dbif_del __P((const int, DBT *, u_int32_t));
+
+#ifdef CNID_BACKEND_DBD_TXN
+extern int        dbif_txn_begin  __P((void));
+extern int        dbif_txn_commit  __P((void));
+extern int        dbif_txn_abort  __P((void));
+extern int        dbif_txn_checkpoint  __P((u_int32_t, u_int32_t, u_int32_t));
+#else
+extern int        dbif_sync  __P((void));
+#endif /* CNID_BACKEND_DBD_TXN */
+
+#endif
diff --git a/etc/cnid_dbd/main.c b/etc/cnid_dbd/main.c
new file mode 100644 (file)
index 0000000..f3955da
--- /dev/null
@@ -0,0 +1,288 @@
+/*
+ * $Id: main.c,v 1.1.4.1 2003-09-09 16:42:20 didg Exp $
+ *
+ * Copyright (C) Joerg Lenneis 2003
+ * All Rights Reserved.  See COPYRIGHT.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <signal.h>
+#include <string.h>
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif /* HAVE_SYS_TYPES_H */
+#include <sys/param.h>
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif /* HAVE_SYS_STAT_H */
+#include <time.h>
+
+#include <netatalk/endian.h>
+#include <atalk/cnid_dbd_private.h>
+#include <atalk/logger.h>
+
+#include "db_param.h"
+#include "dbif.h"
+#include "dbd.h"
+#include "comm.h"
+
+
+#define LOCKFILENAME  "lock"
+
+static int exit_sig = 0;
+
+
+static void sig_exit(int signo)
+{
+    exit_sig = signo;
+    return;
+}
+
+/* 
+   The dbd_XXX and comm_XXX functions all obey the same protocol for return values:
+   
+   1: Success, if transactions are used commit.
+   0: Failure, but we continue to serve requests. If transactions are used abort/rollback.
+  -1: Fatal error, either from the database or from the socket. Abort the transaction if applicable 
+      (which might fail as well) and then exit.
+
+  We always try to notify the client process about the outcome, the result field
+  of the cnid_dbd_rply structure contains further details.
+
+ */
+
+static void block_sigs_onoff(int block)
+{
+    sigset_t set;
+    
+    sigemptyset(&set);
+    sigaddset(&set, SIGINT);
+    sigaddset(&set, SIGTERM);
+    if (block)
+        sigprocmask(SIG_BLOCK, &set, NULL);
+    else
+        sigprocmask(SIG_UNBLOCK, &set, NULL);
+    return;
+}
+
+
+static int loop(struct db_param *dbp)
+{
+    struct cnid_dbd_rqst rqst;
+    struct cnid_dbd_rply rply;
+    int ret, cret;
+    time_t now, time_next_flush, time_last_rqst;
+    int count;
+    static char namebuf[MAXPATHLEN + 1];
+    u_int32_t checkp_flags;
+
+    count = 0;
+    now = time(NULL);
+    time_next_flush = now + dbp->flush_interval;
+    time_last_rqst = now;
+    if (dbp->nosync)
+        checkp_flags = DB_FORCE;
+    else 
+        checkp_flags = 0;
+    
+    rqst.name = namebuf;
+
+    while (1) {
+        if ((cret = comm_rcv(&rqst)) < 0) 
+            return -1;
+
+        now = time(NULL);
+        
+        if (count > dbp->flush_frequency || now > time_next_flush) {
+#ifdef CNID_BACKEND_DBD_TXN
+            if (dbif_txn_checkpoint(0, 0, checkp_flags) < 0)
+                return -1;
+#else
+            if (dbif_sync() < 0)
+                return -1;
+#endif
+            count = 0;
+            time_next_flush = now + dbp->flush_interval;
+        }
+
+        if (cret == 0) {
+            block_sigs_onoff(0);
+            block_sigs_onoff(1);
+            if (exit_sig)
+                return 0;
+           if (dbp->idle_timeout && comm_nbe() <= 0 && (now - time_last_rqst) > dbp->idle_timeout)
+               return 0;
+           continue;
+        }
+        /* We got a request */
+       time_last_rqst = now;
+        count++;
+        
+#ifdef CNID_BACKEND_DBD_TXN
+        if (dbif_txn_begin() < 0) 
+            return -1;
+#endif /* CNID_BACKEND_DBD_TXN */
+
+       memset(&rply, 0, sizeof(rply));
+        switch(rqst.op) {
+            /* ret gets set here */
+        case CNID_DBD_OP_OPEN:
+        case CNID_DBD_OP_CLOSE:
+            /* open/close are noops for now. */
+            rply.namelen = 0; 
+            ret = 1;
+            break;
+        case CNID_DBD_OP_ADD:
+            ret = dbd_add(&rqst, &rply);
+            break;
+        case CNID_DBD_OP_GET:
+            ret = dbd_get(&rqst, &rply);
+            break;
+        case CNID_DBD_OP_RESOLVE:
+            ret = dbd_resolve(&rqst, &rply);
+            break;
+        case CNID_DBD_OP_LOOKUP:
+            ret = dbd_lookup(&rqst, &rply);
+            break;
+        case CNID_DBD_OP_UPDATE:
+            ret = dbd_update(&rqst, &rply);
+            break;
+        case CNID_DBD_OP_DELETE:
+            ret = dbd_delete(&rqst, &rply);
+            break;
+        default:
+            LOG(log_error, logtype_cnid, "loop: unknow op %d", rqst.op);
+            break;
+        }       
+
+        if ((cret = comm_snd(&rply)) < 0 || ret < 0) {
+#ifdef CNID_BACKEND_DBD_TXN
+            dbif_txn_abort();
+#endif /* CNID_BACKEND_DBD_TXN */
+            return -1;
+        }
+#ifdef CNID_BACKEND_DBD_TXN
+        if (ret == 0 || cret == 0) {
+            if (dbif_txn_abort() < 0) 
+                return -1;
+        } else {
+            if (dbif_txn_commit() < 0) 
+                return -1;
+        }
+#endif /* CNID_BACKEND_DBD_TXN */
+    }
+}
+
+
+int main(int argc, char *argv[])
+{
+    struct sigaction sv;
+    struct db_param *dbp;
+    int err = 0;
+    struct stat st;
+    int lockfd;
+    char *dir;
+        
+    if (argc  != 2) {
+        LOG(log_error, logtype_cnid, "main: not enough arguments");
+        exit(1);
+    }
+    dir = argv[1];
+    if (chdir(dir) < 0) {
+        LOG(log_error, logtype_cnid, "chdir to %s failed: %s", dir, strerror(errno));
+        exit(1);
+    }
+    if (stat(".", &st) < 0) {
+        LOG(log_error, logtype_cnid, "error in stat for %s: %s", dir, strerror(errno));
+        exit(1);
+    }
+#if 0
+    LOG(log_info, logtype_cnid, "Setting uid/gid to %i/%i", st.st_uid, st.st_gid);
+    if (setegid(st.st_gid) < 0 || seteuid(st.st_uid) < 0) {
+        LOG(log_error, logtype_cnid, "uid/gid: %s", strerror(errno));
+        exit(1);
+    }
+#endif    
+    /* Before we do anything else, check if there is an instance of cnid_dbd
+       running already and silently exit if yes. */
+    if ((lockfd = open(LOCKFILENAME, O_RDONLY | O_CREAT, 0644)) < 0) {
+        LOG(log_error, logtype_cnid, "main: error opening lockfile: %s", strerror(errno));
+        exit(1);
+    }
+    if (flock(lockfd, LOCK_EX | LOCK_NB) < 0) {
+        if (errno == EWOULDBLOCK) {
+            exit(0);
+        } else {
+            LOG(log_error, logtype_cnid, "main: error in flock: %s", strerror(errno));
+            exit(1);
+        }
+    }
+    LOG(log_info, logtype_cnid, "Startup, DB dir %s", dir);
+
+    sv.sa_handler = sig_exit;
+    sv.sa_flags = 0;
+    sigemptyset(&sv.sa_mask);
+    sigaddset(&sv.sa_mask, SIGINT);
+    sigaddset(&sv.sa_mask, SIGTERM);
+    if (sigaction(SIGINT, &sv, NULL) < 0 || sigaction(SIGTERM, &sv, NULL) < 0) {
+        LOG(log_error, logtype_cnid, "main: sigaction: %s", strerror(errno));
+        exit(1);
+    }
+    sv.sa_handler = SIG_IGN;
+    sigemptyset(&sv.sa_mask);
+    if (sigaction(SIGPIPE, &sv, NULL) < 0) {
+        LOG(log_error, logtype_cnid, "main: sigaction: %s", strerror(errno));
+        exit(1);
+    }
+    /* SIGINT and SIGTERM are always off, unless we get a return code of 0 from
+       comm_rcv (no requests for one second, see above in loop()). That means we
+       only shut down after one second of inactivity. */
+    block_sigs_onoff(1);
+    if ((dbp = db_param_read(dir)) == NULL)
+        exit(1);
+
+    if (dbif_open(dbp) < 0) {
+        dbif_close();
+        exit(2);
+    }
+    if (dbd_stamp() < 0) {
+        dbif_close();
+        exit(5);
+    }
+    if (comm_init(dbp) < 0) {
+        dbif_close();
+        exit(3);
+    }
+    if (loop(dbp) < 0)
+        err++;
+    
+    if (dbif_sync() < 0)
+        err++;
+        
+    if (dbif_close() < 0)
+        err++;
+
+    flock(lockfd, LOCK_UN);
+    close(lockfd);
+    
+    if (err) 
+        exit(4);
+    else {
+       if (exit_sig)
+           LOG(log_info, logtype_cnid, "main: Exiting on signal %i", exit_sig);
+       else
+           LOG(log_info, logtype_cnid, "main: Idle timeout, exiting");
+        exit(0);
+    }
+}
diff --git a/etc/cnid_dbd/pack.c b/etc/cnid_dbd/pack.c
new file mode 100644 (file)
index 0000000..161f8b3
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * $Id: pack.c,v 1.1.4.1 2003-09-09 16:42:20 didg Exp $
+ *
+ * Copyright (C) Joerg Lenneis 2003
+ * All Rights Reserved.  See COPYRIGHT.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include <db.h>
+#include <string.h>
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif /* HAVE_SYS_TYPES_H */
+#include <sys/param.h>
+
+#include <atalk/cnid_dbd_private.h>
+#include <netatalk/endian.h>
+#include "pack.h"
+
+/* --------------- */
+int didname(dbp, pkey, pdata, skey)
+DB *dbp;
+const DBT *pkey, *pdata;
+DBT *skey;
+{
+int len;
+    memset(skey, 0, sizeof(DBT));
+    skey->data = pdata->data + CNID_DID_OFS;
+    len = strlen(skey->data + CNID_DID_LEN);
+    skey->size = CNID_DID_LEN + len + 1;
+    return (0);
+}
+/* --------------- */
+int devino(dbp, pkey, pdata, skey)
+DB *dbp;
+const DBT *pkey, *pdata;
+DBT *skey;
+{
+    memset(skey, 0, sizeof(DBT));
+    skey->data = pdata->data + CNID_DEVINO_OFS;
+    skey->size = CNID_DEVINO_LEN;
+    return (0);
+}
+
+/* The equivalent to make_cnid_data in the cnid library. Non re-entrant. We
+   differ from make_cnid_data in that we never return NULL, rqst->name cannot
+   ever cause start[] to overflow because name length is checked in libatalk. */
+
+char *pack_cnid_data(struct cnid_dbd_rqst *rqst)
+{
+    static char start[CNID_HEADER_LEN + MAXPATHLEN + 1];
+    char *buf = start +CNID_LEN;
+    u_int32_t i;
+
+    memcpy(buf, &rqst->dev, sizeof(rqst->dev));
+    buf += sizeof(rqst->dev);
+
+    memcpy(buf, &rqst->ino, sizeof(rqst->ino));
+    buf += sizeof(rqst->ino);
+
+    i = htonl(rqst->type);
+    memcpy(buf, &i, sizeof(i));
+    buf += sizeof(i);
+
+    /* did is already in network byte order */
+    buf = memcpy(buf, &rqst->did, sizeof(rqst->did));
+    buf += sizeof(rqst->did);
+    buf = memcpy(buf, rqst->name, rqst->namelen);
+    *(buf + rqst->namelen) = '\0';
+
+    return start;
+}
diff --git a/etc/cnid_dbd/pack.h b/etc/cnid_dbd/pack.h
new file mode 100644 (file)
index 0000000..8857beb
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * $Id: pack.h,v 1.1.4.1 2003-09-09 16:42:20 didg Exp $
+ *
+ * Copyright (C) Joerg Lenneis 2003
+ * All Rights Reserved.  See COPYRIGHT.
+ */
+
+#ifndef CNID_DBD_PACK_H
+#define CNID_DBD_PACK_H 1
+
+
+#include <atalk/cnid_dbd_private.h>
+
+#define CNID_OFS                 0
+#define CNID_LEN                 4
+#define CNID_DEV_OFS             CNID_LEN
+#define CNID_DEV_LEN             8
+  
+#define CNID_INO_OFS             (CNID_DEV_OFS + CNID_DEV_LEN)
+#define CNID_INO_LEN             8
+   
+#define CNID_DEVINO_OFS          CNID_LEN
+#define CNID_DEVINO_LEN          (CNID_DEV_LEN +CNID_INO_LEN)
+    
+#define CNID_TYPE_OFS            (CNID_DEVINO_OFS +CNID_DEVINO_LEN)
+#define CNID_TYPE_LEN            4
+     
+#define CNID_DID_OFS             (CNID_TYPE_OFS +CNID_TYPE_LEN)
+#define CNID_DID_LEN             CNID_LEN
+      
+#define CNID_NAME_OFS            (CNID_DID_OFS + CNID_DID_LEN)
+#define CNID_HEADER_LEN          (CNID_NAME_OFS)
+
+#if 0
+#define CNID_DBD_DEVINO_LEN          8
+#define CNID_DBD_DID_LEN             4
+#define CNID_DBD_HEADER_LEN          (CNID_DBD_DEVINO_LEN + CNID_DBD_DID_LEN)
+#endif
+
+extern char      *pack_cnid_data  __P((struct cnid_dbd_rqst *));
+
+#endif /* CNID_DBD_PACK_H */
diff --git a/etc/cnid_dbd/usockfd.c b/etc/cnid_dbd/usockfd.c
new file mode 100644 (file)
index 0000000..69b0a7b
--- /dev/null
@@ -0,0 +1,165 @@
+/*
+ * $Id: usockfd.c,v 1.1.4.1 2003-09-09 16:42:20 didg Exp $
+ *
+ * Copyright (C) Joerg Lenneis 2003
+ * All Rights Reserved.  See COPYRIGHT.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#include <sys/un.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif /* HAVE_SYS_TYPES_H */
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif /* HAVE_SYS_TIME_H */
+
+
+#include <atalk/logger.h>
+#include "usockfd.h"
+
+
+int usockfd_create(char *usock_fn, mode_t mode, int backlog)
+{
+    int sockfd;
+    struct sockaddr_un addr;
+
+
+    if ((sockfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
+        LOG(log_error, logtype_cnid, "error in socket call: %s",
+            strerror(errno));
+        return -1;
+    }
+     
+    if (unlink(usock_fn) < 0 && errno != ENOENT) {
+        LOG(log_error, logtype_cnid, "error unlinking unix socket file %s: %s",
+            usock_fn, strerror(errno));
+        return -1;
+    }
+    memset((char *) &addr, 0, sizeof(struct sockaddr_un));
+    addr.sun_family = AF_UNIX;
+    strncpy(addr.sun_path, usock_fn, sizeof(addr.sun_path) - 1);
+    if (bind(sockfd, (struct sockaddr *) &addr, sizeof(struct sockaddr_un)) < 0) {
+        LOG(log_error, logtype_cnid, "error binding to socket for %s: %s",
+            usock_fn, strerror(errno));
+        return -1;
+    }
+
+    if (listen(sockfd, backlog) < 0) {
+        LOG(log_error, logtype_cnid, "error in listen for %s: %s",
+            usock_fn, strerror(errno));
+        return -1;
+    }
+
+    if (chmod(usock_fn, mode) < 0) {
+        LOG(log_error, logtype_cnid, "error changing permissions for %s: %s",
+            usock_fn, strerror(errno));
+        close(sockfd);
+        return -1;
+    }
+
+    return sockfd;
+}
+
+/* ---------------
+   create a tcp socket (should share dsi stuff)
+*/
+int tsockfd_create(char *address, int ipport, int backlog)
+{
+    int sockfd;
+    struct sockaddr_in addr;
+    int                port;
+
+    if ((sockfd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
+        LOG(log_error, logtype_cnid, "error in socket call: %s", strerror(errno));
+        return -1;
+    }
+     
+    port = htons(ipport);
+    memset((char *) &addr, 0, sizeof(struct sockaddr_in));
+
+    if (inet_aton(address, &addr.sin_addr) == 0) {
+        LOG(log_info, logtype_cnid, "invalid address (%s)", address);
+        return 0;
+    }
+    
+    addr.sin_family = AF_INET;
+    addr.sin_port = port;
+
+#ifdef SO_REUSEADDR
+    port = 1;
+    setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &port, sizeof(port));
+#endif /* SO_REUSEADDR */
+
+#ifdef USE_TCP_NODELAY 
+#ifndef SOL_TCP
+#define SOL_TCP IPPROTO_TCP
+#endif /* ! SOL_TCP */
+    port = 1;
+    setsockopt(sockfd, SOL_TCP, TCP_NODELAY, &port, sizeof(port));
+#endif /* USE_TCP_NODELAY */
+
+    if (bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
+        LOG(log_error, logtype_cnid, "error binding to socket for %s: %s",
+            address, strerror(errno));
+        return -1;
+    }
+
+    if (listen(sockfd, backlog) < 0) {
+        LOG(log_error, logtype_cnid, "error in listen for %s: %s",
+            address, strerror(errno));
+        return -1;
+    }
+
+    return sockfd;
+}
+
+/* --------------------- */
+int usockfd_check(int sockfd, unsigned long ndelay)
+{
+    int fd;
+    int size;
+    fd_set readfds;
+    struct timeval tv;
+    int ret;
+     
+    FD_ZERO(&readfds);
+    FD_SET(sockfd, &readfds);
+
+    tv.tv_usec = ndelay % 1000000;
+    tv.tv_sec  = ndelay / 1000000;
+    if ((ret = select(sockfd + 1, &readfds, NULL, NULL, &tv)) < 0) {
+        if (errno == EINTR)
+            return 0;
+        LOG(log_error, logtype_cnid, "error in select: %s",
+            strerror(errno));
+        return -1;
+    }
+
+    if (ret) {
+        size = 0;
+        if ((fd = accept(sockfd, NULL, &size)) < 0) {
+            if (errno == EINTR)
+                return 0;
+            LOG(log_error, logtype_cnid, "error in accept: %s", 
+                strerror(errno));
+            return -1;
+        }
+        return fd;
+    } else
+        return 0;
+}
diff --git a/etc/cnid_dbd/usockfd.h b/etc/cnid_dbd/usockfd.h
new file mode 100644 (file)
index 0000000..eeb2b2c
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * $Id: usockfd.h,v 1.1.4.1 2003-09-09 16:42:20 didg Exp $
+ *
+ * Copyright (C) Joerg Lenneis 2003
+ * All Rights Reserved.  See COPYRIGHT.
+ */
+
+#ifndef CNID_DBD_USOCKFD_H
+#define CNID_DBD_USOCKFD_H 1
+
+
+
+#include <atalk/cnid_dbd_private.h>
+
+
+extern int      usockfd_create  __P((char *, mode_t, int));
+extern int      tsockfd_create  __P((char *, int, int));
+extern int      usockfd_check   __P((int, unsigned long));
+
+
+#endif /* CNID_DBD_USOCKFD_H */
index 40eeed2a9f03b5209a2b30a89c840917200eb207..b7573266e5009bba68d67025d3affd18f21ce4cd 100644 (file)
@@ -29,4 +29,4 @@ CFLAGS = \
        -D_PATH_PAPDCONF=\"$(pkgconfdir)/papd.conf\" \
        -D_PATH_PAPDUAMPATH=\"$(UAMS_PATH)/\"
 
-LIBS = @PAM_LIBS@
+#LIBS = @PAM_LIBS@
index 7b673fa6c16c86dd3a3bbe5fd7c69edd9b29037a..08af6e4edd4eb4a99c2fa4369f00dafc1117f295 100644 (file)
@@ -6,7 +6,11 @@ SUBDIRS = uams_krb4
 # conditionally build some modules
 #
 
+if USE_GSSAPI
+UAMS_GENERIC = uams_guest.la uams_passwd.la uams_gss.la
+else
 UAMS_GENERIC = uams_guest.la uams_passwd.la
+endif
 
 if USE_DHX
 UAMS_DHX_GENERIC = uams_randnum.la uams_dhx_passwd.la
@@ -43,6 +47,7 @@ uams_pam_la_SOURCES        = uams_pam.c
 uams_pgp_la_SOURCES        = uams_pgp.c
 uams_dhx_passwd_la_SOURCES = uams_dhx_passwd.c
 uams_dhx_pam_la_SOURCES    = uams_dhx_pam.c
+uams_gss_la_SOURCES   = uams_gss.c
 
 #
 # flags
@@ -54,18 +59,20 @@ CFLAGS = @CFLAGS@ @SSL_CFLAGS@
 uams_guest_la_CFLAGS      = @CFLAGS@
 uams_randnum_la_CFLAGS    = @CFLAGS@ @SSL_CFLAGS@
 uams_passwd_la_CFLAGS     = @CFLAGS@
-uams_pam_la_CFLAGS        = @CFLAGS@
+uams_pam_la_CFLAGS        = @CFLAGS@ @PAM_CFLAGS@
 uams_pgp_la_CFLAGS        = @CFLAGS@ @SSL_CFLAGS@
 uams_dhx_passwd_la_CFLAGS = @CFLAGS@ @SSL_CFLAGS@
-uams_dhx_pam_la_CFLAGS    = @CFLAGS@ @SSL_CFLAGS@
+uams_dhx_pam_la_CFLAGS    = @CFLAGS@ @SSL_CFLAGS@ @PAM_CFLAGS@
+uams_gss_la_CFLAGS       = @CFLAGS@ @GSSAPI_CFLAGS@
 
 uams_guest_la_LDFLAGS      = -module -avoid-version
 uams_randnum_la_LDFLAGS    = -module -avoid-version @SSL_LIBS@
 uams_passwd_la_LDFLAGS     = -module -avoid-version
-uams_pam_la_LDFLAGS        = -module -avoid-version -lpam
+uams_pam_la_LDFLAGS        = -module -avoid-version @PAM_LIBS@
 uams_pgp_la_LDFLAGS        = -module -avoid-version @SSL_LIBS@
 uams_dhx_passwd_la_LDFLAGS = -module -avoid-version @SSL_LIBS@
-uams_dhx_pam_la_LDFLAGS    = -module -avoid-version @SSL_LIBS@ -lpam
+uams_dhx_pam_la_LDFLAGS    = -module -avoid-version @SSL_LIBS@ @PAM_LIBS@
+uams_gss_la_LDFLAGS       = -module -avoid-version @GSSAPI_LIBS@ 
 
 #
 # module compilation
index 0e7eed434e790de3a225816bcc35006b73a6cfc8..fe88c06bebaac1d2cd947f74bb24c885f5730e79 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: uams_dhx_pam.c,v 1.24 2003-01-08 22:16:24 didg Exp $
+ * $Id: uams_dhx_pam.c,v 1.24.6.1 2003-09-09 16:42:20 didg Exp $
  *
  * Copyright (c) 1990,1993 Regents of The University of Michigan.
  * Copyright (c) 1999 Adrian Sun (asun@u.washington.edu) 
@@ -37,6 +37,7 @@
 
 #include <atalk/afp.h>
 #include <atalk/uam.h>
+#include <atalk/unicode.h>
 
 #define KEYSIZE 16
 #define PASSWDLEN 64
@@ -351,6 +352,7 @@ static int pam_login(void *obj, struct passwd **uam_pwd,
     memcpy(username, ibuf, len );
     ibuf += len;
     username[ len ] = '\0';
+    len = convert_charset(CH_MAC, CH_UNIX, username, len, username, ulen, 0);
 
     if ((unsigned long) ibuf & 1) /* pad to even boundary */
       ++ibuf;
@@ -389,6 +391,7 @@ static int pam_login_ext(void *obj, char *uname, struct passwd **uam_pwd,
     }
     memcpy(username, uname +2, len );
     username[ len ] = '\0';
+    len = convert_charset(CH_UTF8_MAC, CH_UNIX, username, len, username, ulen, 0);
 
     return (login(obj, username, ulen, uam_pwd, ibuf, ibuflen, rbuf, rbuflen));
 }
diff --git a/etc/uams/uams_gss.c b/etc/uams/uams_gss.c
new file mode 100644 (file)
index 0000000..f54bbc9
--- /dev/null
@@ -0,0 +1,408 @@
+/*\r
+ * $Id: uams_gss.c,v 1.2.2.1 2003-09-09 16:42:20 didg Exp $\r
+ *\r
+ * Copyright (c) 1990,1993 Regents of The University of Michigan.\r
+ * Copyright (c) 1999 Adrian Sun (asun@u.washington.edu) \r
+ * Copyright (c) 2003 The Reed Institute\r
+ * All Rights Reserved.  See COPYRIGHT.\r
+ */\r
+\r
+#ifdef HAVE_CONFIG_H\r
+#include "config.h"\r
+#endif /* HAVE_CONFIG_H */\r
+\r
+#ifndef ATACC\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#ifdef HAVE_UNISTD_H\r
+#include <unistd.h>\r
+#endif /* HAVE_UNISTD_H */\r
+\r
+/* STDC check */\r
+#if STDC_HEADERS\r
+#include <string.h>\r
+#else /* STDC_HEADERS */\r
+#ifndef HAVE_STRCHR\r
+#define strchr index\r
+#define strrchr index\r
+#endif /* HAVE_STRCHR */\r
+char *strchr (), *strrchr ();\r
+#ifndef HAVE_MEMCPY\r
+#define memcpy(d,s,n) bcopy ((s), (d), (n))\r
+#define memmove(d,s,n) bcopy ((s), (d), (n))\r
+#endif /* ! HAVE_MEMCPY */\r
+#endif /* STDC_HEADERS */\r
+\r
+#include <errno.h>\r
+#include <atalk/logger.h>\r
+#include <atalk/afp.h>\r
+#include <atalk/uam.h>\r
+\r
+/* Kerberos includes */\r
+\r
+#if HAVE_GSSAPI_H\r
+#include <gssapi.h>\r
+#endif\r
+\r
+#if HAVE_GSSAPI_GSSAPI_H\r
+#include <gssapi/gssapi.h>\r
+#endif\r
+\r
+#if HAVE_GSSAPI_GSSAPI_GENERIC_H\r
+#include <gssapi/gssapi_generic.h>\r
+#endif\r
+\r
+#if HAVE_GSSAPI_GSSAPI_KRB5_H\r
+#include <gssapi/gssapi_krb5.h>\r
+#endif\r
+\r
+#if HAVE_COM_ERR_H\r
+#include <com_err.h>\r
+#endif\r
+\r
+/* We work around something I don't entirely understand... */\r
+/* BF: This is a Heimdal/MIT compatibility fix */\r
+#ifndef HAVE_GSS_C_NT_HOSTBASED_SERVICE\r
+#define GSS_C_NT_HOSTBASED_SERVICE gss_nt_service_name\r
+#endif\r
+\r
+#define MIN(a, b) ((a > b) ? b : a)\r
+\r
+static void log_status( char *s, OM_uint32 major_status, \r
+                       OM_uint32 minor_status )\r
+{\r
+    gss_buffer_desc msg = GSS_C_EMPTY_BUFFER;\r
+    OM_uint32 min_status, maj_status;\r
+    OM_uint32 maj_ctx = 0, min_ctx = 0;\r
+\r
+    while (1) {\r
+       maj_status = gss_display_status( &min_status, major_status,\r
+                                       GSS_C_GSS_CODE, GSS_C_NULL_OID,\r
+                                       &maj_ctx, &msg );\r
+        LOG(log_info, logtype_uams, "uams_gss.c :do_gss_auth: %s %.*s (error %s)", s,\r
+                               (int)msg.length, msg.value, strerror(errno));\r
+       gss_release_buffer(&min_status, &msg);\r
+\r
+       if (!maj_ctx)\r
+           break;\r
+    }\r
+    while (1) {\r
+       maj_status = gss_display_status( &min_status, minor_status,\r
+                                       GSS_C_MECH_CODE, GSS_C_NULL_OID, // gss_mech_krb5,\r
+                                       &min_ctx, &msg );\r
+        LOG(log_info, logtype_uams, "uams_gss.c :do_gss_auth: %s %.*s (error %s)", s, \r
+                               (int)msg.length, msg.value, strerror(errno));\r
+       gss_release_buffer(&min_status, &msg);\r
+\r
+       if (!min_ctx)\r
+           break;\r
+    }\r
+}\r
+\r
+\r
+void log_ctx_flags( OM_uint32 flags )\r
+{\r
+    if (flags & GSS_C_DELEG_FLAG)\r
+        LOG(log_info, logtype_uams, "uams_gss.c :context flag: GSS_C_DELEG_FLAG" );\r
+    if (flags & GSS_C_MUTUAL_FLAG)\r
+        LOG(log_info, logtype_uams, "uams_gss.c :context flag: GSS_C_MUTUAL_FLAG" );\r
+    if (flags & GSS_C_REPLAY_FLAG)\r
+        LOG(log_info, logtype_uams, "uams_gss.c :context flag: GSS_C_REPLAY_FLAG" );\r
+    if (flags & GSS_C_SEQUENCE_FLAG)\r
+        LOG(log_info, logtype_uams, "uams_gss.c :context flag: GSS_C_SEQUENCE_FLAG" );\r
+    if (flags & GSS_C_CONF_FLAG)\r
+        LOG(log_info, logtype_uams, "uams_gss.c :context flag: GSS_C_CONF_FLAG" );\r
+    if (flags & GSS_C_INTEG_FLAG)\r
+        LOG(log_info, logtype_uams, "uams_gss.c :context flag: GSS_C_INTEG_FLAG" );\r
+}\r
+\r
+/* return 0 on success */\r
+static int do_gss_auth( char *service, char *ibuf, int ticket_len,\r
+                char *rbuf, int *rbuflen, char *username, int ulen ) \r
+{\r
+    OM_uint32 major_status = 0, minor_status = 0;\r
+    gss_name_t server_name;\r
+    gss_cred_id_t server_creds;\r
+    gss_ctx_id_t context_handle = GSS_C_NO_CONTEXT;\r
+    gss_buffer_desc ticket_buffer, authenticator_buff;\r
+    gss_name_t client_name;\r
+    OM_uint32  ret_flags;\r
+    int ret = 0;\r
+    /* FIXME\r
+     * princ specifies the principal to be used.\r
+     * The user specifies it when configuring afpd anyway,\r
+     * we should be able to detect it.\r
+     */\r
+    gss_buffer_desc s_princ_buffer;\r
+\r
+    s_princ_buffer.value = service;\r
+    s_princ_buffer.length = strlen( service ) + 1;\r
+    \r
+    /* outline:\r
+     * gss_import_name (need a way to get this from afpd)\r
+     * gss_acquire_credential\r
+     * gss_accept_sec_context\r
+     * ...\r
+     */\r
+    LOG(log_info, logtype_uams, "uams_gss.c :do_gss_auth: importing name" );\r
+    major_status = gss_import_name( &minor_status, \r
+                   &s_princ_buffer, \r
+                   GSS_C_NT_HOSTBASED_SERVICE,\r
+                   &server_name );\r
+    if (major_status != GSS_S_COMPLETE) {\r
+       log_status( "import_name", major_status, minor_status );\r
+       ret = 1;\r
+       goto cleanup_vars;\r
+    }\r
+    \r
+    LOG(log_info, logtype_uams, \r
+       "uams_gss.c :do_gss_auth: acquiring credentials (uid = %d, keytab = %s)",\r
+        (int)geteuid(), getenv( "KRB5_KTNAME") );\r
+\r
+    major_status = gss_acquire_cred( &minor_status, server_name, \r
+                       GSS_C_INDEFINITE, GSS_C_NO_OID_SET, GSS_C_ACCEPT,\r
+                       &server_creds, NULL, NULL );    \r
+    if (major_status != GSS_S_COMPLETE) {\r
+       log_status( "acquire_cred", major_status, minor_status );\r
+       ret = 1;\r
+       goto cleanup_vars;\r
+    }\r
+\r
+    /* The GSSAPI docs say that this should be done in a big "do" loop,\r
+     * but Apple's implementation doesn't seem to support this behavior.\r
+     */\r
+    ticket_buffer.length = ticket_len;\r
+    ticket_buffer.value = ibuf;\r
+    authenticator_buff.length = 0;\r
+    authenticator_buff.value = NULL;\r
+    LOG(log_info, logtype_uams, "uams_gss.c :do_gss_auth: accepting context (ticketlen: %u, value: %X)", ticket_buffer.length, ticket_buffer.value );\r
+    major_status = gss_accept_sec_context( &minor_status, &context_handle,\r
+                       server_creds, &ticket_buffer, GSS_C_NO_CHANNEL_BINDINGS,\r
+                       &client_name, NULL, &authenticator_buff,\r
+                       &ret_flags, NULL, NULL );\r
+\r
+    if (major_status == GSS_S_COMPLETE) {\r
+       gss_buffer_desc client_name_buffer;\r
+\r
+       log_ctx_flags( ret_flags );\r
+       /* use gss_display_name on client_name */\r
+       major_status = gss_display_name( &minor_status, client_name,\r
+                               &client_name_buffer, (gss_OID *)NULL );\r
+       if (major_status == GSS_S_COMPLETE) {\r
+           u_int16_t auth_len = htons( authenticator_buff.length );\r
+           /* save the username... note that doing it this way is\r
+            * not the best idea: if a principal is truncated, a user could be\r
+            * impersonated\r
+            */\r
+           memcpy( username, client_name_buffer.value, \r
+               MIN(client_name_buffer.length, ulen - 1));\r
+           username[MIN(client_name_buffer.length, ulen - 1)] = 0;\r
+       \r
+            LOG(log_info, logtype_uams, "uams_gss.c :do_gss_auth: user is %s!", username );\r
+           /* copy the authenticator length into the reply buffer */\r
+           memcpy( rbuf, &auth_len, sizeof(auth_len) );\r
+           *rbuflen += sizeof(auth_len), rbuf += sizeof(auth_len);\r
+\r
+           /* copy the authenticator value into the reply buffer */\r
+           memcpy( rbuf, authenticator_buff.value, authenticator_buff.length );\r
+           *rbuflen += authenticator_buff.length;\r
+\r
+           gss_release_buffer( &minor_status, &client_name_buffer );\r
+       } else {\r
+           log_status( "display_name", major_status, minor_status );\r
+           ret = 1;\r
+       }\r
+\r
+\r
+       /* Clean up after ourselves */\r
+        gss_release_name( &minor_status, &client_name );\r
+\r
+       /* This will SIGSEGV, as it would free ibuf */\r
+        /*gss_release_buffer( &minor_status, &ticket_buffer );*/\r
+\r
+       if ( authenticator_buff.value)\r
+               gss_release_buffer( &minor_status, &authenticator_buff );\r
+\r
+        gss_delete_sec_context( &minor_status, \r
+                       &context_handle, NULL );\r
+    } else {\r
+       log_status( "accept_sec_context", major_status, minor_status );\r
+        ret = 1;\r
+    }\r
+    gss_release_cred( &minor_status, &server_creds );\r
+\r
+cleanup_vars:\r
+    gss_release_name( &minor_status, &server_name );\r
+    \r
+    return ret;\r
+}\r
+\r
+/* -------------------------- */\r
+static int gss_login(void *obj, struct passwd **uam_pwd,\r
+                    char *ibuf, int ibuflen,\r
+                    char *rbuf, int *rbuflen)\r
+{\r
+\r
+    u_int16_t  temp16;\r
+\r
+    *rbuflen = 0;\r
+\r
+    /* The reply contains a two-byte ID value - note \r
+     * that Apple's implementation seems to always return 1 as well\r
+     */\r
+    temp16 = htons( 1 );\r
+    memcpy(rbuf, &temp16, sizeof(temp16));\r
+    *rbuflen += sizeof(temp16);\r
+    return AFPERR_AUTHCONT;\r
+}\r
+\r
+static int gss_logincont(void *obj, struct passwd **uam_pwd,\r
+                     char *ibuf, int ibuflen,\r
+                     char *rbuf, int *rbuflen)\r
+{\r
+    struct passwd *pwd = NULL;\r
+    u_int16_t login_id;\r
+    char *username;\r
+    u_int16_t ticket_len;\r
+    char *p;\r
+    int rblen;\r
+    char *service;\r
+    int userlen, servicelen;\r
+\r
+    /* Apple's AFP 3.1 documentation specifies that this command\r
+     * takes the following format:\r
+     * pad (byte)\r
+     * id returned in LoginExt response (u_int16_t)\r
+     * username (format unspecified) padded, when necessary, to end on an even boundary\r
+     * ticket length (u_int16_t)\r
+     * ticket\r
+     */\r
+\r
+    /* Observation of AFP clients in the wild indicate that the actual\r
+     * format of this request is as follows:\r
+     * pad (byte) [consumed before login_ext is called]\r
+     * ?? (byte) - always observed to be 0\r
+     * id returned in LoginExt response (u_int16_t)\r
+     * username, encoding unspecified, null terminated C string, \r
+     *   padded when the terminating null is an even numbered byte.\r
+     *   The packet is formated such that the username begins on an \r
+     *   odd numbered byte. Eg if the username is 3 characters and the\r
+     *   terminating null makes 4, expect to pad the the result.\r
+     *   The encoding of this string is unknown.\r
+     * ticket length (u_int16_t)\r
+     * ticket\r
+     */\r
+\r
+    rblen = *rbuflen = 0;\r
+\r
+    ibuf++, ibuflen--; /* ?? */\r
+\r
+    /* 2 byte ID from LoginExt -- always '00 01' in this implementation */\r
+    memcpy( &login_id, ibuf, sizeof(login_id) );\r
+    ibuf += sizeof(login_id), ibuflen -= sizeof(login_id);\r
+    login_id = ntohs( login_id );\r
+\r
+    if (uam_afpserver_option(obj, UAM_OPTION_USERNAME, (void *) &username, &userlen) < 0)\r
+        return AFPERR_MISC;\r
+\r
+    if (uam_afpserver_option(obj, UAM_OPTION_KRB5SERVICE, (void *)&service, &servicelen) < 0)\r
+       return AFPERR_MISC;\r
+\r
+    if (service == NULL) \r
+       return AFPERR_MISC;\r
+\r
+    /* We skip past the 'username' parameter because all that matters is the ticket */\r
+    p = ibuf;\r
+    while( *ibuf && ibuflen ) { ibuf++, ibuflen--; }\r
+    if (ibuflen < 4) {\r
+        LOG(log_info, logtype_uams, "uams_gss.c :LoginCont: user is %s, no ticket", p);\r
+       return AFPERR_PARAM;\r
+    }\r
+\r
+    ibuf++, ibuflen--; /* null termination */\r
+\r
+    if ((ibuf - p + 1) % 2) ibuf++, ibuflen--; /* deal with potential padding */\r
+\r
+    LOG(log_info, logtype_uams, "uams_gss.c :LoginCont: client thinks user is %s", p);\r
+\r
+    memcpy(&ticket_len, ibuf, sizeof(ticket_len));\r
+    ibuf += sizeof(ticket_len); ibuflen -= sizeof(ticket_len);\r
+    ticket_len = ntohs( ticket_len );\r
+\r
+    if (ticket_len > ibuflen) {\r
+        LOG(log_info, logtype_uams, "uams_gss.c :LoginCont: invalid ticket length");\r
+       return AFPERR_PARAM;\r
+    }\r
+\r
+    if (!do_gss_auth(service, ibuf, ticket_len, rbuf, &rblen, username, userlen)) {\r
+       char *at = strchr( username, '@' );\r
+\r
+       // Chop off the realm name\r
+       if (at)\r
+           *at = '\0';\r
+       if((pwd = uam_getname( username, userlen )) == NULL) {\r
+           LOG(log_info, logtype_uams, "uam_getname() failed for %s", username);\r
+           return AFPERR_PARAM;\r
+       }\r
+       if (uam_checkuser(pwd) < 0) {\r
+           LOG(log_info, logtype_uams, "%s not a valid user", username);\r
+           return AFPERR_NOTAUTH;\r
+       }\r
+       *rbuflen = rblen;\r
+       *uam_pwd = pwd;\r
+       return AFP_OK;\r
+    } else {\r
+       LOG(log_info, logtype_uams, "do_gss_auth failed" );\r
+       *rbuflen = 0;\r
+        return AFPERR_MISC;\r
+    }\r
+}\r
+\r
+/*\r
+ * For the krb5 uam, this function only needs to return a two-byte\r
+ * login-session id. None of the data provided by the client up to this\r
+ * point is trustworthy as we'll have a signed ticket to parse in logincont.\r
+ */\r
+static int gss_login_ext(void *obj, char *uname, struct passwd **uam_pwd,\r
+                    char *ibuf, int ibuflen,\r
+                    char *rbuf, int *rbuflen)\r
+{\r
+    u_int16_t  temp16;\r
+\r
+    *rbuflen = 0;\r
+\r
+    /* The reply contains a two-byte ID value - note \r
+     * that Apple's implementation seems to always return 1 as well\r
+     */\r
+    temp16 = htons( 1 );\r
+    memcpy(rbuf, &temp16, sizeof(temp16));\r
+    *rbuflen += sizeof(temp16);\r
+    return AFPERR_AUTHCONT;\r
+}\r
+\r
+/* logout */\r
+static void gss_logout() {\r
+}\r
+\r
+int uam_setup(const char *path)\r
+{\r
+    if (uam_register(UAM_SERVER_LOGIN_EXT, path, "Client Krb v2", \r
+                  gss_login, gss_logincont, gss_logout, gss_login_ext) < 0)\r
+    if (uam_register(UAM_SERVER_LOGIN, path, "Client Krb v2", \r
+                  gss_login, gss_logincont, gss_logout) < 0)\r
+        return -1;\r
+\r
+  return 0;\r
+}\r
+\r
+static void uam_cleanup(void)\r
+{\r
+  uam_unregister(UAM_SERVER_LOGIN_EXT, "Client Krb v2");\r
+}\r
+\r
+UAM_MODULE_EXPORT struct uam_export uams_gss = {\r
+  UAM_MODULE_SERVER,\r
+  UAM_MODULE_VERSION,\r
+  uam_setup, uam_cleanup\r
+};\r
+#endif\r
index 5e2ba62608e6c30d13cddf5f4f694009698e4d08..7f374253cef6ffa8eab2da5cdb3840a17a15d2bf 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: uams_pam.c,v 1.15.2.1 2003-09-03 20:40:50 didg Exp $
+ * $Id: uams_pam.c,v 1.15.2.1.2.1 2003-09-09 16:42:20 didg Exp $
  *
  * Copyright (c) 1990,1993 Regents of The University of Michigan.
  * Copyright (c) 1999 Adrian Sun (asun@u.washington.edu) 
@@ -35,6 +35,7 @@ char *strchr (), *strrchr ();
 #include <atalk/logger.h>
 
 #include <security/pam_appl.h>
+#include <atalk/unicode.h>
 
 #include <atalk/afp.h>
 #include <atalk/uam.h>
@@ -54,6 +55,8 @@ static char *hostname;
 static char *PAM_username;
 static char *PAM_password;
 
+extern void append(void *, const char *, int);
+
 /* PAM conversation function
  * Here we assume (for now, at least) that echo on means login name, and
  * echo off means password.
@@ -226,6 +229,10 @@ static int pam_login(void *obj, struct passwd **uam_pwd,
     ibuf += len;
 
     username[ len ] = '\0';
+
+    len = convert_charset(CH_MAC, CH_UNIX, username, len, username, ulen, 0);
+
+
     if ((unsigned long) ibuf & 1)  /* pad character */
       ++ibuf;
     return (login(obj, username, ulen, uam_pwd, ibuf, ibuflen, rbuf, rbuflen));
@@ -256,6 +263,8 @@ static int pam_login_ext(void *obj, char *uname, struct passwd **uam_pwd,
     }
     memcpy(username, uname +2, len );
     username[ len ] = '\0';
+    
+    len = convert_charset(CH_UTF8_MAC, CH_UNIX, username, len, username, ulen, 0);
 
     return (login(obj, username, ulen, uam_pwd, ibuf, ibuflen, rbuf, rbuflen));
 }
index 74332071512e3258c836b406d06f995af7143f8f..a5ea63065e205675a89923848b7163c153f05cd1 100644 (file)
@@ -1,4 +1,8 @@
 # Makefile.am for include/atalk/
 
 atalkincludedir = $(includedir)/atalk
-atalkinclude_HEADERS = adouble.h aep.h afp.h asp.h atp.h boolean.h cnid.h compat.h ddp.h dsi.h logger.h nbp.h netddp.h pap.h paths.h rtmp.h server_child.h uam.h util.h zip.h unicode.h
+atalkinclude_HEADERS = adouble.h aep.h afp.h asp.h atp.h boolean.h compat.h ddp.h dsi.h \
+                       logger.h nbp.h netddp.h pap.h paths.h rtmp.h server_child.h uam.h util.h \
+                       zip.h list.h cnid.h tdb.h
+     
+noinst_HEADERS = cnid_dbd_private.h
index 1e72258f6ff87b118eb7a14a67d076f97d89212e..9bf7144b1a6258127a58801571090c310ffd821b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: adouble.h,v 1.21 2003-03-09 19:55:35 didg Exp $
+ * $Id: adouble.h,v 1.21.6.1 2003-09-09 16:42:20 didg Exp $
  * Copyright (c) 1990,1991 Regents of The University of Michigan.
  * All Rights Reserved.
  *
@@ -104,6 +104,11 @@ static __inline__ int sendfile(int fdout, int fdin, off_t *off, size_t count)
 #define HAVE_SENDFILE_READ
 #endif
 
+/* version info */
+#define AD_VERSION1    0x00010000
+#define AD_VERSION2    0x00020000
+#define AD_VERSION     AD_VERSION2
+
 /*
  * AppleDouble entry IDs. 
  */
@@ -123,17 +128,25 @@ static __inline__ int sendfile(int fdout, int fdin, off_t *off, size_t count)
 #define ADEID_AFPFILEI         14 /* where the rest of the FILEI info goes */
 #define ADEID_DID              15
 
+#if AD_VERSION == AD_VERSION1
 #define ADEID_MAX              16
+#else
+/* netatalk private note fileid reused DID */
+#define ADEID_PRIVDEV           16
+#define ADEID_PRIVINO           17
+#define ADEID_PRIVSYN           18 /* in synch with database */
+
+#define AD_DEV                  0x80444556
+#define AD_INO                  0x80494E4F
+#define AD_SYN                  0x8053594E
+#define ADEID_MAX              19
+#endif
 
 /* magic */
 #define AD_APPLESINGLE_MAGIC 0x00051600
 #define AD_APPLEDOUBLE_MAGIC 0x00051607
 #define AD_MAGIC            AD_APPLEDOUBLE_MAGIC
 
-/* version info */
-#define AD_VERSION1    0x00010000
-#define AD_VERSION2    0x00020000
-#define AD_VERSION     AD_VERSION1
 
 /* sizes of relevant entry bits */
 #define ADEDLEN_MAGIC       4
@@ -141,6 +154,7 @@ static __inline__ int sendfile(int fdout, int fdin, off_t *off, size_t count)
 #define ADEDLEN_FILLER      16
 #define ADEDLEN_NENTRIES    2
 
+/* 26 */
 #define AD_HEADER_LEN       (ADEDLEN_MAGIC + ADEDLEN_VERSION + \
                             ADEDLEN_FILLER + ADEDLEN_NENTRIES)
 #define AD_ENTRY_LEN        12  /* size of a single entry header */
@@ -159,10 +173,26 @@ static __inline__ int sendfile(int fdout, int fdin, off_t *off, size_t count)
 #define ADEDLEN_PRODOSFILEI     8
 #define ADEDLEN_MSDOSFILEI      2
 #define ADEDLEN_DID             4
+#define ADEDLEN_PRIVDEV         8
+#define ADEDLEN_PRIVINO         8
+#define ADEDLEN_PRIVSYN         8
+
+#define ADEID_NUM_V1         5 
+#define ADEID_NUM_V2         12  
+
+/* 589 */
+#define AD_DATASZ1      (AD_HEADER_LEN + ADEDLEN_NAME + ADEDLEN_COMMENT +ADEDLEN_FILEI +ADEDLEN_FINDERI+\
+ADEID_NUM_V1*AD_ENTRY_LEN)
+
+#if AD_DATASZ1 != 589
+#error bad size for AD_DATASZ1
+#endif
 
+#define AD_NEWSZ2       (ADEDLEN_DID + ADEDLEN_AFPFILEI +ADEDLEN_SHORTNAME +ADEDLEN_PRODOSFILEI \
++ADEDLEN_PRIVDEV +ADEDLEN_PRIVINO +ADEDLEN_PRIVSYN)
 
-#define AD_DATASZ1      589  
-#define AD_DATASZ2      665  /* v1 + 4 new entries (entry desc. + entry) */
+/* 725 */
+#define AD_DATASZ2      (AD_DATASZ1 + (ADEID_NUM_V2 -ADEID_NUM_V1)*AD_ENTRY_LEN)
 #define AD_DATASZ_MAX   1024
 #if AD_VERSION == AD_VERSION1
 #define AD_DATASZ      AD_DATASZ1 /* hold enough for the entries */
@@ -349,8 +379,11 @@ extern char *ad_dir   __P((const char *));
 extern char *ad_path  __P((const char *, int));
 extern int ad_mode    __P((const char *, int));
 extern int ad_mkdir   __P((const char *, int));
+extern void ad_init   __P((struct adouble *, int ));
+
 extern int ad_open    __P((const char *, int, int, int, struct adouble *)); 
 extern int ad_refresh __P((struct adouble *));
+extern int ad_stat    __P((const char *, struct stat *));
 
 /* extend header to RW if R or W (W if R for locking),
  */ 
@@ -411,6 +444,12 @@ extern int ad_getdate __P((const struct adouble *, unsigned int, u_int32_t *));
 extern int ad_setattr __P((const struct adouble *, const u_int16_t));
 extern int ad_getattr __P((const struct adouble *, u_int16_t *));
 
+#if AD_VERSION == AD_VERSION2
+extern int ad_setid __P((struct adouble *, const struct stat *, const u_int32_t, const void *));
+#else
+#define ad_setid(a, b, c)
+#endif
+
 #ifdef HAVE_SENDFILE_READ
 extern ssize_t ad_readfile __P((const struct adouble *, const int, 
                                const int, off_t, const size_t));
index f7e676c05554e374369b0909de20f713e0cec2ad..490d09977c8214a4ae6a103bdfca26e296cb085e 100644 (file)
@@ -1,17 +1,37 @@
 /* 
- * interface for database access to cnids. i do it this way to abstract
- * things a bit in case we want to change the underlying implementation.
+ * $Id: cnid.h,v 1.9.6.1 2003-09-09 16:42:20 didg Exp $
+ *
+ * Copyright (c) 2003 the Netatalk Team
+ * Copyright (c) 2003 Rafal Lewczuk <rlewczuk@pronet.pl>
+ * 
+ * This program is free software; you can redistribute and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation version 2 of the License or later
+ * version if explicitly stated by any of above copyright holders.
+ *
  */
 
-#ifndef _ATALK_CNID_H
-#define _ATALK_CNID_H 1
+/* 
+ * This file contains all generic CNID related stuff 
+ * declarations. Included:
+ * - CNID factory, which retrieves (eventually instantiates) 
+ *   CNID objects on demand
+ * - selection of CNID backends (default, detected by volume)
+ * - full set of CNID operations needed by server core.
+ */
+
+#ifndef _ATALK_CNID__H
+#define _ATALK_CNID__H 1
 
 #include <sys/cdefs.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <string.h>
+#include <atalk/adouble.h>
+#include <atalk/list.h>
 
-#include <netatalk/endian.h>
+/* CNID object flags */
+#define CNID_FLAG_PERSISTENT   0x01      /* This backend implements DID persistence */
+#define CNID_FLAG_MANGLING     0x02      /* This backend has name mangling feature. */
+#define CNID_FLAG_SETUID       0x04      /* Set db owner to parent folder owner. */
+#define CNID_FLAG_BLOCK        0x08      /* block signals in update. */
 
 #define CNID_INVALID   0
 
 #define CNID_ERR_CLOSE 0x80000004   /* the db was not open */
 #define CNID_ERR_MAX   0x80000005
 
-/* cnid_open.c */
-extern void *cnid_open __P((const char *, mode_t));
+/*
+ * This is instance of CNID database object.
+ */
+struct _cnid_db {
+       
+       u_int32_t flags;        /* Flags describing some CNID backend aspects. */
+       char *volpath;          /* Volume path this particular CNID db refers to. */
+       void *_private;             /* back-end speficic data */
+       char *stamp[ADEDLEN_PRIVSYN];
+       
+       /* */
+       cnid_t (*cnid_add)(struct _cnid_db *cdb, const struct stat *st, const cnid_t did, 
+                       const char *name, const int len, cnid_t hint);
+       int (*cnid_delete)(struct _cnid_db *cdb, cnid_t id);
+       cnid_t (*cnid_get)(struct _cnid_db *cdb, const cnid_t did, const char *name,
+                       const int len);
+       cnid_t (*cnid_lookup)(struct _cnid_db *cdb, const struct stat *st, const cnid_t did,
+                       const char *name, const int len);
+       cnid_t (*cnid_nextid)(struct _cnid_db *cdb);
+       char *(*cnid_resolve)(struct _cnid_db *cdb, cnid_t *id, void *buffer, u_int32_t len);
+       int (*cnid_update)(struct _cnid_db *cdb, const cnid_t id, const struct stat *st, 
+                       const cnid_t did, const char *name, const int len);     
+       void (*cnid_close)(struct _cnid_db *cdb);
+       int  (*cnid_getstamp)(struct _cnid_db *cdb, void *buffer, const int len);
+};
+typedef struct _cnid_db cnid_db;
+
+/*
+ * CNID module - represents particular CNID implementation
+ */
+struct _cnid_module {
+       char *name;
+       struct list_head db_list;   /* CNID modules are also stored on a bidirectional list. */
+       struct _cnid_db *(*cnid_open)(const char *dir, mode_t mask);
+       u_int32_t flags;            /* Flags describing some CNID backend aspects. */
+
+};
+typedef struct _cnid_module cnid_module;
+
+/* Registers new CNID backend module */
+void cnid_register(struct _cnid_module *module);
+
+/* This function opens a CNID database for selected volume. */
+struct _cnid_db *cnid_open(const char *volpath, mode_t mask, char *type);
 
-/* cnid_close.c */
-extern void cnid_close __P((void *));
+cnid_t cnid_add(struct _cnid_db *cdb, const struct stat *st, const cnid_t did, 
+                       const char *name, const int len, cnid_t hint);
 
-/* cnid_add.c */
-extern cnid_t cnid_add __P((void *, const struct stat *, const cnid_t,
-                           const char *, const int, cnid_t));
+int    cnid_delete(struct _cnid_db *cdb, cnid_t id);
 
-/* cnid_get.c */
-extern cnid_t cnid_get __P((void *, const cnid_t, const char *, const int)); 
-extern char *cnid_resolve __P((void *, cnid_t *, void *, u_int32_t )); 
-extern cnid_t cnid_lookup __P((void *, const struct stat *, const cnid_t,
-                              const char *, const int));
+cnid_t cnid_get   (struct _cnid_db *cdb, const cnid_t did, const char *name,const int len);
 
-/* cnid_update.c */
-extern int cnid_update __P((void *, const cnid_t, const struct stat *,
-                           const cnid_t, const char *, int));
+cnid_t cnid_getstamp(struct _cnid_db *cdb, void *buffer, const int len);
 
-/* cnid_delete.c */
-extern int cnid_delete __P((void *, const cnid_t));
+cnid_t cnid_lookup(struct _cnid_db *cdb, const struct stat *st, const cnid_t did,
+                       const char *name, const int len);
 
-/* cnid_nextid.c */
-extern cnid_t cnid_nextid __P((void *));
+char *cnid_resolve(struct _cnid_db *cdb, cnid_t *id, void *buffer, u_int32_t len);
 
-/* cnid_mangle_* */
-extern int cnid_mangle_add __P((void *, char *, char *));
-extern char *cnid_mangle_get __P((void *, char *));
+int cnid_update   (struct _cnid_db *cdb, const cnid_t id, const struct stat *st, 
+                       const cnid_t did, const char *name, const int len);     
 
-extern int cnid_lock   __P((void *));
-extern int cnid_unlock __P((void *));
+/* This function closes a CNID database and frees all resources assigned to it. */ 
+void cnid_close(struct _cnid_db *db);
+
+#endif
+
+/*
+ * $Log: cnid.h,v $
+ * Revision 1.9.6.1  2003-09-09 16:42:20  didg
+ *
+ * big merge for db frontend and unicode.
+ *
+ * Revision 1.9.4.2  2003/06/11 15:29:11  rlewczuk
+ * Removed obsolete parameter from cnid_add. Spotted by Didier.
+ *
+ * Revision 1.9.4.1  2003/05/29 07:53:19  rlewczuk
+ * Selectable CNIDs. Some refactoring. Propably needs more of refactoring, mainly
+ * a well designed API (current API is just an old cnid_* API enclosed in VMT).
+ *
+ */
 
-#endif /* include/atalk/cnid.h */
diff --git a/include/atalk/cnid_dbd_private.h b/include/atalk/cnid_dbd_private.h
new file mode 100644 (file)
index 0000000..58819e3
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ *  Interface to the cnid_dbd daemon that stores/retrieves CNIDs from a database.
+ */
+
+
+#ifndef _ATALK_CNID_DBD_PRIVATE_H
+#define _ATALK_CNID_DBD_PRIVATE_H 1
+
+#include <sys/stat.h>
+#include <atalk/adouble.h>
+#include <sys/param.h>
+
+#define CNID_META_DEFAULT_USOCK "/tmp/cnid_meta" 
+
+#define CNID_DBD_OP_OPEN        0x01
+#define CNID_DBD_OP_CLOSE       0x02
+#define CNID_DBD_OP_ADD         0x03
+#define CNID_DBD_OP_GET         0x04
+#define CNID_DBD_OP_RESOLVE     0x05
+#define CNID_DBD_OP_LOOKUP      0x06
+#define CNID_DBD_OP_UPDATE      0x07
+#define CNID_DBD_OP_DELETE      0x08
+#define CNID_DBD_OP_MANGLE_ADD  0x09
+#define CNID_DBD_OP_MANGLE_GET  0x0a
+
+#define CNID_DBD_RES_OK            0x00
+#define CNID_DBD_RES_NOTFOUND      0x01
+#define CNID_DBD_RES_ERR_DB        0x02
+#define CNID_DBD_RES_ERR_MAX       0x03
+#define CNID_DBD_RES_ERR_DUPLCNID  0x04
+
+#define CNID_DB_MAGIC   0x434E4944U  /* CNID */
+#define CNID_DATA_MAGIC 0x434E4945U  /* CNIE */
+
+#define CNID_OFS                 0
+#define CNID_LEN                 4
+#define CNID_DEV_OFS             CNID_LEN
+#define CNID_DEV_LEN             8
+#define CNID_INO_OFS             (CNID_DEV_OFS + CNID_DEV_LEN)
+#define CNID_INO_LEN             8
+#define CNID_DEVINO_OFS          CNID_LEN
+#define CNID_DEVINO_LEN          (CNID_DEV_LEN +CNID_INO_LEN)
+#define CNID_TYPE_OFS            (CNID_DEVINO_OFS +CNID_DEVINO_LEN)
+#define CNID_TYPE_LEN            4
+#define CNID_DID_OFS             (CNID_TYPE_OFS +CNID_TYPE_LEN)
+#define CNID_DID_LEN             CNID_LEN
+#define CNID_NAME_OFS            (CNID_DID_OFS + CNID_DID_LEN)
+#define CNID_HEADER_LEN          (CNID_NAME_OFS)
+
+#define CNID_START               17
+
+#define CNIDFLAG_ROOTINFO_RO     (1 << 0)
+#define CNIDFLAG_DB_RO           (1 << 1)
+
+/* the key is in the form of a did/name pair. in this case,
+ * we use 0/RootInfo. */
+#define ROOTINFO_KEY    "\0\0\0\0"
+#define ROOTINFO_KEYLEN 4
+
+struct cnid_dbd_rqst {
+    int     op;
+    cnid_t  cnid;
+    dev_t   dev;
+    ino_t   ino;
+    int     type;
+    cnid_t  did;
+    char   *name;
+    int     namelen;
+    char   *mname;
+    int     mnamelen;
+};
+
+struct cnid_dbd_rply {
+    int     result;    
+    cnid_t  cnid;
+    cnid_t  did;
+    char   *name;
+    int     namelen;
+};
+
+typedef struct CNID_private {
+    u_int32_t magic;
+    char db_dir[MAXPATHLEN + 1];
+    char usock_file[MAXPATHLEN + 1];
+    char mnamebuf[MAXPATHLEN + 1];
+    int fd;
+} CNID_private;
+
+
+#endif /* include/atalk/cnid_dbd.h */
diff --git a/include/atalk/list.h b/include/atalk/list.h
new file mode 100644 (file)
index 0000000..59206f4
--- /dev/null
@@ -0,0 +1,164 @@
+/* This code has been stolen from Linux kernel :) */
+/* distributed under GNU GPL version 2. */
+
+#ifndef _ATALK_LIST_H
+#define _ATALK_LIST_H
+/*
+ * Simple doubly linked list implementation.
+ *
+ * Some of the internal functions ("__xxx") are useful when
+ * manipulating whole lists rather than single entries, as
+ * sometimes we already know the next/prev entries and we can
+ * generate better code by using them directly rather than
+ * using the generic single-entry routines.
+ */
+
+struct list_head {
+    struct list_head *next, *prev;
+};
+
+#define LIST_HEAD_INIT(name) { &(name), &(name) }
+
+#define LIST_HEAD(name) \
+    struct list_head name = LIST_HEAD_INIT(name)
+
+#define INIT_LIST_HEAD(ptr) do { \
+    (ptr)->next = (ptr); (ptr)->prev = (ptr); \
+} while (0)
+
+#ifdef USE_LIST
+/*
+ * Insert a new entry between two known consecutive entries. 
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static __inline__ void __list_add(struct list_head * new,
+                                  struct list_head * prev,
+                                  struct list_head * next)
+{
+    next->prev = new;
+    new->next = next;
+    new->prev = prev;
+    prev->next = new;
+}
+
+/**
+ * list_add - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it after
+ *
+ * Insert a new entry after the specified head.
+ * This is good for implementing stacks.
+ */
+static __inline__ void list_add(struct list_head *new, struct list_head *head)
+{
+    __list_add(new, head, head->next);
+}
+
+/**
+ * list_add_tail - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it before
+ *
+ * Insert a new entry before the specified head.
+ * This is useful for implementing queues.
+ */
+static __inline__ void list_add_tail(struct list_head *new, struct list_head *head)
+{
+    __list_add(new, head->prev, head);
+}
+
+/*
+ * Delete a list entry by making the prev/next entries
+ * point to each other.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static __inline__ void __list_del(struct list_head * prev,
+                                  struct list_head * next)
+{
+    next->prev = prev;
+    prev->next = next;
+}
+
+/**
+ * list_del - deletes entry from list.
+ * @entry: the element to delete from the list.
+ * Note: list_empty on entry does not return true after this, the entry is in an undefined state.
+ */
+static __inline__ void list_del(struct list_head *entry)
+{
+    __list_del(entry->prev, entry->next);
+}
+
+/**
+ * list_del_init - deletes entry from list and reinitialize it.
+ * @entry: the element to delete from the list.
+ */
+static __inline__ void list_del_init(struct list_head *entry)
+{
+    __list_del(entry->prev, entry->next);
+    INIT_LIST_HEAD(entry);
+}
+
+/**
+ * list_empty - tests whether a list is empty
+ * @head: the list to test.
+ */
+static __inline__ int list_empty(struct list_head *head)
+{
+    return head->next == head;
+}
+
+/**
+ * list_splice - join two lists
+ * @list: the new list to add.
+ * @head: the place to add it in the first list.
+ */
+static __inline__ void list_splice(struct list_head *list, struct list_head *head)
+{
+    struct list_head *first = list->next;
+
+    if (first != list) {
+        struct list_head *last = list->prev;
+        struct list_head *at = head->next;
+
+        first->prev = head;
+        head->next = first;
+
+        last->next = at;
+        at->prev = last;
+    }
+}
+
+#endif
+/**
+ * list_entry - get the struct for this entry
+ * @ptr:       the &struct list_head pointer.
+ * @type:      the type of the struct this is embedded in.
+ * @member:    the name of the list_struct within the struct.
+ */
+#define list_entry(ptr, type, member) \
+    ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
+
+/**
+ * list_for_each       -       iterate over a list
+ * @pos:       the &struct list_head to use as a loop counter.
+ * @n:         another &struct list_head to use as temporary storage
+ * @head:      the head for your list.
+ */
+#define list_for_each(pos, head) \
+    for (pos = (head)->next; pos != (head); \
+        pos = pos->next)
+
+/**
+ * list_for_each_prev  -       iterate over a list in reverse order
+ * @pos:       the &struct list_head to use as a loop counter.
+ * @head:      the head for your list.
+ */
+#define list_for_each_prev(pos, head) \
+    for (pos = (head)->prev; pos != (head); \
+        pos = pos->prev)
+#endif
diff --git a/include/atalk/tdb.h b/include/atalk/tdb.h
new file mode 100644 (file)
index 0000000..6f3b1ff
--- /dev/null
@@ -0,0 +1,144 @@
+#ifndef __TDB_H__
+#define __TDB_H__
+
+/* 
+   Unix SMB/CIFS implementation.
+   Samba database functions
+   Copyright (C) Andrew Tridgell 1999
+   
+   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.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+
+/* flags to tdb_store() */
+#define TDB_REPLACE 1
+#define TDB_INSERT 2
+#define TDB_MODIFY 3
+
+/* flags for tdb_open() */
+#define TDB_DEFAULT 0 /* just a readability place holder */
+#define TDB_CLEAR_IF_FIRST 1
+#define TDB_INTERNAL 2 /* don't store on disk */
+#define TDB_NOLOCK   4 /* don't do any locking */
+#define TDB_NOMMAP   8 /* don't use mmap */
+#define TDB_CONVERT 16 /* convert endian (internal use) */
+#define TDB_BIGENDIAN 32 /* header is big-endian (internal use) */
+
+#define TDB_ERRCODE(code, ret) ((tdb->ecode = (code)), ret)
+
+/* error codes */
+enum TDB_ERROR {TDB_SUCCESS=0, TDB_ERR_CORRUPT, TDB_ERR_IO, TDB_ERR_LOCK, 
+               TDB_ERR_OOM, TDB_ERR_EXISTS, TDB_ERR_NOEXIST, TDB_ERR_NOLOCK, TDB_ERR_LOCK_TIMEOUT };
+
+#ifndef u32
+#define u32 unsigned
+#endif
+
+typedef struct {
+       char *dptr;
+       size_t dsize;
+} TDB_DATA;
+
+typedef u32 tdb_len;
+typedef u32 tdb_off;
+
+/* this is stored at the front of every database */
+struct tdb_header {
+       char magic_food[32]; /* for /etc/magic */
+       u32 version; /* version of the code */
+       u32 hash_size; /* number of hash entries */
+       tdb_off rwlocks;
+       tdb_off reserved[31];
+};
+
+struct tdb_lock_type {
+       u32 count;
+       u32 ltype;
+};
+
+struct tdb_traverse_lock {
+       struct tdb_traverse_lock *next;
+       u32 off;
+       u32 hash;
+};
+
+/* this is the context structure that is returned from a db open */
+typedef struct tdb_context {
+       char *name; /* the name of the database */
+       void *map_ptr; /* where it is currently mapped */
+       int fd; /* open file descriptor for the database */
+       tdb_len map_size; /* how much space has been mapped */
+       int read_only; /* opened read-only */
+       struct tdb_lock_type *locked; /* array of chain locks */
+       enum TDB_ERROR ecode; /* error code for last tdb error */
+       struct tdb_header header; /* a cached copy of the header */
+       u32 flags; /* the flags passed to tdb_open */
+       u32 *lockedkeys; /* array of locked keys: first is #keys */
+       struct tdb_traverse_lock travlocks; /* current traversal locks */
+       struct tdb_context *next; /* all tdbs to avoid multiple opens */
+       dev_t device;   /* uniquely identifies this tdb */
+       ino_t inode;    /* uniquely identifies this tdb */
+       void (*log_fn)(struct tdb_context *tdb, int level, const char *, ...); /* logging function */
+       int open_flags; /* flags used in the open - needed by reopen */
+} TDB_CONTEXT;
+
+typedef int (*tdb_traverse_func)(TDB_CONTEXT *, TDB_DATA, TDB_DATA, void *);
+typedef void (*tdb_log_func)(TDB_CONTEXT *, int , const char *, ...);
+
+TDB_CONTEXT *tdb_open(const char *name, int hash_size, int tdb_flags,
+                     int open_flags, mode_t mode);
+TDB_CONTEXT *tdb_open_ex(const char *name, int hash_size, int tdb_flags,
+                        int open_flags, mode_t mode,
+                        tdb_log_func log_fn);
+
+int tdb_reopen(TDB_CONTEXT *tdb);
+int tdb_reopen_all(void);
+void tdb_logging_function(TDB_CONTEXT *tdb, tdb_log_func);
+enum TDB_ERROR tdb_error(TDB_CONTEXT *tdb);
+const char *tdb_errorstr(TDB_CONTEXT *tdb);
+TDB_DATA tdb_fetch(TDB_CONTEXT *tdb, TDB_DATA key);
+int tdb_delete(TDB_CONTEXT *tdb, TDB_DATA key);
+int tdb_store(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA dbuf, int flag);
+int tdb_append(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA new_dbuf);
+int tdb_close(TDB_CONTEXT *tdb);
+TDB_DATA tdb_firstkey(TDB_CONTEXT *tdb);
+TDB_DATA tdb_nextkey(TDB_CONTEXT *tdb, TDB_DATA key);
+int tdb_traverse(TDB_CONTEXT *tdb, tdb_traverse_func fn, void *state);
+int tdb_exists(TDB_CONTEXT *tdb, TDB_DATA key);
+int tdb_lockkeys(TDB_CONTEXT *tdb, u32 number, TDB_DATA keys[]);
+void tdb_unlockkeys(TDB_CONTEXT *tdb);
+int tdb_lockall(TDB_CONTEXT *tdb);
+void tdb_unlockall(TDB_CONTEXT *tdb);
+
+/* Low level locking functions: use with care */
+void tdb_set_lock_alarm(sig_atomic_t *palarm);
+int tdb_chainlock(TDB_CONTEXT *tdb, TDB_DATA key);
+int tdb_chainunlock(TDB_CONTEXT *tdb, TDB_DATA key);
+
+/* Debug functions. Not used in production. */
+void tdb_dump_all(TDB_CONTEXT *tdb);
+int tdb_printfreelist(TDB_CONTEXT *tdb);
+
+extern TDB_DATA tdb_null;
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif /* tdb.h */
index 0578c6ac10979e7646106f570773e877f100584d..9f2620d65b89f5fa0a5057a4479db560a40516b5 100644 (file)
@@ -2,7 +2,7 @@
 #ifndef _ATALK_UNICODE_H
 #define _ATALK_UNICODE_H 1
 
-
+#include <atalk/list.h>
 
 #define ucs2_t u_int16_t
 
@@ -18,11 +18,34 @@ typedef struct {
         char *from_name, *to_name;
 } *atalk_iconv_t;
 
+#define CHARSET_CLIENT 1
+#define CHARSET_VOLUME 2
+#define CHARSET_PRECOMPOSED 4
+#define CHARSET_DECOMPOSED  8
+#define CHARSET_MULTIBYTE   16
+#define CHARSET_WIDECHAR    32
+#define CHARSET_ICONV      64
+
+#define IGNORE_CHAR    '_'
+
+/* conversion flags */
+#define CONV_IGNORE            (1<<0) /* ignore EILSEQ, replace with IGNORE_CHAR */
+#define CONV_ESCAPEHEX         (1<<1) /* escape unconvertable chars with :[UCS2HEX] */
+#define CONV_ESCAPEDOTS                (1<<2) /* escape leading dots with :2600 */
+#define CONV_UNESCAPEHEX       (1<<3) 
+#define CONV_TOUPPER           (1<<4) /* convert to UPPERcase */
+#define CONV_TOLOWER           (1<<5) /* convert to lowercase */
+#define CONV_PRECOMPOSE                (1<<6) /* precompose */
+#define CONV_DECOMPOSE         (1<<7) /* precompose */
+
+/* conversion return flags */
+#define CONV_REQMANGLE (1<<14) /* mangling of returned name is required */
+#define CONV_REQESCAPE (1<<15) /* espace unconvertable chars with :[UCS2HEX] */
 
 /* this defines the charset types used in samba */
-typedef enum {CH_UCS2=0, CH_UTF8=1, CH_MAC=2, CH_UNIX=3} charset_t;
+typedef enum {CH_UCS2=0, CH_UTF8=1, CH_MAC=2, CH_UNIX=3, CH_UTF8_MAC=4} charset_t;
 
-#define NUM_CHARSETS 4
+#define NUM_CHARSETS 5
 
 /*
  *   for each charset we have a function that pulls from that charset to
@@ -31,10 +54,12 @@ typedef enum {CH_UCS2=0, CH_UTF8=1, CH_MAC=2, CH_UNIX=3} charset_t;
 
 struct charset_functions {
         const char *name;
+       const long kTextEncoding;
         size_t (*pull)(void *, char **inbuf, size_t *inbytesleft,
                                    char **outbuf, size_t *outbytesleft);
         size_t (*push)(void *, char **inbuf, size_t *inbytesleft,
                                    char **outbuf, size_t *outbytesleft);
+       u_int32_t flags;
         struct charset_functions *prev, *next;
 };
 
@@ -43,6 +68,7 @@ extern atalk_iconv_t  atalk_iconv_open __P((const char *, const char *));
 extern size_t          atalk_iconv __P((atalk_iconv_t, const char **, size_t *, char **, size_t *));
 extern size_t          atalk_iconv_ignore __P((atalk_iconv_t, const char **, size_t *, char **, size_t *, int*));
 extern int             atalk_iconv_close __P((atalk_iconv_t));
+extern struct charset_functions *find_charset_functions(const char *name);
 
 extern ucs2_t  toupper_w  __P((ucs2_t));
 extern ucs2_t  tolower_w  __P((ucs2_t));
@@ -64,8 +90,8 @@ extern ucs2_t         *strncpy_w __P((ucs2_t *, const ucs2_t *, const size_t));
 extern ucs2_t  *strncat_w __P((ucs2_t *, const ucs2_t *, const size_t));
 extern ucs2_t  *strcat_w  __P((ucs2_t *, const ucs2_t *));
 
-extern char    *precompose_w __P((ucs2_t *, size_t, size_t *));
-extern char    *decompose_w  __P((ucs2_t *, size_t, size_t *));
+extern size_t  precompose_w __P((ucs2_t *, size_t, ucs2_t *,size_t *));
+extern size_t  decompose_w  __P((ucs2_t *, size_t, ucs2_t *,size_t *));
 extern size_t  utf8_charlen __P(( char* ));
 extern size_t  utf8_strlen_validate __P(( char *));
 
@@ -79,6 +105,8 @@ extern size_t         mac_strupper __P((const char *, size_t, char *, size_t));
 extern size_t   mac_strlower __P((const char *, size_t, char *, size_t));
 extern size_t  unix_strupper __P((const char *, size_t, char *, size_t));
 extern size_t  unix_strlower __P((const char *, size_t, char *, size_t));
+extern size_t  charset_strupper __P((charset_t, const char *, size_t, char *, size_t));
+extern size_t  charset_strlower __P((charset_t, const char *, size_t, char *, size_t));
 
 extern size_t  mac_to_ucs2_allocate __P((ucs2_t **dest, const char *src));
 extern size_t  mac_to_utf8_allocate __P((char **dest, const char *src));
@@ -87,6 +115,12 @@ extern size_t       utf8_to_mac_allocate __P((void **dest, const char *src));
 
 extern size_t  utf8_to_mac __P((char *, size_t, char *, size_t));
 extern size_t  utf8_to_mac_charset __P((charset_t, char *, size_t, char *, size_t, int*));
+extern size_t  vol_to_mac_charset __P((charset_t, charset_t, char *, size_t, char *, size_t, int*));
+extern size_t  mac_to_vol_charset __P((charset_t, charset_t, char *, size_t, char *, size_t));
+extern size_t  convert_charset __P((charset_t, charset_t, char *, size_t, char *, size_t, u_int16_t *));
+
+extern size_t   encode_cap __P((charset_t, char*, size_t, char*, size_t));
+extern size_t   decode_cap __P((charset_t, char*, size_t, char*, size_t, u_int16_t *));
 
 extern size_t  utf8_precompose __P(( char *, size_t, char *, size_t));
 extern size_t  utf8_decompose  __P(( char *, size_t, char *, size_t));
index 8dc3a7a66268c7d687df9d2025ea122563767fe6..77f521e45ff33472a8dfb553e80cb6cf37b10a3c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: util.h,v 1.7 2002-02-01 07:03:49 morgana Exp $
+ * $Id: util.h,v 1.7.10.1 2003-09-09 16:42:20 didg Exp $
  */
 
 #ifndef _ATALK_UTIL_H
@@ -25,6 +25,7 @@ extern int strdiacasecmp  __P((const char *, const char *));
 extern int strndiacasecmp __P((const char *, const char *, size_t));
 extern pid_t server_lock  __P((char * /*program*/, char * /*file*/, 
                               int /*debug*/));
+extern void fault_setup          __P((void (*fn)(void *)));
 #define server_unlock(x)  (unlink(x))
 
 #ifndef HAVE_DLFCN_H
index 7ac776c1acf5017cc272df5daf1d51fd3bd7e567..763c5b95978f2bffeba9272ee2dd3e23c1765c92 100644 (file)
@@ -1,6 +1,6 @@
 # Makefile.am for libatalk/
 
-SUBDIRS = adouble asp atp compat cnid dsi nbp netddp util unicode
+SUBDIRS = adouble asp atp compat cnid dsi nbp netddp util tdb unicode
 
 lib_LTLIBRARIES = libatalk.la
 
@@ -14,6 +14,7 @@ LIBATALK_DEPS = \
        nbp/libnbp.la           \
        netddp/libnetddp.la     \
        util/libutil.la         \
+        tdb/libtdb.la           \
        unicode/libunicode.la
 
 libatalk_la_SOURCES = dummy.c
index 947ba9123e562a8866c6c856411fa8a5486572b1..725286cf8e572ff08d8c50afaab810b11e8b6f33 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: ad_attr.c,v 1.4 2002-09-29 17:39:59 didg Exp $
+ * $Id: ad_attr.c,v 1.4.8.1 2003-09-09 16:42:21 didg Exp $
  */
 
 #ifdef HAVE_CONFIG_H
@@ -43,3 +43,28 @@ int ad_setattr(const struct adouble *ad, const u_int16_t attr)
 
   return 0;
 }
+
+/* -------------- 
+ * save file/folder ID in AppleDoubleV2 netatalk private parameters
+*/
+#if AD_VERSION == AD_VERSION2
+int ad_setid (struct adouble *adp, const struct stat *st, const u_int32_t id, const void *stamp)
+{
+    if (adp->ad_flags == AD_VERSION2 && sizeof(dev_t) == ADEDLEN_PRIVDEV && sizeof(ino_t) == ADEDLEN_PRIVINO) 
+    {
+        ad_setentrylen( adp, ADEID_PRIVDEV, sizeof(dev_t));
+        memcpy(ad_entry( adp, ADEID_PRIVDEV ), &st->st_dev, sizeof(dev_t));
+
+        ad_setentrylen( adp, ADEID_PRIVINO, sizeof(ino_t));
+        memcpy(ad_entry( adp, ADEID_PRIVINO ), &st->st_ino, sizeof(ino_t));
+
+        ad_setentrylen( adp, ADEID_DID, sizeof(id));
+        memcpy(ad_entry( adp, ADEID_DID ), &id, sizeof(id));
+
+        ad_setentrylen( adp, ADEID_PRIVSYN, ADEDLEN_PRIVSYN);
+        memcpy(ad_entry( adp, ADEID_PRIVSYN ), stamp, ADEDLEN_PRIVSYN);
+    }
+    return 0;
+}
+
+#endif
index 7eb6fba3d16783b24cc35aa627e65d70214ba534..87006a8f601988e11e138f55ef95c56c4fa405b9 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: ad_flush.c,v 1.6 2003-01-28 15:30:56 srittau Exp $
+ * $Id: ad_flush.c,v 1.6.6.1 2003-09-09 16:42:21 didg Exp $
  *
  * Copyright (c) 1990,1991 Regents of The University of Michigan.
  * All Rights Reserved.
 #include <errno.h>
 
 #include "ad_private.h"
+#if AD_VERSION == AD_VERSION1 
+
+#define EID_DISK(a) (a)
+
+#else
+
+static const u_int32_t set_eid[] = {
+0,1,2,3,4,5,6,7,8,
+9,10,11,12,13,14,15,
+AD_DEV, AD_INO, AD_SYN
+};
+
+#define EID_DISK(a) (set_eid[a])
+#endif
 
 /* rebuild the header */
 void ad_rebuild_header(struct adouble *ad)
@@ -67,7 +81,7 @@ void ad_rebuild_header(struct adouble *ad)
       if ( ad->ad_eid[ eid ].ade_off == 0 ) {
        continue;
       }
-      temp = htonl( eid );
+      temp = htonl( EID_DISK(eid) );
       memcpy(buf, &temp, sizeof( temp ));
       buf += sizeof( temp );
 
index 64f9ea3d4c106e2eb39f453b4eac8a21b60c8e84..b66fca0475349c143889a46570cbe2727bb7b9af 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: ad_open.c,v 1.30 2003-04-10 22:58:42 didg Exp $
+ * $Id: ad_open.c,v 1.30.6.1 2003-09-09 16:42:21 didg Exp $
  *
  * Copyright (c) 1999 Adrian Sun (asun@u.washington.edu)
  * Copyright (c) 1990,1991 Regents of The University of Michigan.
@@ -97,7 +97,6 @@
 #undef ADEDOFF_FILEI
 #endif /* ADEDOFF_FILEI */
 
-#define ADEID_NUM_V1         5
 #define ADEDOFF_NAME_V1             (AD_HEADER_LEN + ADEID_NUM_V1*AD_ENTRY_LEN)
 #define ADEDOFF_COMMENT_V1   (ADEDOFF_NAME_V1 + ADEDLEN_NAME)
 #define ADEDOFF_FILEI        (ADEDOFF_COMMENT_V1 + ADEDLEN_COMMENT)
 /* i stick things in a slightly different order than their eid order in 
  * case i ever want to separate RootInfo behaviour from the rest of the 
  * stuff. */
-#define ADEID_NUM_V2         9
 #define ADEDOFF_NAME_V2      (AD_HEADER_LEN + ADEID_NUM_V2*AD_ENTRY_LEN)
 #define ADEDOFF_COMMENT_V2   (ADEDOFF_NAME_V2 + ADEDLEN_NAME)
 #define ADEDOFF_FILEDATESI   (ADEDOFF_COMMENT_V2 + ADEDLEN_COMMENT)
 #define ADEDOFF_AFPFILEI     (ADEDOFF_DID + ADEDLEN_DID)
 #define ADEDOFF_SHORTNAME    (ADEDOFF_AFPFILEI + ADEDLEN_AFPFILEI)
 #define ADEDOFF_PRODOSFILEI  (ADEDOFF_SHORTNAME + ADEDLEN_SHORTNAME)
-#define ADEDOFF_RFORK_V2     (ADEDOFF_PRODOSFILEI + ADEDLEN_PRODOSFILEI)
-
+#define ADEDOFF_PRIVDEV      (ADEDOFF_PRODOSFILEI + ADEDLEN_PRODOSFILEI)
+#define ADEDOFF_PRIVINO      (ADEDOFF_PRIVDEV + ADEDLEN_PRIVDEV)
+#define ADEDOFF_PRIVSYN      (ADEDOFF_PRIVINO + ADEDLEN_PRIVINO)
 
+#define ADEDOFF_RFORK_V2     (ADEDOFF_PRIVSYN + ADEDLEN_PRIVSYN)
 
 /* we keep local copies of a bunch of stuff so that we can initialize things 
  * correctly. */
@@ -149,17 +149,39 @@ struct entry {
   u_int32_t id, offset, len;
 };
 
-#if AD_VERSION == AD_VERSION1 
-static const struct entry entry_order[] = {
-  {ADEID_NAME, ADEDOFF_NAME_V1, ADEDLEN_INIT},
-  {ADEID_COMMENT, ADEDOFF_COMMENT_V1, ADEDLEN_INIT},
-  {ADEID_FILEI, ADEDOFF_FILEI, ADEDLEN_FILEI},
-  {ADEID_FINDERI, ADEDOFF_FINDERI_V1, ADEDLEN_FINDERI},
-  {ADEID_RFORK, ADEDOFF_RFORK_V1, ADEDLEN_INIT},
+static const struct entry entry_order1[ADEID_NUM_V1 +1] = {
+  {ADEID_NAME,    ADEDOFF_NAME_V1,    ADEDLEN_INIT},      /* 3 */
+  {ADEID_COMMENT, ADEDOFF_COMMENT_V1, ADEDLEN_INIT},      /* 4 */
+  {ADEID_FILEI,   ADEDOFF_FILEI,      ADEDLEN_FILEI},     /* 7 */
+  {ADEID_FINDERI, ADEDOFF_FINDERI_V1, ADEDLEN_FINDERI},   /* 9 */
+  {ADEID_RFORK,   ADEDOFF_RFORK_V1,   ADEDLEN_INIT},      /* 2 */
   {0, 0, 0}
 };
+
+#if AD_VERSION == AD_VERSION1 
+#define DISK_EID(ad, a) (a)
+
 #else /* AD_VERSION == AD_VERSION2 */
-static const struct entry entry_order[] = {
+
+static u_int32_t get_eid(struct adouble *ad, u_int32_t eid) 
+{
+    if (eid <= 15)
+        return eid;
+    if (ad->ad_version == AD_VERSION1)
+        return 0;
+    if (eid == AD_DEV)
+        return ADEID_PRIVDEV;
+    if (eid == AD_INO)
+        return ADEID_PRIVINO;
+    if (eid == AD_SYN)
+        return ADEID_PRIVSYN;
+
+    return 0;
+}
+
+#define DISK_EID(ad, a) get_eid(ad, a)
+
+static const struct entry entry_order2[ADEID_NUM_V2 +1] = {
   {ADEID_NAME, ADEDOFF_NAME_V2, ADEDLEN_INIT},
   {ADEID_COMMENT, ADEDOFF_COMMENT_V2, ADEDLEN_INIT},
   {ADEID_FILEDATESI, ADEDOFF_FILEDATESI, ADEDLEN_FILEDATESI},
@@ -168,15 +190,19 @@ static const struct entry entry_order[] = {
   {ADEID_AFPFILEI, ADEDOFF_AFPFILEI, ADEDLEN_AFPFILEI},
   {ADEID_SHORTNAME, ADEDOFF_SHORTNAME, ADEDLEN_INIT},
   {ADEID_PRODOSFILEI, ADEDOFF_PRODOSFILEI, ADEDLEN_PRODOSFILEI},
+  {ADEID_PRIVDEV,     ADEDOFF_PRIVDEV, ADEDLEN_INIT},
+  {ADEID_PRIVINO,     ADEDOFF_PRIVINO, ADEDLEN_INIT},
+  {ADEID_PRIVSYN,     ADEDOFF_PRIVSYN, ADEDLEN_INIT},
   {ADEID_RFORK, ADEDOFF_RFORK_V2, ADEDLEN_INIT},
+
   {0, 0, 0}
 };
 #endif /* AD_VERSION == AD_VERSION2 */
 
 #if AD_VERSION == AD_VERSION2
 
-
-static __inline__ int ad_v1tov2(struct adouble *ad, const char *path)
+/* FIXME work only if < 2GB */
+static int ad_v1tov2(struct adouble *ad, const char *path)
 {
   struct stat st;
   u_int16_t attr;
@@ -187,6 +213,17 @@ static __inline__ int ad_v1tov2(struct adouble *ad, const char *path)
   if (!path || (ad->ad_version != AD_VERSION1))
     return 0;
 
+  /* we want version1 anyway */
+  if (ad->ad_flags == AD_VERSION1)
+      return 0;
+
+
+  if (!ad->ad_flags) {
+      /* we don't really know what we want */
+      ad->ad_flags = ad->ad_version;
+      return 0;
+  }
+
   /* convert from v1 to v2. what does this mean?
    *  1) change FILEI into FILEDATESI
    *  2) create space for SHORTNAME, AFPFILEI, DID, and PRODOSI
@@ -209,6 +246,10 @@ static __inline__ int ad_v1tov2(struct adouble *ad, const char *path)
       ftruncate(fd, st.st_size + SHIFTDATA) < 0) {
     goto bail_open;
   }
+  if (st.st_size > 0x7fffffff) {
+      LOG(log_debug, logtype_default, "ad_v1tov2: file too big."); 
+      goto bail_truncate;
+  }
   
   /* last place for failure. */
   if ((void *) (buf = (char *) 
@@ -247,6 +288,13 @@ static __inline__ int ad_v1tov2(struct adouble *ad, const char *path)
   ad->ad_eid[ADEID_PRODOSFILEI].ade_off = ADEDOFF_PRODOSFILEI;
   ad->ad_eid[ADEID_PRODOSFILEI].ade_len = ADEDLEN_PRODOSFILEI;
   
+  ad->ad_eid[ADEID_PRIVDEV].ade_off = ADEDOFF_PRIVDEV;
+  ad->ad_eid[ADEID_PRIVDEV].ade_len = ADEDLEN_INIT;
+  ad->ad_eid[ADEID_PRIVINO].ade_off = ADEDOFF_PRIVINO;
+  ad->ad_eid[ADEID_PRIVINO].ade_len = ADEDLEN_INIT;
+  ad->ad_eid[ADEID_PRIVSYN].ade_off = ADEDOFF_PRIVSYN;
+  ad->ad_eid[ADEID_PRIVSYN].ade_len = ADEDLEN_INIT;
+  
   /* shift the old entries (NAME, COMMENT, FINDERI, RFORK) */
   ad->ad_eid[ADEID_NAME].ade_off = ADEDOFF_NAME_V2;
   ad->ad_eid[ADEID_COMMENT].ade_off = ADEDOFF_COMMENT_V2;
@@ -321,7 +369,7 @@ static void parse_entries(struct adouble *ad, char *buf,
     /* now, read in the entry bits */
     for (; nentries > 0; nentries-- ) {
        memcpy(&eid, buf, sizeof( eid ));
-       eid = ntohl( eid );
+       eid = DISK_EID(ad, ntohl( eid ));
        buf += sizeof( eid );
        memcpy(&off, buf, sizeof( off ));
        off = ntohl( off );
@@ -520,8 +568,9 @@ char
 {
     static char                modebuf[ MAXPATHLEN + 1];
     char               *slash;
+    size_t              len;
 
-    if ( strlen( path ) >= MAXPATHLEN ) {
+    if ( (len = strlen( path )) >= MAXPATHLEN ) {
         errno = ENAMETOOLONG;
        return NULL;  /* can't do it */
     }
@@ -532,7 +581,18 @@ char
      * For a path which is just a filename, use "." instead.
      */
     strcpy( modebuf, path );
-    if (NULL != ( slash = strrchr( modebuf, '/' )) ) {
+    slash = strrchr( modebuf, '/' );
+    /* is last char a '/' */
+    if (slash && slash[1] == 0) {
+        while (modebuf < slash && slash[-1] == '/') {
+            --slash;
+        }
+        if (modebuf < slash) {
+           *slash = '\0';              /* remove pathname component */
+           slash = strrchr( modebuf, '/' );
+       }
+    }
+    if (slash) {
        *slash = '\0';          /* remove pathname component */
     } else {
        modebuf[0] = '.';       /* use current directory */
@@ -559,7 +619,7 @@ uid_t ad_getfuid(void)
 /* ---------------- 
    return inode of path parent directory
 */
-static int ad_stat(const char *path, struct stat *stbuf)
+int ad_stat(const char *path, struct stat *stbuf)
 {
     char                *p;
 
@@ -670,7 +730,14 @@ static int new_rfork(const char *path, struct adouble *ad, int adflags);
 #else 
 #define AD_SET(a) a = 0
 #endif
-/*
+
+void ad_init(struct adouble *ad, int flags)
+{
+    memset( ad, 0, sizeof( struct adouble ) );
+    ad->ad_flags = flags;
+}
+
+/* -------------------
  * It's not possible to open the header file O_RDONLY -- the read
  * will fail and return an error. this refcounts things now. 
  */
@@ -858,12 +925,20 @@ static int new_rfork(const char *path, struct adouble *ad, int adflags)
     struct stat         st;
 
     ad->ad_magic = AD_MAGIC;
+    ad->ad_version = ad->ad_flags;
+    if (!ad->ad_version)
     ad->ad_version = AD_VERSION;
 
     memset(ad->ad_filler, 0, sizeof( ad->ad_filler ));
     memset(ad->ad_data, 0, sizeof(ad->ad_data));
 
-    eid = entry_order;
+#if AD_VERSION == AD_VERSION2
+    if (ad->ad_version == AD_VERSION2)
+       eid = entry_order2;
+    else
+#endif
+       eid = entry_order1;
+
     while (eid->id) {
         ad->ad_eid[eid->id].ade_off = eid->offset;
        ad->ad_eid[eid->id].ade_len = eid->len;
@@ -871,7 +946,7 @@ static int new_rfork(const char *path, struct adouble *ad, int adflags)
     }
            
     /* put something sane in the directory finderinfo */
-    if (adflags & ADFLAGS_DIR) {
+    if ((adflags & ADFLAGS_DIR)) {
         /* set default view */
        ashort = htons(FINDERINFO_CLOSEDVIEW);
        memcpy(ad_entry(ad, ADEID_FINDERI) + FINDERINFO_FRVIEWOFF, 
index c7fabbf5a9abe9e2f20b9baa2098a24ace971d4d..42a54555ccb2ea8cac984394ee2068c04069978e 100644 (file)
@@ -3,10 +3,20 @@
 CFLAGS = @CFLAGS@ @BDB_CFLAGS@
 LIBS = @LIBS@ @BDB_LIBS@
 
+SUBDIRS = db3 last mtab cdb dbd hash tdb
+
 noinst_LTLIBRARIES = libcnid.la
 
-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
+LIBCNID_DEPS = db3/libcnid_db3.la \
+               cdb/libcnid_cdb.la \
+               last/libcnid_last.la \
+               mtab/libcnid_mtab.la \
+               hash/libcnid_hash.la \
+               tdb/libcnid_tdb.la \
+               dbd/libcnid_dbd.la 
+
+libcnid_la_SOURCES = cnid.c cnid_init.c
+libcnid_la_LIBADD = $(LIBCNID_DEPS)
 
-noinst_HEADERS = cnid_meta.h cnid_private.h 
+EXTRA_DIST = README
 
-EXTRA_DIST = README cnid_meta.c cnid_nextid.c
index b39889bfcea84934f0e1f38dc3b79a0d91be168e..b78f9af8a7de434e40f9031fea6a9609a1a2c372 100644 (file)
@@ -1,35 +1,50 @@
-the catalog database keeps track of three mappings:
-    CNID     -> dev/ino and did/name
-    dev/ino  -> CNID
-    did/name -> CNID
-
-dev/ino is used to keep track of magically moved files. did/name is
-for quick lookups of CNIDs. 
-
-NOTE: the database will append a nul byte to the end of name. in
-addition, name should be given as it appears on disk. this allows the
-creation of cnid updating/cleaning programs that don't have to deal
-with knowing what the particular codepage is.
-
-here's the ritual:
-       1) open a volume. call cnid_open.
-       2) every time you need a CNID, call cnid_add(). it will
-          automatically look for an existing cnid and add a new one
-          if one isn't already there. you can pass a hint if you
-          want. the only use this has right now is to enable
-          consistency between AFP and HFS. in the future, it would
-          allow people to write conversion utilities that
-          pre-instantiate a database without needing to re-assign
-          CNIDs.
-       3) if you want to just look for a CNID without automatically
-          adding one in, you have two choices:
-            a) cnid_resolve takes a CNID, returns name, and
-               over-writes the CNID given with the parent DID. this
-               is good for FPResolveID.
-             b) cnid_lookup returns a CNID corresponding to the
-               dev/ino,did/name keys. it will auto-update the catalog
-               database if there's a discrepancy. 
-               NOTE: cnid_add calls this before adding a new CNID. 
-       4) when you delete a file or directory, you need to call
-          cnid_delete with the CNID for that file/directory.
-       5) call cnid_close when closing the volume.
+  
+  CNID back-end refactoring
+  
+This patch allows to compile all DID schemes into 
+afpd  binary and then select desired schemes at runtime,
+per volume.
+
+
+Changes:
+
+Libatalk/cnid directory as been restructured. Now it contains
+subdirectories representing particular back-end types and a
+simple cnid-object factory (cnid.c and cnid_init.c).
+
+All CNID functions have been grouped into a structure which 
+contains function pointers and some data. Main afpd code uses
+them in a object manner rather than structural: it calls cnid 
+functions through fields of cnid_db structure. 
+
+Actually there are standard backends: transactional db3, cdb, 
+last and mtab (I'm not sure how to call mtab - it does some magic
+with dev/inode numbers, but mtab has been removed some time ago).
+
+Changes in ./configure options:
+
+Options --with-did=xxx, --with-cdb have been removed.
+
+Instead, there are following options:
+--with-cnid-cdb-backend    - compile DB3 Concurrent Datastore backend
+--with-cnid-db3-backend    - compile DB3 transactional backend
+--with-cnid-last-backend   - compile LAST backend
+--with-cnid-mtab-backend   - compile MTAB backend
+--with-cnid-default-backend={cdb|db3|last|mtab}
+
+Some of the backend names should be (propably) changed (mtab? db3?).
+
+AppleVolumes.default file has a new option: -cnidscheme:{db3|cdb|last|mtab}
+
+Again, sorry for this weird naming. I didn't care about it while coding,
+some cleanups have to be done later.
+
+Was tested mainly against test-suite and against MacOS 9 client.
+
+Things to do:
+- some really reliable kind of backend should be developed
+- file-name mangling should be runtime option
+- naming- and code cleanups are still needed
+- optional dynamic CNID backend loading - lower priority, static linking
+option has still to be available
+
diff --git a/libatalk/cnid/cdb/Makefile.am b/libatalk/cnid/cdb/Makefile.am
new file mode 100644 (file)
index 0000000..8a30dcd
--- /dev/null
@@ -0,0 +1,20 @@
+# Makefile.am for libatalk/cnid/
+
+CFLAGS = @CFLAGS@ @BDB_CFLAGS@
+LIBS = @LIBS@ @BDB_LIBS@
+
+noinst_LTLIBRARIES = libcnid_cdb.la
+
+libcnid_cdb_la_SOURCES = cnid_cdb_add.c \
+                        cnid_cdb_close.c \
+                        cnid_cdb_delete.c \
+                        cnid_cdb_get.c \
+                        cnid_cdb_lookup.c \
+                        cnid_cdb_open.c \
+                        cnid_cdb_resolve.c \
+                        cnid_cdb_update.c \
+                        cnid_cdb.h
+
+noinst_HEADERS = cnid_cdb_meta.h cnid_cdb_private.h 
+
+EXTRA_DIST = README cnid_cdb_meta.c cnid_cdb_nextid.c
diff --git a/libatalk/cnid/cdb/README b/libatalk/cnid/cdb/README
new file mode 100644 (file)
index 0000000..b39889b
--- /dev/null
@@ -0,0 +1,35 @@
+the catalog database keeps track of three mappings:
+    CNID     -> dev/ino and did/name
+    dev/ino  -> CNID
+    did/name -> CNID
+
+dev/ino is used to keep track of magically moved files. did/name is
+for quick lookups of CNIDs. 
+
+NOTE: the database will append a nul byte to the end of name. in
+addition, name should be given as it appears on disk. this allows the
+creation of cnid updating/cleaning programs that don't have to deal
+with knowing what the particular codepage is.
+
+here's the ritual:
+       1) open a volume. call cnid_open.
+       2) every time you need a CNID, call cnid_add(). it will
+          automatically look for an existing cnid and add a new one
+          if one isn't already there. you can pass a hint if you
+          want. the only use this has right now is to enable
+          consistency between AFP and HFS. in the future, it would
+          allow people to write conversion utilities that
+          pre-instantiate a database without needing to re-assign
+          CNIDs.
+       3) if you want to just look for a CNID without automatically
+          adding one in, you have two choices:
+            a) cnid_resolve takes a CNID, returns name, and
+               over-writes the CNID given with the parent DID. this
+               is good for FPResolveID.
+             b) cnid_lookup returns a CNID corresponding to the
+               dev/ino,did/name keys. it will auto-update the catalog
+               database if there's a discrepancy. 
+               NOTE: cnid_add calls this before adding a new CNID. 
+       4) when you delete a file or directory, you need to call
+          cnid_delete with the CNID for that file/directory.
+       5) call cnid_close when closing the volume.
diff --git a/libatalk/cnid/cdb/cnid_cdb.h b/libatalk/cnid/cdb/cnid_cdb.h
new file mode 100644 (file)
index 0000000..5ad0be7
--- /dev/null
@@ -0,0 +1,48 @@
+/* 
+ * interface for database access to cnids. i do it this way to abstract
+ * things a bit in case we want to change the underlying implementation.
+ */
+
+#ifndef _ATALK_CNID_CDB__H
+#define _ATALK_CNID_CDB__H 1
+
+#include <sys/cdefs.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <string.h>
+
+#include <netatalk/endian.h>
+#include <atalk/cnid.h>
+
+/* cnid_open.c */
+extern struct _cnid_module cnid_cdb_module;
+extern struct _cnid_db *cnid_cdb_open __P((const char *, mode_t));
+
+/* cnid_close.c */
+extern void cnid_cdb_close __P((struct _cnid_db *));
+
+/* cnid_add.c */
+extern cnid_t cnid_cdb_add __P((struct _cnid_db *, const struct stat *, const cnid_t,
+                           const char *, const int, cnid_t));
+
+/* cnid_get.c */
+extern cnid_t cnid_cdb_get __P((struct _cnid_db *, const cnid_t, const char *, const int)); 
+extern char *cnid_cdb_resolve __P((struct _cnid_db *, cnid_t *, void *, u_int32_t )); 
+extern cnid_t cnid_cdb_lookup __P((struct _cnid_db *, const struct stat *, const cnid_t,
+                              const char *, const int));
+
+/* cnid_update.c */
+extern int cnid_cdb_update __P((struct _cnid_db *, const cnid_t, const struct stat *,
+                           const cnid_t, const char *, int));
+
+/* cnid_delete.c */
+extern int cnid_cdb_delete __P((struct _cnid_db *, const cnid_t));
+
+/* cnid_nextid.c */
+extern cnid_t cnid_cdb_nextid __P((struct _cnid_db *));
+
+extern int cnid_cdb_lock   __P((void *));
+extern int cnid_cdb_unlock __P((void *));
+
+#endif /* include/atalk/cnid_cdb.h */
+
diff --git a/libatalk/cnid/cdb/cnid_cdb_add.c b/libatalk/cnid/cdb/cnid_cdb_add.c
new file mode 100644 (file)
index 0000000..6604401
--- /dev/null
@@ -0,0 +1,230 @@
+/*
+ * $Id: cnid_cdb_add.c,v 1.1.4.1 2003-09-09 16:42:21 didg Exp $
+ *
+ * Copyright (c) 1999. Adrian Sun (asun@zoology.washington.edu)
+ * All Rights Reserved. See COPYRIGHT.
+ *
+ * cnid_add (db, dev, ino, did, name, hint):
+ * add a name to the CNID database. we use both dev/ino and did/name
+ * to keep track of things.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#ifdef CNID_BACKEND_CDB
+
+#include <stdio.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <string.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif /* HAVE_FCNTL_H */
+#include <errno.h>
+#include <atalk/logger.h>
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif /* HAVE_SYS_TIME_H */
+
+#include <db.h>
+#include <netatalk/endian.h>
+
+#include <atalk/adouble.h>
+#include "cnid_cdb.h"
+#include <atalk/util.h>
+
+#include "cnid_cdb_private.h"
+
+    #define tid    NULL
+
+#ifdef ATACC
+char *make_cnid_data(const struct stat *st,const cnid_t did,
+                     const char *name, const int len)
+{
+    static char start[CNID_HEADER_LEN + MAXPATHLEN + 1];
+    char *buf = start  +CNID_LEN;
+    u_int32_t i;
+
+    if (len > MAXPATHLEN)
+        return NULL;
+
+    memcpy(buf, &st->st_dev, sizeof(st->st_dev));
+    buf += sizeof(st->st_dev);
+
+    i = htonl(st->st_ino);
+    memcpy(buf , &st->st_ino, sizeof(st->st_ino));
+    buf += sizeof(st->st_ino);
+
+    i = S_ISDIR(st->st_mode)?1:0;
+    i = htonl(i);
+    memcpy(buf, &i, sizeof(i));
+    buf += sizeof(i);
+    
+    /* did is already in network byte order */
+    memcpy(buf, &did, sizeof(did));
+    buf += sizeof(did);
+
+    memcpy(buf, name, len);
+    *(buf + len) = '\0';
+
+    return start;
+}    
+#endif
+
+extern int cnid_cdb_update(struct _cnid_db *cdb, const cnid_t id, const struct stat *st,
+                const cnid_t did, const char *name, const int len);
+
+/* ----------------------------- */
+static cnid_t get_cnid(CNID_private *db)
+{
+    DBT rootinfo_key, rootinfo_data;
+    DBC  *cursor;
+    int rc;
+    int flag;
+    cnid_t hint,id;
+    char buf[ROOTINFO_DATALEN];      
+     
+    if ((rc = db->db_cnid->cursor(db->db_cnid, NULL, &cursor, DB_WRITECURSOR) ) != 0) {
+        LOG(log_error, logtype_default, "get_cnid: Unable to get a cursor: %s", db_strerror(rc));
+        return CNID_INVALID;
+    }
+
+    memset(&rootinfo_key, 0, sizeof(rootinfo_key));
+    memset(&rootinfo_data, 0, sizeof(rootinfo_data));
+    rootinfo_key.data = ROOTINFO_KEY;
+    rootinfo_key.size = ROOTINFO_KEYLEN;
+
+    switch (rc = cursor->c_get(cursor, &rootinfo_key, &rootinfo_data, DB_SET)) {
+    case 0:
+        memcpy(&hint, (char *)rootinfo_data.data +CNID_TYPE_OFS, sizeof(hint));
+        id = ntohl(hint);
+        /* If we've hit the max CNID allowed, we return a fatal error.  CNID
+         * needs to be recycled before proceding. */
+        if (++id == CNID_INVALID) {
+            LOG(log_error, logtype_default, "cnid_add: FATAL: CNID database has reached its limit.");
+            errno = CNID_ERR_MAX;
+            goto cleanup;
+        }
+        hint = htonl(id);
+        flag = DB_CURRENT;
+        break;
+    case DB_NOTFOUND:
+        hint = htonl(CNID_START);
+        flag = DB_KEYFIRST;
+        break;
+    default:
+        LOG(log_error, logtype_default, "cnid_add: Unable to lookup rootinfo: %s", db_strerror(rc));
+       errno = CNID_ERR_DB; 
+        goto cleanup;
+    }
+    
+    memcpy(buf, ROOTINFO_DATA, ROOTINFO_DATALEN);
+    rootinfo_data.data = buf;
+    rootinfo_data.size = ROOTINFO_DATALEN;
+    memcpy((char *)rootinfo_data.data +CNID_TYPE_OFS, &hint, sizeof(hint));
+    
+    switch (rc = cursor->c_put(cursor, &rootinfo_key, &rootinfo_data, flag)) {
+    case 0:
+        break;
+    default:
+        LOG(log_error, logtype_default, "cnid_add: Unable to update rootinfo: %s", db_strerror(rc));
+       errno = CNID_ERR_DB; 
+        goto cleanup;
+    }
+    if ((rc = cursor->c_close(cursor)) != 0) {
+        LOG(log_error, logtype_default, "get_cnid: Unable to close cursor: %s", db_strerror(rc));
+       errno = CNID_ERR_DB; 
+        return CNID_INVALID;
+    }
+    return hint;
+cleanup:
+    if ((rc = cursor->c_close(cursor)) != 0) {
+        LOG(log_error, logtype_default, "get_cnid: Unable to close cursor: %s", db_strerror(rc));
+        return CNID_INVALID;
+    }
+    return CNID_INVALID;
+}
+
+/* ------------------------ */
+cnid_t cnid_cdb_add(struct _cnid_db *cdb, const struct stat *st,
+                const cnid_t did, const char *name, const int len,
+                cnid_t hint)
+{
+    CNID_private *db;
+    DBT key, data;
+    cnid_t id;
+    int rc;
+
+    if (!cdb || !(db = cdb->_private) || !st || !name) {
+        errno = CNID_ERR_PARAM;
+        return CNID_INVALID;
+    }
+
+    /* Do a lookup. */
+    id = cnid_cdb_lookup(cdb, st, did, name, len);
+    /* ... Return id if it is valid, or if Rootinfo is read-only. */
+    if (id || (db->flags & CNIDFLAG_DB_RO)) {
+#ifdef DEBUG
+        LOG(log_info, logtype_default, "cnid_add: Looked up did %u, name %s as %u", ntohl(did), name, ntohl(id));
+#endif
+        return id;
+    }
+
+    /* Initialize our DBT data structures. */
+    memset(&key, 0, sizeof(key));
+    memset(&data, 0, sizeof(data));
+
+    if ((data.data = make_cnid_data(st, did, name, len)) == NULL) {
+        LOG(log_error, logtype_default, "cnid_add: Path name is too long");
+        errno = CNID_ERR_PATH;
+        return CNID_INVALID;
+    }
+    data.size = CNID_HEADER_LEN + len + 1;
+
+    if ((hint = get_cnid(db)) == 0) {
+         errno = CNID_ERR_DB;
+         return CNID_INVALID;
+    }
+    memcpy(data.data, &hint, sizeof(hint));
+    
+    key.data = &hint;
+    key.size = sizeof(hint);
+
+    /* Now we need to add the CNID data to the databases. */
+    if ((rc = db->db_cnid->put(db->db_cnid, tid, &key, &data, DB_NOOVERWRITE))) {
+        if (rc == EINVAL) {
+            /* if we have a duplicate
+             * on cnid it's a fatal error.
+             * on dev:inode
+             *   - leftover should have been delete before.
+             *   - a second process already updated the db
+             *   - it's a new file eg our file is already deleted and replaced
+             * on did:name leftover
+            */
+            if (cnid_cdb_update(cdb, hint, st, did, name, len)) {
+                errno = CNID_ERR_DB;
+                return CNID_INVALID;
+            }
+        }
+        else {
+            LOG(log_error, logtype_default
+                   , "cnid_add: Failed to add CNID for %s to database using hint %u: %s", 
+                   name, ntohl(hint), db_strerror(rc));  
+            errno = CNID_ERR_DB;
+            return CNID_INVALID;
+        }
+    }
+
+#ifdef DEBUG
+    LOG(log_info, logtype_default, "cnid_add: Returned CNID for did %u, name %s as %u", ntohl(did), name, ntohl(hint));
+#endif
+
+    return hint;
+}
+
+#endif /* CNID_BACKEND_CDB */
diff --git a/libatalk/cnid/cdb/cnid_cdb_close.c b/libatalk/cnid/cdb/cnid_cdb_close.c
new file mode 100644 (file)
index 0000000..a777319
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * $Id: cnid_cdb_close.c,v 1.1.4.1 2003-09-09 16:42:21 didg Exp $
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#ifdef CNID_BACKEND_CDB
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif /* HAVE_FCNTL_H */
+#include <stdlib.h>
+#include <atalk/logger.h>
+#include <db.h>
+#include <errno.h>
+#include <string.h>
+
+#include "cnid_cdb_private.h"
+#include "cnid_cdb.h"
+
+void cnid_cdb_close(struct _cnid_db *cdb) {
+    CNID_private *db;
+
+    if (!cdb) {
+           LOG(log_error, logtype_afpd, "cnid_close called with NULL argument !");
+           return;
+    }
+
+    if (!(db = cdb->_private)) {
+        return;
+    }
+    db->db_didname->sync(db->db_didname, 0); 
+    db->db_devino->sync(db->db_devino, 0);
+    db->db_cnid->sync(db->db_cnid, 0);
+    
+    db->db_didname->close(db->db_didname, 0);
+    db->db_devino->close(db->db_devino, 0);
+    db->db_cnid->close(db->db_cnid, 0);
+
+    db->dbenv->close(db->dbenv, 0);
+
+    free(db);
+    free(cdb->volpath);
+    free(cdb);
+}
+
+#endif /* CNID_BACKEND_CDB */
diff --git a/libatalk/cnid/cdb/cnid_cdb_delete.c b/libatalk/cnid/cdb/cnid_cdb_delete.c
new file mode 100644 (file)
index 0000000..5281b12
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * $Id: cnid_cdb_delete.c,v 1.1.4.1 2003-09-09 16:42:21 didg Exp $
+ *
+ * Copyright (c) 1999. Adrian Sun (asun@zoology.washington.edu)
+ * All Rights Reserved. See COPYRIGHT.
+ *
+ * cnid_delete: delete a CNID from the database 
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#ifdef CNID_BACKEND_CDB
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <atalk/logger.h>
+
+#include <db.h>
+#include <netatalk/endian.h>
+#include <atalk/adouble.h>
+#include "cnid_cdb.h"
+
+#include "cnid_cdb_private.h"
+
+#define tid    NULL
+
+int cnid_cdb_delete(struct _cnid_db *cdb, const cnid_t id) {
+    CNID_private *db;
+    DBT key;
+    int rc;
+
+    if (!cdb || !(db = cdb->_private) || !id || (db->flags & CNIDFLAG_DB_RO)) {
+        return -1;
+    }
+
+    memset(&key, 0, sizeof(key));
+
+    /* Get from ain CNID database. */
+    key.data = (cnid_t *)&id;
+    key.size = sizeof(id);
+    
+    if ((rc = db->db_cnid->del(db->db_cnid, tid, &key, 0))) {
+        LOG(log_error, logtype_default, "cnid_delete: Unable to delete CNID %u: %s",
+            ntohl(id), db_strerror(rc));
+    }
+    else {
+#ifdef DEBUG
+        LOG(log_info, logtype_default, "cnid_delete: Deleting CNID %u", ntohl(id));
+#endif
+    }
+    return rc;
+}
+
+#endif /* CNID_BACKEND_CDB */
diff --git a/libatalk/cnid/cdb/cnid_cdb_get.c b/libatalk/cnid/cdb/cnid_cdb_get.c
new file mode 100644 (file)
index 0000000..c6d538b
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * $Id: cnid_cdb_get.c,v 1.1.4.1 2003-09-09 16:42:21 didg Exp $
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#ifdef CNID_BACKEND_CDB
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <atalk/logger.h>
+#include <errno.h>
+
+#include <db.h>
+#include <netatalk/endian.h>
+#include <atalk/adouble.h>
+#include "cnid_cdb.h"
+
+#include "cnid_cdb_private.h"
+
+/* Return CNID for a given did/name. */
+cnid_t cnid_cdb_get(struct _cnid_db *cdb, const cnid_t did, const char *name,
+                const int len)
+{
+    char start[CNID_DID_LEN + MAXPATHLEN + 1], *buf;
+    CNID_private *db;
+    DBT key, data;
+    cnid_t id;
+    int rc;
+
+    if (!cdb || !(db = cdb->_private) || (len > MAXPATHLEN)) {
+        return 0;
+    }
+
+    memset(&key, 0, sizeof(key));
+    memset(&data, 0, sizeof(data));
+
+    buf = start;
+    memcpy(buf, &did, sizeof(did));
+    buf += sizeof(did);
+    memcpy(buf, name, len);
+    *(buf + len) = '\0'; /* Make it a C-string. */
+    key.data = start;
+    key.size = CNID_DID_LEN + len + 1;
+
+    while ((rc = db->db_didname->get(db->db_didname, NULL, &key, &data, 0))) {
+
+        if (rc != DB_NOTFOUND) {
+            LOG(log_error, logtype_default, "cnid_get: Unable to get CNID %u, name %s: %s",
+                ntohl(did), name, db_strerror(rc));
+        }
+
+        return 0;
+    }
+
+    memcpy(&id, data.data, sizeof(id));
+#ifdef DEBUG
+    LOG(log_info, logtype_default, "cnid_get: Returning CNID for %u, name %s as %u",
+        ntohl(did), name, ntohl(id));
+#endif
+    return id;
+}
+
+#endif /* CNID_BACKEND_CDB */
diff --git a/libatalk/cnid/cdb/cnid_cdb_lookup.c b/libatalk/cnid/cdb/cnid_cdb_lookup.c
new file mode 100644 (file)
index 0000000..325877e
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * $Id: cnid_cdb_lookup.c,v 1.1.4.1 2003-09-09 16:42:21 didg Exp $
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#ifdef CNID_BACKEND_CDB
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <atalk/logger.h>
+#include <errno.h>
+
+#include <db.h>
+#include <netatalk/endian.h>
+#include <atalk/adouble.h>
+#include "cnid_cdb.h"
+
+#include "cnid_cdb_private.h"
+
+#define LOGFILEMAX    100  /* kbytes */
+#define CHECKTIMEMAX   30  /* minutes */
+
+/* This returns the CNID corresponding to a particular file.  It will
+ * also fix up the various databases if there's a problem. */
+cnid_t cnid_cdb_lookup(struct _cnid_db *cdb, const struct stat *st, const cnid_t did,
+                   const char *name, const int len)
+{
+    char *buf;
+    CNID_private *db;
+    DBT key, diddata;
+    dev_t dev;
+    ino_t ino;  
+    cnid_t id = 0;
+    int rc;
+
+    if (!cdb || !(db = cdb->_private) || !st || !name) {
+        return 0;
+    }
+    
+    if ((buf = make_cnid_data(st, did, name, len)) == NULL) {
+        LOG(log_error, logtype_default, "cnid_lookup: Pathname is too long");
+        return 0;
+    }
+
+    memset(&key, 0, sizeof(key));
+    memset(&diddata, 0, sizeof(diddata));
+
+    /* Look for a CNID for our did/name */
+    key.data = buf +CNID_DID_OFS;
+    key.size = CNID_DID_LEN + len + 1;
+
+    memcpy(&dev, buf + CNID_DEV_OFS, sizeof(dev));
+    memcpy(&ino, buf + CNID_INO_OFS, sizeof(ino));
+
+    if (0 != (rc = db->db_didname->get(db->db_didname, NULL, &key, &diddata, 0 )) ) {
+        if (rc != DB_NOTFOUND) {
+           LOG(log_error, logtype_default, "cnid_lookup: Unable to get CNID did 0x%x, name %s: %s",
+               did, name, db_strerror(rc));
+        }
+        return 0;
+    }
+    memcpy(&id, diddata.data, sizeof(id));
+    /* if dev:ino the same */
+    if (!memcmp(&dev, (char *)diddata.data + CNID_DEV_OFS, sizeof(dev)) &&
+        !memcmp(&ino, (char *)diddata.data + CNID_INO_OFS, sizeof(ino))
+        /* FIXME and type are the same */
+       )
+    {
+        /* then it's what we are looking for */
+        return id;
+    }
+    /* with have a did:name but it's not one the same dev:inode
+     * it should be always a different file, but in moveandrename with cross/dev
+     * we don't update the db.
+    */
+    if (!memcmp(&dev, (char *)diddata.data + CNID_DEV_OFS, sizeof(dev)))
+       /* FIXME or diff type */
+    {
+       /* dev are the same so it's a copy */
+        return 0;
+    }
+    /* Fix up the database. */
+    cnid_cdb_update(cdb, id, st, did, name, len);
+
+#ifdef DEBUG
+    LOG(log_info, logtype_default, "cnid_lookup: Looked up did %u, name %s, as %u (needed update)", ntohl(did), name, ntohl(id));
+#endif
+    return id;
+}
+
+#endif /* CNID_BACKEND_CDB */
diff --git a/libatalk/cnid/cdb/cnid_cdb_meta.c b/libatalk/cnid/cdb/cnid_cdb_meta.c
new file mode 100644 (file)
index 0000000..fa8a47b
--- /dev/null
@@ -0,0 +1,9 @@
+/*
+ * $Id: cnid_cdb_meta.c,v 1.1.4.1 2003-09-09 16:42:21 didg Exp $
+ *
+ * Copyright (c) 1999. Adrian Sun (asun@zoology.washington.edu)
+ * All Rights Reserved. See COPYRIGHT.
+ *
+ * deal with metadata
+ *
+ */
diff --git a/libatalk/cnid/cdb/cnid_cdb_meta.h b/libatalk/cnid/cdb/cnid_cdb_meta.h
new file mode 100644 (file)
index 0000000..1255fe4
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * $Id: cnid_cdb_meta.h,v 1.1.4.1 2003-09-09 16:42:21 didg Exp $
+ */
+
+#define CNID_META_CNID_LEN      4
+#define CNID_META_MDATE_LEN     4  /* space for 8 */
+#define CNID_META_CDATE_LEN     4  /* space for 8 */
+#define CNID_META_BDATE_LEN     4  /* ditto */
+#define CNID_META_ADATE_LEN     4  /* ditto */
+#define CNID_META_AFPI_LEN      4  /* plus permission bits */
+#define CNID_META_FINDERI_LEN   32 
+#define CNID_META_PRODOSI_LEN   8
+#define CNID_META_RFORKLEN_LEN  4  /* space for 8 */
+#define CNID_META_MACNAME_LEN   32 /* maximum size */
+#define CNID_META_SHORTNAME_LEN 12 /* max size (8.3) */
+#define CNID_META_FILLER_LEN    4
+
+#define CNID_META_CNID_OFF     0
+#define CNID_META_MDATE_OFF    (CNID_META_CNID_OFF + CNID_META_CNID_LEN + \
+                               CNID_META_FILLER_LEN)
+#define CNID_META_CDATE_OFF    (CNID_META_MDATE_OFF + CNID_META_MDATE_LEN + \
+                               CNID_META_FILLER_LEN)
+#define CNID_META_BDATE_OFF    (CNID_META_CDATE_OFF + CNID_META_CDATE_LEN + \
+                               CNID_META_FILLER_LEN)
+#define CNID_META_ADATE_OFF    (CNID_META_BDATE_OFF + CNID_META_BDATE_LEN + \
+                               CNID_META_FILLER_LEN)
+#define CNID_META_AFPI_OFF     (CNID_META_ADATE_OFF + CNID_META_ADATE_LEN)
+#define CNID_META_FINDERI_OFF  (CNID_META_AFPI_OFF + CNID_META_AFPI_LEN)
+#define CNID_META_PRODOSI_OFF  (CNID_META_FINDERI_OFF + CNID_META_FINDERI_LEN)
+#define CNID_META_RFORKLEN_OFF (CNID_META_PRODOSI_OFF + CNID_META_PRODOSI_LEN)
+#define CNID_META_MACNAME_OFF  (CNID_META_RFORKLEN_OFF + \
+                               CNID_META_RFORKLEN_LEN)
+#define CNID_META_SHORTNAME_OFF (CNID_META_MACNAME_OFF + 
+
+
+#define cnid_meta_clear(a)  
+#define cnid_meta_get(id)
+
+#define cnid_meta_cnid(a)  
+#define cnid_meta_modifydate(a)
+#define cnid_meta_createdate(a)
+#define cnid_meta_backupdate(a)
+#define cnid_meta_accessdate(a)
+#define cnid_meta_afpi(a)
+#define cnid_meta_finderi(a)
+#define cnid_meta_prodosi(a)
+#define cnid_meta_rforklen(a)
+#define cnid_meta_macname(a)
+#define cnid_meta_shortname(a)
+#define cnid_meta_longname(a)
+
diff --git a/libatalk/cnid/cdb/cnid_cdb_nextid.c b/libatalk/cnid/cdb/cnid_cdb_nextid.c
new file mode 100644 (file)
index 0000000..e392f9d
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * $Id: cnid_cdb_nextid.c,v 1.1.4.1 2003-09-09 16:42:21 didg Exp $
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#ifdef CNID_BACKEND_CDB
+
+#ifdef unused
+
+#include <db.h>
+
+#include <atalk/adouble.h>
+#include "cnid_cdb.h"
+
+#include <atalk/logger.h>
+
+#include "cnid_cdb_private.h"
+
+/* return the next id. we use the fact that ad files are memory
+ * mapped. */
+cnid_t cnid_cdb_nextid(struct _cnid_db *cdb)
+{
+    CNID_private *db;
+    cnid_t id;
+
+    if (!cdb || !(db = cdb->_private))
+        return 0;
+
+    memcpy(&id, ad_entry(&db->rootinfo, ADEID_DID), sizeof(id));
+    return id;
+}
+#endif
+
+#endif /* CNID_BACKEND_CDB */
\ No newline at end of file
diff --git a/libatalk/cnid/cdb/cnid_cdb_open.c b/libatalk/cnid/cdb/cnid_cdb_open.c
new file mode 100644 (file)
index 0000000..199ce34
--- /dev/null
@@ -0,0 +1,403 @@
+
+/*
+ * $Id: cnid_cdb_open.c,v 1.1.4.1 2003-09-09 16:42:21 didg Exp $
+ *
+ * Copyright (c) 1999. Adrian Sun (asun@zoology.washington.edu)
+ * All Rights Reserved. See COPYRIGHT.
+ *
+ * CNID database support. 
+ *
+ * here's the deal:
+ *  1) afpd already caches did's. 
+ *  2) the database stores cnid's as both did/name and dev/ino pairs. 
+ *  3) RootInfo holds the value of the NextID.
+ *  4) the cnid database gets called in the following manner --
+ *     start a database:
+ *     cnid = cnid_open(root_dir);
+ *
+ *     allocate a new id: 
+ *     newid = cnid_add(cnid, dev, ino, parent did,
+ *     name, id); id is a hint for a specific id. pass 0 if you don't
+ *     care. if the id is already assigned, you won't get what you
+ *     requested.
+ *
+ *     given an id, get a did/name and dev/ino pair.
+ *     name = cnid_get(cnid, &id); given an id, return the corresponding
+ *     info.
+ *     return code = cnid_delete(cnid, id); delete an entry. 
+ *
+ * with AFP, CNIDs 0-2 have special meanings. here they are:
+ * 0 -- invalid cnid
+ * 1 -- parent of root directory (handled by afpd) 
+ * 2 -- root directory (handled by afpd)
+ *
+ * CNIDs 4-16 are reserved according to page 31 of the AFP 3.0 spec so, 
+ * CNID_START begins at 17.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#ifdef CNID_BACKEND_CDB
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif /* HAVE_FCNTL_H */
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <atalk/logger.h>
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif /* HAVE_SYS_TIME_H */
+
+#include <db.h>
+
+#include <atalk/adouble.h>
+#include <atalk/cnid.h>
+#include "cnid_cdb.h"
+#include <atalk/util.h>
+
+#include "cnid_cdb_private.h"
+
+#ifndef MIN
+#define MIN(a, b)  ((a) < (b) ? (a) : (b))
+#endif /* ! MIN */
+
+#define DBHOME        ".AppleDB"
+#define DBCNID        "cnid2.db"
+#define DBDEVINO      "devino.db"
+#define DBDIDNAME     "didname.db"      /* did/full name mapping */
+#define DBLOCKFILE    "cnid.lock"
+
+#define DBHOMELEN    8
+#define DBLEN        10
+
+/* we version the did/name database so that we can change the format
+ * if necessary. the key is in the form of a did/name pair. in this case,
+ * we use 0/0. */
+#define DBVERSION_KEY    "\0\0\0\0\0"
+#define DBVERSION_KEYLEN 5
+#define DBVERSION1       0x00000001U
+#define DBVERSION        DBVERSION1
+
+#define DBOPTIONS    (DB_CREATE | DB_INIT_CDB | DB_INIT_MPOOL)
+
+#define MAXITER     0xFFFF      /* maximum number of simultaneously open CNID
+                                 * databases. */
+
+/* -----------------------
+ * bandaid for LanTest performance pb. for now not used, cf. ifdef 0 below
+*/
+static int my_yield(void)
+{
+    struct timeval t;
+    int ret;
+
+    t.tv_sec = 0;
+    t.tv_usec = 1000;
+    ret = select(0, NULL, NULL, NULL, &t);
+    return 0;
+}
+
+/* --------------- */
+static int didname(dbp, pkey, pdata, skey)
+DB *dbp;
+const DBT *pkey, *pdata;
+DBT *skey;
+{
+int len;
+    memset(skey, 0, sizeof(DBT));
+    skey->data = pdata->data + CNID_DID_OFS;
+    len = strlen(skey->data + CNID_DID_LEN);
+    skey->size = CNID_DID_LEN + len + 1;
+    return (0);
+}
+/* --------------- */
+static int devino(dbp, pkey, pdata, skey)
+DB *dbp;
+const DBT *pkey, *pdata;
+DBT *skey;
+{
+    memset(skey, 0, sizeof(DBT));
+    skey->data = pdata->data + CNID_DEVINO_OFS;
+    skey->size = CNID_DEVINO_LEN;
+    return (0);
+}
+/* --------------- */
+static int  my_associate (DB *p, DB *s,
+                   int (*callback)(DB *, const DBT *,const DBT *, DBT *),
+                   u_int32_t flags)
+{
+#if DB_VERSION_MAJOR > 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 1)
+    return p->associate(p, NULL, s, callback, flags);
+#else
+    return p->associate(p,       s, callback, flags);
+#endif
+}
+
+/* --------------- */
+static int my_open(DB * p, const char *f, const char *d, DBTYPE t, u_int32_t flags, int mode)
+{
+#if DB_VERSION_MAJOR > 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 1)
+    return p->open(p, NULL, f, d, t, flags, mode);
+#else
+    return p->open(p, f, d, t, flags, mode);
+#endif
+}
+
+/* --------------- */
+static struct _cnid_db *cnid_cdb_new(const char *volpath)
+{
+    struct _cnid_db *cdb;
+
+    if ((cdb = (struct _cnid_db *) calloc(1, sizeof(struct _cnid_db))) == NULL)
+        return NULL;
+
+    if ((cdb->volpath = strdup(volpath)) == NULL) {
+        free(cdb);
+        return NULL;
+    }
+
+    cdb->flags = CNID_FLAG_PERSISTENT;
+
+    cdb->cnid_add = cnid_cdb_add;
+    cdb->cnid_delete = cnid_cdb_delete;
+    cdb->cnid_get = cnid_cdb_get;
+    cdb->cnid_lookup = cnid_cdb_lookup;
+    cdb->cnid_nextid = NULL;    /*cnid_cdb_nextid;*/
+    cdb->cnid_resolve = cnid_cdb_resolve;
+    cdb->cnid_update = cnid_cdb_update;
+    cdb->cnid_close = cnid_cdb_close;
+
+    return cdb;
+}
+
+/* --------------- */
+struct _cnid_db *cnid_cdb_open(const char *dir, mode_t mask)
+{
+    struct stat st;
+    char path[MAXPATHLEN + 1];
+    CNID_private *db;
+    struct _cnid_db *cdb;
+    int open_flag, len;
+    static int first = 0;
+    int rc;
+
+    if (!dir || *dir == 0) {
+        return NULL;
+    }
+
+    /* this checks .AppleDB */
+    if ((len = strlen(dir)) > (MAXPATHLEN - DBLEN - 1)) {
+        LOG(log_error, logtype_default, "cnid_open: Pathname too large: %s", dir);
+        return NULL;
+    }
+
+    if ((cdb = cnid_cdb_new(dir)) == NULL) {
+        LOG(log_error, logtype_default, "cnid_open: Unable to allocate memory for database");
+        return NULL;
+    }
+
+    if ((db = (CNID_private *) calloc(1, sizeof(CNID_private))) == NULL) {
+        LOG(log_error, logtype_default, "cnid_open: Unable to allocate memory for database");
+        goto fail_cdb;
+    }
+
+    cdb->_private = (void *) db;
+    db->magic = CNID_DB_MAGIC;
+
+    strcpy(path, dir);
+    if (path[len - 1] != '/') {
+        strcat(path, "/");
+        len++;
+    }
+
+    strcpy(path + len, DBHOME);
+    if ((stat(path, &st) < 0) && (ad_mkdir(path, 0777 & ~mask) < 0)) {
+        LOG(log_error, logtype_default, "cnid_open: DBHOME mkdir failed for %s", path);
+        goto fail_adouble;
+    }
+
+    open_flag = DB_CREATE;
+
+    /* We need to be able to open the database environment with full
+     * transaction, logging, and locking support if we ever hope to 
+     * be a true multi-acess file server. */
+    if ((rc = db_env_create(&db->dbenv, 0)) != 0) {
+        LOG(log_error, logtype_default, "cnid_open: db_env_create: %s", db_strerror(rc));
+        goto fail_lock;
+    }
+
+    /* Open the database environment. */
+    if ((rc = db->dbenv->open(db->dbenv, path, DBOPTIONS, 0666 & ~mask)) != 0) {
+        if (rc == DB_RUNRECOVERY) {
+            /* This is the mother of all errors.  We _must_ fail here. */
+            LOG(log_error, logtype_default,
+                "cnid_open: CATASTROPHIC ERROR opening database environment %s.  Run db_recovery -c immediately", path);
+            goto fail_lock;
+        }
+
+        /* We can't get a full transactional environment, so multi-access
+         * is out of the question.  Let's assume a read-only environment,
+         * and try to at least get a shared memory pool. */
+        if ((rc = db->dbenv->open(db->dbenv, path, DB_INIT_MPOOL, 0666 & ~mask)) != 0) {
+            /* Nope, not a MPOOL, either.  Last-ditch effort: we'll try to
+             * open the environment with no flags. */
+            if ((rc = db->dbenv->open(db->dbenv, path, 0, 0666 & ~mask)) != 0) {
+                LOG(log_error, logtype_default, "cnid_open: dbenv->open of %s failed: %s", path, db_strerror(rc));
+                goto fail_lock;
+            }
+        }
+        db->flags |= CNIDFLAG_DB_RO;
+        open_flag = DB_RDONLY;
+        LOG(log_info, logtype_default, "cnid_open: Obtained read-only database environment %s", path);
+    }
+
+    /* ---------------------- */
+    /* Main CNID database.  Use a hash for this one. */
+
+    if ((rc = db_create(&db->db_cnid, db->dbenv, 0)) != 0) {
+        LOG(log_error, logtype_default, "cnid_open: Failed to create cnid database: %s",
+            db_strerror(rc));
+        goto fail_appinit;
+    }
+
+    if ((rc = my_open(db->db_cnid, DBCNID, DBCNID, DB_HASH, open_flag, 0666 & ~mask)) != 0) {
+        LOG(log_error, logtype_default, "cnid_open: Failed to open dev/ino database: %s",
+            db_strerror(rc));
+        goto fail_appinit;
+    }
+
+    /* ---------------------- */
+    /* did/name reverse mapping.  We use a BTree for this one. */
+
+    if ((rc = db_create(&db->db_didname, db->dbenv, 0)) != 0) {
+        LOG(log_error, logtype_default, "cnid_open: Failed to create did/name database: %s",
+            db_strerror(rc));
+        goto fail_appinit;
+    }
+
+    if ((rc = my_open(db->db_didname, DBCNID, DBDIDNAME,DB_HASH, open_flag, 0666 & ~mask))) {
+        LOG(log_error, logtype_default, "cnid_open: Failed to open did/name database: %s",
+            db_strerror(rc));
+        goto fail_appinit;
+    }
+
+    /* ---------------------- */
+    /* dev/ino reverse mapping.  Use a hash for this one. */
+
+    if ((rc = db_create(&db->db_devino, db->dbenv, 0)) != 0) {
+        LOG(log_error, logtype_default, "cnid_open: Failed to create dev/ino database: %s",
+            db_strerror(rc));
+        goto fail_appinit;
+    }
+
+    if ((rc = my_open(db->db_devino, DBCNID, DBDEVINO, DB_HASH, open_flag, 0666 & ~mask)) != 0) {
+        LOG(log_error, logtype_default, "cnid_open: Failed to open devino database: %s",
+            db_strerror(rc));
+        goto fail_appinit;
+    }
+
+    /* ---------------------- */
+    /* Associate the secondary with the primary. */ 
+    if ((rc = my_associate(db->db_cnid, db->db_didname, didname, 0)) != 0) {
+        LOG(log_error, logtype_default, "cnid_open: Failed to associate didname database: %s",
+            db_strerror(rc));
+        goto fail_appinit;
+    }
+    if ((rc = my_associate(db->db_cnid, db->db_devino, devino, 0)) != 0) {
+        LOG(log_error, logtype_default, "cnid_open: Failed to associate devino database: %s",
+            db_strerror(rc));
+        goto fail_appinit;
+    }
+#if 0
+    DBT key, pkey, data;
+    /* ---------------------- */
+    /* Check for version.  This way we can update the database if we need
+     * to change the format in any way. */
+    memset(&key, 0, sizeof(key));
+    memset(&pkey, 0, sizeof(DBT));
+    memset(&data, 0, sizeof(data));
+    key.data = DBVERSION_KEY;
+    key.size = DBVERSION_KEYLEN;
+
+    if ((rc = db->db_didname->pget(db->db_didname, NULL, &key, &pkey, &data, 0)) != 0) {
+        int ret;
+        {
+            u_int32_t version = htonl(DBVERSION);
+
+            data.data = &version;
+            data.size = sizeof(version);
+        }
+        if ((ret = db->db_didname->put(db->db_cnid, NULL, &key, &data,
+                                       DB_NOOVERWRITE))) {
+            LOG(log_error, logtype_default, "cnid_open: Error putting new version: %s",
+                db_strerror(ret));
+            db->db_didname->close(db->db_didname, 0);
+            goto fail_appinit;
+        }
+    }
+#endif
+
+    /* TODO In the future we might check for version number here. */
+#if 0
+    memcpy(&version, data.data, sizeof(version));
+    if (version != ntohl(DBVERSION)) {
+        /* Do stuff here. */
+    }
+#endif /* 0 */
+
+    /* Print out the version of BDB we're linked against. */
+    if (!first) {
+        first = 1;
+        LOG(log_info, logtype_default, "CNID DB initialized using %s", db_version(NULL, NULL, NULL));
+    }
+
+    db_env_set_func_yield(my_yield);
+    return cdb;
+
+  fail_appinit:
+    if (db->db_didname)
+        db->db_didname->close(db->db_didname, 0);
+    if (db->db_devino)
+        db->db_devino->close(db->db_devino, 0);
+    if (db->db_cnid)
+        db->db_cnid->close(db->db_cnid, 0);
+    LOG(log_error, logtype_default, "cnid_open: Failed to setup CNID DB environment");
+    db->dbenv->close(db->dbenv, 0);
+
+  fail_lock:
+
+  fail_adouble:
+
+    free(db);
+
+  fail_cdb:
+    if (cdb->volpath != NULL)
+        free(cdb->volpath);
+    free(cdb);
+
+    return NULL;
+}
+
+struct _cnid_module cnid_cdb_module = {
+    "cdb",
+    {NULL, NULL},
+    cnid_cdb_open,
+    CNID_FLAG_SETUID | CNID_FLAG_BLOCK
+};
+
+
+#endif /* CNID_BACKEND_CDB */
diff --git a/libatalk/cnid/cdb/cnid_cdb_private.h b/libatalk/cnid/cdb/cnid_cdb_private.h
new file mode 100644 (file)
index 0000000..4f4453a
--- /dev/null
@@ -0,0 +1,194 @@
+/*
+ * $Id: cnid_cdb_private.h,v 1.1.4.1 2003-09-09 16:42:21 didg Exp $
+ */
+
+#ifndef LIBATALK_CDB_PRIVATE_H
+#define LIBATALK_CDB_PRIVATE_H 1
+
+#include <string.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+
+#include <db.h>
+
+#include <atalk/adouble.h>
+#include "cnid_cdb.h"
+
+#define CNID_DB_MAGIC   0x434E4944U  /* CNID */
+#define CNID_DATA_MAGIC 0x434E4945U  /* CNIE */
+
+/* record structure 
+   cnid                4
+   dev                 8
+   inode               8
+   type/last cnid      4 Not used    
+   did                 4
+   name                strlen(name) +1
+
+primary key 
+cnid
+secondary keys
+dev/inode
+did/name   
+
+*/
+
+typedef struct cnid_record { /* helper for debug don't use */
+  unsigned int  cnid;
+  dev_t    dev;
+  ino_t    inode;
+  unsigned int  type;
+  unsigned int  did;
+  char          name[50];
+} cnid_record;
+
+#define CNID_OFS                 0
+#define CNID_LEN                 4
+
+#define CNID_DEV_OFS             CNID_LEN
+#define CNID_DEV_LEN             8
+
+#define CNID_INO_OFS             (CNID_DEV_OFS + CNID_DEV_LEN)
+#define CNID_INO_LEN             8
+
+#define CNID_DEVINO_OFS          CNID_LEN
+#define CNID_DEVINO_LEN          (CNID_DEV_LEN +CNID_INO_LEN)
+
+#define CNID_TYPE_OFS            (CNID_DEVINO_OFS +CNID_DEVINO_LEN)
+#define CNID_TYPE_LEN            4
+
+#define CNID_DID_OFS             (CNID_TYPE_OFS +CNID_TYPE_LEN)
+#define CNID_DID_LEN             CNID_LEN
+
+#define CNID_NAME_OFS            (CNID_DID_OFS + CNID_DID_LEN)
+#define CNID_HEADER_LEN          (CNID_NAME_OFS)
+
+#define CNID_START               17
+
+#define CNIDFLAG_ROOTINFO_RO     (1 << 0)
+#define CNIDFLAG_DB_RO           (1 << 1)
+
+/* the key is cnid 0 
+ * we use 0/RootInfo. */
+#define ROOTINFO_KEY    "\0\0\0\0"
+#define ROOTINFO_KEYLEN 4
+
+/* FIXME assume dev_t == ino_t == 8 */
+/*                         cnid   - dev        - inode     - type  - did  - name */
+#define ROOTINFO_DATA    "\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\0RootInfo"
+#define ROOTINFO_DATALEN (3*4 +2*8  +9)
+
+
+typedef struct CNID_private {
+    u_int32_t magic;
+    DB *db_cnid;
+    DB *db_didname;
+    DB *db_devino;
+    DB_ENV *dbenv;
+    int lockfd, flags;
+    char lock_file[MAXPATHLEN + 1];
+} CNID_private;
+
+/* on-disk data format (in network byte order where appropriate) --
+ * db_cnid:      (key: cnid)
+ * name          size (in bytes)
+ * dev           4
+ * ino           4
+ * did           4
+ * unix name     strlen(name) + 1 
+ *
+ * db_didname:   (key: did/unix name)
+ * -- this also caches the bits of .AppleDouble used by FPGetFilDirParam
+ *    so that we don't have to open the header file.
+ *    NOTE: FPCatSearch has to search through all of the directories as
+ *          this stuff doesn't get entered until needed.
+ *          if the entire volume is in the database, though, we can use
+ *          cursor operations to make this faster.
+ *
+ *    version number is stored with did/name key of 0/0
+ *
+ * cnid          4
+ * modfiller     4 (dates only use 4 bytes right now, but we leave space 
+ * moddate       4  for 8. moddate is also used to keep this info 
+ * createfiller  4  up-to-date.)
+ * createdate    4
+ * backfiller    4
+ * backupdate    4
+ * accfiller     4 (unused)
+ * accdate       4 (unused)
+ * AFP info      4 (stores a couple permission bits as well)
+ * finder info   32
+ * prodos info   8
+ * rforkfiller   4
+ * rforklen      4
+ * macname       32 (nul-terminated)
+ * shortname     12 (nul-terminated)
+ * longname      longnamelen (nul-terminated)
+ * ---------------
+ *             132 bytes + longnamelen
+ * 
+ * db_devino:    (key: dev/ino) 
+ * -- this is only used for consistency checks and isn't 1-1
+ * cnid          4 
+ *
+ * these correspond to the different path types. longname is for the
+ * 255 unicode character names (path type == ?), macname is for the
+ * 32-character names (path type == 2), and shortname is for the
+ * 8+3-character names (path type == 1).
+ *
+ * db_longname: (key: did/longname)
+ * name          namelen = strlen(name) + 1
+ *
+ * db_macname:   (key: did/macname)
+ * name          namelen = strlen(name) + 1
+ *
+ * db_shortname: (key: did/shortname)
+ * name namelen = strlen(name) + 1 
+ */
+
+#ifndef __inline__
+#define __inline__
+#endif /* __inline__ */
+
+/* construct db_cnid data. NOTE: this is not re-entrant.  */
+#ifndef ATACC
+static __inline__ char *make_cnid_data(const struct stat *st,
+                                       const cnid_t did,
+                                       const char *name, const int len)
+{
+    static char start[CNID_HEADER_LEN + MAXPATHLEN + 1];
+    char *buf = start  +CNID_LEN;
+    u_int32_t i;
+
+    if (len > MAXPATHLEN)
+        return NULL;
+
+    memcpy(buf, &st->st_dev, sizeof(st->st_dev));
+    buf += sizeof(st->st_dev);
+
+    memcpy(buf, &st->st_ino, sizeof(st->st_ino));
+    buf += sizeof(st->st_ino);
+
+    i = S_ISDIR(st->st_mode)?1:0;
+    i = htonl(i);
+    memcpy(buf, &i, sizeof(i));
+    buf += sizeof(i);
+    
+    /* did is already in network byte order */
+    memcpy(buf, &did, sizeof(did));
+    buf += sizeof(did);
+
+    memcpy(buf, name, len);
+    *(buf + len) = '\0';
+
+    return start;
+}
+#else
+extern char *make_cnid_data __P((const struct stat *,const cnid_t ,
+                                       const char *, const int ));
+#endif
+
+#endif /* atalk/cnid/cnid_private.h */
diff --git a/libatalk/cnid/cdb/cnid_cdb_resolve.c b/libatalk/cnid/cdb/cnid_cdb_resolve.c
new file mode 100644 (file)
index 0000000..0994a2b
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * $Id: cnid_cdb_resolve.c,v 1.1.4.1 2003-09-09 16:42:21 didg Exp $
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#ifdef CNID_BACKEND_CDB
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <atalk/logger.h>
+#include <errno.h>
+
+#include <db.h>
+#include <netatalk/endian.h>
+#include <atalk/adouble.h>
+#include "cnid_cdb.h"
+
+#include "cnid_cdb_private.h"
+
+/* Return the did/name pair corresponding to a CNID. */
+char *cnid_cdb_resolve(struct _cnid_db *cdb, cnid_t *id, void *buffer, u_int32_t len) {
+    CNID_private *db;
+    DBT key, data;
+    int rc;
+
+    if (!cdb || !(db = cdb->_private) || !id || !(*id)) {
+        return NULL;
+    }
+
+    memset(&key, 0, sizeof(key));
+    memset(&data, 0, sizeof(data));
+
+    data.data = buffer;
+    data.ulen = len;
+    data.flags = DB_DBT_USERMEM;
+
+    key.data = id;
+    key.size = sizeof(cnid_t);
+    while ((rc = db->db_cnid->get(db->db_cnid, NULL, &key, &data, 0))) {
+
+        if (rc != DB_NOTFOUND) {
+            LOG(log_error, logtype_default, "cnid_resolve: Unable to get did/name: %s",
+                db_strerror(rc));
+        }
+
+        *id = 0;
+        return NULL;
+    }
+
+    memcpy(id, (char *)data.data +CNID_DID_OFS, sizeof(cnid_t));
+#ifdef DEBUG
+    LOG(log_info, logtype_default, "cnid_resolve: Returning id = %u, did/name = %s",
+        ntohl(*id), (char *)data.data + CNID_NAME_OFS);
+#endif
+    return (char *)data.data +  CNID_NAME_OFS;
+}
+
+#endif
diff --git a/libatalk/cnid/cdb/cnid_cdb_update.c b/libatalk/cnid/cdb/cnid_cdb_update.c
new file mode 100644 (file)
index 0000000..cdfb980
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * $Id: cnid_cdb_update.c,v 1.1.4.1 2003-09-09 16:42:21 didg Exp $
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#ifdef CNID_BACKEND_CDB
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <atalk/logger.h>
+
+#include <db.h>
+#include <netatalk/endian.h>
+#include <atalk/adouble.h>
+#include "cnid_cdb.h"
+
+#include "cnid_cdb_private.h"
+
+#define tid    NULL
+
+/* cnid_update: takes the given cnid and updates the metadata.  To
+ * handle the did/name data, there are a bunch of functions to get
+ * and set the various fields. */
+int cnid_cdb_update(struct _cnid_db *cdb, const cnid_t id, const struct stat *st,
+                const cnid_t did, const char *name, const int len
+                /*, const char *info, const int infolen*/)
+{
+    char *buf;
+    CNID_private *db;
+    DBT key, data;
+    int rc;
+    int notfound = 0;
+
+    if (!cdb || !(db = cdb->_private) || !id || !st || !name || (db->flags & CNIDFLAG_DB_RO)) {
+        return -1;
+    }
+
+    memset(&key, 0, sizeof(key));
+
+    buf = make_cnid_data(st, did, name, len);
+
+    key.data = buf +CNID_DEVINO_OFS;
+    key.size = CNID_DEVINO_LEN;
+
+    if (0 != (rc = db->db_devino->del(db->db_devino, tid, &key, 0)) ) {
+        if (rc != DB_NOTFOUND && rc != DB_SECONDARY_BAD) {
+           LOG(log_error, logtype_default, "cnid_update: Unable to del devino CNID %u, name %s: %s",
+               ntohl(did), name, db_strerror(rc));
+           goto fin;
+        }
+        notfound = 1;
+    }
+
+    buf = make_cnid_data(st, did, name, len);
+    key.data = buf + CNID_DID_OFS;
+    key.size = CNID_DID_LEN + len + 1;
+
+    if (0 != (rc = db->db_didname->del(db->db_didname, tid, &key, 0)) ) {
+        if (rc != DB_NOTFOUND && rc != DB_SECONDARY_BAD) {
+           LOG(log_error, logtype_default, "cnid_update: Unable to del didname CNID %u, name %s: %s",
+               ntohl(did), name, db_strerror(rc));
+           goto fin;
+        }
+        notfound |= 2;
+    }
+
+    memset(&key, 0, sizeof(key));
+    key.data = (cnid_t *)&id;
+    key.size = sizeof(id);
+
+    memset(&data, 0, sizeof(data));
+    /* Make a new entry. */
+    buf = make_cnid_data(st, did, name, len);
+    data.data = buf;
+    memcpy(data.data, &id, sizeof(id));
+    data.size = CNID_HEADER_LEN + len + 1;
+
+    /* Update the old CNID with the new info. */
+    if ((rc = db->db_cnid->put(db->db_cnid, tid, &key, &data, 0))) {
+        LOG(log_error, logtype_default, "cnid_update: (%d) Unable to update CNID %u:%s: %s",
+            notfound, ntohl(id), name, db_strerror(rc));
+        goto fin;
+    }
+
+    return 0;
+fin:
+    return -1;
+}
+
+#endif
diff --git a/libatalk/cnid/cnid.c b/libatalk/cnid/cnid.c
new file mode 100644 (file)
index 0000000..8c3e33d
--- /dev/null
@@ -0,0 +1,264 @@
+/* 
+ * $Id: cnid.c,v 1.1.4.1 2003-09-09 16:42:21 didg Exp $
+ *
+ * Copyright (c) 2003 the Netatalk Team
+ * Copyright (c) 2003 Rafal Lewczuk <rlewczuk@pronet.pl>
+ * 
+ * This program is free software; you can redistribute and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation version 2 of the License or later
+ * version if explicitly stated by any of above copyright holders.
+ *
+ */
+#define USE_LIST
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <signal.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <atalk/cnid.h>
+#include <atalk/list.h>
+#include <atalk/logger.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* List of all registered modules. */
+static struct list_head modules = LIST_HEAD_INIT(modules);
+
+static sigset_t sigblockset;
+static const struct itimerval none = {{0, 0}, {0, 0}};
+static struct itimerval savetimer;
+
+/* Registers new CNID backend module. */
+
+/* Once module has been registered, it cannot be unregistered. */
+void cnid_register(struct _cnid_module *module)
+{
+    struct list_head *ptr;
+
+    /* Check if our module is already registered. */
+    list_for_each(ptr, &modules)
+        if (0 == strcmp(list_entry(ptr, cnid_module, db_list)->name, module->name)) {
+        LOG(log_error, logtype_afpd, "Module with name [%s] is already registered !", module->name);
+        return;
+    }
+
+    LOG(log_info, logtype_afpd, "Registering CNID module [%s]", module->name);
+    ptr = &(module->db_list);
+    list_add_tail(ptr, &modules);
+}
+
+/* --------------- */
+static int cnid_dir(const char *dir, mode_t mask)
+{
+   struct stat st; 
+
+   if (stat(dir, &st) < 0) {
+       if (errno != ENOENT) 
+           return -1;
+       if (ad_stat( dir, &st) < 0)
+          return -1;
+
+       LOG(log_info, logtype_cnid, "Setting uid/gid to %d/%d", st.st_uid, st.st_gid);
+       if (setegid(st.st_gid) < 0 || seteuid(st.st_uid) < 0) {
+           LOG(log_error, logtype_cnid, "uid/gid: %s", strerror(errno));
+           return -1;
+       }
+
+       if (mkdir(dir, 0777 & ~mask) < 0)
+           return -1;
+   } else {
+       LOG(log_info, logtype_cnid, "Setting uid/gid to %d/%d", st.st_uid, st.st_gid);
+       if (setegid(st.st_gid) < 0 || seteuid(st.st_uid) < 0) {
+           LOG(log_error, logtype_cnid, "uid/gid: %s", strerror(errno));
+           return -1;
+       }
+   }
+   return 0;
+}
+
+/* Opens CNID database using particular back-end */
+struct _cnid_db *cnid_open(const char *volpath, mode_t mask, char *type)
+{
+    struct _cnid_db *db;
+    cnid_module *mod = NULL;
+    struct list_head *ptr;
+    uid_t uid;
+    gid_t gid;
+    
+    list_for_each(ptr, &modules) {
+        if (0 == strcmp(list_entry(ptr, cnid_module, db_list)->name, type)) {
+           mod = list_entry(ptr, cnid_module, db_list);
+        break;
+        }
+    }
+
+    if (NULL == mod) {
+        LOG(log_error, logtype_afpd, "Cannot find module named [%s] in registered module list!", type);
+        return NULL;
+    }
+    if ((mod->flags & CNID_FLAG_SETUID)) {
+        uid = geteuid();
+        gid = getegid();
+        if (seteuid(0)) {
+            LOG(log_error, logtype_afpd, "seteuid failed %s", strerror(errno));
+            return NULL;
+        }
+        if (cnid_dir(volpath, mask) < 0) {
+            if ( setegid(gid) < 0 || seteuid(uid) < 0) {
+                LOG(log_error, logtype_afpd, "can't seteuid back %s", strerror(errno));
+                exit(1);
+            }
+            return NULL;
+        }
+    }
+
+    db = mod->cnid_open(volpath, mask);
+
+    if ((mod->flags & CNID_FLAG_SETUID)) {
+        seteuid(0);
+        if ( setegid(gid) < 0 || seteuid(uid) < 0) {
+            LOG(log_error, logtype_afpd, "can't seteuid back %s", strerror(errno));
+            exit(1);
+        }
+    }
+
+    if (NULL == db) {
+        LOG(log_error, logtype_afpd, "Cannot open CNID db at [%s].", volpath);
+        return NULL;
+    }
+    db->flags |= mod->flags;
+
+    if (db->flags |= CNID_FLAG_BLOCK) {
+        sigemptyset(&sigblockset);
+        sigaddset(&sigblockset, SIGTERM);
+        sigaddset(&sigblockset, SIGHUP);
+        sigaddset(&sigblockset, SIGUSR1);
+        sigaddset(&sigblockset, SIGALRM);
+    }
+
+    return db;
+}
+
+/* ------------------- */
+static void block_signal(struct _cnid_db *db)
+{
+    if ((db->flags & CNID_FLAG_BLOCK)) {
+        sigprocmask(SIG_BLOCK, &sigblockset, NULL);
+        setitimer(ITIMER_REAL, &none, &savetimer);
+    }
+}
+
+/* ------------------- */
+static void unblock_signal(struct _cnid_db *db)
+{
+    if ((db->flags & CNID_FLAG_BLOCK)) {
+        setitimer(ITIMER_REAL, &savetimer, NULL);
+        sigprocmask(SIG_UNBLOCK, &sigblockset, NULL);
+    }
+}
+
+/* Closes CNID database. Currently it's just a wrapper around db->cnid_close(). */
+void cnid_close(struct _cnid_db *db)
+{
+    if (NULL == db) {
+        LOG(log_error, logtype_afpd, "Error: cnid_close called with NULL argument !");
+        return;
+    }
+    block_signal(db);
+    db->cnid_close(db);
+    unblock_signal(db);
+}
+
+/* --------------- */
+cnid_t cnid_add(struct _cnid_db *cdb, const struct stat *st, const cnid_t did, 
+                       const char *name, const int len, cnid_t hint)
+{
+cnid_t ret;
+
+    block_signal(cdb);
+    ret = cdb->cnid_add(cdb, st, did, name, len, hint);
+    unblock_signal(cdb);
+    return ret;
+}
+
+/* --------------- */
+int cnid_delete(struct _cnid_db *cdb, cnid_t id)
+{
+int ret;
+
+    block_signal(cdb);
+    ret = cdb->cnid_delete(cdb, id);
+    unblock_signal(cdb);
+    return ret;
+}
+
+
+/* --------------- */
+cnid_t cnid_get(struct _cnid_db *cdb, const cnid_t did, const char *name,const int len)
+{
+cnid_t ret;
+
+    block_signal(cdb);
+    ret = cdb->cnid_get(cdb, did, name, len);
+    unblock_signal(cdb);
+    return ret;
+}
+
+/* --------------- */
+cnid_t cnid_getstamp(struct _cnid_db *cdb,  void *buffer, const int len)
+{
+cnid_t ret;
+
+    if (!cdb->cnid_getstamp) {
+        return -1;
+    }
+    block_signal(cdb);
+    ret = cdb->cnid_getstamp(cdb, buffer, len);
+    unblock_signal(cdb);
+    return ret;
+}
+
+/* --------------- */
+cnid_t cnid_lookup(struct _cnid_db *cdb, const struct stat *st, const cnid_t did,
+                       const char *name, const int len)
+{
+cnid_t ret;
+
+    block_signal(cdb);
+    ret = cdb->cnid_lookup(cdb, st, did, name, len);
+    unblock_signal(cdb);
+    return ret;
+}
+
+/* --------------- */
+char *cnid_resolve(struct _cnid_db *cdb, cnid_t *id, void *buffer, u_int32_t len)
+{
+char *ret;
+
+    block_signal(cdb);
+    ret = cdb->cnid_resolve(cdb, id, buffer, len);
+    unblock_signal(cdb);
+    return ret;
+}
+
+/* --------------- */
+int cnid_update   (struct _cnid_db *cdb, const cnid_t id, const struct stat *st, 
+                       const cnid_t did, const char *name, const int len)
+{
+int ret;
+
+    block_signal(cdb);
+    ret = cdb->cnid_update(cdb, id, st, did, name, len);
+    unblock_signal(cdb);
+    return ret;
+}
+                       
+
diff --git a/libatalk/cnid/cnid_init.c b/libatalk/cnid/cnid_init.c
new file mode 100644 (file)
index 0000000..60ad25a
--- /dev/null
@@ -0,0 +1,89 @@
+
+/* 
+ * $Id: cnid_init.c,v 1.1.4.1 2003-09-09 16:42:21 didg Exp $
+ *
+ * Copyright (c) 2003 the Netatalk Team
+ * Copyright (c) 2003 Rafal Lewczuk <rlewczuk@pronet.pl>
+ * 
+ * This program is free software; you can redistribute and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation version 2 of the License or later
+ * version if explicitly stated by any of above copyright holders.
+ *
+ */
+
+/*
+ * This file contains initialization stuff for CNID backends.
+ * Currently it only employs static bindings. 
+ * No plans for dynamically loaded CNID backends here (temporary). 
+ * Maybe somewhere in the future.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include <atalk/cnid.h>
+#include <atalk/list.h>
+#include <atalk/logger.h>
+#include <stdlib.h>
+
+
+#ifdef CNID_BACKEND_DB3
+extern struct _cnid_module cnid_db3_module;
+#endif
+
+#ifdef CNID_BACKEND_HASH
+extern struct _cnid_module cnid_hash_module;
+#endif
+
+#ifdef CNID_BACKEND_LAST
+extern struct _cnid_module cnid_last_module;
+#endif
+
+#ifdef CNID_BACKEND_MTAB
+extern struct _cnid_module cnid_mtab_module;
+#endif
+
+#ifdef CNID_BACKEND_CDB
+extern struct _cnid_module cnid_cdb_module;
+#endif
+
+#ifdef CNID_BACKEND_DBD
+extern struct _cnid_module cnid_dbd_module;
+#endif
+
+#ifdef CNID_BACKEND_TDB
+extern struct _cnid_module cnid_tdb_module;
+#endif
+
+void cnid_init()
+{
+#ifdef CNID_BACKEND_DB3
+    cnid_register(&cnid_db3_module);
+#endif
+
+#ifdef CNID_BACKEND_HASH
+    cnid_register(&cnid_hash_module);
+#endif
+
+#ifdef CNID_BACKEND_LAST
+    cnid_register(&cnid_last_module);
+#endif
+
+#ifdef CNID_BACKEND_MTAB
+    cnid_register(&cnid_mtab_module);
+#endif
+
+#ifdef CNID_BACKEND_CDB
+    cnid_register(&cnid_cdb_module);
+#endif
+
+#ifdef CNID_BACKEND_DBD
+    cnid_register(&cnid_dbd_module);
+#endif
+
+#ifdef CNID_BACKEND_TDB
+    cnid_register(&cnid_tdb_module);
+#endif
+}
diff --git a/libatalk/cnid/db3/Makefile.am b/libatalk/cnid/db3/Makefile.am
new file mode 100644 (file)
index 0000000..665722b
--- /dev/null
@@ -0,0 +1,20 @@
+# Makefile.am for libatalk/cnid/
+
+CFLAGS = @CFLAGS@ @BDB_CFLAGS@
+LIBS = @LIBS@ @BDB_LIBS@
+
+noinst_LTLIBRARIES = libcnid_db3.la
+
+libcnid_db3_la_SOURCES = cnid_db3_add.c \
+                        cnid_db3_close.c \
+                        cnid_db3_delete.c \
+                        cnid_db3_get.c \
+                        cnid_db3_lookup.c \
+                        cnid_db3_open.c \
+                        cnid_db3_resolve.c \
+                        cnid_db3_update.c \
+                        cnid_db3.h
+
+noinst_HEADERS = cnid_db3_meta.h cnid_db3_private.h 
+
+EXTRA_DIST = README cnid_db3_meta.c cnid_db3_nextid.c
diff --git a/libatalk/cnid/db3/README b/libatalk/cnid/db3/README
new file mode 100644 (file)
index 0000000..b39889b
--- /dev/null
@@ -0,0 +1,35 @@
+the catalog database keeps track of three mappings:
+    CNID     -> dev/ino and did/name
+    dev/ino  -> CNID
+    did/name -> CNID
+
+dev/ino is used to keep track of magically moved files. did/name is
+for quick lookups of CNIDs. 
+
+NOTE: the database will append a nul byte to the end of name. in
+addition, name should be given as it appears on disk. this allows the
+creation of cnid updating/cleaning programs that don't have to deal
+with knowing what the particular codepage is.
+
+here's the ritual:
+       1) open a volume. call cnid_open.
+       2) every time you need a CNID, call cnid_add(). it will
+          automatically look for an existing cnid and add a new one
+          if one isn't already there. you can pass a hint if you
+          want. the only use this has right now is to enable
+          consistency between AFP and HFS. in the future, it would
+          allow people to write conversion utilities that
+          pre-instantiate a database without needing to re-assign
+          CNIDs.
+       3) if you want to just look for a CNID without automatically
+          adding one in, you have two choices:
+            a) cnid_resolve takes a CNID, returns name, and
+               over-writes the CNID given with the parent DID. this
+               is good for FPResolveID.
+             b) cnid_lookup returns a CNID corresponding to the
+               dev/ino,did/name keys. it will auto-update the catalog
+               database if there's a discrepancy. 
+               NOTE: cnid_add calls this before adding a new CNID. 
+       4) when you delete a file or directory, you need to call
+          cnid_delete with the CNID for that file/directory.
+       5) call cnid_close when closing the volume.
diff --git a/libatalk/cnid/db3/cnid_db3.h b/libatalk/cnid/db3/cnid_db3.h
new file mode 100644 (file)
index 0000000..4e3b37d
--- /dev/null
@@ -0,0 +1,85 @@
+/* 
+ * interface for database access to cnids. i do it this way to abstract
+ * things a bit in case we want to change the underlying implementation.
+ */
+
+#ifndef _ATALK_CNID_DB3__H
+#define _ATALK_CNID_DB3__H 1
+
+#include <sys/cdefs.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <string.h>
+
+#include <netatalk/endian.h>
+#include <atalk/cnid.h>
+
+static __inline__ int db3_txn_abort(DB_TXN *db_txn)
+{
+    int ret;
+#if DB_VERSION_MAJOR >= 4
+    ret = db_txn->abort(db_txn);
+#else
+    ret = txn_abort(db_txn);
+#endif
+    return ret;
+}
+
+/* -------------------- */
+static __inline__ int db3_txn_begin(DB_ENV *db_env, DB_TXN *parent, DB_TXN **db_txn, u_int32_t flags)
+{
+    int ret;
+#if DB_VERSION_MAJOR >= 4
+    ret = db_env->txn_begin(db_env, parent, db_txn, flags);
+#else
+    ret = txn_begin(db_env, paren, db_txn, flags);
+#endif
+    return ret;
+}
+            
+/* -------------------- */
+static __inline__ int db3_txn_commit(DB_TXN *db_txn, u_int32_t flags)
+{
+    int ret;
+#if DB_VERSION_MAJOR >= 4
+    ret = db_txn->commit(db_txn, flags);
+#else
+    ret = txn_commit(db_txn, flags);
+#endif
+    return ret;
+}
+
+/* -----------------------
+   cnid_open.c 
+*/
+extern struct _cnid_module cnid_db3_module;
+extern struct _cnid_db *cnid_db3_open __P((const char *, mode_t));
+
+/* cnid_close.c */
+extern void cnid_db3_close __P((struct _cnid_db *));
+
+/* cnid_add.c */
+extern cnid_t cnid_db3_add __P((struct _cnid_db *, const struct stat *, const cnid_t,
+                           const char *, const int, cnid_t));
+
+/* cnid_get.c */
+extern cnid_t cnid_db3_get __P((struct _cnid_db *, const cnid_t, const char *, const int)); 
+extern char *cnid_db3_resolve __P((struct _cnid_db *, cnid_t *, void *, u_int32_t )); 
+extern cnid_t cnid_db3_lookup __P((struct _cnid_db *, const struct stat *, const cnid_t,
+                              const char *, const int));
+
+/* cnid_update.c */
+extern int cnid_db3_update __P((struct _cnid_db *, const cnid_t, const struct stat *,
+                           const cnid_t, const char *, int));
+
+/* cnid_delete.c */
+extern int cnid_db3_delete __P((struct _cnid_db *, const cnid_t));
+
+/* cnid_nextid.c */
+extern cnid_t cnid_db3_nextid __P((struct _cnid_db *));
+
+extern int cnid_db3_lock   __P((void *));
+extern int cnid_db3_unlock __P((void *));
+
+#endif /* include/atalk/cnid_db3.h */
+
diff --git a/libatalk/cnid/db3/cnid_db3_add.c b/libatalk/cnid/db3/cnid_db3_add.c
new file mode 100644 (file)
index 0000000..8798875
--- /dev/null
@@ -0,0 +1,282 @@
+/*
+ * $Id: cnid_db3_add.c,v 1.1.4.1 2003-09-09 16:42:21 didg Exp $
+ *
+ * Copyright (c) 1999. Adrian Sun (asun@zoology.washington.edu)
+ * All Rights Reserved. See COPYRIGHT.
+ *
+ * cnid_add (db, dev, ino, did, name, hint):
+ * add a name to the CNID database. we use both dev/ino and did/name
+ * to keep track of things.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#ifdef CNID_BACKEND_DB3
+
+#include <stdio.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <string.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif /* HAVE_FCNTL_H */
+#include <errno.h>
+#include <atalk/logger.h>
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif /* HAVE_SYS_TIME_H */
+
+#include <db.h>
+#include <netatalk/endian.h>
+
+#include <atalk/adouble.h>
+#include "cnid_db3.h"
+#include <atalk/util.h>
+
+#include "cnid_db3_private.h"
+
+/* add an entry to the CNID databases. we do this as a transaction
+ * to prevent messiness. */
+static int add_cnid(CNID_private *db, DBT *key, DBT *data) {
+    DBT altkey, altdata;
+    DB_TXN *tid;
+    int rc, ret;
+
+    memset(&altkey, 0, sizeof(altkey));
+    memset(&altdata, 0, sizeof(altdata));
+
+retry:
+    if ((rc = db3_txn_begin(db->dbenv, NULL, &tid, 0)) != 0) {
+        return rc;
+    }
+
+    /* main database */
+    if ((rc = db->db_cnid->put(db->db_cnid, tid, key, data, DB_NOOVERWRITE))) {
+        if (rc == DB_LOCK_DEADLOCK) {
+            if ((ret = db3_txn_abort(tid)) != 0) {
+                return ret;
+            }
+            goto retry;
+        }
+        goto abort;
+    }
+
+    /* dev/ino database */
+    altkey.data = data->data;
+    altkey.size = CNID_DEVINO_LEN;
+    altdata.data = key->data;
+    altdata.size = key->size;
+    if ((rc = db->db_devino->put(db->db_devino, tid, &altkey, &altdata, 0))) {
+        if (rc == DB_LOCK_DEADLOCK) {
+            if ((ret = db3_txn_abort(tid)) != 0) {
+                return ret;
+            }
+            goto retry;
+        }
+        goto abort;
+    }
+
+    /* did/name database */
+    altkey.data = (char *) data->data + CNID_DEVINO_LEN;
+    altkey.size = data->size - CNID_DEVINO_LEN;
+    if ((rc = db->db_didname->put(db->db_didname, tid, &altkey, &altdata, 0))) {
+        if (rc == DB_LOCK_DEADLOCK) {
+            if ((ret = db3_txn_abort(tid)) != 0) {
+                return ret;
+            }
+            goto retry;
+        }
+        goto abort;
+    }
+
+    if ((rc = db3_txn_commit(tid, 0)) != 0) {
+        LOG(log_error, logtype_default, "add_cnid: Failed to commit transaction: %s", db_strerror(rc));
+        return rc;
+    }
+
+    return 0;
+
+abort:
+    if ((ret = db3_txn_abort(tid)) != 0) {
+        return ret;
+    }
+    return rc;
+}
+
+/* ---------------------- */
+static cnid_t get_cnid(CNID_private *db)
+{
+    DBT rootinfo_key, rootinfo_data;
+    DB_TXN *tid;
+    int rc;
+    int flag;
+    cnid_t hint,id;
+
+    memset(&rootinfo_key, 0, sizeof(rootinfo_key));
+    memset(&rootinfo_data, 0, sizeof(rootinfo_data));
+    rootinfo_key.data = ROOTINFO_KEY;
+    rootinfo_key.size = ROOTINFO_KEYLEN;
+
+retry:
+    if ((rc = db3_txn_begin(db->dbenv, NULL, &tid, 0)) != 0) {
+        LOG(log_error, logtype_default, "cnid_add: Failed to begin transaction: %s", db_strerror(rc));
+        errno = CNID_ERR_DB;
+        return CNID_INVALID;
+    }
+    switch (rc = db->db_didname->get(db->db_didname, tid, &rootinfo_key,
+                                     &rootinfo_data, DB_RMW)) {
+    case DB_LOCK_DEADLOCK:
+        if ((rc = db3_txn_abort(tid)) != 0) {
+            LOG(log_error, logtype_default, "cnid_add: txn_abort: %s", db_strerror(rc));
+            errno = CNID_ERR_DB;
+            return CNID_INVALID;
+        }
+        goto retry;
+    case 0:
+        memcpy(&hint, rootinfo_data.data, sizeof(hint));
+        id = ntohl(hint);
+        /* If we've hit the max CNID allowed, we return a fatal error.  CNID
+         * needs to be recycled before proceding. */
+        if (++id == CNID_INVALID) {
+            db3_txn_abort(tid);
+            LOG(log_error, logtype_default, "cnid_add: FATAL: Cannot add CNID.  CNID database has reached its limit.");
+            errno = CNID_ERR_MAX;
+            return CNID_INVALID;
+        }
+        hint = htonl(id);
+/* #ifdef DEBUG */
+#if 0
+        LOG(log_info, logtype_default, "cnid_add: Found rootinfo for did %u, name %s as %u", ntohl(did), name, ntohl(hint));
+#endif
+        break;
+    case DB_NOTFOUND:
+        hint = htonl(CNID_START);
+/* #ifdef DEBUG */
+#if 0
+        LOG(log_info, logtype_default, "cnid_add: Using CNID_START for did %u, name %s", ntohl(did), name);
+#endif
+        break;
+    default:
+        LOG(log_error, logtype_default, "cnid_add: Unable to lookup rootinfo: %s", db_strerror(rc));
+        goto cleanup_abort;
+    }
+
+    rootinfo_data.data = &hint;
+    rootinfo_data.size = sizeof(hint);
+
+    switch (rc = db->db_didname->put(db->db_didname, tid, &rootinfo_key, &rootinfo_data, 0)) {
+    case DB_LOCK_DEADLOCK:
+        if ((rc = db3_txn_abort(tid)) != 0) {
+            LOG(log_error, logtype_default, "cnid_add: txn_abort: %s", db_strerror(rc));
+            errno = CNID_ERR_DB;
+            return CNID_INVALID;
+        }
+        goto retry;
+    case 0:
+        /* The transaction finished, commit it. */
+        if ((rc = db3_txn_commit(tid, 0)) != 0) {
+            LOG(log_error, logtype_default, "cnid_add: Unable to commit transaction: %s", db_strerror(rc));
+            errno = CNID_ERR_DB;
+            return CNID_INVALID;
+        }
+        break;
+    default:
+        LOG(log_error, logtype_default, "cnid_add: Unable to update rootinfo: %s", db_strerror(rc));
+        goto cleanup_abort;
+    }
+    return hint;
+    
+cleanup_abort:
+    db3_txn_abort(tid);
+    errno = CNID_ERR_DB;
+    return CNID_INVALID;
+}
+
+/* ------------------------ */
+cnid_t cnid_db3_add(struct _cnid_db *cdb, const struct stat *st,
+                const cnid_t did, const char *name, const int len,
+                cnid_t hint)
+{
+    CNID_private *db;
+    DBT key, data;
+    cnid_t id;
+    int rc;
+
+    if (!cdb || !(db = cdb->_private) || !st || !name) {
+        errno = CNID_ERR_PARAM;
+        return CNID_INVALID;
+    }
+
+    /* Do a lookup. */
+    id = cnid_db3_lookup(cdb, st, did, name, len);
+    /* ... Return id if it is valid, or if Rootinfo is read-only. */
+    if (id || (db->flags & CNIDFLAG_DB_RO)) {
+#ifdef DEBUG
+        LOG(log_info, logtype_default, "cnid_add: Looked up did %u, name %s as %u", ntohl(did), name, ntohl(id));
+#endif
+        return id;
+    }
+
+    /* Initialize our DBT data structures. */
+    memset(&key, 0, sizeof(key));
+    memset(&data, 0, sizeof(data));
+
+    /* Just tickle hint, and the key will change (gotta love pointers). */
+    key.data = &hint;
+    key.size = sizeof(hint);
+
+    if ((data.data = make_cnid_data(st, did, name, len)) == NULL) {
+        LOG(log_error, logtype_default, "cnid_add: Path name is too long");
+        errno = CNID_ERR_PATH;
+        return CNID_INVALID;
+    }
+
+    data.size = CNID_HEADER_LEN + len + 1;
+
+    /* Start off with the hint.  It should be in network byte order.
+     * We need to make sure that somebody doesn't add in restricted
+     * cnid's to the database. */
+    if (ntohl(hint) >= CNID_START) {
+        /* If the key doesn't exist, add it in.  Don't fiddle with nextID. */
+        rc = add_cnid(db, &key, &data);
+        switch (rc) {
+        case DB_KEYEXIST: /* Need to use RootInfo after all. */
+            break;
+        default:
+            LOG(log_error, logtype_default, "cnid_add: Unable to add CNID %u: %s", ntohl(hint), db_strerror(rc));
+            errno = CNID_ERR_DB;
+            return CNID_INVALID;
+        case 0:
+#ifdef DEBUG
+            LOG(log_info, logtype_default, "cnid_add: Used hint for did %u, name %s as %u", ntohl(did), name, ntohl(hint));
+#endif
+            return hint;
+        }
+    }
+    hint = get_cnid(db);
+    if (hint == 0) {
+        errno = CNID_ERR_DB;
+        return CNID_INVALID;
+    }
+    
+    /* Now we need to add the CNID data to the databases. */
+    rc = add_cnid(db, &key, &data);
+    if (rc) {
+        LOG(log_error, logtype_default, "cnid_add: Failed to add CNID for %s to database using hint %u: %s", name, ntohl(hint), db_strerror(rc));
+        errno = CNID_ERR_DB;
+        return CNID_INVALID;
+    }
+
+#ifdef DEBUG
+    LOG(log_info, logtype_default, "cnid_add: Returned CNID for did %u, name %s as %u", ntohl(did), name, ntohl(hint));
+#endif
+
+    return hint;
+}
+
+#endif /* CNID_BACKEND_DB3 */
diff --git a/libatalk/cnid/db3/cnid_db3_close.c b/libatalk/cnid/db3/cnid_db3_close.c
new file mode 100644 (file)
index 0000000..b17d4ee
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * $Id: cnid_db3_close.c,v 1.1.4.1 2003-09-09 16:42:21 didg Exp $
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#ifdef CNID_BACKEND_DB3
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif /* HAVE_FCNTL_H */
+#include <stdlib.h>
+#include <atalk/logger.h>
+#include <db.h>
+#include <errno.h>
+#include <string.h>
+
+#include "cnid_db3_private.h"
+#include "cnid_db3.h"
+
+void cnid_db3_close(struct _cnid_db *cdb) {
+    CNID_private *db;
+    int rc;
+
+    if (!cdb) {
+           LOG(log_error, logtype_afpd, "cnid_close called with NULL argument !");
+           return;
+    }
+
+    if (!(db = cdb->_private)) {
+        return;
+    }
+
+    /* Flush the transaction log and delete the log file if we can. */
+    if ((db->lockfd > -1) && ((db->flags & CNIDFLAG_DB_RO) == 0)) {
+        struct flock lock;
+
+    lock.l_type = F_WRLCK;
+    lock.l_whence = SEEK_SET;
+    lock.l_start = lock.l_len = 0;
+    if (fcntl(db->lockfd, F_SETLK, &lock) == 0) {
+            char **list, **first;
+
+
+            /* Checkpoint the databases until we can checkpoint no
+             * more. */
+#if DB_VERSION_MAJOR >= 4
+#if DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 1
+            db->dbenv->txn_checkpoint(db->dbenv, 0, 0, 0);
+#else
+            rc = db->dbenv->txn_checkpoint(db->dbenv, 0, 0, 0);
+#endif /* DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 1 */
+#else
+            rc = txn_checkpoint(db->dbenv, 0, 0, 0);
+#endif /* DB_VERSION_MAJOR >= 4 */
+#if DB_VERSION_MAJOR < 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR < 1)
+            while (rc == DB_INCOMPLETE) {
+#if DB_VERSION_MAJOR >= 4
+                rc = db->dbenv->txn_checkpoint(db->dbenv, 0, 0, 0);
+#else
+                rc = txn_checkpoint(db->dbenv, 0, 0, 0);
+#endif /* DB_VERSION_MAJOR >= 4 */
+            }
+#endif /* DB_VERSION_MAJOR < 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR < 1) */
+
+#if DB_VERSION_MAJOR >= 4
+            if ((rc = db->dbenv->log_archive(db->dbenv, &list, DB_ARCH_ABS)) != 0) {
+#elif DB_VERSION_MINOR > 2
+            if ((rc = log_archive(db->dbenv, &list, DB_ARCH_ABS)) != 0) {
+#else /* DB_VERSION_MINOR < 2 */
+            if ((rc = log_archive(db->dbenv, &list, DB_ARCH_ABS, NULL)) != 0) {
+#endif /* DB_VERSION_MINOR */
+                LOG(log_error, logtype_default, "cnid_close: Unable to archive logfiles: %s", db_strerror(rc));
+            }
+
+            if (list != NULL) {
+                for (first = list; *list != NULL; ++list) {
+                    if ((rc = remove(*list)) != 0) {
+#ifdef DEBUG
+                            LOG(log_info, logtype_default, "cnid_close: failed to remove %s: %s", *list, strerror(rc));
+#endif
+                        }
+                }
+                free(first);
+            }
+        }
+        (void)remove(db->lock_file);
+    }
+
+    db->db_didname->close(db->db_didname, 0);
+    db->db_devino->close(db->db_devino, 0);
+    db->db_cnid->close(db->db_cnid, 0);
+    db->dbenv->close(db->dbenv, 0);
+
+    if (db->lockfd > -1) {
+        close(db->lockfd); /* This will also release any locks we have. */
+    }
+
+    free(db);
+    free(cdb->volpath);
+    free(cdb);
+}
+
+#endif /* CNID_BACKEND_DB3 */
diff --git a/libatalk/cnid/db3/cnid_db3_delete.c b/libatalk/cnid/db3/cnid_db3_delete.c
new file mode 100644 (file)
index 0000000..e7c544b
--- /dev/null
@@ -0,0 +1,155 @@
+/*
+ * $Id: cnid_db3_delete.c,v 1.1.4.1 2003-09-09 16:42:21 didg Exp $
+ *
+ * Copyright (c) 1999. Adrian Sun (asun@zoology.washington.edu)
+ * All Rights Reserved. See COPYRIGHT.
+ *
+ * cnid_delete: delete a CNID from the database 
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#ifdef CNID_BACKEND_DB3
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <atalk/logger.h>
+
+#include <db.h>
+#include <netatalk/endian.h>
+#include <atalk/adouble.h>
+#include "cnid_db3.h"
+
+#include "cnid_db3_private.h"
+
+int cnid_db3_delete(struct _cnid_db *cdb, const cnid_t id) {
+    CNID_private *db;
+    DBT key, data;
+    DB_TXN *tid;
+    int rc, found = 0;
+
+    if (!cdb || !(db = cdb->_private) || !id || (db->flags & CNIDFLAG_DB_RO)) {
+        return -1;
+    }
+
+    memset(&key, 0, sizeof(key));
+    memset(&data, 0, sizeof(data));
+
+    /* Get from ain CNID database. */
+    key.data = (cnid_t *)&id;
+    key.size = sizeof(id);
+    while (!found) {
+        rc = db->db_cnid->get(db->db_cnid, NULL, &key, &data, 0);
+        switch (rc) {
+        case 0:
+            found = 1;
+            break;
+        case DB_LOCK_DEADLOCK:
+            break;
+        case DB_NOTFOUND:
+#ifdef DEBUG
+            LOG(log_info, logtype_default, "cnid_delete: CNID %u not in database",
+                ntohl(id));
+#endif
+            return 0;
+        default:
+            LOG(log_error, logtype_default, "cnid_delete: Unable to delete entry: %s",
+                db_strerror(rc));
+            return rc;
+        }
+    }
+
+retry:
+    if ((rc = db3_txn_begin(db->dbenv, NULL, &tid, 0)) != 0) {
+        LOG(log_error, logtype_default, "cnid_delete: Failed to begin transaction: %s",
+            db_strerror(rc));
+        return rc;
+    }
+
+    /* Now delete from the main CNID database. */
+    key.data = (cnid_t *)&id;
+    key.size = sizeof(id);
+    if ((rc = db->db_cnid->del(db->db_cnid, tid, &key, 0))) {
+        int ret;
+        if ((ret = db3_txn_abort(tid)) != 0) {
+            LOG(log_error, logtype_default, "cnid_delete: txn_abort: %s", db_strerror(ret));
+            return ret;
+        }
+        switch (rc) {
+        case DB_LOCK_DEADLOCK:
+            goto retry;
+        default:
+            goto abort_err;
+        }
+    }
+
+    /* Now delete from dev/ino database. */
+    key.data = data.data;
+    key.size = CNID_DEVINO_LEN;
+    if ((rc = db->db_devino->del(db->db_devino, tid, &key, 0))) {
+        switch (rc) {
+        case DB_LOCK_DEADLOCK:
+            if ((rc = db3_txn_abort(tid)) != 0) {
+                LOG(log_error, logtype_default, "cnid_delete: txn_abort: %s",
+                    db_strerror(rc));
+                return rc;
+            }
+            goto retry;
+        case DB_NOTFOUND:
+            /* Quietly fall through if the entry isn't found. */
+            break;
+        default:
+            if ((rc = db3_txn_abort(tid)) != 0) {
+                LOG(log_error, logtype_default, "cnid_delete: txn_abort: %s",
+                    db_strerror(rc));
+                return rc;
+            }
+            goto abort_err;
+        }
+    }
+
+    /* Get data from the did/name database.
+     * TODO Also handle did/macname, did/shortname, and did/longname. */
+    key.data = (char *)data.data + CNID_DEVINO_LEN;
+    key.size = data.size - CNID_DEVINO_LEN;
+    if ((rc = db->db_didname->del(db->db_didname, tid, &key, 0))) {
+        switch (rc) {
+        case DB_LOCK_DEADLOCK:
+            if ((rc = db3_txn_abort(tid)) != 0) {
+                LOG(log_error, logtype_default, "cnid_delete: txn_abort: %s",
+                    db_strerror(rc));
+                return rc;
+            }
+            goto retry;
+        case DB_NOTFOUND:
+            break;
+        default:
+            if ((rc = db3_txn_abort(tid)) != 0) {
+                LOG(log_error, logtype_default, "cnid_delete: txn_abort: %s",
+                    db_strerror(rc));
+                return rc;
+            }
+            goto abort_err;
+        }
+    }
+
+#ifdef DEBUG
+    LOG(log_info, logtype_default, "cnid_delete: Deleting CNID %u", ntohl(id));
+#endif
+    if ((rc = db3_txn_commit(tid, 0)) != 0) {
+        LOG(log_error, logtype_default, "cnid_delete: Failed to commit transaction: %s",
+            db_strerror(rc));
+        return rc;
+    }
+    return 0;
+
+abort_err:
+    LOG(log_error, logtype_default, "cnid_delete: Unable to delete CNID %u: %s",
+        ntohl(id), db_strerror(rc));
+    return rc;
+}
+
+#endif /* CNID_BACKEND_DB3 */
diff --git a/libatalk/cnid/db3/cnid_db3_get.c b/libatalk/cnid/db3/cnid_db3_get.c
new file mode 100644 (file)
index 0000000..35d643a
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * $Id: cnid_db3_get.c,v 1.1.4.1 2003-09-09 16:42:21 didg Exp $
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#ifdef CNID_BACKEND_DB3
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <atalk/logger.h>
+#include <errno.h>
+
+#include <db.h>
+#include <netatalk/endian.h>
+#include <atalk/adouble.h>
+#include "cnid_db3.h"
+
+#include "cnid_db3_private.h"
+
+/* Return CNID for a given did/name. */
+cnid_t cnid_db3_get(struct _cnid_db *cdb, const cnid_t did, const char *name,
+                const int len)
+{
+    char start[CNID_DID_LEN + MAXPATHLEN + 1], *buf;
+    CNID_private *db;
+    DBT key, data;
+    cnid_t id;
+    int rc;
+
+    if (!cdb || !(db = cdb->_private) || (len > MAXPATHLEN)) {
+        // FIXME: shall we report some error !
+        return 0;
+    }
+
+    memset(&key, 0, sizeof(key));
+    memset(&data, 0, sizeof(data));
+
+    buf = start;
+    memcpy(buf, &did, sizeof(did));
+    buf += sizeof(did);
+    memcpy(buf, name, len);
+    *(buf + len) = '\0'; /* Make it a C-string. */
+    key.data = start;
+    key.size = CNID_DID_LEN + len + 1;
+
+    while ((rc = db->db_didname->get(db->db_didname, NULL, &key, &data, 0))) {
+        if (rc == DB_LOCK_DEADLOCK) {
+            continue;
+        }
+
+        if (rc != DB_NOTFOUND) {
+            LOG(log_error, logtype_default, "cnid_get: Unable to get CNID %u, name %s: %s",
+                ntohl(did), name, db_strerror(rc));
+        }
+
+        return 0;
+    }
+
+    memcpy(&id, data.data, sizeof(id));
+#ifdef DEBUG
+    LOG(log_info, logtype_default, "cnid_get: Returning CNID for %u, name %s as %u",
+        ntohl(did), name, ntohl(id));
+#endif
+    return id;
+}
+
+#endif /* CNID_BACKEND_DB3 */
diff --git a/libatalk/cnid/db3/cnid_db3_lookup.c b/libatalk/cnid/db3/cnid_db3_lookup.c
new file mode 100644 (file)
index 0000000..9a29e79
--- /dev/null
@@ -0,0 +1,144 @@
+
+/*
+ * $Id: cnid_db3_lookup.c,v 1.1.4.1 2003-09-09 16:42:21 didg Exp $
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#ifdef CNID_BACKEND_DB3
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <atalk/logger.h>
+#include <errno.h>
+
+#include <db.h>
+#include <netatalk/endian.h>
+#include <atalk/adouble.h>
+#include "cnid_db3.h"
+
+#include "cnid_db3_private.h"
+
+#define LOGFILEMAX    100       /* kbytes */
+#define CHECKTIMEMAX   30       /* minutes */
+
+/* This returns the CNID corresponding to a particular file.  It will
+ * also fix up the various databases if there's a problem. */
+cnid_t cnid_db3_lookup(struct _cnid_db *cdb, const struct stat *st, const cnid_t did, const char *name, const int len)
+{
+    char *buf;
+    CNID_private *db;
+    DBT key, devdata, diddata;
+    int devino = 1, didname = 1;
+    cnid_t id = 0;
+    int rc;
+
+    if (!cdb || !(db = cdb->_private) || !st || !name) {
+        return 0;
+    }
+
+    /* Do a little checkpointing if necessary.  I stuck it here as cnid_lookup
+     * gets called when we do directory lookups.  Only do this if we're using
+     * a read-write database. */
+    if ((db->flags & CNIDFLAG_DB_RO) == 0) {
+#ifdef DEBUG
+        LOG(log_info, logtype_default, "cnid_lookup: Running database checkpoint");
+#endif
+#if DB_VERSION_MAJOR > 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 1)
+        if ((rc = db->dbenv->txn_checkpoint(db->dbenv, LOGFILEMAX, CHECKTIMEMAX, 0))) {
+            LOG(log_error, logtype_default, "cnid_lookup: txn_checkpoint: %s", db_strerror(rc));
+            return 0;
+        }
+#else
+#if DB_VERSION_MAJOR >= 4
+        switch (rc = db->dbenv->txn_checkpoint(db->dbenv, LOGFILEMAX, CHECKTIMEMAX, 0)) {
+#else
+        switch (rc = txn_checkpoint(db->dbenv, LOGFILEMAX, CHECKTIMEMAX, 0)) {
+#endif /* DB_VERSION_MAJOR >= 4 */
+        case 0:
+        case DB_INCOMPLETE:
+            break;
+        default:
+            LOG(log_error, logtype_default, "cnid_lookup: txn_checkpoint: %s", db_strerror(rc));
+            return 0;
+        }
+#endif /* DB_VERSION_MAJOR > 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 1) */
+    }
+
+    if ((buf = make_cnid_data(st, did, name, len)) == NULL) {
+        LOG(log_error, logtype_default, "cnid_lookup: Pathname is too long");
+        return 0;
+    }
+
+    memset(&key, 0, sizeof(key));
+    memset(&devdata, 0, sizeof(devdata));
+    memset(&diddata, 0, sizeof(diddata));
+
+    /* Look for a CNID.  We have two options: dev/ino or did/name.  If we
+     * only get a match in one of them, that means a file has moved. */
+    key.data = buf;
+    key.size = CNID_DEVINO_LEN;
+    while ((rc = db->db_devino->get(db->db_devino, NULL, &key, &devdata, 0))) {
+        if (rc == DB_LOCK_DEADLOCK) {
+            continue;
+        }
+
+        if (rc == DB_NOTFOUND) {
+            devino = 0;
+            break;
+        }
+
+        LOG(log_error, logtype_default, "cnid_lookup: Unable to get CNID dev %u, ino %u: %s",
+            st->st_dev, st->st_ino, db_strerror(rc));
+        return 0;
+    }
+
+    /* did/name now */
+    key.data = buf + CNID_DEVINO_LEN;
+    key.size = CNID_DID_LEN + len + 1;
+    while ((rc = db->db_didname->get(db->db_didname, NULL, &key, &diddata, 0))) {
+        if (rc == DB_LOCK_DEADLOCK) {
+            continue;
+        }
+
+        if (rc == DB_NOTFOUND) {
+            didname = 0;
+            break;
+        }
+
+        LOG(log_error, logtype_default, "cnid_lookup: Unable to get CNID %u, name %s: %s",
+            ntohl(did), name, db_strerror(rc));
+        return 0;
+    }
+
+    /* Set id.  Honor did/name over dev/ino as dev/ino isn't necessarily
+     * 1-1. */
+    if (didname) {
+        memcpy(&id, diddata.data, sizeof(id));
+    } else if (devino) {
+        memcpy(&id, devdata.data, sizeof(id));
+    }
+
+    /* Either entries are in both databases or neither of them. */
+    if ((devino && didname) || !(devino || didname)) {
+#ifdef DEBUG
+        LOG(log_info, logtype_default, "cnid_lookup: Looked up did %u, name %s, as %u", ntohl(did), name, ntohl(id));
+#endif
+        return id;
+    }
+
+    /* Fix up the database. */
+    cnid_db3_update(cdb, id, st, did, name, len);
+#ifdef DEBUG
+    LOG(log_info, logtype_default, "cnid_lookup: Looked up did %u, name %s, as %u (needed update)", ntohl(did), name,
+        ntohl(id));
+#endif
+    return id;
+}
+
+
+#endif /* CNID_BACKEND_DB3 */
diff --git a/libatalk/cnid/db3/cnid_db3_meta.c b/libatalk/cnid/db3/cnid_db3_meta.c
new file mode 100644 (file)
index 0000000..5495f13
--- /dev/null
@@ -0,0 +1,9 @@
+/*
+ * $Id: cnid_db3_meta.c,v 1.1.4.1 2003-09-09 16:42:21 didg Exp $
+ *
+ * Copyright (c) 1999. Adrian Sun (asun@zoology.washington.edu)
+ * All Rights Reserved. See COPYRIGHT.
+ *
+ * deal with metadata
+ *
+ */
diff --git a/libatalk/cnid/db3/cnid_db3_meta.h b/libatalk/cnid/db3/cnid_db3_meta.h
new file mode 100644 (file)
index 0000000..bc591a6
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * $Id: cnid_db3_meta.h,v 1.1.4.1 2003-09-09 16:42:21 didg Exp $
+ */
+
+#define CNID_META_CNID_LEN      4
+#define CNID_META_MDATE_LEN     4  /* space for 8 */
+#define CNID_META_CDATE_LEN     4  /* space for 8 */
+#define CNID_META_BDATE_LEN     4  /* ditto */
+#define CNID_META_ADATE_LEN     4  /* ditto */
+#define CNID_META_AFPI_LEN      4  /* plus permission bits */
+#define CNID_META_FINDERI_LEN   32 
+#define CNID_META_PRODOSI_LEN   8
+#define CNID_META_RFORKLEN_LEN  4  /* space for 8 */
+#define CNID_META_MACNAME_LEN   32 /* maximum size */
+#define CNID_META_SHORTNAME_LEN 12 /* max size (8.3) */
+#define CNID_META_FILLER_LEN    4
+
+#define CNID_META_CNID_OFF     0
+#define CNID_META_MDATE_OFF    (CNID_META_CNID_OFF + CNID_META_CNID_LEN + \
+                               CNID_META_FILLER_LEN)
+#define CNID_META_CDATE_OFF    (CNID_META_MDATE_OFF + CNID_META_MDATE_LEN + \
+                               CNID_META_FILLER_LEN)
+#define CNID_META_BDATE_OFF    (CNID_META_CDATE_OFF + CNID_META_CDATE_LEN + \
+                               CNID_META_FILLER_LEN)
+#define CNID_META_ADATE_OFF    (CNID_META_BDATE_OFF + CNID_META_BDATE_LEN + \
+                               CNID_META_FILLER_LEN)
+#define CNID_META_AFPI_OFF     (CNID_META_ADATE_OFF + CNID_META_ADATE_LEN)
+#define CNID_META_FINDERI_OFF  (CNID_META_AFPI_OFF + CNID_META_AFPI_LEN)
+#define CNID_META_PRODOSI_OFF  (CNID_META_FINDERI_OFF + CNID_META_FINDERI_LEN)
+#define CNID_META_RFORKLEN_OFF (CNID_META_PRODOSI_OFF + CNID_META_PRODOSI_LEN)
+#define CNID_META_MACNAME_OFF  (CNID_META_RFORKLEN_OFF + \
+                               CNID_META_RFORKLEN_LEN)
+#define CNID_META_SHORTNAME_OFF (CNID_META_MACNAME_OFF + 
+
+
+#define cnid_meta_clear(a)  
+#define cnid_meta_get(id)
+
+#define cnid_meta_cnid(a)  
+#define cnid_meta_modifydate(a)
+#define cnid_meta_createdate(a)
+#define cnid_meta_backupdate(a)
+#define cnid_meta_accessdate(a)
+#define cnid_meta_afpi(a)
+#define cnid_meta_finderi(a)
+#define cnid_meta_prodosi(a)
+#define cnid_meta_rforklen(a)
+#define cnid_meta_macname(a)
+#define cnid_meta_shortname(a)
+#define cnid_meta_longname(a)
+
diff --git a/libatalk/cnid/db3/cnid_db3_nextid.c b/libatalk/cnid/db3/cnid_db3_nextid.c
new file mode 100644 (file)
index 0000000..70a1360
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * $Id: cnid_db3_nextid.c,v 1.1.4.1 2003-09-09 16:42:21 didg Exp $
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#ifdef CNID_BACKEND_DB3
+
+#ifdef unused
+
+#include <db.h>
+
+#include <atalk/adouble.h>
+#include "cnid_db3.h"
+
+#include <atalk/logger.h>
+
+#include "cnid_db3_private.h"
+
+/* return the next id. we use the fact that ad files are memory
+ * mapped. */
+cnid_t cnid_db3_nextid(struct _cnid_db *cdb)
+{
+    CNID_private *db;
+    cnid_t id;
+
+    if (!cdb || !(db = cdb->_private))
+        return 0;
+
+    memcpy(&id, ad_entry(&db->rootinfo, ADEID_DID), sizeof(id));
+    return id;
+}
+#endif
+
+#endif /* CNID_BACKEND_DB3 */
diff --git a/libatalk/cnid/db3/cnid_db3_open.c b/libatalk/cnid/db3/cnid_db3_open.c
new file mode 100644 (file)
index 0000000..2785d15
--- /dev/null
@@ -0,0 +1,513 @@
+
+/*
+ * $Id: cnid_db3_open.c,v 1.1.4.1 2003-09-09 16:42:21 didg Exp $
+ *
+ * Copyright (c) 1999. Adrian Sun (asun@zoology.washington.edu)
+ * All Rights Reserved. See COPYRIGHT.
+ *
+ * CNID database support. 
+ *
+ * here's the deal:
+ *  1) afpd already caches did's. 
+ *  2) the database stores cnid's as both did/name and dev/ino pairs. 
+ *  3) RootInfo holds the value of the NextID.
+ *  4) the cnid database gets called in the following manner --
+ *     start a database:
+ *     cnid = cnid_open(root_dir);
+ *
+ *     allocate a new id: 
+ *     newid = cnid_add(cnid, dev, ino, parent did,
+ *     name, id); id is a hint for a specific id. pass 0 if you don't
+ *     care. if the id is already assigned, you won't get what you
+ *     requested.
+ *
+ *     given an id, get a did/name and dev/ino pair.
+ *     name = cnid_get(cnid, &id); given an id, return the corresponding
+ *     info.
+ *     return code = cnid_delete(cnid, id); delete an entry. 
+ *
+ * with AFP, CNIDs 0-2 have special meanings. here they are:
+ * 0 -- invalid cnid
+ * 1 -- parent of root directory (handled by afpd) 
+ * 2 -- root directory (handled by afpd)
+ *
+ * CNIDs 4-16 are reserved according to page 31 of the AFP 3.0 spec so, 
+ * CNID_START begins at 17.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#ifdef CNID_BACKEND_DB3
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif /* HAVE_FCNTL_H */
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <atalk/logger.h>
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif /* HAVE_SYS_TIME_H */
+
+#include <db.h>
+
+#include <atalk/adouble.h>
+#include <atalk/cnid.h>
+#include "cnid_db3.h"
+#include <atalk/util.h>
+
+#include "cnid_db3_private.h"
+
+#ifndef MIN
+#define MIN(a, b)  ((a) < (b) ? (a) : (b))
+#endif /* ! MIN */
+
+#define DBHOME        ".AppleDB"
+#define DBCNID        "cnid.db"
+#define DBDEVINO      "devino.db"
+#define DBDIDNAME     "didname.db"      /* did/full name mapping */
+#define DBLOCKFILE    "cnid.lock"
+#define DBRECOVERFILE "cnid.dbrecover"
+#define DBCLOSEFILE   "cnid.close"
+
+#define DBHOMELEN    8
+#define DBLEN        10
+
+/* we version the did/name database so that we can change the format
+ * if necessary. the key is in the form of a did/name pair. in this case,
+ * we use 0/0. */
+#define DBVERSION_KEY    "\0\0\0\0\0"
+#define DBVERSION_KEYLEN 5
+#define DBVERSION1       0x00000001U
+#define DBVERSION        DBVERSION1
+
+#if DB_VERSION_MAJOR >= 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR > 1)
+#define DBOPTIONS    (DB_CREATE | DB_INIT_MPOOL | DB_INIT_LOCK | \
+DB_INIT_LOG | DB_INIT_TXN)
+#else /* DB_VERSION_MINOR < 1 */
+
+/*#define DBOPTIONS    (DB_CREATE | DB_INIT_MPOOL | DB_INIT_LOCK | \
+DB_INIT_LOG | DB_INIT_TXN | DB_TXN_NOSYNC)*/
+#define DBOPTIONS    (DB_CREATE | DB_INIT_MPOOL | DB_INIT_LOCK | \
+DB_INIT_LOG | DB_INIT_TXN)
+#endif /* DB_VERSION_MINOR */
+
+/* Let's try and use the youngest lock detector if present.
+ * If we can't do that, then let BDB use its default deadlock detector. */
+#if defined DB_LOCK_YOUNGEST
+#define DEAD_LOCK_DETECT DB_LOCK_YOUNGEST
+#else /* DB_LOCK_YOUNGEST */
+#define DEAD_LOCK_DETECT DB_LOCK_DEFAULT
+#endif /* DB_LOCK_YOUNGEST */
+
+#define MAXITER     0xFFFF      /* maximum number of simultaneously open CNID
+                                 * databases. */
+
+/* -----------------------
+ * bandaid for LanTest performance pb. for now not used, cf. ifdef 0 below
+*/
+static int my_yield(void)
+{
+    struct timeval t;
+    int ret;
+
+    t.tv_sec = 0;
+    t.tv_usec = 1000;
+    ret = select(0, NULL, NULL, NULL, &t);
+    return 0;
+}
+
+/* --------------- */
+static int my_open(DB * p, const char *f, const char *d, DBTYPE t, u_int32_t flags, int mode)
+{
+#if DB_VERSION_MAJOR > 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 1)
+    return p->open(p, NULL, f, d, t, flags | DB_AUTO_COMMIT, mode);
+#else
+    return p->open(p, f, d, t, flags, mode);
+#endif
+}
+
+/* --------------- */
+
+/* the first compare that's always done. */
+static __inline__ int compare_did(const DBT * a, const DBT * b)
+{
+    u_int32_t dida, didb;
+
+    memcpy(&dida, a->data, sizeof(dida));
+    memcpy(&didb, b->data, sizeof(didb));
+    return dida - didb;
+}
+
+/* sort did's and then names. this is for unix paths.
+ * i.e., did/unixname lookups. */
+#if DB_VERSION_MAJOR >= 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR > 1)
+static int compare_unix(DB * db, const DBT * a, const DBT * b)
+#else /* DB_VERSION_MINOR < 1 */
+static int compare_unix(const DBT * a, const DBT * b)
+#endif                          /* DB_VERSION_MINOR */
+{
+    u_int8_t *sa, *sb;
+    int len, ret;
+
+    /* sort by did */
+    if ((ret = compare_did(a, b)))
+        return ret;
+
+    sa = (u_int8_t *) a->data + 4;      /* shift past did */
+    sb = (u_int8_t *) b->data + 4;
+    for (len = MIN(a->size, b->size); len-- > 4; sa++, sb++)
+        if ((ret = (*sa - *sb)))
+            return ret;         /* sort by lexical ordering */
+
+    return a->size - b->size;   /* sort by length */
+}
+
+/* sort did's and then names. this is for macified paths (i.e.,
+ * did/macname, and did/shortname. i think did/longname needs a
+ * unicode table to work. also, we can't use strdiacasecmp as that
+ * returns a match if a < b. */
+#if DB_VERSION_MAJOR >= 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR > 1)
+static int compare_mac(DB * db, const DBT * a, const DBT * b)
+#else /* DB_VERSION_MINOR < 1 */
+static int compare_mac(const DBT * a, const DBT * b)
+#endif                          /* DB_VERSION_MINOR */
+{
+    u_int8_t *sa, *sb;
+    int len, ret;
+
+    /* sort by did */
+    if ((ret = compare_did(a, b)))
+        return ret;
+
+    sa = (u_int8_t *) a->data + 4;
+    sb = (u_int8_t *) b->data + 4;
+    for (len = MIN(a->size, b->size); len-- > 4; sa++, sb++)
+        if ((ret = (_diacasemap[*sa] - _diacasemap[*sb])))
+            return ret;         /* sort by lexical ordering */
+
+    return a->size - b->size;   /* sort by length */
+}
+
+
+/* for unicode names -- right now it's the same as compare_mac. */
+#if DB_VERSION_MAJOR >= 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR > 1)
+static int compare_unicode(DB * db, const DBT * a, const DBT * b)
+#else /* DB_VERSION_MINOR < 1 */
+static int compare_unicode(const DBT * a, const DBT * b)
+#endif                          /* DB_VERSION_MINOR */
+{
+#if DB_VERSION_MAJOR >= 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR > 1)
+    return compare_mac(db, a, b);
+#else /* DB_VERSION_MINOR < 1 */
+    return compare_mac(a, b);
+#endif /* DB_VERSION_MINOR */
+}
+
+static struct _cnid_db *cnid_db3_new(const char *volpath)
+{
+    struct _cnid_db *cdb;
+
+    if ((cdb = (struct _cnid_db *) calloc(1, sizeof(struct _cnid_db))) == NULL)
+        return NULL;
+
+    if ((cdb->volpath = strdup(volpath)) == NULL) {
+        free(cdb);
+        return NULL;
+    }
+
+    cdb->flags = CNID_FLAG_PERSISTENT;
+
+    cdb->cnid_add = cnid_db3_add;
+    cdb->cnid_delete = cnid_db3_delete;
+    cdb->cnid_get = cnid_db3_get;
+    cdb->cnid_lookup = cnid_db3_lookup;
+    cdb->cnid_nextid = NULL;    /*cnid_db3_nextid;*/
+    cdb->cnid_resolve = cnid_db3_resolve;
+    cdb->cnid_update = cnid_db3_update;
+    cdb->cnid_close = cnid_db3_close;
+
+    return cdb;
+}
+
+struct _cnid_db *cnid_db3_open(const char *dir, mode_t mask)
+{
+    struct stat st;
+    struct flock lock;
+    char path[MAXPATHLEN + 1];
+    CNID_private *db;
+    struct _cnid_db *cdb;
+    DBT key, data;
+    DB_TXN *tid = NULL;
+    int open_flag, len;
+    int rc;
+
+    if (!dir) {
+        return NULL;
+    }
+
+    /* this checks .AppleDB */
+    if ((len = strlen(dir)) > (MAXPATHLEN - DBLEN - 1)) {
+        LOG(log_error, logtype_default, "cnid_open: Pathname too large: %s", dir);
+        return NULL;
+    }
+
+    if ((cdb = cnid_db3_new(dir)) == NULL) {
+        LOG(log_error, logtype_default, "cnid_open: Unable to allocate memory for database");
+        return NULL;
+    }
+
+    if ((db = (CNID_private *) calloc(1, sizeof(CNID_private))) == NULL) {
+        LOG(log_error, logtype_default, "cnid_open: Unable to allocate memory for database");
+        goto fail_cdb;
+    }
+
+    cdb->_private = (void *) db;
+    db->magic = CNID_DB_MAGIC;
+
+    strcpy(path, dir);
+    if (path[len - 1] != '/') {
+        strcat(path, "/");
+        len++;
+    }
+
+    strcpy(path + len, DBHOME);
+    if ((stat(path, &st) < 0) && (ad_mkdir(path, 0777 & ~mask) < 0)) {
+        LOG(log_error, logtype_default, "cnid_open: DBHOME mkdir failed for %s", path);
+        goto fail_adouble;
+    }
+
+    lock.l_type = F_WRLCK;
+    lock.l_whence = SEEK_SET;
+    /* Make sure cnid.lock goes in .AppleDB. */
+    strcat(path, "/");
+    len++;
+
+    /* Search for a byte lock.  This allows us to cleanup the log files
+     * at cnid_close() in a clean fashion.
+     *
+     * NOTE: This won't work if multiple volumes for the same user refer
+     * to the sahe directory. */
+    strcat(path, DBLOCKFILE);
+    strcpy(db->lock_file, path);
+    if ((db->lockfd = open(path, O_RDWR | O_CREAT, 0666 & ~mask)) > -1) {
+        lock.l_start = 0;
+        lock.l_len = 1;
+        while (fcntl(db->lockfd, F_SETLK, &lock) < 0) {
+            if (++lock.l_start > MAXITER) {
+                LOG(log_error, logtype_default,
+                    "cnid_open: Cannot establish logfile cleanup for database environment %s lock (lock failed)", path);
+                close(db->lockfd);
+                db->lockfd = -1;
+                break;
+            }
+        }
+    } else {
+        LOG(log_error, logtype_default,
+            "cnid_open: Cannot establish logfile cleanup lock for database environment %s (open() failed)", path);
+    }
+
+    path[len + DBHOMELEN] = '\0';
+    open_flag = DB_CREATE;
+
+    /* We need to be able to open the database environment with full
+     * transaction, logging, and locking support if we ever hope to 
+     * be a true multi-acess file server. */
+    if ((rc = db_env_create(&db->dbenv, 0)) != 0) {
+        LOG(log_error, logtype_default, "cnid_open: db_env_create: %s", db_strerror(rc));
+        goto fail_lock;
+    }
+
+    /* Setup internal deadlock detection. */
+    if ((rc = db->dbenv->set_lk_detect(db->dbenv, DEAD_LOCK_DETECT)) != 0) {
+        LOG(log_error, logtype_default, "cnid_open: set_lk_detect: %s", db_strerror(rc));
+        goto fail_lock;
+    }
+
+#if DB_VERSION_MAJOR >= 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR > 1)
+#if 0
+    /* Take care of setting the DB_TXN_NOSYNC flag in db3 > 3.1.x. */
+    if ((rc = db->dbenv->set_flags(db->dbenv, DB_TXN_NOSYNC, 1)) != 0) {
+        LOG(log_error, logtype_default, "cnid_open: set_flags: %s", db_strerror(rc));
+        goto fail_lock;
+    }
+#endif
+#endif /* DB_VERSION_MINOR > 1 */
+
+    /* Open the database environment. */
+    if ((rc = db->dbenv->open(db->dbenv, path, DBOPTIONS, 0666 & ~mask)) != 0) {
+        if (rc == DB_RUNRECOVERY) {
+            /* This is the mother of all errors.  We _must_ fail here. */
+            LOG(log_error, logtype_default,
+                "cnid_open: CATASTROPHIC ERROR opening database environment %s.  Run db_recovery -c immediately", path);
+            goto fail_lock;
+        }
+
+        /* We can't get a full transactional environment, so multi-access
+         * is out of the question.  Let's assume a read-only environment,
+         * and try to at least get a shared memory pool. */
+        if ((rc = db->dbenv->open(db->dbenv, path, DB_INIT_MPOOL, 0666 & ~mask)) != 0) {
+            /* Nope, not a MPOOL, either.  Last-ditch effort: we'll try to
+             * open the environment with no flags. */
+            if ((rc = db->dbenv->open(db->dbenv, path, 0, 0666 & ~mask)) != 0) {
+                LOG(log_error, logtype_default, "cnid_open: dbenv->open of %s failed: %s", path, db_strerror(rc));
+                goto fail_lock;
+            }
+        }
+        db->flags |= CNIDFLAG_DB_RO;
+        open_flag = DB_RDONLY;
+        LOG(log_info, logtype_default, "cnid_open: Obtained read-only database environment %s", path);
+    }
+    /* did/name reverse mapping.  We use a BTree for this one. */
+    if ((rc = db_create(&db->db_didname, db->dbenv, 0)) != 0) {
+        LOG(log_error, logtype_default, "cnid_open: Failed to create did/name database: %s", db_strerror(rc));
+        goto fail_appinit;
+    }
+
+    /*db->db_didname->set_bt_compare(db->db_didname, &compare_unix); */
+    if ((rc = my_open(db->db_didname, DBDIDNAME, NULL, DB_HASH, open_flag, 0666 & ~mask))) {
+        LOG(log_error, logtype_default, "cnid_open: Failed to open did/name database: %s", db_strerror(rc));
+        goto fail_appinit;
+    }
+
+    /* Check for version.  This way we can update the database if we need
+     * to change the format in any way. */
+    memset(&key, 0, sizeof(key));
+    memset(&data, 0, sizeof(data));
+    key.data = DBVERSION_KEY;
+    key.size = DBVERSION_KEYLEN;
+
+  dbversion_retry:
+    if ((rc = db3_txn_begin(db->dbenv, NULL, &tid, 0)) != 0) {
+        LOG(log_error, logtype_default, "cnid_open: txn_begin: failed to check db version: %s", db_strerror(rc));
+        goto fail_appinit;
+    }
+
+    while ((rc = db->db_didname->get(db->db_didname, tid, &key, &data, DB_RMW))) {
+        int ret;
+
+        switch (rc) {
+        case DB_LOCK_DEADLOCK:
+            if ((ret = db3_txn_abort(tid)) != 0) {
+                LOG(log_error, logtype_default, "cnid_open: txn_abort: %s", db_strerror(ret));
+                goto fail_appinit;
+            }
+            goto dbversion_retry;
+        case DB_NOTFOUND:
+            {
+                u_int32_t version = htonl(DBVERSION);
+
+                data.data = &version;
+                data.size = sizeof(version);
+            }
+
+            if ((ret = db->db_didname->put(db->db_didname, tid, &key, &data, DB_NOOVERWRITE))) {
+                if (ret == DB_LOCK_DEADLOCK) {
+                    if ((ret = db3_txn_abort(tid)) != 0) {
+                        LOG(log_error, logtype_default, "cnid_open: txn_abort: %s", db_strerror(ret));
+                        goto fail_appinit;
+                    }
+                    goto dbversion_retry;
+                } else if (ret == DB_RUNRECOVERY) {
+                    /* At this point, we don't care if the transaction aborts
+                     * successfully or not. */
+                    db3_txn_abort(tid);
+                    LOG(log_error, logtype_default, "cnid_open: Error putting new version: %s", db_strerror(ret));
+                    goto fail_appinit;
+                }
+            }
+            break;              /* while loop */
+        default:
+            db3_txn_abort(tid);
+            LOG(log_error, logtype_default, "cnid_open: Failed to check db version: %s", db_strerror(rc));
+            goto fail_appinit;
+        }
+    }
+
+    if ((rc = db3_txn_commit(tid, 0)) != 0) {
+        LOG(log_error, logtype_default, "cnid_open: Failed to commit db version: %s", db_strerror(rc));
+        goto fail_appinit;
+    }
+
+    /* TODO In the future we might check for version number here. */
+#if 0
+    memcpy(&version, data.data, sizeof(version));
+    if (version != ntohl(DBVERSION)) {
+        /* Do stuff here. */
+    }
+#endif /* 0 */
+
+    /* dev/ino reverse mapping.  Use a hash for this one. */
+    if ((rc = db_create(&db->db_devino, db->dbenv, 0)) != 0) {
+        LOG(log_error, logtype_default, "cnid_open: Failed to create dev/ino database: %s", db_strerror(rc));
+        goto fail_appinit;
+    }
+
+    if ((rc = my_open(db->db_devino, DBDEVINO, NULL, DB_HASH, open_flag, 0666 & ~mask))) {
+        LOG(log_error, logtype_default, "cnid_open: Failed to open devino database: %s", db_strerror(rc));
+        goto fail_appinit;
+    }
+
+    /* Main CNID database.  Use a hash for this one. */
+    if ((rc = db_create(&db->db_cnid, db->dbenv, 0)) != 0) {
+        LOG(log_error, logtype_default, "cnid_open: Failed to create cnid database: %s", db_strerror(rc));
+        goto fail_appinit;
+    }
+
+    if ((rc = my_open(db->db_cnid, DBCNID, NULL, DB_HASH, open_flag, 0666 & ~mask))) {
+        LOG(log_error, logtype_default, "cnid_open: Failed to open dev/ino database: %s", db_strerror(rc));
+        goto fail_appinit;
+    }
+
+    /* Print out the version of BDB we're linked against. */
+    LOG(log_info, logtype_default, "CNID DB initialized using %s", db_version(NULL, NULL, NULL));
+#if 0
+    db_env_set_func_yield(my_yield);
+#endif
+    return cdb;
+
+  fail_appinit:
+    if (db->db_didname)
+        db->db_didname->close(db->db_didname, 0);
+    if (db->db_devino)
+        db->db_devino->close(db->db_devino, 0);
+    if (db->db_cnid)
+        db->db_cnid->close(db->db_cnid, 0);
+    LOG(log_error, logtype_default, "cnid_open: Failed to setup CNID DB environment");
+    db->dbenv->close(db->dbenv, 0);
+
+  fail_lock:
+    if (db->lockfd > -1) {
+        close(db->lockfd);
+        (void) remove(db->lock_file);
+    }
+
+  fail_adouble:
+
+  fail_db:
+    free(db);
+
+  fail_cdb:
+    if (cdb->volpath != NULL)
+        free(cdb->volpath);
+    free(cdb);
+
+    return NULL;
+}
+
+struct _cnid_module cnid_db3_module = {
+    "db3",
+    {NULL, NULL},
+    cnid_db3_open,
+    CNID_FLAG_BLOCK
+};
+
+#endif /* CNID_BACKEND_DB3 */
diff --git a/libatalk/cnid/db3/cnid_db3_private.h b/libatalk/cnid/db3/cnid_db3_private.h
new file mode 100644 (file)
index 0000000..7ee6193
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ * $Id: cnid_db3_private.h,v 1.1.4.1 2003-09-09 16:42:21 didg Exp $
+ */
+
+#ifndef LIBATALK_CNID_PRIVATE_H
+#define LIBATALK_CNID_PRIVATE_H 1
+
+#include <string.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+
+#include <db.h>
+
+#include <atalk/adouble.h>
+#include "cnid_db3.h"
+
+#define CNID_DB_MAGIC   0x434E4944U  /* CNID */
+#define CNID_DATA_MAGIC 0x434E4945U  /* CNIE */
+
+#define CNID_DEVINO_LEN          8
+#define CNID_DID_LEN             4
+#define CNID_HEADER_LEN          (CNID_DEVINO_LEN + CNID_DID_LEN)
+
+#define CNID_START               17
+
+#define CNIDFLAG_ROOTINFO_RO     (1 << 0)
+#define CNIDFLAG_DB_RO           (1 << 1)
+
+/* the key is in the form of a did/name pair. in this case,
+ * we use 0/RootInfo. */
+#define ROOTINFO_KEY    "\0\0\0\0RootInfo"
+#define ROOTINFO_KEYLEN 12
+
+typedef struct CNID_private {
+    u_int32_t magic;
+    DB *db_cnid;
+    DB *db_didname;
+    DB *db_devino;
+    DB_ENV *dbenv;
+    int lockfd, flags;
+    char lock_file[MAXPATHLEN + 1];
+} CNID_private;
+
+/* on-disk data format (in network byte order where appropriate) --
+ * db_cnid:      (key: cnid)
+ * name          size (in bytes)
+ * dev           4
+ * ino           4
+ * did           4
+ * unix name     strlen(name) + 1 
+ *
+ * db_didname:   (key: did/unix name)
+ * -- this also caches the bits of .AppleDouble used by FPGetFilDirParam
+ *    so that we don't have to open the header file.
+ *    NOTE: FPCatSearch has to search through all of the directories as
+ *          this stuff doesn't get entered until needed.
+ *          if the entire volume is in the database, though, we can use
+ *          cursor operations to make this faster.
+ *
+ *    version number is stored with did/name key of 0/0
+ *
+ * cnid          4
+ * modfiller     4 (dates only use 4 bytes right now, but we leave space 
+ * moddate       4  for 8. moddate is also used to keep this info 
+ * createfiller  4  up-to-date.)
+ * createdate    4
+ * backfiller    4
+ * backupdate    4
+ * accfiller     4 (unused)
+ * accdate       4 (unused)
+ * AFP info      4 (stores a couple permission bits as well)
+ * finder info   32
+ * prodos info   8
+ * rforkfiller   4
+ * rforklen      4
+ * macname       32 (nul-terminated)
+ * shortname     12 (nul-terminated)
+ * longname      longnamelen (nul-terminated)
+ * ---------------
+ *             132 bytes + longnamelen
+ * 
+ * db_devino:    (key: dev/ino) 
+ * -- this is only used for consistency checks and isn't 1-1
+ * cnid          4 
+ *
+ * these correspond to the different path types. longname is for the
+ * 255 unicode character names (path type == ?), macname is for the
+ * 32-character names (path type == 2), and shortname is for the
+ * 8+3-character names (path type == 1).
+ *
+ * db_longname: (key: did/longname)
+ * name          namelen = strlen(name) + 1
+ *
+ * db_macname:   (key: did/macname)
+ * name          namelen = strlen(name) + 1
+ *
+ * db_shortname: (key: did/shortname)
+ * name namelen = strlen(name) + 1 
+ */
+
+#ifndef __inline__
+#define __inline__
+#endif /* __inline__ */
+
+/* construct db_cnid data. NOTE: this is not re-entrant.  */
+static __inline__ char *make_cnid_data(const struct stat *st,
+                                       const cnid_t did,
+                                       const char *name, const int len)
+{
+    static char start[CNID_HEADER_LEN + MAXPATHLEN + 1];
+    char *buf = start;
+    u_int32_t i;
+
+    if (len > MAXPATHLEN)
+        return NULL;
+
+    i = htonl(st->st_dev);
+    buf = memcpy(buf, &i, sizeof(i));
+    i = htonl(st->st_ino);
+    buf = memcpy(buf + sizeof(i), &i, sizeof(i));
+    /* did is already in network byte order */
+    buf = memcpy(buf + sizeof(i), &did, sizeof(did));
+    buf = memcpy(buf + sizeof(did), name, len);
+    *(buf + len) = '\0';
+    buf += len + 1;
+
+    return start;
+}
+
+#endif /* atalk/cnid/cnid_private.h */
diff --git a/libatalk/cnid/db3/cnid_db3_resolve.c b/libatalk/cnid/db3/cnid_db3_resolve.c
new file mode 100644 (file)
index 0000000..d1ceba1
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * $Id: cnid_db3_resolve.c,v 1.1.4.1 2003-09-09 16:42:21 didg Exp $
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#ifdef CNID_BACKEND_DB3
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <atalk/logger.h>
+#include <errno.h>
+
+#include <db.h>
+#include <netatalk/endian.h>
+#include <atalk/adouble.h>
+#include "cnid_db3.h"
+
+#include "cnid_db3_private.h"
+
+/* Return the did/name pair corresponding to a CNID. */
+char *cnid_db3_resolve(struct _cnid_db *cdb, cnid_t *id, void *buffer, u_int32_t len) {
+    CNID_private *db;
+    DBT key, data;
+    int rc;
+
+    if (!cdb || !(db = cdb->_private) || !id || !(*id)) {
+        return NULL;
+    }
+
+    memset(&key, 0, sizeof(key));
+    memset(&data, 0, sizeof(data));
+
+    data.data = buffer;
+    data.ulen = len;
+    data.flags = DB_DBT_USERMEM;
+
+    key.data = id;
+    key.size = sizeof(cnid_t);
+    while ((rc = db->db_cnid->get(db->db_cnid, NULL, &key, &data, 0))) {
+        if (rc == DB_LOCK_DEADLOCK) {
+            continue;
+        }
+
+        if (rc != DB_NOTFOUND) {
+            LOG(log_error, logtype_default, "cnid_resolve: Unable to get did/name: %s",
+                db_strerror(rc));
+        }
+
+        *id = 0;
+        return NULL;
+    }
+
+    memcpy(id, (char *)data.data + CNID_DEVINO_LEN, sizeof(cnid_t));
+#ifdef DEBUG
+    LOG(log_info, logtype_default, "cnid_resolve: Returning id = %u, did/name = %s",
+        ntohl(*id), (char *)data.data + CNID_HEADER_LEN);
+#endif
+    return (char *)data.data + CNID_HEADER_LEN;
+}
+
+#endif /* CNID_BACKEND_DB3 */
diff --git a/libatalk/cnid/db3/cnid_db3_update.c b/libatalk/cnid/db3/cnid_db3_update.c
new file mode 100644 (file)
index 0000000..1d71d27
--- /dev/null
@@ -0,0 +1,155 @@
+/*
+ * $Id: cnid_db3_update.c,v 1.1.4.1 2003-09-09 16:42:21 didg Exp $
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#ifdef CNID_BACKEND_DB3
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <atalk/logger.h>
+
+#include <db.h>
+#include <netatalk/endian.h>
+#include <atalk/adouble.h>
+#include "cnid_db3.h"
+
+#include "cnid_db3_private.h"
+
+/* cnid_update: takes the given cnid and updates the metadata.  To
+ * handle the did/name data, there are a bunch of functions to get
+ * and set the various fields. */
+int cnid_db3_update(struct _cnid_db *cdb, const cnid_t id, const struct stat *st,
+                const cnid_t did, const char *name, const int len
+                /*, const char *info, const int infolen*/)
+{
+    CNID_private *db;
+    DBT key, data, altdata;
+    DB_TXN *tid;
+    int rc;
+
+    if (!cdb || !(db = cdb->_private) || !id || !st || !name || (db->flags & CNIDFLAG_DB_RO)) {
+        return -1;
+    }
+
+    memset(&key, 0, sizeof(key));
+    memset(&altdata, 0, sizeof(altdata));
+
+retry:
+    if ((rc = db3_txn_begin(db->dbenv, NULL, &tid, 0))) {
+        LOG(log_error, logtype_default, "cnid_update: Failed to begin transaction: %s", db_strerror(rc));
+        return rc;
+    }
+
+    /* Get the old info. */
+    key.data = (cnid_t *)&id;
+    key.size = sizeof(id);
+    memset(&data, 0, sizeof(data));
+    if ((rc = db->db_cnid->get(db->db_cnid, tid, &key, &data, DB_RMW))) {
+        db3_txn_abort(tid);
+        switch (rc) {
+        case DB_LOCK_DEADLOCK:
+            goto retry;
+        case DB_NOTFOUND:
+            /* Silently fail here.  We're allowed to do this since this CNID
+             * might have been deleted out from under us, or someone has
+             * called cnid_lookup then cnid_update (which is redundant). */
+            return 0;
+        default:
+            goto update_err;
+        }
+    }
+
+    /* Delete the old dev/ino mapping. */
+    key.data = data.data;
+    key.size = CNID_DEVINO_LEN;
+    if ((rc = db->db_devino->del(db->db_devino, tid, &key, 0))) {
+        switch (rc) {
+        case DB_LOCK_DEADLOCK:
+            db3_txn_abort(tid);
+            goto retry;
+        case DB_NOTFOUND:
+            break;
+        default:
+            db3_txn_abort(tid);
+            goto update_err;
+        }
+    }
+
+    /* Delete the old did/name mapping. */
+    key.data = (char *) data.data + CNID_DEVINO_LEN;
+    key.size = data.size - CNID_DEVINO_LEN;
+    if ((rc = db->db_didname->del(db->db_didname, tid, &key, 0))) {
+        switch (rc) {
+        case DB_LOCK_DEADLOCK:
+            db3_txn_abort(tid);
+            goto retry;
+        case DB_NOTFOUND:
+            break;
+        default:
+            db3_txn_abort(tid);
+            goto update_err;
+        }
+    }
+
+    /* Make a new entry. */
+    data.data = make_cnid_data(st, did, name, len);
+    data.size = CNID_HEADER_LEN + len + 1;
+
+    /* Update the old CNID with the new info. */
+    key.data = (cnid_t *) &id;
+    key.size = sizeof(id);
+    if ((rc = db->db_cnid->put(db->db_cnid, tid, &key, &data, 0))) {
+        db3_txn_abort(tid);
+        switch (rc) {
+        case DB_LOCK_DEADLOCK:
+            goto retry;
+        default:
+            goto update_err;
+        }
+    }
+
+    /* Put in a new dev/ino mapping. */
+    key.data = data.data;
+    key.size = CNID_DEVINO_LEN;
+    altdata.data = (cnid_t *) &id;
+    altdata.size = sizeof(id);
+    if ((rc = db->db_devino->put(db->db_devino, tid, &key, &altdata, 0))) {
+        db3_txn_abort(tid);
+        switch (rc) {
+        case DB_LOCK_DEADLOCK:
+            goto retry;
+        default:
+            goto update_err;
+        }
+    }
+
+    /* put in a new did/name mapping. */
+    key.data = (char *) data.data + CNID_DEVINO_LEN;
+    key.size = data.size - CNID_DEVINO_LEN;
+    if ((rc = db->db_didname->put(db->db_didname, tid, &key, &altdata, 0))) {
+        db3_txn_abort(tid);
+        switch (rc) {
+        case DB_LOCK_DEADLOCK:
+            goto retry;
+        default:
+            goto update_err;
+        }
+    }
+
+
+    return db3_txn_commit(tid, 0);
+
+update_err:
+    LOG(log_error, logtype_default, "cnid_update: Unable to update CNID %u: %s",
+        ntohl(id), db_strerror(rc));
+    return -1;
+}
+
+#endif /* CNID_BACKEND_DB3 */
diff --git a/libatalk/cnid/dbd/Makefile.am b/libatalk/cnid/dbd/Makefile.am
new file mode 100644 (file)
index 0000000..b85eb32
--- /dev/null
@@ -0,0 +1,9 @@
+# Makefile.am for libatalk/cnid/
+
+CFLAGS = @CFLAGS@ @BDB_CFLAGS@
+LIBS = @LIBS@ @BDB_LIBS@
+
+noinst_LTLIBRARIES = libcnid_dbd.la
+
+libcnid_dbd_la_SOURCES = cnid_dbd.c cnid_dbd.h cnid_dbd_private.h
+
diff --git a/libatalk/cnid/dbd/cnid_dbd.c b/libatalk/cnid/dbd/cnid_dbd.c
new file mode 100644 (file)
index 0000000..216412a
--- /dev/null
@@ -0,0 +1,665 @@
+/*
+ * $Id: cnid_dbd.c,v 1.1.4.1 2003-09-09 16:42:21 didg Exp $
+ *
+ * Copyright (C) Joerg Lenneis 2003
+ * All Rights Reserved.  See COPYRIGHT.
+ */
+
+/*
+ *  Replacement functions for cnid_xxx if we use the cnid_dbd database
+ *  daemon. Basically we just check parameters for obvious errors and then pass
+ *  the request to the daemon for further processing.
+ *  
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#ifdef CNID_BACKEND_DBD
+
+#include <stdlib.h>
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif /* HAVE_SYS_STAT_H */
+#include <sys/un.h>
+#include <sys/socket.h>
+#include <sys/param.h>
+#include <errno.h>
+
+#include <netinet/in.h>
+#include <net/if.h>
+#include <netinet/tcp.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <errno.h>
+#include <netdb.h>
+
+#include <netatalk/endian.h>
+#include <atalk/logger.h>
+#include <atalk/adouble.h>
+#include <atalk/cnid.h>
+#include "cnid_dbd.h"
+#include <atalk/cnid_dbd_private.h>
+
+#define RQST_RESET(r) do { (r).namelen = 0; } while (0)
+
+/* ----------- */
+extern char             *Cnid_srv;
+extern int              Cnid_port;
+
+static int tsock_getfd(char *host, int port, int silent)
+{
+int sock;
+struct sockaddr_in server;
+struct hostent* hp;
+int attr;
+    server.sin_family=AF_INET;
+    server.sin_port=htons((unsigned short)port);
+    if (!host) {
+        LOG(log_error, logtype_cnid, "transmit: -cnidserver not defined");
+        return -1;
+    }
+    
+    hp=gethostbyname(host);
+    if (!hp) {
+        unsigned long int addr=inet_addr(host);
+        if (addr!= (unsigned)-1)
+            hp=gethostbyaddr((char*)addr,sizeof(addr),AF_INET);
+       if (!hp) {
+            if (!silent)
+                LOG(log_error, logtype_cnid, "transmit: get_fd %s: %s", host, strerror(errno));
+           return(-1);
+       }
+    }
+    memcpy((char*)&server.sin_addr,(char*)hp->h_addr,sizeof(server.sin_addr));
+    sock=socket(PF_INET,SOCK_STREAM,0);
+    if (sock==-1) {
+        if (!silent)
+            LOG(log_error, logtype_cnid, "transmit: socket %s: %s", host, strerror(errno));
+       return(-1);
+    }
+    attr = 1;
+    setsockopt(sock, SOL_TCP, TCP_NODELAY, &attr, sizeof(attr));
+    if(connect(sock ,(struct sockaddr*)&server,sizeof(server))==-1) {
+        struct timeval tv;
+        switch (errno) {
+        case ENETUNREACH:
+        case ECONNREFUSED: 
+            
+            tv.tv_usec = 0;
+            tv.tv_sec  = 5;
+            select(0, NULL, NULL, NULL, &tv);
+            break;
+        }
+       close(sock);
+       sock=-1;
+        if (!silent)
+            LOG(log_error, logtype_cnid, "transmit: connect %s: %s", host, strerror(errno));
+    }
+    return(sock);
+}
+
+/* --------------------- */
+static int init_tsockfn(CNID_private *db)
+{
+    int fd;
+    int len;
+    
+    if ((fd = tsock_getfd(Cnid_srv, Cnid_port, 0)) < 0) 
+        return -1;
+    len = strlen(db->db_dir);
+    if (write(fd, &len, sizeof(int)) != sizeof(int)) {
+        LOG(log_error, logtype_cnid, "get_usock: Error/short write: %s", strerror(errno));
+        close(fd);
+        return -1;
+    }
+    if (write(fd, db->db_dir, len) != len) {
+        LOG(log_error, logtype_cnid, "get_usock: Error/short write dir: %s", strerror(errno));
+        close(fd);
+        return -1;
+    }
+    return fd;
+}
+
+/* --------------------- */
+static int send_packet(CNID_private *db, struct cnid_dbd_rqst *rqst)
+{
+    struct iovec iov[2];
+    size_t towrite;
+    ssize_t len;
+  
+    iov[0].iov_base = rqst;
+    iov[0].iov_len  = sizeof(struct cnid_dbd_rqst);
+    
+    if (!rqst->namelen) {
+        if (write(db->fd, rqst, sizeof(struct cnid_dbd_rqst)) != sizeof(struct cnid_dbd_rqst)) {
+            return -1;
+        }
+        return 0;
+    }
+    iov[1].iov_base = rqst->name;
+    iov[1].iov_len  = rqst->namelen;
+
+    towrite = sizeof(struct cnid_dbd_rqst) +rqst->namelen;
+    while (towrite > 0) {
+        if (((len = writev(db->fd, iov, 2)) == -1 && errno == EINTR) || !len)
+            continue;
+        if (len == towrite) /* wrote everything out */
+            break;
+        else if (len < 0) { /* error */
+            return -1;
+        }
+        towrite -= len;
+        if (towrite > rqst->namelen) { /* skip part of header */
+            iov[0].iov_base = (char *) iov[0].iov_base + len;
+            iov[0].iov_len -= len;
+        } else { /* skip to data */
+            if (iov[0].iov_len) {
+                len -= iov[0].iov_len;
+                iov[0].iov_len = 0;
+            }
+            iov[1].iov_base = (char *) iov[1].iov_base + len;
+            iov[1].iov_len -= len;
+        }
+    }
+    return 0;
+}
+
+/* --------------------- */
+static int transmit(CNID_private *db, struct cnid_dbd_rqst *rqst, struct cnid_dbd_rply *rply)
+{
+    char *nametmp;
+    int  ret;
+    
+    while (1) {
+
+        if (db->fd == -1 && (db->fd = init_tsockfn(db)) < 0) {
+           goto transmit_fail;
+        }
+        if (send_packet(db, rqst) < 0) {
+            goto transmit_fail;
+        }
+        nametmp = rply->name;
+        if ((ret = read(db->fd, rply, sizeof(struct cnid_dbd_rply))) != sizeof(struct cnid_dbd_rply)) {
+            LOG(log_error, logtype_cnid, "transmit: Error reading header from fd for usock %s: %s",
+                db->usock_file, ret == -1?strerror(errno):"closed");
+            rply->name = nametmp;
+            goto transmit_fail;
+        }
+        rply->name = nametmp;
+        if (rply->namelen && (ret = read(db->fd, rply->name, rply->namelen)) != rply->namelen) {
+            LOG(log_error, logtype_cnid, "transmit: Error reading name from fd for usock %s: %s",
+                db->usock_file, ret == -1?strerror(errno):"closed");
+           goto transmit_fail;
+        }
+        return 0;
+ transmit_fail:
+        if (db->fd != -1) {
+            close(db->fd);
+        }
+        db->fd = -1;
+    }
+    return -1;
+}
+
+static struct _cnid_db *cnid_dbd_new(const char *volpath)
+{
+    struct _cnid_db *cdb;
+    
+    if ((cdb = (struct _cnid_db *)calloc(1, sizeof(struct _cnid_db))) == NULL)
+       return NULL;
+       
+    if ((cdb->volpath = strdup(volpath)) == NULL) {
+        free(cdb);
+       return NULL;
+    }
+    
+    cdb->flags = CNID_FLAG_PERSISTENT;
+    
+    cdb->cnid_add = cnid_dbd_add;
+    cdb->cnid_delete = cnid_dbd_delete;
+    cdb->cnid_get = cnid_dbd_get;
+    cdb->cnid_lookup = cnid_dbd_lookup;
+    cdb->cnid_nextid = NULL;
+    cdb->cnid_resolve = cnid_dbd_resolve;
+    cdb->cnid_getstamp = cnid_dbd_getstamp;
+    cdb->cnid_update = cnid_dbd_update;
+    cdb->cnid_close = cnid_dbd_close;
+    
+    return cdb;
+}
+
+/* ---------------------- */
+struct _cnid_db *cnid_dbd_open(const char *dir, mode_t mask)
+{
+    CNID_private *db = NULL;
+    struct _cnid_db *cdb = NULL;
+
+    if (!dir) {
+         return NULL;
+    }
+    
+    if ((cdb = cnid_dbd_new(dir)) == NULL) {
+        LOG(log_error, logtype_default, "cnid_open: Unable to allocate memory for database");
+       return NULL;
+    }
+        
+    if ((db = (CNID_private *)calloc(1, sizeof(CNID_private))) == NULL) {
+        LOG(log_error, logtype_cnid, "cnid_open: Unable to allocate memory for database");
+        goto cnid_dbd_open_fail;
+    }
+    
+    cdb->_private = db;
+
+    /* We keep a copy of the directory in the db structure so that we can
+       transparently reconnect later. */
+    strcpy(db->db_dir, dir);
+    db->usock_file[0] = '\0';
+    db->magic = CNID_DB_MAGIC;
+    db->fd = -1;
+#ifdef DEBUG
+    LOG(log_info, logtype_cnid, "opening database connection to %s", db->db_dir); 
+#endif
+    return cdb;
+
+cnid_dbd_open_fail:
+    if (cdb != NULL) {
+       if (cdb->volpath != NULL) {
+           free(cdb->volpath);
+       }
+       free(cdb);
+    }
+    if (db != NULL)
+       free(db);
+       
+    return NULL;
+}
+
+/* ---------------------- */
+void cnid_dbd_close(struct _cnid_db *cdb)
+{
+    CNID_private *db;
+
+    if (!cdb) {
+        LOG(log_error, logtype_afpd, "cnid_close called with NULL argument !");
+       return;
+    }
+
+    if ((db = cdb->_private) != NULL) {
+#ifdef DEBUG 
+        LOG(log_info, logtype_cnid, "closing database connection to %s", db->db_dir);
+#endif  
+       if (db->fd >= 0)
+           close(db->fd);
+        free(db);
+    }
+    
+    free(cdb->volpath);
+    free(cdb);
+    
+    return;
+}
+
+/* ---------------------- */
+cnid_t cnid_dbd_add(struct _cnid_db *cdb, const struct stat *st,
+                const cnid_t did, const char *name, const int len,
+                cnid_t hint)
+{
+    CNID_private *db;
+    struct cnid_dbd_rqst rqst;
+    struct cnid_dbd_rply rply;
+    cnid_t id;
+
+    if (!cdb || !(db = cdb->_private) || !st || !name) {
+        LOG(log_error, logtype_cnid, "cnid_add: Parameter error");
+        errno = CNID_ERR_PARAM;
+        return CNID_INVALID;
+    }
+
+    if (len > MAXPATHLEN) {
+        LOG(log_error, logtype_cnid, "cnid_add: Path name is too long");
+        errno = CNID_ERR_PATH;
+        return CNID_INVALID;
+    }
+
+    RQST_RESET(rqst);
+    rqst.op = CNID_DBD_OP_ADD;
+    rqst.dev = st->st_dev;
+    rqst.ino = st->st_ino;
+    rqst.type = S_ISDIR(st->st_mode)?1:0;
+    rqst.did = did;
+    rqst.name = name;
+    rqst.namelen = len;
+
+    if (transmit(db, &rqst, &rply) < 0) {
+        errno = CNID_ERR_DB;
+        return CNID_INVALID;
+    }
+    
+    switch(rply.result) {
+    case CNID_DBD_RES_OK:
+        id = rply.cnid;
+        break;
+    case CNID_DBD_RES_ERR_MAX:
+        errno = CNID_ERR_MAX;
+        id = CNID_INVALID;
+        break;
+    case CNID_DBD_RES_ERR_DB:
+    case CNID_DBD_RES_ERR_DUPLCNID:
+        errno = CNID_ERR_DB;
+        id = CNID_INVALID;
+        break;
+    default:
+        abort();
+    }
+    return id;
+}
+
+/* ---------------------- */
+cnid_t cnid_dbd_get(struct _cnid_db *cdb, const cnid_t did, const char *name,
+                const int len)
+{
+    CNID_private *db;
+    struct cnid_dbd_rqst rqst;
+    struct cnid_dbd_rply rply;
+    cnid_t id;
+
+
+    if (!cdb || !(db = cdb->_private) || !name) {
+        LOG(log_error, logtype_cnid, "cnid_get: Parameter error");
+        errno = CNID_ERR_PARAM;        
+        return CNID_INVALID;
+    }
+
+    if (len > MAXPATHLEN) {
+        LOG(log_error, logtype_cnid, "cnid_add: Path name is too long");
+        errno = CNID_ERR_PATH;
+        return CNID_INVALID;
+    }
+
+    RQST_RESET(rqst);
+    rqst.op = CNID_DBD_OP_GET;
+    rqst.did = did;
+    rqst.name = name;
+    rqst.namelen = len;
+
+    if (transmit(db, &rqst, &rply) < 0) {
+        errno = CNID_ERR_DB;
+        return CNID_INVALID;
+    }
+    
+    switch(rply.result) {
+    case CNID_DBD_RES_OK:
+        id = rply.cnid;
+        break;
+    case CNID_DBD_RES_NOTFOUND:
+        id = CNID_INVALID;
+        break;
+    case CNID_DBD_RES_ERR_DB:
+        id = CNID_INVALID;
+        errno = CNID_ERR_DB;
+        break;
+    default: 
+        abort();
+    }
+
+    return id;
+}
+
+/* ---------------------- */
+char *cnid_dbd_resolve(struct _cnid_db *cdb, cnid_t *id, void *buffer, u_int32_t len)
+{
+    CNID_private *db;
+    struct cnid_dbd_rqst rqst;
+    struct cnid_dbd_rply rply;
+    char *name;
+
+    if (!cdb || !(db = cdb->_private) || !id || !(*id)) {
+        LOG(log_error, logtype_cnid, "cnid_resolve: Parameter error");
+        errno = CNID_ERR_PARAM;                
+        return NULL;
+    }
+
+    /* TODO: We should maybe also check len. At the moment we rely on the caller
+       to provide a buffer that is large enough for MAXPATHLEN plus
+       CNID_HEADER_LEN plus 1 byte, which is large enough for the maximum that
+       can come from the database. */
+
+    RQST_RESET(rqst);
+    rqst.op = CNID_DBD_OP_RESOLVE;
+    rqst.cnid = *id;
+
+    /* This mimicks the behaviour of the "regular" cnid_resolve. So far,
+       nobody uses the content of buffer. It only provides space for the
+       name in the caller. */
+    rply.name = buffer + CNID_HEADER_LEN;
+
+    if (transmit(db, &rqst, &rply) < 0) {
+        errno = CNID_ERR_DB;
+        *id = CNID_INVALID;
+        return NULL;
+    }
+
+    switch (rply.result) {
+    case CNID_DBD_RES_OK:
+        *id = rply.did;
+        name = rply.name;
+        break;
+    case CNID_DBD_RES_NOTFOUND:
+        *id = CNID_INVALID;
+        name = NULL;
+        break;
+    case CNID_DBD_RES_ERR_DB:
+        errno = CNID_ERR_DB;
+        *id = CNID_INVALID;
+        name = NULL;
+        break;
+    default:
+        abort();
+    }
+
+    return name;
+}
+
+/* ---------------------- */
+int cnid_dbd_getstamp(struct _cnid_db *cdb, void *buffer, u_int32_t len)
+{
+    CNID_private *db;
+    struct cnid_dbd_rqst rqst;
+    struct cnid_dbd_rply rply;
+    cnid_t id = 0;
+    char temp[12 + MAXPATHLEN + 1];
+
+    if (!cdb || !(db = cdb->_private)) {
+        LOG(log_error, logtype_cnid, "cnid_getstamp: Parameter error");
+        errno = CNID_ERR_PARAM;                
+        return -1;
+    }
+
+    /* TODO: We should maybe also check len. At the moment we rely on the caller
+       to provide a buffer that is large enough for MAXPATHLEN plus
+       CNID_HEADER_LEN plus 1 byte, which is large enough for the maximum that
+       can come from the database. */
+
+    RQST_RESET(rqst);
+    rqst.op = CNID_DBD_OP_RESOLVE;
+    rqst.cnid = id;
+
+    memset(buffer, 0, len);
+
+    /* This mimicks the behaviour of the "regular" cnid_resolve. So far,
+       nobody uses the content of buffer. It only provides space for the
+       name in the caller. */
+    rply.name = temp + CNID_HEADER_LEN;
+
+    if (transmit(db, &rqst, &rply) < 0) {
+        errno = CNID_ERR_DB;
+        return -1;
+    }
+
+    switch (rply.result) {
+    case CNID_DBD_RES_OK:
+        memcpy(buffer, &rply.did, sizeof(cnid_t));
+        break;
+    case CNID_DBD_RES_NOTFOUND:
+        return -1;
+    case CNID_DBD_RES_ERR_DB:
+        errno = CNID_ERR_DB;
+        return -1;
+    default:
+        abort();
+    }
+
+    return 0;
+}
+
+/* ---------------------- */
+cnid_t cnid_dbd_lookup(struct _cnid_db *cdb, const struct stat *st, const cnid_t did,
+                   const char *name, const int len)
+{
+    CNID_private *db;
+    struct cnid_dbd_rqst rqst;
+    struct cnid_dbd_rply rply;
+    cnid_t id;
+
+    if (!cdb || !(db = cdb->_private) || !st || !name) {
+        LOG(log_error, logtype_cnid, "cnid_lookup: Parameter error");
+        errno = CNID_ERR_PARAM;        
+        return CNID_INVALID;
+    }
+
+    if (len > MAXPATHLEN) {
+        LOG(log_error, logtype_cnid, "cnid_lookup: Path name is too long");
+        errno = CNID_ERR_PATH;
+        return CNID_INVALID;
+    }
+
+    RQST_RESET(rqst);
+    rqst.op = CNID_DBD_OP_LOOKUP;
+    rqst.dev = st->st_dev;
+    rqst.ino = st->st_ino;
+    rqst.type = S_ISDIR(st->st_mode)?1:0;
+    rqst.did = did;
+    rqst.name = name;
+    rqst.namelen = len;
+
+    if (transmit(db, &rqst, &rply) < 0) {
+        errno = CNID_ERR_DB;
+        return CNID_INVALID;
+    }
+
+    switch (rply.result) {
+    case CNID_DBD_RES_OK:
+        id = rply.cnid;
+        break;
+    case CNID_DBD_RES_NOTFOUND:
+        id = CNID_INVALID;
+        break;
+    case CNID_DBD_RES_ERR_DB:
+        errno = CNID_ERR_DB;
+        id = CNID_INVALID;
+        break;
+    default:
+        abort();
+    }
+
+    return id;
+}
+
+/* ---------------------- */
+int cnid_dbd_update(struct _cnid_db *cdb, const cnid_t id, const struct stat *st,
+                const cnid_t did, const char *name, const int len)
+{
+    CNID_private *db;
+    struct cnid_dbd_rqst rqst;
+    struct cnid_dbd_rply rply;
+
+    
+    if (!cdb || !(db = cdb->_private) || !id || !st || !name) {
+        LOG(log_error, logtype_cnid, "cnid_update: Parameter error");
+        errno = CNID_ERR_PARAM;        
+        return -1;
+    }
+
+    if (len > MAXPATHLEN) {
+        LOG(log_error, logtype_cnid, "cnid_update: Path name is too long");
+        errno = CNID_ERR_PATH;
+        return -1;
+    }
+
+    RQST_RESET(rqst);
+    rqst.op = CNID_DBD_OP_UPDATE;
+    rqst.cnid = id;
+    rqst.dev = st->st_dev;
+    rqst.ino = st->st_ino;
+    rqst.type = S_ISDIR(st->st_mode)?1:0;
+    rqst.did = did;
+    rqst.name = name;
+    rqst.namelen = len;
+
+    if (transmit(db, &rqst, &rply) < 0) {
+        errno = CNID_ERR_DB;
+        return -1;
+    }
+
+    switch (rply.result) {
+    case CNID_DBD_RES_OK:
+    case CNID_DBD_RES_NOTFOUND:
+        return 0;
+    case CNID_DBD_RES_ERR_DB:
+        errno = CNID_ERR_DB;
+        return -1;
+    default:
+        abort();
+    }
+}
+
+/* ---------------------- */
+int cnid_dbd_delete(struct _cnid_db *cdb, const cnid_t id) 
+{
+    CNID_private *db;
+    struct cnid_dbd_rqst rqst;
+    struct cnid_dbd_rply rply;
+
+
+    if (!cdb || !(db = cdb->_private) || !id) {
+        LOG(log_error, logtype_cnid, "cnid_delete: Parameter error");
+        errno = CNID_ERR_PARAM;        
+        return -1;
+    }
+
+    RQST_RESET(rqst);
+    rqst.op = CNID_DBD_OP_DELETE;
+    rqst.cnid = id;
+
+    if (transmit(db, &rqst, &rply) < 0) {
+        errno = CNID_ERR_DB;
+        return -1;
+    }
+
+    switch (rply.result) {
+    case CNID_DBD_RES_OK:
+    case CNID_DBD_RES_NOTFOUND:
+        return 0;
+    case CNID_DBD_RES_ERR_DB:
+        errno = CNID_ERR_DB;
+        return -1;
+    default:
+        abort();
+    }
+}
+
+struct _cnid_module cnid_dbd_module = {
+    "dbd",
+    {NULL, NULL},
+    cnid_dbd_open,
+};
+
+#endif /* CNID_DBD */
+
diff --git a/libatalk/cnid/dbd/cnid_dbd.h b/libatalk/cnid/dbd/cnid_dbd.h
new file mode 100644 (file)
index 0000000..0d10d7b
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * $Id: cnid_dbd.h,v 1.1.4.1 2003-09-09 16:42:21 didg Exp $
+ *
+ * Copyright (C) Joerg Lenneis 2003
+ * All Rights Reserved.  See COPYRIGHT.
+ */
+
+
+#ifndef _ATALK_CNID_DBD__H
+#define _ATALK_CNID_DBD__H 1
+
+#include <sys/cdefs.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <string.h>
+
+#include <netatalk/endian.h>
+#include <atalk/cnid.h>
+
+extern struct _cnid_module cnid_dbd_module;
+extern struct _cnid_db *cnid_dbd_open __P((const char *, mode_t));
+extern void cnid_dbd_close __P((struct _cnid_db *));
+extern cnid_t cnid_dbd_add __P((struct _cnid_db *, const struct stat *, const cnid_t,
+                           const char *, const int, cnid_t));
+extern cnid_t cnid_dbd_get __P((struct _cnid_db *, const cnid_t, const char *, const int)); 
+extern char *cnid_dbd_resolve __P((struct _cnid_db *, cnid_t *, void *, u_int32_t )); 
+extern int cnid_dbd_getstamp __P((struct _cnid_db *, void *, u_int32_t )); 
+extern cnid_t cnid_dbd_lookup __P((struct _cnid_db *, const struct stat *, const cnid_t,
+                              const char *, const int));
+extern int cnid_dbd_update __P((struct _cnid_db *, const cnid_t, const struct stat *,
+                           const cnid_t, const char *, int));
+extern int cnid_dbd_delete __P((struct _cnid_db *, const cnid_t));
+
+#endif /* include/atalk/cnid_dbd.h */
+
diff --git a/libatalk/cnid/hash/Makefile.am b/libatalk/cnid/hash/Makefile.am
new file mode 100644 (file)
index 0000000..e7636c8
--- /dev/null
@@ -0,0 +1,18 @@
+# Makefile.am for libatalk/cnid/
+
+CFLAGS = @CFLAGS@ @BDB_CFLAGS@
+LIBS = @LIBS@ @BDB_LIBS@
+
+noinst_LTLIBRARIES = libcnid_hash.la
+
+libcnid_hash_la_SOURCES = cnid_hash_add.c \
+                        cnid_hash_close.c \
+                        cnid_hash_delete.c \
+                        cnid_hash_get.c \
+                        cnid_hash_lookup.c \
+                        cnid_hash_open.c \
+                        cnid_hash_resolve.c \
+                        cnid_hash_update.c \
+                        cnid_hash.h
+
+EXTRA_DIST = README cnid_hash_nextid.c
diff --git a/libatalk/cnid/hash/README b/libatalk/cnid/hash/README
new file mode 100644 (file)
index 0000000..b39889b
--- /dev/null
@@ -0,0 +1,35 @@
+the catalog database keeps track of three mappings:
+    CNID     -> dev/ino and did/name
+    dev/ino  -> CNID
+    did/name -> CNID
+
+dev/ino is used to keep track of magically moved files. did/name is
+for quick lookups of CNIDs. 
+
+NOTE: the database will append a nul byte to the end of name. in
+addition, name should be given as it appears on disk. this allows the
+creation of cnid updating/cleaning programs that don't have to deal
+with knowing what the particular codepage is.
+
+here's the ritual:
+       1) open a volume. call cnid_open.
+       2) every time you need a CNID, call cnid_add(). it will
+          automatically look for an existing cnid and add a new one
+          if one isn't already there. you can pass a hint if you
+          want. the only use this has right now is to enable
+          consistency between AFP and HFS. in the future, it would
+          allow people to write conversion utilities that
+          pre-instantiate a database without needing to re-assign
+          CNIDs.
+       3) if you want to just look for a CNID without automatically
+          adding one in, you have two choices:
+            a) cnid_resolve takes a CNID, returns name, and
+               over-writes the CNID given with the parent DID. this
+               is good for FPResolveID.
+             b) cnid_lookup returns a CNID corresponding to the
+               dev/ino,did/name keys. it will auto-update the catalog
+               database if there's a discrepancy. 
+               NOTE: cnid_add calls this before adding a new CNID. 
+       4) when you delete a file or directory, you need to call
+          cnid_delete with the CNID for that file/directory.
+       5) call cnid_close when closing the volume.
diff --git a/libatalk/cnid/hash/cnid_hash.h b/libatalk/cnid/hash/cnid_hash.h
new file mode 100644 (file)
index 0000000..c67ecd3
--- /dev/null
@@ -0,0 +1,67 @@
+/* 
+ * interface for database access to cnids. i do it this way to abstract
+ * things a bit in case we want to change the underlying implementation.
+ */
+
+#ifndef _ATALK_CNID_HASH__H
+#define _ATALK_CNID_HASH__H 1
+
+#include <sys/cdefs.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <string.h>
+
+#include <netatalk/endian.h>
+#include <atalk/cnid.h>
+#define STANDALONE 1
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <signal.h>
+#include <atalk/tdb.h>
+
+#define HASH_ERROR_LINK  1
+#define HASH_ERROR_DEV   2
+#define HASH_ERROR_INODE 4
+
+struct _cnid_hash_private {
+    dev_t  st_dev;
+    int    st_set;
+    int    error;
+    TDB_CONTEXT *tdb;  
+};
+
+/* cnid_open.c */
+extern struct _cnid_module cnid_hash_module;
+extern struct _cnid_db *cnid_hash_open __P((const char *, mode_t));
+
+/* cnid_close.c */
+extern void cnid_hash_close __P((struct _cnid_db *));
+
+/* cnid_add.c */
+extern cnid_t cnid_hash_add __P((struct _cnid_db *, const struct stat *, const cnid_t,
+                                 const char *, const int, cnid_t));
+
+/* cnid_get.c */
+extern cnid_t cnid_hash_get __P((struct _cnid_db *, const cnid_t, const char *, const int));
+extern char *cnid_hash_resolve __P((struct _cnid_db *, cnid_t *, void *, u_int32_t));
+extern cnid_t cnid_hash_lookup __P((struct _cnid_db *, const struct stat *, const cnid_t, const char *, const int));
+
+/* cnid_update.c */
+extern int cnid_hash_update __P((struct _cnid_db *, const cnid_t, const struct stat *,
+                                 const cnid_t, const char *, int));
+
+/* cnid_delete.c */
+extern int cnid_hash_delete __P((struct _cnid_db *, const cnid_t));
+
+/* cnid_nextid.c */
+extern cnid_t cnid_hash_nextid __P((struct _cnid_db *));
+
+#endif /* include/atalk/cnid_hash.h */
diff --git a/libatalk/cnid/hash/cnid_hash_add.c b/libatalk/cnid/hash/cnid_hash_add.c
new file mode 100644 (file)
index 0000000..304b599
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * $Id: cnid_hash_add.c,v 1.1.2.1 2003-09-09 16:42:21 didg Exp $
+ *
+ * Copyright (c) 1999. Adrian Sun (asun@zoology.washington.edu)
+ * All Rights Reserved. See COPYRIGHT.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#ifdef CNID_BACKEND_HASH
+
+#include "cnid_hash.h"
+#include <atalk/util.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <atalk/logger.h>
+
+/* ------------------------ */
+cnid_t cnid_hash_add(struct _cnid_db *cdb, const struct stat *st,
+                     const cnid_t did, const char *name, const int len, cnid_t hint)
+{
+    struct stat lst;
+    const struct stat *lstp;
+    cnid_t aint;
+    struct _cnid_hash_private *priv;
+    static char buffer[sizeof(cnid_t) + MAXPATHLEN + 1];        
+    TDB_DATA key, data;       
+    
+    if (!cdb || !(cdb->_private))
+        return CNID_INVALID;
+
+    priv = (struct _cnid_hash_private *) (cdb->_private);
+    lstp = lstat(name, &lst) < 0 ? st : &lst;
+    aint = lstp->st_ino & 0xffffffff;
+
+    if (!priv->st_set) {
+        priv->st_set = 1;
+        priv->st_dev = lstp->st_dev;
+    }
+    if (!(priv->error & HASH_ERROR_DEV)) {
+        if (lstp->st_dev != priv->st_dev) {
+            priv->error |= HASH_ERROR_DEV;
+            LOG(log_error, logtype_default, "cnid_hash_add: %s not on the same device", name);
+        }
+    }
+    if (!(priv->error & HASH_ERROR_LINK)) {
+        if (!S_ISDIR(lstp->st_mode) && lstp->st_nlink > 1) {
+            priv->error |= HASH_ERROR_DEV;
+            LOG(log_error, logtype_default, "cnid_hash_add: %s more than one hardlink", name);
+        }
+    }
+    if (sizeof(ino_t) > 4 && !(priv->error & HASH_ERROR_INODE)) {
+        if (aint != lstp->st_ino) {
+            priv->error |= HASH_ERROR_INODE;
+            LOG(log_error, logtype_default, "cnid_hash_add: %s high bits set, duplicate", name);
+        }
+    }
+    key.dptr = (char *)&aint;
+    key.dsize = sizeof(cnid_t);
+                
+    memcpy(buffer, &did, sizeof(cnid_t));
+    memcpy(buffer+sizeof(cnid_t), name, len +1);
+    data.dptr = buffer;
+    data.dsize = len+1 +sizeof(cnid_t);
+    if (tdb_store(priv->tdb, key, data, TDB_REPLACE)) {
+        LOG(log_error, logtype_default, "cnid_hash_add: unable to add %s", name);
+    }
+    return aint;
+}
+
+#endif /* CNID_BACKEND_HASH */
diff --git a/libatalk/cnid/hash/cnid_hash_close.c b/libatalk/cnid/hash/cnid_hash_close.c
new file mode 100644 (file)
index 0000000..01354e4
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * $Id: cnid_hash_close.c,v 1.1.2.1 2003-09-09 16:42:21 didg Exp $
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#ifdef CNID_BACKEND_HASH
+
+#include "cnid_hash.h"
+
+void cnid_hash_close(struct _cnid_db *cdb)
+{
+    struct _cnid_hash_private *db;
+
+    free(cdb->volpath);
+    db = (struct _cnid_hash_private *)cdb->_private;
+    tdb_close(db->tdb);    
+    free(cdb->_private);
+    free(cdb);
+}
+
+#endif /* CNID_BACKEND_HASH */
diff --git a/libatalk/cnid/hash/cnid_hash_delete.c b/libatalk/cnid/hash/cnid_hash_delete.c
new file mode 100644 (file)
index 0000000..85d2fe4
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * $Id: cnid_hash_delete.c,v 1.1.2.1 2003-09-09 16:42:21 didg Exp $
+ *
+ * Copyright (c) 1999. Adrian Sun (asun@zoology.washington.edu)
+ * All Rights Reserved. See COPYRIGHT.
+ *
+ * cnid_delete: delete a CNID from the database 
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#ifdef CNID_BACKEND_HASH
+
+#include "cnid_hash.h"
+
+int cnid_hash_delete(struct _cnid_db *cdb, const cnid_t id)
+{
+    struct _cnid_hash_private *db;
+    TDB_DATA key;      
+
+    if (!cdb || !(db = cdb->_private) || !id) {
+        return -1;
+    }
+    key.dptr  = (char *)&id;
+    key.dsize = sizeof(cnid_t);
+    tdb_delete(db->tdb, key); 
+
+    return 0;
+}
+
+#endif /* CNID_BACKEND_HASH */
diff --git a/libatalk/cnid/hash/cnid_hash_get.c b/libatalk/cnid/hash/cnid_hash_get.c
new file mode 100644 (file)
index 0000000..8117bcb
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ * $Id: cnid_hash_get.c,v 1.1.2.1 2003-09-09 16:42:21 didg Exp $
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#ifdef CNID_BACKEND_HASH
+
+#include "cnid_hash.h"
+
+/* Return CNID for a given did/name. */
+cnid_t cnid_hash_get(struct _cnid_db *cdb, const cnid_t did, const char *name, const int len)
+{
+    return CNID_INVALID;
+}
+
+#endif /* CNID_BACKEND_HASH */
diff --git a/libatalk/cnid/hash/cnid_hash_lookup.c b/libatalk/cnid/hash/cnid_hash_lookup.c
new file mode 100644 (file)
index 0000000..20ce8db
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * $Id: cnid_hash_lookup.c,v 1.1.2.1 2003-09-09 16:42:21 didg Exp $
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#ifdef CNID_BACKEND_HASH
+
+#include "cnid_hash.h"
+
+cnid_t cnid_hash_lookup(struct _cnid_db *cdb, const struct stat *st, const cnid_t did, const char *name, const int len)
+{
+    return cnid_hash_add(cdb, st, did, name, len, 0  /*hint*/);
+}
+
+#endif /* CNID_BACKEND_HASH */
diff --git a/libatalk/cnid/hash/cnid_hash_nextid.c b/libatalk/cnid/hash/cnid_hash_nextid.c
new file mode 100644 (file)
index 0000000..551ae68
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * $Id: cnid_hash_nextid.c,v 1.1.2.1 2003-09-09 16:42:21 didg Exp $
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#ifdef CNID_BACKEND_HASH
+
+#include "cnid_hash.h"
+
+cnid_t cnid_hash_nextid(struct _cnid_db *cdb)
+{
+    return CNID_INVALID;
+}
+
+#endif /* CNID_BACKEND_HASH */
diff --git a/libatalk/cnid/hash/cnid_hash_open.c b/libatalk/cnid/hash/cnid_hash_open.c
new file mode 100644 (file)
index 0000000..a0cc97a
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ * $Id: cnid_hash_open.c,v 1.1.2.1 2003-09-09 16:42:21 didg Exp $
+ *
+ * Copyright (c) 1999. Adrian Sun (asun@zoology.washington.edu)
+ * All Rights Reserved. See COPYRIGHT.
+ *
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef CNID_BACKEND_HASH
+#include <sys/param.h>   
+
+#include "cnid_hash.h"
+#include <atalk/logger.h>
+#include <stdlib.h>
+#define DBHOME       ".AppleDB" 
+#define DBNAME       "private_tdb.%sX"
+#define DBHOMELEN    9
+#define DBLEN        24 
+
+static struct _cnid_db *cnid_hash_new(const char *volpath)
+{
+    struct _cnid_db *cdb;
+    struct _cnid_hash_private *priv;
+
+    if ((cdb = (struct _cnid_db *) calloc(1, sizeof(struct _cnid_db))) == NULL)
+        return NULL;
+
+    if ((cdb->volpath = strdup(volpath)) == NULL) {
+        free(cdb);
+        return NULL;
+    }
+
+    if ((cdb->_private = calloc(1, sizeof(struct _cnid_hash_private))) == NULL) {
+        free(cdb->volpath);
+        free(cdb);
+        return NULL;
+    }
+
+    /* Set up private state */
+    priv = (struct _cnid_hash_private *) (cdb->_private);
+
+    /* Set up standard fields */
+    cdb->flags = CNID_FLAG_PERSISTENT;
+
+    cdb->cnid_add = cnid_hash_add;
+    cdb->cnid_delete = cnid_hash_delete;
+    cdb->cnid_get = cnid_hash_get;
+    cdb->cnid_lookup = cnid_hash_lookup;
+    cdb->cnid_nextid = NULL;    /*cnid_hash_nextid;*/
+    cdb->cnid_resolve = cnid_hash_resolve;
+    cdb->cnid_update = cnid_hash_update;
+    cdb->cnid_close = cnid_hash_close;
+    
+    return cdb;
+}
+
+/* ---------------------------- */
+struct _cnid_db *cnid_hash_open(const char *dir, mode_t mask)
+{
+    struct stat               st;
+    struct _cnid_db           *cdb;
+    struct _cnid_hash_private *db;
+    size_t                    len;
+    char                      path[MAXPATHLEN + 1];
+    
+    if (!dir) {
+        return NULL;
+    }
+
+    if ((len = strlen(dir)) > (MAXPATHLEN - DBLEN - 1)) {
+        LOG(log_error, logtype_default, "cnid_open: Pathname too large: %s", dir);
+        return NULL;
+    }
+    
+    if ((cdb = cnid_hash_new(dir)) == NULL) {
+        LOG(log_error, logtype_default, "cnid_open: Unable to allocate memory for hash");
+        return NULL;
+    }
+    strcpy(path, dir);
+    if (path[len - 1] != '/') {
+        strcat(path, "/");
+        len++;
+    }
+    strcpy(path + len, DBHOME);
+    if ((stat(path, &st) < 0) && (ad_mkdir(path, 0777 & ~mask) < 0)) {
+        LOG(log_error, logtype_default, "cnid_open: DBHOME mkdir failed for %s", path);
+        goto fail;
+    }
+    strcat(path, "/");
+    path[len + DBHOMELEN] = '\0';
+    strcat(path, DBNAME);
+    db = (struct _cnid_hash_private *)cdb->_private;
+    db->tdb = tdb_open(path, 0, TDB_CLEAR_IF_FIRST | TDB_INTERNAL, O_RDWR | O_CREAT | O_TRUNC, 0600);
+    if (!db->tdb) {
+        LOG(log_error, logtype_default, "cnid_open: unable to open tdb", path);
+        goto fail;
+    }
+
+    return cdb;
+
+fail:
+    free(cdb->_private);
+    free(cdb->volpath);
+    free(cdb);
+    
+    return NULL;
+}
+
+struct _cnid_module cnid_hash_module = {
+    "hash",
+    {NULL, NULL},
+    cnid_hash_open,
+};
+
+
+#endif /* CNID_BACKEND_HASH */
diff --git a/libatalk/cnid/hash/cnid_hash_resolve.c b/libatalk/cnid/hash/cnid_hash_resolve.c
new file mode 100644 (file)
index 0000000..9bdb14a
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * $Id: cnid_hash_resolve.c,v 1.1.2.1 2003-09-09 16:42:21 didg Exp $
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#ifdef CNID_BACKEND_HASH
+
+#include "cnid_hash.h"
+
+/* Return the did/name pair corresponding to a CNID. */
+char *cnid_hash_resolve(struct _cnid_db *cdb, cnid_t * id, void *buffer, u_int32_t len)
+{
+    struct _cnid_hash_private *db;
+    TDB_DATA key, data;      
+
+    if (!cdb || !(db = cdb->_private) || !id || !(*id)) {
+        return NULL;
+    }
+    key.dptr  = (char *)id;
+    key.dsize = sizeof(cnid_t);
+    data = tdb_fetch(db->tdb, key);
+    if (data.dptr) 
+    {
+        if (data.dsize < len && data.dsize > sizeof(cnid_t)) {
+            memcpy(id, data.dptr, sizeof(cnid_t));
+            memcpy(buffer, data.dptr +sizeof(cnid_t), data.dsize -sizeof(cnid_t));
+            free(data.dptr);
+            return buffer;
+        }
+        free(data.dptr);
+    }
+    return NULL;
+}
+
+#endif /* CNID_BACKEND_HASH */
diff --git a/libatalk/cnid/hash/cnid_hash_update.c b/libatalk/cnid/hash/cnid_hash_update.c
new file mode 100644 (file)
index 0000000..a2dddd1
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * $Id: cnid_hash_update.c,v 1.1.2.1 2003-09-09 16:42:21 didg Exp $
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#ifdef CNID_BACKEND_HASH
+
+#include "cnid_hash.h"
+
+int cnid_hash_update(struct _cnid_db *cdb, const cnid_t id, const struct stat *st,
+                     const cnid_t did, const char *name, const int len
+                     /*, const char *info, const int infolen */ )
+{
+    return 0;
+}
+
+#endif  /* CNID_BACKEND_HASH */
diff --git a/libatalk/cnid/last/Makefile.am b/libatalk/cnid/last/Makefile.am
new file mode 100644 (file)
index 0000000..0140786
--- /dev/null
@@ -0,0 +1,11 @@
+# Makefile.am for libatalk/cnid/
+
+CFLAGS = @CFLAGS@
+LIBS = @LIBS@
+
+noinst_LTLIBRARIES = libcnid_last.la
+
+libcnid_last_la_SOURCES = cnid_last.c \
+                        cnid_last.h
+
+EXTRA_DIST = README 
diff --git a/libatalk/cnid/last/README b/libatalk/cnid/last/README
new file mode 100644 (file)
index 0000000..3fe80f6
--- /dev/null
@@ -0,0 +1,4 @@
+This is [last] DID scheme implementation. 
+
+TODO: this scheme doesn't exactly mimic real, persistent CNID schemes, so 
+      things like name mangling won't work. 
diff --git a/libatalk/cnid/last/cnid_last.c b/libatalk/cnid/last/cnid_last.c
new file mode 100644 (file)
index 0000000..39f7946
--- /dev/null
@@ -0,0 +1,184 @@
+
+/*
+ * $Id: cnid_last.c,v 1.1.4.1 2003-09-09 16:42:21 didg Exp $
+ *
+ * Copyright (c) 1999. Adrian Sun (asun@zoology.washington.edu)
+ * All Rights Reserved. See COPYRIGHT.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#ifdef CNID_BACKEND_LAST
+#include <stdlib.h>
+#include "cnid_last.h"
+#include <atalk/util.h>
+#include <atalk/logger.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+/* ------------------------ */
+cnid_t cnid_last_add(struct _cnid_db *cdb, const struct stat *st,
+                     const cnid_t did, const char *name, const int len, cnid_t hint)
+{
+
+    /* FIXME: it relies on fact, that this is never called twice for the same file/dir. */
+    /* Propably we should look through DID tree. */
+
+    /*
+     * First thing:  DID and FNUMs are
+     * in the same space for purposes of enumerate (and several
+     * other wierd places).  While we consider this Apple's bug,
+     * this is the work-around:  In order to maintain constant and
+     * unique DIDs and FNUMs, we monotonically generate the DIDs
+     * during the session, and derive the FNUMs from the filesystem.
+     * Since the DIDs are small, we insure that the FNUMs are fairly
+     * large by setting thier high bits to the device number.
+     *
+     * AFS already does something very similar to this for the
+     * inode number, so we don't repeat the procedure.
+     *
+     * new algorithm:
+     * due to complaints over did's being non-persistent,
+     * here's the current hack to provide semi-persistent
+     * did's:
+     *      1) we reserve the first bit for file ids.
+     *      2) the next 7 bits are for the device.
+     *      3) the remaining 24 bits are for the inode.
+     *
+     * both the inode and device information are actually hashes
+     * that are then truncated to the requisite bit length.
+     *
+     * it should be okay to use lstat to deal with symlinks.
+     */
+
+    struct _cnid_last_private *priv;
+
+    if (!cdb || !(cdb->_private))
+        return CNID_INVALID;
+
+    priv = (struct _cnid_last_private *) (cdb->_private);
+
+    if (S_ISDIR(st->st_mode))
+        return htonl(priv->last_did++);
+    else
+        return htonl((st->st_dev << 16) | (st->st_ino & 0x0000ffff));
+}
+
+
+
+void cnid_last_close(struct _cnid_db *cdb)
+{
+    free(cdb->volpath);
+    free(cdb->_private);
+    free(cdb);
+}
+
+
+
+int cnid_last_delete(struct _cnid_db *cdb, const cnid_t id)
+{
+    return CNID_INVALID;
+}
+
+
+
+/* Return CNID for a given did/name. */
+cnid_t cnid_last_get(struct _cnid_db *cdb, const cnid_t did, const char *name, const int len)
+{
+    /* FIXME: it relies on fact, that this is never called twice for the same file/dir. */
+    /* Propably we should look through DID tree. */
+    return CNID_INVALID;
+}
+
+
+
+/* */
+cnid_t cnid_last_lookup(struct _cnid_db *cdb, const struct stat *st, const cnid_t did, const char *name, const int len)
+{
+    /* FIXME: this function doesn't work in [last] scheme ! */
+    /* Should be never called or CNID should be somewhat refactored again. */
+    return CNID_INVALID;
+}
+
+
+static struct _cnid_db *cnid_last_new(const char *volpath)
+{
+    struct _cnid_db *cdb;
+    struct _cnid_last_private *priv;
+
+    if ((cdb = (struct _cnid_db *) calloc(1, sizeof(struct _cnid_db))) == NULL)
+        return NULL;
+
+    if ((cdb->volpath = strdup(volpath)) == NULL) {
+        free(cdb);
+        return NULL;
+    }
+
+    if ((cdb->_private = calloc(1, sizeof(struct _cnid_last_private))) == NULL) {
+        free(cdb->volpath);
+        free(cdb);
+        return NULL;
+    }
+
+    /* Set up private state */
+    priv = (struct _cnid_last_private *) (cdb->_private);
+    priv->last_did = 17;
+
+    /* Set up standard fields */
+    cdb->flags = 0;
+    cdb->cnid_add = cnid_last_add;
+    cdb->cnid_delete = cnid_last_delete;
+    cdb->cnid_get = cnid_last_get;
+    cdb->cnid_lookup = cnid_last_lookup;
+    cdb->cnid_nextid = NULL;    /* cnid_last_nextid; */
+    cdb->cnid_resolve = cnid_last_resolve;
+    cdb->cnid_update = cnid_last_update;
+    cdb->cnid_close = cnid_last_close;
+    
+    return cdb;
+}
+
+struct _cnid_db *cnid_last_open(const char *dir, mode_t mask)
+{
+    struct _cnid_db *cdb;
+
+    if (!dir) {
+        return NULL;
+    }
+
+    if ((cdb = cnid_last_new(dir)) == NULL) {
+        LOG(log_error, logtype_default, "cnid_open: Unable to allocate memory for database");
+        return NULL;
+    }
+
+    return cdb;
+}
+
+struct _cnid_module cnid_last_module = {
+    "last",
+    {NULL, NULL},
+    cnid_last_open,
+};
+
+/* Return the did/name pair corresponding to a CNID. */
+char *cnid_last_resolve(struct _cnid_db *cdb, cnid_t * id, void *buffer, u_int32_t len)
+{
+    /* FIXME: frankly, it does not work. As get, add and other functions. */
+    return NULL;
+}
+
+
+int cnid_last_update(struct _cnid_db *cdb, const cnid_t id, const struct stat *st,
+                     const cnid_t did, const char *name, const int len
+                     /*, const char *info, const int infolen */ )
+{
+    return 0;
+}
+
+
+#endif /* CNID_BACKEND_LAST */
diff --git a/libatalk/cnid/last/cnid_last.h b/libatalk/cnid/last/cnid_last.h
new file mode 100644 (file)
index 0000000..499b181
--- /dev/null
@@ -0,0 +1,34 @@
+
+/* 
+ * interface for database access to cnids. i do it this way to abstract
+ * things a bit in case we want to change the underlying implementation.
+ */
+
+#ifndef _ATALK_CNID_LAST__H
+#define _ATALK_CNID_LAST__H 1
+
+#include <sys/cdefs.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <string.h>
+
+#include <netatalk/endian.h>
+#include <atalk/cnid.h>
+
+struct _cnid_last_private {
+    cnid_t last_did;
+};
+
+extern struct _cnid_module cnid_last_module;
+extern struct _cnid_db *cnid_last_open __P((const char *, mode_t));
+extern void cnid_last_close __P((struct _cnid_db *));
+extern cnid_t cnid_last_add __P((struct _cnid_db *, const struct stat *, const cnid_t,
+                                 const char *, const int, cnid_t));
+extern cnid_t cnid_last_get __P((struct _cnid_db *, const cnid_t, const char *, const int));
+extern char *cnid_last_resolve __P((struct _cnid_db *, cnid_t *, void *, u_int32_t));
+extern cnid_t cnid_last_lookup __P((struct _cnid_db *, const struct stat *, const cnid_t, const char *, const int));
+extern int cnid_last_update __P((struct _cnid_db *, const cnid_t, const struct stat *,
+                                 const cnid_t, const char *, int));
+extern int cnid_last_delete __P((struct _cnid_db *, const cnid_t));
+
+#endif /* include/atalk/cnid_last.h */
diff --git a/libatalk/cnid/mtab/Makefile.am b/libatalk/cnid/mtab/Makefile.am
new file mode 100644 (file)
index 0000000..6303594
--- /dev/null
@@ -0,0 +1,11 @@
+# Makefile.am for libatalk/cnid/
+
+CFLAGS = @CFLAGS@
+LIBS = @LIBS@
+
+noinst_LTLIBRARIES = libcnid_mtab.la
+
+libcnid_mtab_la_SOURCES = cnid_mtab.c \
+                        cnid_mtab.h
+
+EXTRA_DIST = README
diff --git a/libatalk/cnid/mtab/README b/libatalk/cnid/mtab/README
new file mode 100644 (file)
index 0000000..19e634f
--- /dev/null
@@ -0,0 +1 @@
+There are still things to do. See ../last/README for details.
diff --git a/libatalk/cnid/mtab/cnid_mtab.c b/libatalk/cnid/mtab/cnid_mtab.c
new file mode 100644 (file)
index 0000000..517a933
--- /dev/null
@@ -0,0 +1,137 @@
+
+/*
+ * $Id: cnid_mtab.c,v 1.1.4.1 2003-09-09 16:42:21 didg Exp $
+ *
+ * Copyright (c) 1999. Adrian Sun (asun@zoology.washington.edu)
+ * All Rights Reserved. See COPYRIGHT.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#ifdef CNID_BACKEND_MTAB
+
+#include "cnid_mtab.h"
+#include <atalk/logger.h>
+#include <stdlib.h>
+
+#ifndef AFS
+#define CNID_XOR(a) (((a) >> 16) ^ (a))
+#define CNID_DEV(a) ((((CNID_XOR(major((a)->st_dev)) & 0xf) << 3) |\
+               (CNID_XOR(minor((a)->st_dev)) & 0x7)) << 24)
+#define CNID_INODE(a) (((a)->st_ino ^ (((a)->st_ino & 0xff000000) >> 8)) \
+               & 0x00ffffff)
+#define CNID_FILE(a) (((a) & 0x1) << 31)
+#define CNID(a,b) (CNID_DEV(a) | CNID_INODE(a) | CNID_FILE(b))
+#else
+#define CNID(a,b) (((a)->st_ino & 0x7fffffff) | CNID_FILE(b))
+#endif
+
+/* ------------------------ */
+cnid_t cnid_mtab_add(struct _cnid_db *cdb, const struct stat *st,
+                     const cnid_t did, const char *name, const int len, cnid_t hint)
+{
+    struct stat lst;
+    const struct stat *lstp;
+
+    lstp = lstat(name, &lst) < 0 ? st : &lst;
+
+    return htonl(CNID(lstp, 1));
+}
+
+
+
+void cnid_mtab_close(struct _cnid_db *cdb)
+{
+    free(cdb->volpath);
+    free(cdb);
+}
+
+
+
+int cnid_mtab_delete(struct _cnid_db *cdb, const cnid_t id)
+{
+    return CNID_INVALID;
+}
+
+
+
+/* Return CNID for a given did/name. */
+cnid_t cnid_mtab_get(struct _cnid_db *cdb, const cnid_t did, const char *name, const int len)
+{
+    return CNID_INVALID;
+}
+
+
+cnid_t cnid_mtab_lookup(struct _cnid_db *cdb, const struct stat *st, const cnid_t did, const char *name, const int len)
+{
+    return CNID_INVALID;
+}
+
+
+static struct _cnid_db *cnid_mtab_new(const char *volpath)
+{
+    struct _cnid_db *cdb;
+
+    if ((cdb = (struct _cnid_db *) calloc(1, sizeof(struct _cnid_db))) == NULL)
+        return NULL;
+
+    if ((cdb->volpath = strdup(volpath)) == NULL) {
+        free(cdb);
+        return NULL;
+    }
+
+    cdb->flags = 0;
+    cdb->cnid_add = cnid_mtab_add;
+    cdb->cnid_delete = cnid_mtab_delete;
+    cdb->cnid_get = cnid_mtab_get;
+    cdb->cnid_lookup = cnid_mtab_lookup;
+    cdb->cnid_nextid = NULL;    //cnid_mtab_nextid;
+    cdb->cnid_resolve = cnid_mtab_resolve;
+    cdb->cnid_update = cnid_mtab_update;
+    cdb->cnid_close = cnid_mtab_close;
+    
+    return cdb;
+}
+
+struct _cnid_db *cnid_mtab_open(const char *dir, mode_t mask)
+{
+    struct _cnid_db *cdb;
+
+    if (!dir) {
+        return NULL;
+    }
+
+    if ((cdb = cnid_mtab_new(dir)) == NULL) {
+        LOG(log_error, logtype_default, "cnid_open: Unable to allocate memory for database");
+        return NULL;
+    }
+
+    cdb->_private = NULL;
+    return cdb;
+}
+
+struct _cnid_module cnid_mtab_module = {
+    "mtab",
+    {NULL, NULL},
+    cnid_mtab_open,
+};
+
+
+/* Return the did/name pair corresponding to a CNID. */
+char *cnid_mtab_resolve(struct _cnid_db *cdb, cnid_t * id, void *buffer, u_int32_t len)
+{
+    return NULL;
+}
+
+
+int cnid_mtab_update(struct _cnid_db *cdb, const cnid_t id, const struct stat *st,
+                     const cnid_t did, const char *name, const int len
+                     /*, const char *info, const int infolen */ )
+{
+    return 0;
+}
+
+#endif /* CNID_BACKEND_MTAB */
diff --git a/libatalk/cnid/mtab/cnid_mtab.h b/libatalk/cnid/mtab/cnid_mtab.h
new file mode 100644 (file)
index 0000000..c2027da
--- /dev/null
@@ -0,0 +1,31 @@
+
+/* 
+ * interface for database access to cnids. i do it this way to abstract
+ * things a bit in case we want to change the underlying implementation.
+ */
+
+#ifndef _ATALK_CNID_MTAB__H
+#define _ATALK_CNID_MTAB__H 1
+
+#include <sys/cdefs.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <string.h>
+
+#include <netatalk/endian.h>
+#include <atalk/cnid.h>
+
+extern struct _cnid_module cnid_mtab_module;
+
+extern struct _cnid_db *cnid_mtab_open __P((const char *, mode_t));
+extern void cnid_mtab_close __P((struct _cnid_db *));
+extern cnid_t cnid_mtab_add __P((struct _cnid_db *, const struct stat *, const cnid_t,
+                                 const char *, const int, cnid_t));
+extern cnid_t cnid_mtab_get __P((struct _cnid_db *, const cnid_t, const char *, const int));
+extern char *cnid_mtab_resolve __P((struct _cnid_db *, cnid_t *, void *, u_int32_t));
+extern cnid_t cnid_mtab_lookup __P((struct _cnid_db *, const struct stat *, const cnid_t, const char *, const int));
+extern int cnid_mtab_update __P((struct _cnid_db *, const cnid_t, const struct stat *,
+                                 const cnid_t, const char *, int));
+extern int cnid_mtab_delete __P((struct _cnid_db *, const cnid_t));
+
+#endif /* include/atalk/cnid_mtab.h */
diff --git a/libatalk/cnid/tdb/Makefile.am b/libatalk/cnid/tdb/Makefile.am
new file mode 100644 (file)
index 0000000..1ad39b3
--- /dev/null
@@ -0,0 +1,18 @@
+# Makefile.am for libatalk/cnid/
+
+CFLAGS = @CFLAGS@ @BDB_CFLAGS@
+LIBS = @LIBS@ @BDB_LIBS@
+
+noinst_LTLIBRARIES = libcnid_tdb.la
+
+libcnid_tdb_la_SOURCES = cnid_tdb_add.c \
+                        cnid_tdb_close.c \
+                        cnid_tdb_delete.c \
+                        cnid_tdb_get.c \
+                        cnid_tdb_lookup.c \
+                        cnid_tdb_open.c \
+                        cnid_tdb_resolve.c \
+                        cnid_tdb_update.c \
+                        cnid_tdb.h
+
+EXTRA_DIST = README cnid_tdb_nextid.c
diff --git a/libatalk/cnid/tdb/README b/libatalk/cnid/tdb/README
new file mode 100644 (file)
index 0000000..b39889b
--- /dev/null
@@ -0,0 +1,35 @@
+the catalog database keeps track of three mappings:
+    CNID     -> dev/ino and did/name
+    dev/ino  -> CNID
+    did/name -> CNID
+
+dev/ino is used to keep track of magically moved files. did/name is
+for quick lookups of CNIDs. 
+
+NOTE: the database will append a nul byte to the end of name. in
+addition, name should be given as it appears on disk. this allows the
+creation of cnid updating/cleaning programs that don't have to deal
+with knowing what the particular codepage is.
+
+here's the ritual:
+       1) open a volume. call cnid_open.
+       2) every time you need a CNID, call cnid_add(). it will
+          automatically look for an existing cnid and add a new one
+          if one isn't already there. you can pass a hint if you
+          want. the only use this has right now is to enable
+          consistency between AFP and HFS. in the future, it would
+          allow people to write conversion utilities that
+          pre-instantiate a database without needing to re-assign
+          CNIDs.
+       3) if you want to just look for a CNID without automatically
+          adding one in, you have two choices:
+            a) cnid_resolve takes a CNID, returns name, and
+               over-writes the CNID given with the parent DID. this
+               is good for FPResolveID.
+             b) cnid_lookup returns a CNID corresponding to the
+               dev/ino,did/name keys. it will auto-update the catalog
+               database if there's a discrepancy. 
+               NOTE: cnid_add calls this before adding a new CNID. 
+       4) when you delete a file or directory, you need to call
+          cnid_delete with the CNID for that file/directory.
+       5) call cnid_close when closing the volume.
diff --git a/libatalk/cnid/tdb/cnid_tdb.h b/libatalk/cnid/tdb/cnid_tdb.h
new file mode 100644 (file)
index 0000000..14bfc2d
--- /dev/null
@@ -0,0 +1,115 @@
+/* 
+ * interface for database access to cnids. i do it this way to abstract
+ * things a bit in case we want to change the underlying implementation.
+ */
+
+#ifndef _ATALK_CNID_TDB__H
+#define _ATALK_CNID_TDB__H 1
+
+#include <sys/cdefs.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <string.h>
+
+#include <sys/param.h>
+
+#include <netatalk/endian.h>
+#include <atalk/cnid.h>
+#define STANDALONE 1
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <signal.h>
+#include <atalk/tdb.h>
+
+#define TDB_ERROR_LINK  1
+#define TDB_ERROR_DEV   2
+#define TDB_ERROR_INODE 4
+
+#define TDB_DB_MAGIC   0x434E4944U  /* CNID */
+#define TDB_DATA_MAGIC 0x434E4945U  /* CNIE */
+
+#define TDB_DEVINO_LEN          8
+#define TDB_DID_LEN             4
+#define TDB_HEADER_LEN          (TDB_DEVINO_LEN + TDB_DID_LEN)
+
+#define TDB_START               17
+
+#define TDBFLAG_ROOTINFO_RO     (1 << 0)
+#define TDBFLAG_DB_RO           (1 << 1)
+
+/* the key is in the form of a did/name pair. in this case,
+ * we use 0/RootInfo. */
+#define ROOTINFO_KEY    "\0\0\0\0RootInfo"
+#define ROOTINFO_KEYLEN 12
+
+struct _cnid_tdb_private {
+    dev_t  st_dev;
+    int    st_set;
+    int    error;
+    int    flags;
+    TDB_CONTEXT *tdb_cnid;
+    TDB_CONTEXT *tdb_didname;
+    TDB_CONTEXT *tdb_devino;
+
+};
+
+/* cnid_open.c */
+extern struct _cnid_module cnid_tdb_module;
+extern struct _cnid_db *cnid_tdb_open __P((const char *, mode_t));
+
+/* cnid_close.c */
+extern void cnid_tdb_close __P((struct _cnid_db *));
+
+/* cnid_add.c */
+extern cnid_t cnid_tdb_add __P((struct _cnid_db *, const struct stat *, const cnid_t,
+                                 const char *, const int, cnid_t));
+
+/* cnid_get.c */
+extern cnid_t cnid_tdb_get __P((struct _cnid_db *, const cnid_t, const char *, const int));
+extern char *cnid_tdb_resolve __P((struct _cnid_db *, cnid_t *, void *, u_int32_t));
+extern cnid_t cnid_tdb_lookup __P((struct _cnid_db *, const struct stat *, const cnid_t, const char *, const int));
+
+/* cnid_update.c */
+extern int cnid_tdb_update __P((struct _cnid_db *, const cnid_t, const struct stat *,
+                                 const cnid_t, const char *, int));
+
+/* cnid_delete.c */
+extern int cnid_tdb_delete __P((struct _cnid_db *, const cnid_t));
+
+/* cnid_nextid.c */
+extern cnid_t cnid_tdb_nextid __P((struct _cnid_db *));
+
+/* construct db_cnid data. NOTE: this is not re-entrant.  */
+static __inline__ char *make_tdb_data(const struct stat *st,
+                                       const cnid_t did,
+                                       const char *name, const int len)
+{
+    static char start[TDB_HEADER_LEN + MAXPATHLEN + 1];
+    char *buf = start;
+    u_int32_t i;
+
+    if (len > MAXPATHLEN)
+        return NULL;
+
+    i = htonl(st->st_dev);
+    buf = memcpy(buf, &i, sizeof(i));
+    i = htonl(st->st_ino);
+    buf = memcpy(buf + sizeof(i), &i, sizeof(i));
+    /* did is already in network byte order */
+    buf = memcpy(buf + sizeof(i), &did, sizeof(did));
+    buf = memcpy(buf + sizeof(did), name, len);
+    *(buf + len) = '\0';
+    buf += len + 1;
+
+    return start;
+}
+
+#endif /* include/atalk/cnid_tdb.h */
diff --git a/libatalk/cnid/tdb/cnid_tdb_add.c b/libatalk/cnid/tdb/cnid_tdb_add.c
new file mode 100644 (file)
index 0000000..407424d
--- /dev/null
@@ -0,0 +1,161 @@
+/*
+ * $Id: cnid_tdb_add.c,v 1.1.2.1 2003-09-09 16:42:21 didg Exp $
+ *
+ * Copyright (c) 1999. Adrian Sun (asun@zoology.washington.edu)
+ * All Rights Reserved. See COPYRIGHT.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef CNID_BACKEND_TDB
+#include "cnid_tdb.h"
+#include <atalk/util.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <atalk/logger.h>
+
+/* add an entry to the CNID databases. we do this as a transaction
+ * to prevent messiness. */
+
+static int add_cnid (struct _cnid_tdb_private *db, TDB_DATA *key, TDB_DATA *data) {
+    TDB_DATA altkey, altdata;
+    int rc;
+
+    memset(&altkey, 0, sizeof(altkey));
+    memset(&altdata, 0, sizeof(altdata));
+
+
+    /* main database */
+    if (tdb_store(db->tdb_cnid, *key, *data, TDB_REPLACE)) {
+        goto abort;
+    }
+
+    /* dev/ino database */
+    altkey.dptr = data->dptr;
+    altkey.dsize = TDB_DEVINO_LEN;
+    altdata.dptr = key->dptr;
+    altdata.dsize = key->dsize;
+    if (tdb_store(db->tdb_devino, altkey, altdata, TDB_REPLACE)) {
+        goto abort;
+    }
+
+    /* did/name database */
+    altkey.dptr = (char *) data->dptr + TDB_DEVINO_LEN;
+    altkey.dsize = data->dsize - TDB_DEVINO_LEN;
+    if (tdb_store(db->tdb_didname, altkey, altdata, TDB_REPLACE)) {
+        goto abort;
+    }
+    return 0;
+
+abort:
+    return rc;
+}
+
+/* ----------------------- */
+static cnid_t get_cnid(struct _cnid_tdb_private *db)
+{
+    TDB_DATA rootinfo_key, data;
+    cnid_t hint,id;
+    
+    memset(&rootinfo_key, 0, sizeof(rootinfo_key));
+    memset(&data, 0, sizeof(data));
+    rootinfo_key.dptr = ROOTINFO_KEY;
+    rootinfo_key.dsize = ROOTINFO_KEYLEN;
+    
+    tdb_chainlock(db->tdb_didname, rootinfo_key);  
+    data = tdb_fetch(db->tdb_didname, rootinfo_key);
+    if (data.dptr)
+    {
+        memcpy(&hint, data.dptr, sizeof(cnid_t));
+        free(data.dptr);
+        id = ntohl(hint);
+        /* If we've hit the max CNID allowed, we return a fatal error.  CNID
+         * needs to be recycled before proceding. */
+        if (++id == CNID_INVALID) {
+            LOG(log_error, logtype_default, "cnid_add: FATAL: CNID database has reached its limit.");
+            errno = CNID_ERR_MAX;
+            goto cleanup;
+        }
+        hint = htonl(id);
+    }
+    else {
+        hint = htonl(TDB_START);
+    }
+    
+    memset(&data, 0, sizeof(data));
+    data.dptr = (char *)&hint;
+    data.dsize = sizeof(hint);
+    if (tdb_store(db->tdb_didname, rootinfo_key, data, TDB_REPLACE)) {
+        goto cleanup;
+    }
+
+    tdb_chainunlock(db->tdb_didname, rootinfo_key );  
+    return hint;
+cleanup:
+    tdb_chainunlock(db->tdb_didname, rootinfo_key);  
+    return CNID_INVALID;
+}
+
+
+/* ------------------------ */
+cnid_t cnid_tdb_add(struct _cnid_db *cdb, const struct stat *st,
+                     const cnid_t did, const char *name, const int len, cnid_t hint)
+{
+    const struct stat *lstp;
+    cnid_t id;
+    struct _cnid_tdb_private *priv;
+    TDB_DATA key, data; 
+    int rc;      
+    
+    if (!cdb || !(priv = cdb->_private) || !st || !name) {
+        errno = CNID_ERR_PARAM;
+        return CNID_INVALID;
+    }
+    /* Do a lookup. */
+    id = cnid_tdb_lookup(cdb, st, did, name, len);
+    /* ... Return id if it is valid, or if Rootinfo is read-only. */
+    if (id || (priv->flags & TDBFLAG_DB_RO)) {
+        return id;
+    }
+
+#if 0
+    struct stat lst;
+    lstp = lstat(name, &lst) < 0 ? st : &lst;
+#endif
+    lstp = st;
+
+    /* Initialize our DBT data structures. */
+    memset(&key, 0, sizeof(key));
+    memset(&data, 0, sizeof(data));
+
+    key.dptr = (char *)&hint;
+    key.dsize = sizeof(cnid_t);
+    if ((data.dptr = make_tdb_data(lstp, did, name, len)) == NULL) {
+        LOG(log_error, logtype_default, "tdb_add: Path name is too long");
+        errno = CNID_ERR_PATH;
+        return CNID_INVALID;
+    }
+    data.dsize = TDB_HEADER_LEN + len + 1;
+    hint = get_cnid(priv);
+    if (hint == 0) {
+        errno = CNID_ERR_DB;
+        return CNID_INVALID;
+    }
+    
+    /* Now we need to add the CNID data to the databases. */
+    rc = add_cnid(priv, &key, &data);
+    if (rc) {
+        LOG(log_error, logtype_default, "tdb_add: Failed to add CNID for %s to database using hint %u", name, ntohl(hint));
+        errno = CNID_ERR_DB;
+        return CNID_INVALID;
+    }
+
+    return hint;
+}
+
+#endif
diff --git a/libatalk/cnid/tdb/cnid_tdb_close.c b/libatalk/cnid/tdb/cnid_tdb_close.c
new file mode 100644 (file)
index 0000000..063bb2f
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * $Id: cnid_tdb_close.c,v 1.1.2.1 2003-09-09 16:42:21 didg Exp $
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef CNID_BACKEND_TDB
+
+#include "cnid_tdb.h"
+
+void cnid_tdb_close(struct _cnid_db *cdb)
+{
+    struct _cnid_tdb_private *db;
+
+    free(cdb->volpath);
+    db = (struct _cnid_tdb_private *)cdb->_private;
+    tdb_close(db->tdb_cnid);
+    tdb_close(db->tdb_didname);
+    tdb_close(db->tdb_devino);
+    free(cdb->_private);
+    free(cdb);
+}
+
+#endif
diff --git a/libatalk/cnid/tdb/cnid_tdb_delete.c b/libatalk/cnid/tdb/cnid_tdb_delete.c
new file mode 100644 (file)
index 0000000..ebdcaa2
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * $Id: cnid_tdb_delete.c,v 1.1.2.1 2003-09-09 16:42:21 didg Exp $
+ *
+ * Copyright (c) 1999. Adrian Sun (asun@zoology.washington.edu)
+ * All Rights Reserved. See COPYRIGHT.
+ *
+ * cnid_delete: delete a CNID from the database 
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif 
+
+#ifdef CNID_BACKEND_TDB
+
+#include "cnid_tdb.h"
+
+int cnid_tdb_delete(struct _cnid_db *cdb, const cnid_t id)
+{
+    struct _cnid_tdb_private *db;
+    TDB_DATA key, data;
+
+    if (!cdb || !(db = cdb->_private) || !id) {
+        return -1;
+    }
+    memset(&key, 0, sizeof(key));
+    memset(&data, 0, sizeof(data));
+
+    key.dptr  = (char *)&id;
+    key.dsize = sizeof(cnid_t);
+    data = tdb_fetch(db->tdb_cnid, key);
+    if (!data.dptr)
+    {
+        return 0;
+    }
+    
+    tdb_delete(db->tdb_cnid, key); 
+
+    key.dptr = data.dptr;
+    key.dsize = TDB_DEVINO_LEN;
+    tdb_delete(db->tdb_devino, key); 
+
+    key.dptr = (char *)data.dptr + TDB_DEVINO_LEN;
+    key.dsize = data.dsize - TDB_DEVINO_LEN;
+    tdb_delete(db->tdb_didname, key); 
+
+    free(data.dptr);
+    return 0;
+}
+
+#endif 
diff --git a/libatalk/cnid/tdb/cnid_tdb_get.c b/libatalk/cnid/tdb/cnid_tdb_get.c
new file mode 100644 (file)
index 0000000..0e6a7ad
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * $Id: cnid_tdb_get.c,v 1.1.2.1 2003-09-09 16:42:21 didg Exp $
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef CNID_BACKEND_TDB
+
+#include "cnid_tdb.h"
+
+/* Return CNID for a given did/name. */
+cnid_t cnid_tdb_get(struct _cnid_db *cdb, const cnid_t did, const char *name, const int len)
+{
+    char start[TDB_DID_LEN + MAXPATHLEN + 1], *buf;
+    struct _cnid_tdb_private *db;
+    TDB_DATA key, data;
+    cnid_t id;
+
+    if (!cdb || !(db = cdb->_private) || (len > MAXPATHLEN)) {
+        return 0;
+    }
+
+    memset(&key, 0, sizeof(key));
+    memset(&data, 0, sizeof(data));
+
+    buf = start;
+    memcpy(buf, &did, sizeof(did));
+    buf += sizeof(did);
+    memcpy(buf, name, len);
+    *(buf + len) = '\0'; /* Make it a C-string. */
+    key.dptr = start;
+    key.dsize = TDB_DID_LEN + len + 1;
+    data = tdb_fetch(db->tdb_didname, key);
+    if (!data.dptr)
+        return 0;
+
+    memcpy(&id, data.dptr, sizeof(id));
+    free(data.dptr);
+    return id;
+}
+
+#endif
diff --git a/libatalk/cnid/tdb/cnid_tdb_lookup.c b/libatalk/cnid/tdb/cnid_tdb_lookup.c
new file mode 100644 (file)
index 0000000..9268138
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * $Id: cnid_tdb_lookup.c,v 1.1.2.1 2003-09-09 16:42:21 didg Exp $
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef CNID_BACKEND_TDB
+
+#include "cnid_tdb.h"
+#include <atalk/logger.h>
+
+cnid_t cnid_tdb_lookup(struct _cnid_db *cdb, const struct stat *st, const cnid_t did, const char *name, const int len)
+{
+    char *buf;
+    struct _cnid_tdb_private *db;
+    TDB_DATA key, devdata, diddata;
+    int devino = 1, didname = 1;
+    cnid_t id = 0;
+
+    if (!cdb || !(db = cdb->_private) || !st || !name) {
+        return 0;
+    }
+
+    if ((buf = make_tdb_data(st, did, name, len)) == NULL) {
+        LOG(log_error, logtype_default, "tdb_lookup: Pathname is too long");
+        return 0;
+    }
+
+    memset(&key, 0, sizeof(key));
+    memset(&devdata, 0, sizeof(devdata));
+    memset(&diddata, 0, sizeof(diddata));
+
+    /* Look for a CNID.  We have two options: dev/ino or did/name.  If we
+    * only get a match in one of them, that means a file has moved. */
+    key.dptr = buf;
+    key.dsize  = TDB_DEVINO_LEN;
+    devdata = tdb_fetch(db->tdb_devino, key);
+    if (!devdata.dptr) {
+         devino = 0;
+    }
+    /* did/name now */
+    key.dptr = buf + TDB_DEVINO_LEN;
+    key.dsize = TDB_DID_LEN + len + 1;
+    diddata = tdb_fetch(db->tdb_didname, key);
+    if (!diddata.dptr) {
+        didname = 0;
+    }
+    /* Set id.  Honor did/name over dev/ino as dev/ino isn't necessarily
+     * 1-1. */
+    if (didname) {
+        memcpy(&id, diddata.dptr, sizeof(id));
+    }
+    else if (devino) {
+        memcpy(&id, devdata.dptr, sizeof(id));
+    }
+    free(devdata.dptr);
+    free(diddata.dptr);
+    /* Either entries are in both databases or neither of them. */
+    if ((devino && didname) || !(devino || didname)) {
+        return id;
+    }
+
+    /* Fix up the database. */
+    cnid_tdb_update(cdb, id, st, did, name, len);
+    return id;
+}
+
+#endif
diff --git a/libatalk/cnid/tdb/cnid_tdb_nextid.c b/libatalk/cnid/tdb/cnid_tdb_nextid.c
new file mode 100644 (file)
index 0000000..1abafe3
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * $Id: cnid_tdb_nextid.c,v 1.1.2.1 2003-09-09 16:42:21 didg Exp $
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif 
+
+#ifdef CNID_BACKEND_TDB
+
+#include "cnid_tdb.h"
+
+cnid_t cnid_tdb_nextid(struct _cnid_db *cdb)
+{
+    return CNID_INVALID;
+}
+
+#endif 
diff --git a/libatalk/cnid/tdb/cnid_tdb_open.c b/libatalk/cnid/tdb/cnid_tdb_open.c
new file mode 100644 (file)
index 0000000..aa9359f
--- /dev/null
@@ -0,0 +1,171 @@
+/*
+ * $Id: cnid_tdb_open.c,v 1.1.2.1 2003-09-09 16:42:21 didg Exp $
+ *
+ * Copyright (c) 1999. Adrian Sun (asun@zoology.washington.edu)
+ * All Rights Reserved. See COPYRIGHT.
+ *
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef CNID_BACKEND_TDB
+#include <sys/param.h>   
+
+#include "cnid_tdb.h"
+#include <atalk/logger.h>
+#include <stdlib.h>
+#define DBHOME       ".AppleDB"
+#define DBNAME       "private_tdb.%sX"
+#define DBHOMELEN    9                  /* strlen(DBHOME) +1 for / */
+#define DBLEN        12
+#define DBCNID       "cnid.tdb"
+#define DBDEVINO     "devino.tdb"
+#define DBDIDNAME    "didname.tdb"      /* did/full name mapping */
+
+#define DBVERSION_KEY    "\0\0\0\0\0"
+#define DBVERSION_KEYLEN 5
+#define DBVERSION1       0x00000001U
+#define DBVERSION        DBVERSION1
+
+static struct _cnid_db *cnid_tdb_new(const char *volpath)
+{
+    struct _cnid_db *cdb;
+    struct _cnid_tdb_private *priv;
+
+    if ((cdb = (struct _cnid_db *) calloc(1, sizeof(struct _cnid_db))) == NULL)
+        return NULL;
+
+    if ((cdb->volpath = strdup(volpath)) == NULL) {
+        free(cdb);
+        return NULL;
+    }
+
+    if ((cdb->_private = calloc(1, sizeof(struct _cnid_tdb_private))) == NULL) {
+        free(cdb->volpath);
+        free(cdb);
+        return NULL;
+    }
+
+    /* Set up private state */
+    priv = (struct _cnid_tdb_private *) (cdb->_private);
+
+    /* Set up standard fields */
+    cdb->flags = CNID_FLAG_PERSISTENT;
+
+    cdb->cnid_add = cnid_tdb_add;
+    cdb->cnid_delete = cnid_tdb_delete;
+    cdb->cnid_get = cnid_tdb_get;
+    cdb->cnid_lookup = cnid_tdb_lookup;
+    cdb->cnid_nextid = NULL;    /*cnid_tdb_nextid;*/
+    cdb->cnid_resolve = cnid_tdb_resolve;
+    cdb->cnid_update = cnid_tdb_update;
+    cdb->cnid_close = cnid_tdb_close;
+    
+    return cdb;
+}
+
+/* ---------------------------- */
+struct _cnid_db *cnid_tdb_open(const char *dir, mode_t mask)
+{
+    struct stat               st;
+    struct _cnid_db           *cdb;
+    struct _cnid_tdb_private *db;
+    size_t                    len;
+    char                      path[MAXPATHLEN + 1];
+    TDB_DATA                  key, data;
+    
+    if (!dir) {
+        return NULL;
+    }
+
+    if ((len = strlen(dir)) > (MAXPATHLEN - DBLEN - 1)) {
+        LOG(log_error, logtype_default, "tdb_open: Pathname too large: %s", dir);
+        return NULL;
+    }
+    
+    if ((cdb = cnid_tdb_new(dir)) == NULL) {
+        LOG(log_error, logtype_default, "tdb_open: Unable to allocate memory for tdb");
+        return NULL;
+    }
+    strcpy(path, dir);
+    if (path[len - 1] != '/') {
+        strcat(path, "/");
+        len++;
+    }
+    strcpy(path + len, DBHOME);
+    if ((stat(path, &st) < 0) && (ad_mkdir(path, 0777 & ~mask) < 0)) {
+        LOG(log_error, logtype_default, "tdb_open: DBHOME mkdir failed for %s", path);
+        goto fail;
+    }
+    strcat(path, "/");
+    db = (struct _cnid_tdb_private *)cdb->_private;
+
+    path[len + DBHOMELEN] = '\0';
+    strcat(path, DBCNID);
+    db->tdb_cnid = tdb_open(path, 0, 0 , O_RDWR | O_CREAT, 0666 & ~mask);
+    if (!db->tdb_cnid) {
+        LOG(log_error, logtype_default, "tdb_open: unable to open tdb", path);
+        goto fail;
+    }
+    /* ------------- */
+
+    path[len + DBHOMELEN] = '\0';
+    strcat(path, DBDIDNAME);
+    db->tdb_didname = tdb_open(path, 0, 0 , O_RDWR | O_CREAT, 0666 & ~mask);
+    if (!db->tdb_cnid) {
+        LOG(log_error, logtype_default, "tdb_open: unable to open tdb", path);
+        goto fail;
+    }
+    /* Check for version.  This way we can update the database if we need
+     * to change the format in any way. */
+    memset(&key, 0, sizeof(key));
+    memset(&data, 0, sizeof(data));
+    key.dptr = DBVERSION_KEY;
+    key.dsize = DBVERSION_KEYLEN;
+
+    data = tdb_fetch(db->tdb_didname, key);
+    if (!data.dptr) {
+        u_int32_t version = htonl(DBVERSION);
+
+        data.dptr = (char *)&version;
+        data.dsize = sizeof(version);
+        if (tdb_store(db->tdb_didname, key, data, TDB_REPLACE)) {
+            LOG(log_error, logtype_default, "tdb_open: Error putting new version");
+            goto fail;
+        }
+    }
+    else {
+        free(data.dptr);
+    }
+        
+    /* ------------- */
+    path[len + DBHOMELEN] = '\0';
+    strcat(path, DBDEVINO);
+    db->tdb_devino = tdb_open(path, 0, 0 , O_RDWR | O_CREAT, 0666 & ~mask);
+    if (!db->tdb_devino) {
+        LOG(log_error, logtype_default, "tdb_open: unable to open tdb", path);
+        goto fail;
+    }
+
+    return cdb;
+
+fail:
+    free(cdb->_private);
+    free(cdb->volpath);
+    free(cdb);
+    
+    return NULL;
+}
+
+struct _cnid_module cnid_tdb_module = {
+    "tdb",
+    {NULL, NULL},
+    cnid_tdb_open,
+    CNID_FLAG_SETUID
+};
+
+
+#endif
diff --git a/libatalk/cnid/tdb/cnid_tdb_resolve.c b/libatalk/cnid/tdb/cnid_tdb_resolve.c
new file mode 100644 (file)
index 0000000..4c3fa0c
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * $Id: cnid_tdb_resolve.c,v 1.1.2.1 2003-09-09 16:42:21 didg Exp $
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef CNID_BACKEND_TDB
+
+#include "cnid_tdb.h"
+
+/* Return the did/name pair corresponding to a CNID. */
+char *cnid_tdb_resolve(struct _cnid_db *cdb, cnid_t * id, void *buffer, u_int32_t len)
+{
+    struct _cnid_tdb_private *db;
+    TDB_DATA key, data;      
+
+    if (!cdb || !(db = cdb->_private) || !id || !(*id)) {
+        return NULL;
+    }
+    key.dptr  = (char *)id;
+    key.dsize = sizeof(cnid_t);
+    data = tdb_fetch(db->tdb_cnid, key);
+    if (data.dptr) 
+    {
+        if (data.dsize < len && data.dsize > sizeof(cnid_t)) {
+            memcpy(id, (char *)data.dptr + TDB_DEVINO_LEN, sizeof(cnid_t));
+            strcpy(buffer, (char *)data.dptr + TDB_HEADER_LEN);
+            free(data.dptr);
+            return buffer;
+        }
+        free(data.dptr);
+    }
+    return NULL;
+}
+
+#endif
diff --git a/libatalk/cnid/tdb/cnid_tdb_update.c b/libatalk/cnid/tdb/cnid_tdb_update.c
new file mode 100644 (file)
index 0000000..a4e1d07
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * $Id: cnid_tdb_update.c,v 1.1.2.1 2003-09-09 16:42:21 didg Exp $
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef CNID_BACKEND_TDB
+
+#include "cnid_tdb.h"
+#include <atalk/logger.h>
+
+int cnid_tdb_update(struct _cnid_db *cdb, const cnid_t id, const struct stat *st,
+                     const cnid_t did, const char *name, const int len
+                     /*, const char *info, const int infolen */ )
+{
+    struct _cnid_tdb_private *db;
+    TDB_DATA key, data, altdata;
+
+    if (!cdb || !(db = cdb->_private) || !id || !st || !name || (db->flags & TDBFLAG_DB_RO)) {
+        return -1;
+    }
+
+    memset(&key, 0, sizeof(key));
+    memset(&altdata, 0, sizeof(altdata));
+
+
+    /* Get the old info. */
+    key.dptr = (char *)&id;
+    key.dsize = sizeof(id);
+    memset(&data, 0, sizeof(data));
+    data = tdb_fetch(db->tdb_cnid, key);
+    if (!data.dptr)
+        return 0;
+
+    key.dptr = data.dptr;
+    key.dsize = TDB_DEVINO_LEN;
+    tdb_delete(db->tdb_devino, key); 
+
+    key.dptr = (char *)data.dptr + TDB_DEVINO_LEN;
+    key.dsize = data.dsize - TDB_DEVINO_LEN;
+    tdb_delete(db->tdb_didname, key); 
+
+    free(data.dptr);
+    /* Make a new entry. */
+    data.dptr = make_tdb_data(st, did, name, len);
+    data.dsize = TDB_HEADER_LEN + len + 1;
+
+    /* Update the old CNID with the new info. */
+    key.dptr = (char *) &id;
+    key.dsize = sizeof(id);
+    if (tdb_store(db->tdb_cnid, key, data, TDB_REPLACE)) {
+        goto update_err;
+    }
+
+    /* Put in a new dev/ino mapping. */
+    key.dptr = data.dptr;
+    key.dsize = TDB_DEVINO_LEN;
+    altdata.dptr  = (char *) &id;
+    altdata.dsize = sizeof(id);
+    if (tdb_store(db->tdb_devino, key, altdata, TDB_REPLACE)) {
+        goto update_err;
+    }
+    /* put in a new did/name mapping. */
+    key.dptr = (char *) data.dptr + TDB_DEVINO_LEN;
+    key.dsize = data.dsize - TDB_DEVINO_LEN;
+    if (tdb_store(db->tdb_didname, key, altdata, TDB_REPLACE)) {
+        goto update_err;
+    }
+
+    return 0;
+update_err:
+    LOG(log_error, logtype_default, "cnid_update: Unable to update CNID %u",
+        ntohl(id));
+    return -1;
+
+}
+
+#endif
index deeb839e54aa197fdf0cbd847a3c6002de971337..caff2d7db0a539057d3e9f2eca9aabccad502e7d 100644 (file)
@@ -1,5 +1,9 @@
 # Makefile.am for libatalk/dsi/
 
+INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/sys
+
+LIBS = @LIBS@ @WRAP_LIBS@
+
 noinst_LTLIBRARIES = libdsi.la
 
 libdsi_la_SOURCES = dsi_attn.c dsi_close.c dsi_cmdreply.c dsi_getsess.c dsi_getstat.c dsi_init.c dsi_opensess.c dsi_read.c dsi_tcp.c dsi_tickle.c dsi_write.c dsi_stream.c
index 008edf895eeb72220627abcf234b24d9ad9a51f4..f4a6b24fe22827df9bd72c73be62a7b2905d74a7 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: dsi_tcp.c,v 1.9 2002-01-24 16:27:31 jmarcus Exp $
+ * $Id: dsi_tcp.c,v 1.9.10.1 2003-09-09 16:42:22 didg Exp $
  *
  * Copyright (c) 1997, 1998 Adrian Sun (asun@zoology.washington.edu)
  * All rights reserved. See COPYRIGHT.
@@ -93,6 +93,11 @@ static void timeout_handler()
   exit(1);
 }
 
+#ifdef ATACC
+#define fork aTaC_fork
+#endif
+
+static struct itimerval itimer;
 /* accept the socket and do a little sanity checking */
 static int dsi_tcp_open(DSI *dsi)
 {
@@ -120,7 +125,8 @@ static int dsi_tcp_open(DSI *dsi)
   if (dsi->socket < 0)
     return -1;
 
-  if ((pid = fork()) == 0) { /* child */
+  getitimer(ITIMER_PROF, &itimer);
+  if (0 == (pid = fork()) ) { /* child */
     static const struct itimerval timer = {{0, 0}, {DSI_TCPTIMEOUT, 0}};
     struct sigaction newact, oldact;
     u_int8_t block[DSI_BLOCKSIZ];
@@ -136,6 +142,8 @@ static int dsi_tcp_open(DSI *dsi)
     newact.sa_flags = 0;
     sigemptyset(&oldact.sa_mask);
     oldact.sa_flags = 0;
+    setitimer(ITIMER_PROF, &itimer, NULL);
+
     if ((sigaction(SIGALRM, &newact, &oldact) < 0) ||
         (setitimer(ITIMER_REAL, &timer, NULL) < 0)) {
        LOG(log_error, logtype_default, "dsi_tcp_open: %s", strerror(errno));
index d06486a79265d837947e82e213b45a2dc102a1f1..978439d2b9e876925ed94744ece90b213da7adb4 100644 (file)
@@ -2,11 +2,21 @@
 
 noinst_LTLIBRARIES = libunicode.la
 
-CFLAGS = -I$(top_srcdir)/sys @CFLAGS@
+CFLAGS = -I$(top_srcdir)/sys @CFLAGS@ @ICONV_CFLAGS@
+
+SUBDIRS = charsets
+
+LIBUNICODE_DEPS = charsets/libcharsets.la 
+
 
 libunicode_la_SOURCES = \
        util_unistr.c   \
        iconv.c         \
-       charcnv.c       
+       charcnv.c       \
+       utf8.c
+
+libunicode_la_LIBADD = $(LIBUNICODE_DEPS)
+
+noinst_HEADERS = ucs2_casetable.h precompose.h
 
-noinst_HEADERS = mac_roman.h ucs2_casetable.h precompose.h
+LIBS=@ICONV_LIBS@
index e5f063b90a5af7dfe01453e568c0dae30d98fa10..31ef0911364f390b9f9207fc24bdfea5d92cfed3 100644 (file)
@@ -30,6 +30,7 @@
 #include <unistd.h>
 #include <string.h>
 #include <sys/param.h>
+#include <ctype.h>
 #include <sys/stat.h>
 #include <atalk/logger.h>
 #include <errno.h>
 #include <iconv.h>
 #endif
 
+#if HAVE_LOCALE_H
+#include <locale.h>
+#endif
+
+#if HAVE_LANGINFO_H
+#include <langinfo.h>
+#endif
+
 
 /**
  * @file
 
 #define MAX_CHARSETS 10
 
-static atalk_iconv_t conv_handles[MAX_CHARSETS][MAX_CHARSETS];
+#define CHECK_FLAGS(a,b) (((a)!=NULL) ? (*(a) & (b)) : 0 )
 
+static atalk_iconv_t conv_handles[MAX_CHARSETS][MAX_CHARSETS];
 static char* charset_names[MAX_CHARSETS];
-
-struct charset {
-        const char *name;
-       charset_t ch_charset_t;
-        struct charset *prev, *next;
-};
+static struct charset_functions* charsets[MAX_CHARSETS];
+static char hexdig[] = "0123456789abcdef";
+#define hextoint( c )   ( isdigit( c ) ? c - '0' : c + 10 - 'a' )
 
 /**
  * Return the name of a charset to give to iconv().
@@ -78,17 +85,52 @@ static const char *charset_name(charset_t ch)
        const char *ret = NULL;
 
        if (ch == CH_UCS2) ret = "UCS-2LE";
-       else if (ch == CH_UNIX) ret = "ASCII"; /*lp_unix_charset();*/
-       else if (ch == CH_MAC) ret = "MAC"; /*lp_display_charset();*/
+       else if (ch == CH_UNIX) ret = "LOCALE"; /*lp_unix_charset();*/
+       else if (ch == CH_MAC) ret = "MAC_ROMAN"; /*lp_display_charset();*/
        else if (ch == CH_UTF8) ret = "UTF8";
+       else if (ch == CH_UTF8_MAC) ret = "UTF8-MAC";
 
        if (!ret)
                ret = charset_names[ch];
 
+#if defined(HAVE_NL_LANGINFO) && defined(CODESET)
+       if (ret && strcasecmp(ret, "LOCALE") == 0) {
+               const char *ln = NULL;
+
+#ifdef HAVE_SETLOCALE
+               setlocale(LC_ALL, "");
+#endif
+               ln = nl_langinfo(CODESET);
+               if (ln) {
+                       /* Check whether the charset name is supported
+                          by iconv */
+                       atalk_iconv_t handle = atalk_iconv_open(ln,"UCS-2LE");
+                       if (handle == (atalk_iconv_t) -1) {
+                               LOG(log_debug, logtype_default, "Locale charset '%s' unsupported, using ASCII instead", ln);
+                               ln = NULL;
+                       } else {
+                               atalk_iconv_close(handle);
+                       }
+               }
+               ret = ln;
+       }
+#endif
+
        if (!ret || !*ret) ret = "ASCII";
        return ret;
 }
 
+struct charset_functions* get_charset_functions (charset_t ch)
+{
+       if (charsets[ch] != NULL)
+               return charsets[ch];
+
+       charsets[ch] = find_charset_functions(charset_name(ch));
+
+       return charsets[ch];
+}
+       
+
 void lazy_initialize_conv(void)
 {
        static int initialized = 0;
@@ -103,35 +145,37 @@ charset_t add_charset(char* name)
 {
        static charset_t max_charset_t = NUM_CHARSETS-1;
        charset_t cur_charset_t = max_charset_t+1;
-       int c1, c2;
+       unsigned int c1, c2;
+
+       lazy_initialize_conv();
 
        for (c1=0; c1<=max_charset_t;c1++) {
-               if ( strcmp(name, charset_name(c1)) == 0)
+               if ( strcasecmp(name, charset_name(c1)) == 0)
                        return (c1);
        }
 
        if ( cur_charset_t >= MAX_CHARSETS )  {
                LOG (log_debug, logtype_default, "Adding charset %s failed, too many charsets (max. %u allowed)", 
                        name, MAX_CHARSETS);
-               return 0;
+               return (charset_t) -1;
        }
 
        /* First try to setup the required conversions */
 
        conv_handles[cur_charset_t][CH_UCS2] = atalk_iconv_open( charset_name(CH_UCS2), name);
         if (conv_handles[cur_charset_t][CH_UCS2] == (atalk_iconv_t)-1) {
-               LOG(log_error, logtype_default, "Required conversion from %s to %s not supported\n",
+               LOG(log_error, logtype_default, "Required conversion from %s to %s not supported",
                        name,  charset_name(CH_UCS2));
                conv_handles[cur_charset_t][CH_UCS2] = NULL;
-               return 0;
+               return (charset_t) -1;
        }
 
        conv_handles[CH_UCS2][cur_charset_t] = atalk_iconv_open( name, charset_name(CH_UCS2));
         if (conv_handles[CH_UCS2][cur_charset_t] == (atalk_iconv_t)-1) {
-               LOG(log_error, logtype_default, "Required conversion from %s to %s not supported\n",
+               LOG(log_error, logtype_default, "Required conversion from %s to %s not supported",
                        charset_name(CH_UCS2), name);
                conv_handles[CH_UCS2][cur_charset_t] = NULL;
-               return 0;
+               return (charset_t) -1;
        }
 
        /* register the new charset_t name */
@@ -152,16 +196,31 @@ charset_t add_charset(char* name)
 
                        conv_handles[c1][c2] = atalk_iconv_open(n2,n1);
                        if (conv_handles[c1][c2] == (atalk_iconv_t)-1) {
-                               LOG(log_debug, logtype_default, "Conversion from %s to %s not supported\n",
+#ifdef DEBUG
+                               LOG(log_debug, logtype_default, "Conversion from %s to %s not supported",
                                         charset_name((charset_t)c1), charset_name((charset_t)c2));
+#endif /* DEBUG */
                                conv_handles[c1][c2] = NULL;
                        }
+#ifdef DEBUG
+                       else
+                               LOG(log_debug, logtype_default, "Added conversion from %s to %s", n1, n2);
+#endif /* DEBUG */
                }
+               charsets[c1] = get_charset_functions (c1);
        }
 
        max_charset_t++;
 
+#ifdef DEBUG
        LOG(log_debug, logtype_default, "Added charset %s with handle %u", name, cur_charset_t);
+
+       for (c1=0; c1 <= cur_charset_t; c1++) {
+               for (c2=0; c2 <=cur_charset_t; c2++) {
+                       LOG ( log_debug, logtype_default, "Conversion descriptor[%u][%u] = [%s][%s]", c1,c2,conv_handles[c1][c2]->from_name, conv_handles[c1][c2]->to_name );
+               }
+       }
+#endif /* DEBUG */
        return (cur_charset_t);
 }
 
@@ -202,7 +261,14 @@ void init_iconv(void)
                                         charset_name((charset_t)c1), charset_name((charset_t)c2));
                                conv_handles[c1][c2] = NULL;
                        }
+#ifdef DEBUG
+                       else
+                               LOG(log_debug, logtype_default, "Added conversion from %s to %s",
+                                        n1, n2);
+#endif
+                               
                }
+               charsets[c1] = get_charset_functions (c1);
        }
 }
 
@@ -346,15 +412,14 @@ convert:
        return destlen;
 }
 
-
-size_t unix_strupper(const char *src, size_t srclen, char *dest, size_t destlen)
+size_t charset_strupper(charset_t ch, const char *src, size_t srclen, char *dest, size_t destlen)
 {
        size_t size;
        ucs2_t *buffer;
        
-       size = convert_string_allocate(CH_UNIX, CH_UCS2, src, srclen,
+       size = convert_string_allocate(ch, CH_UCS2, src, srclen,
                                       (void **) &buffer);
-       if (size == -1) {
+       if (size == (size_t)-1) {
                free(buffer);
                return size;
        }
@@ -363,32 +428,43 @@ size_t unix_strupper(const char *src, size_t srclen, char *dest, size_t destlen)
                return srclen;
        }
        
-       size = convert_string(CH_UCS2, CH_UNIX, buffer, size, dest, destlen);
+       size = convert_string(CH_UCS2, ch, buffer, size, dest, destlen);
        free(buffer);
        return size;
 }
 
-size_t unix_strlower(const char *src, size_t srclen, char *dest, size_t destlen)
+size_t charset_strlower(charset_t ch, const char *src, size_t srclen, char *dest, size_t destlen)
 {
        size_t size;
        ucs2_t *buffer;
        
-       size = convert_string_allocate(CH_UNIX, CH_UCS2, src, srclen,
+       size = convert_string_allocate(ch, CH_UCS2, src, srclen,
                                       (void **) &buffer);
-       if (size == -1) {
+       if (size == (size_t)-1) {
                free(buffer);
                return size;
-       /*      smb_panic("failed to create UCS2 buffer");*/
        }
        if (!strlower_w(buffer) && (dest == src)) {
                free(buffer);
                return srclen;
        }
-       size = convert_string(CH_UCS2, CH_UNIX, buffer, size, dest, destlen);
+       
+       size = convert_string(CH_UCS2, ch, buffer, size, dest, destlen);
        free(buffer);
        return size;
 }
 
+
+size_t unix_strupper(const char *src, size_t srclen, char *dest, size_t destlen)
+{
+       return charset_strupper( CH_UNIX, src, srclen, dest, destlen);
+}
+
+size_t unix_strlower(const char *src, size_t srclen, char *dest, size_t destlen)
+{
+       return charset_strlower( CH_UNIX, src, srclen, dest, destlen);
+}
+
 size_t utf8_strupper(const char *src, size_t srclen, char *dest, size_t destlen)
 {
        size_t size;
@@ -396,7 +472,7 @@ size_t utf8_strupper(const char *src, size_t srclen, char *dest, size_t destlen)
        
        size = convert_string_allocate(CH_UTF8, CH_UCS2, src, srclen,
                                       (void **) &buffer);
-       if (size == -1) {
+       if (size == (size_t) -1) {
                free(buffer);
                return size;
        }
@@ -417,7 +493,7 @@ size_t utf8_strlower(const char *src, size_t srclen, char *dest, size_t destlen)
        
        size = convert_string_allocate(CH_UTF8, CH_UCS2, src, srclen,
                                       (void **) &buffer);
-       if (size == -1) {
+       if (size == (size_t)-1) {
                free(buffer);
                return size;
        }
@@ -438,7 +514,7 @@ size_t mac_strupper(const char *src, size_t srclen, char *dest, size_t destlen)
        
        size = convert_string_allocate(CH_MAC, CH_UCS2, src, srclen,
                                       (void **) &buffer);
-       if (size == -1) {
+       if (size == (size_t)-1) {
                free(buffer);
                return size;
        }
@@ -459,7 +535,7 @@ size_t mac_strlower(const char *src, size_t srclen, char *dest, size_t destlen)
        
        size = convert_string_allocate(CH_MAC, CH_UCS2, src, srclen,
                                       (void **) &buffer);
-       if (size == -1) {
+       if (size == (size_t)-1) {
                free(buffer);
                return size;
        }
@@ -529,6 +605,7 @@ size_t ucs2_to_mac_allocate(char **dest, const ucs2_t *src)
  * @returns The number of bytes occupied by the string in the destination
  **/
 
+#if 0
 static char convbuf[MAXPATHLEN+1];
 size_t utf8_to_mac_allocate(void **dest, const char *src)
 {
@@ -545,27 +622,6 @@ size_t utf8_to_mac ( char* src, size_t src_len, char* dest, size_t dest_len)
        return convert_string(CH_UTF8, CH_MAC, convbuf, src_len, dest, dest_len);       
 }
 
-static char  debugbuf[ MAXPATHLEN +1 ];
-char * debug_out ( char * seq, size_t len)
-{
-        size_t i = 0;
-        unsigned char *p;
-        char *q;
-
-        p = (unsigned char*) seq;
-        q = debugbuf;
-
-        for ( i = 0; i<=(len-1); i++)
-        {
-                sprintf(q, "%2.2x.", *p);
-                q += 3;
-                p++;
-        }
-        *q=0;
-        q = debugbuf;
-        return q;
-}
-
 
 size_t utf8_precompose ( char * src, size_t inlen, char * dst, size_t outlen)
 {
@@ -637,4 +693,468 @@ size_t utf8_to_mac_charset ( charset_t ch, char* src, size_t src_len, char* dest
        dest[dest_len-o_len] = 0;
        return dest_len-o_len;
 }
+#endif
+
+
+static char  debugbuf[ MAXPATHLEN +1 ];
+char * debug_out ( char * seq, size_t len)
+{
+        size_t i = 0;
+        unsigned char *p;
+        char *q;
+
+        p = (unsigned char*) seq;
+        q = debugbuf;
+
+        for ( i = 0; i<=(len-1); i++)
+        {
+                sprintf(q, "%2.2x.", *p);
+                q += 3;
+                p++;
+        }
+        *q=0;
+        q = debugbuf;
+        return q;
+}
+
+/* 
+ * Convert from MB to UCS2 charset 
+ * Flags:
+ *             CONV_UNESCAPEHEX:        ':XXXX' will be converted to an UCS2 character
+ *             CONV_IGNORE:            unconvertable characters will be replaced with '_'
+ * FIXME:
+ *             This will *not* work if the destination charset is not multibyte, i.e. UCS2->UCS2 will fail
+ *             The (un)escape scheme is not compatible to the old cap style escape. This is bad, we need it 
+ *             for e.g. HFS cdroms.
+ */
+
+size_t pull_charset_flags (charset_t from_set, char* src, size_t srclen, char* dest, size_t destlen, u_int16_t *flags)
+{
+       size_t i_len, o_len;
+       size_t retval, j = 0;
+       const char* inbuf = (const char*)src;
+       char* outbuf = (char*)dest;
+       atalk_iconv_t descriptor;
+       char *o_save, *s;
+
+       if (srclen == (size_t)-1)
+               srclen = strlen(src)+1;
+
+       lazy_initialize_conv();
+
+       descriptor = conv_handles[from_set][CH_UCS2];
+
+       if (descriptor == (atalk_iconv_t)-1 || descriptor == (atalk_iconv_t)0) {
+               return (size_t) -1;
+       }
+
+       i_len=srclen;
+       o_len=destlen;
+       o_save=outbuf;
+       
+conversion_loop:
+       if ( flags && (*flags & CONV_UNESCAPEHEX)) {
+               if ( NULL != (s = strchr ( inbuf, ':'))) {
+                       j = i_len - (s - inbuf);
+                       if ( 0 == (i_len = (s - inbuf)))
+                               goto unhex_char;
+       }
+       }
+       
+       retval = atalk_iconv(descriptor,  &inbuf, &i_len, &outbuf, &o_len);
+       if(retval==(size_t)-1) {
+               if (errno == EILSEQ && flags && (*flags & CONV_IGNORE)) {
+                               if (o_len < 2) {
+                                       errno = E2BIG;
+                                       return (size_t) -1;
+                               }
+                               o_save[destlen-o_len]   = '_';
+                               o_save[destlen-o_len+1] = 0x0;
+                               o_len -= 2;
+                               outbuf = o_save + destlen - o_len;
+                               inbuf += 1;
+                               i_len -= 1;
+                               *flags |= CONV_REQMANGLE;
+                               goto conversion_loop;
+           }
+           else
+               return (size_t) -1;
+    }
+    
+unhex_char:
+       if (j && flags && (*flags & CONV_UNESCAPEHEX )) {
+               /* we're at the start on an hex encoded ucs2 char */
+               if (o_len < 2) {
+                       errno = E2BIG;
+                       return (size_t) -1;
+               }
+               inbuf++;
+               o_save[destlen-o_len]   = hextoint( *inbuf ) << 4;
+               inbuf++;
+               o_save[destlen-o_len]  |= hextoint( *inbuf );                   
+               inbuf++;
+               o_save[destlen-o_len+1] = hextoint( *inbuf ) << 4;
+               inbuf++;
+               o_save[destlen-o_len+1]|= hextoint( *inbuf );
+               inbuf++;
+               o_len  -= 2;
+               outbuf += 2;
+               i_len  = j-5;
+               j = 0;
+               goto conversion_loop;
+       }
+
+       return destlen-o_len;
+}
+
+/* 
+ * Convert from UCS2 to MB charset 
+ * Flags:
+ *             CONV_ESCAPEDOTS: escape leading dots
+ *             CONV_ESCAPEHEX:  unconvertable characters and '/' will be escaped to :XXXX
+ *             CONV_IGNORE:     unconvertable characters will be replaced with '_'
+ * FIXME:
+ *             CONV_IGNORE and CONV_ESCAPEHEX can't work together. Should we check this ?
+ *             This will *not* work if the destination charset is not multibyte, i.e. UCS2->UCS2 will fail
+ *             The escape scheme is not compatible to the old cap style escape. This is bad, we need it 
+ *             for e.g. HFS cdroms.
+ */
+
+
+size_t push_charset_flags (charset_t to_set, char* src, size_t srclen, char* dest, size_t destlen, u_int16_t *flags)
+{
+    size_t i_len, o_len, i;
+    size_t retval, j = 0;
+    const char* inbuf = (const char*)src;
+    char* outbuf = (char*)dest;
+    atalk_iconv_t descriptor;
+    char *o_save;
+    
+    lazy_initialize_conv();
+    
+    descriptor = conv_handles[CH_UCS2][to_set];
+    
+    if (descriptor == (atalk_iconv_t)-1 || descriptor == (atalk_iconv_t)0) {
+        return (size_t) -1;
+    }
+    
+    i_len=srclen;
+    o_len=destlen;
+    o_save=outbuf;
+    
+    if (*inbuf == '.' && flags && (*flags & CONV_ESCAPEDOTS)) {
+        if (o_len < 5) {
+            errno = E2BIG;
+            return (size_t) -1;
+        }
+        o_save[0] = ':';
+        o_save[1] = '2';
+        o_save[2] = 'e';
+        o_save[3] = o_save[4] = '0';
+        o_len -= 5;
+        inbuf += 2;
+        i_len -= 2;
+        outbuf = o_save + 5;
+        if (flags) *flags |= CONV_REQESCAPE;
+    }
+       
+conversion_loop:
+    if ( flags && (*flags & CONV_ESCAPEHEX)) {
+        for ( i = 0; i < i_len; i+=2) {
+            if ( inbuf[i] == '/' ) {
+                j = i_len - i;
+                if ( 0 == ( i_len = i))
+                    goto escape_slash;
+                break;
+            }
+        }
+    }
+    
+    retval = atalk_iconv(descriptor,  &inbuf, &i_len, &outbuf, &o_len);
+    if (retval==(size_t)-1) {
+        if (errno == EILSEQ && flags && (*flags & CONV_IGNORE)) {
+            if (o_len == 0) {
+                errno = E2BIG;
+                return (size_t) -1;
+            }
+            o_save[destlen-o_len] = '_';
+            o_len -=1;
+            outbuf = o_save + destlen - o_len;
+            inbuf += 2;
+            i_len -= 2;
+            if (flags ) *flags |= CONV_REQMANGLE;
+                goto conversion_loop;
+        }
+        else if ( errno == EILSEQ && flags && (*flags & CONV_ESCAPEHEX)) {
+            if (o_len < 5) {
+                errno = E2BIG;
+                return (size_t) -1;
+            }
+            i = destlen-o_len;
+            o_save[i++]   = ':';
+            o_save[i++] = hexdig[ ( *inbuf & 0xf0 ) >> 4 ];
+            o_save[i++] = hexdig[ *inbuf & 0x0f ];
+            inbuf++;
+            o_save[i++] = hexdig[ ( *inbuf & 0xf0 ) >> 4 ];
+            o_save[i++] = hexdig[ *inbuf & 0x0f ];
+            inbuf++;
+            o_len -= 5;
+            outbuf = o_save + destlen - o_len;
+            i_len -= 2;
+            if (flags) *flags |= CONV_REQESCAPE;
+            goto conversion_loop;
+        }
+        else
+           return (size_t)(-1);        
+    }
+       
+escape_slash:
+    if (j && flags && (*flags & CONV_ESCAPEHEX)) {
+        if (o_len < 5) {
+            errno = E2BIG;
+            return (size_t) -1;
+        }
+        o_save[destlen -o_len]   = ':';
+        o_save[destlen -o_len+1] = '2';
+        o_save[destlen -o_len+2] = 'f';
+        o_save[destlen -o_len+3] = '0';
+        o_save[destlen -o_len+4] = '0';
+        inbuf  += 2;
+        i_len   = j-2;
+        o_len  -= 5;
+        outbuf += 5;
+        j = 0;
+        goto conversion_loop;
+    }
+    return destlen -o_len;
+}
+
+size_t convert_charset ( charset_t from_set, charset_t to_set, char* src, size_t src_len, char* dest, size_t dest_len, u_int16_t *flags)
+{
+       size_t i_len, o_len;
+       char *u;
+       char buffer[MAXPATHLEN];
+       char buffer2[MAXPATHLEN];
+       int composition = 0;
+       
+       lazy_initialize_conv();
+
+       /* convert from_set to UCS2 */
+       if ((size_t)(-1) == ( o_len = pull_charset_flags( from_set, src, src_len, buffer, MAXPATHLEN, flags)) ) {
+               LOG(log_error, logtype_default, "Conversion failed ( %s to CH_UCS2 )", charset_name(from_set));
+               return (size_t) -1;
+       }
+
+       /* Do pre/decomposition */
+       if (CHECK_FLAGS(flags, CONV_PRECOMPOSE) || 
+               ((!(charsets[to_set])   || !(charsets[to_set]->flags & CHARSET_DECOMPOSED)) && 
+               (!(charsets[from_set]) || (charsets[from_set]->flags & CHARSET_DECOMPOSED))))
+           composition = 1;
+       if (CHECK_FLAGS(flags, CONV_DECOMPOSE) || (charsets[to_set] && charsets[to_set]->flags & CHARSET_DECOMPOSED) )
+           composition = 2;
+       i_len = MAXPATHLEN;
+       u = buffer2;
+
+       if ( composition == 1 ) { 
+            if ( (size_t)-1 == (i_len = precompose_w((ucs2_t *)buffer, o_len, (ucs2_t *)u, &i_len)) )
+               return (size_t)(-1);
+       }
+       if ( composition == 2 ) {
+            if ( (size_t)-1 == (i_len = decompose_w((ucs2_t *)buffer, o_len, (ucs2_t *)u, &i_len)) )
+               return (size_t)(-1);
+       }
+       if (composition == 0 ) {
+           u = buffer;
+           i_len = o_len;
+       }
+  
+       /* Do case conversions */       
+       if (CHECK_FLAGS(flags, CONV_TOUPPER)) {
+           if (!strupper_w((ucs2_t *) u)) 
+               return (size_t)(-1);
+       }
+       if (CHECK_FLAGS(flags, CONV_TOLOWER)) {
+           if (!strlower_w((ucs2_t *) u)) 
+               return (size_t)(-1);
+       }
+
+       /* Convert UCS2 to to_set */
+       if ((size_t)(-1) == ( o_len = push_charset_flags( to_set, u, i_len, dest, dest_len, flags )) ) {
+               LOG(log_error, logtype_default, "Conversion failed (CH_UCS2 to %s):%s", charset_name(to_set), strerror(errno));
+               return (size_t) -1;
+       }
+
+       return o_len;
+}
+
+/* ----------------- */
+
+size_t decode_cap (charset_t ch_mac, char* src, size_t src_len, char* dest, size_t dest_len, u_int16_t *flags)
+{
+       size_t i_len, o_len;
+       char* inbuf = src;
+       char* outbuf = dest;
+       char h[MAXPATHLEN];
+       char *buf, *buf_save;
+       size_t buflen, hlen;
+       /* Convert old style cap format to new escape format */
+       
+       i_len = src_len;
+       o_len = dest_len;
+       
+       while ( i_len > 0 && o_len >> 0)
+       {
+               if ( *inbuf == ':') {
+                  if ( i_len >= 3 && isxdigit( *(inbuf+1)) && isxdigit( *(inbuf+2))) {
+                       if (i_len < 3) {
+                               errno = E2BIG;
+                               return (size_t) -1;
+                       } 
+                       hlen = 0;
+                       while ( *inbuf == ':' && isxdigit( *(inbuf+1)) && isxdigit( *(inbuf+2))) {
+                               if (i_len < 3) {
+                                       errno = E2BIG;
+                                       return (size_t) -1;
+                               } 
+                               ++inbuf;
+                               h[hlen] = hextoint( *inbuf ) << 4;
+                               ++inbuf;        
+                               h[hlen] |= hextoint( *inbuf );
+                               ++inbuf;
+                               hlen++;
+                               i_len -= 3;
+                       }
+                       /* FIXME: What should we do if this fails ? */
+                       if ((size_t) -1 == (buflen = convert_string_allocate ( ch_mac, CH_UCS2, &h, hlen, (void**) &buf)) ) 
+                       {
+                               errno = EILSEQ;
+                               return buflen;
+                       }                                       
+                       buf_save = buf;
+                       while ( buflen > 0) {
+                               if (o_len < 5) {
+                                       errno=E2BIG;
+                                       return (size_t) -1;
+                               }
+                               *outbuf = ':';
+                               outbuf++;
+                               *outbuf = hexdig[ ( *buf & 0xf0 ) >> 4 ];
+                               outbuf++;
+                               *outbuf = hexdig[ *buf & 0x0f ];
+                               outbuf++;
+                               buf++;
+                               *outbuf = hexdig[ ( *buf & 0xf0 ) >> 4 ];
+                               outbuf++;
+                               *outbuf = hexdig[ *buf & 0x0f ];
+                               outbuf++;
+                               buflen -= 2;
+                               o_len -= 5;
+                       }
+                       SAFE_FREE(buf_save);
+                       buflen = 0;
+                  }
+                  else {
+                       /* We have an invalid :xx sequence */
+                       if (CHECK_FLAGS(flags, CONV_IGNORE)) {
+                               *outbuf++ = '_';
+                               inbuf++;
+                               o_len -= 1;
+                               i_len -= 1;
+                               *flags |= CONV_REQMANGLE;
+                       }
+                       else {
+                               errno=EILSEQ;
+                               return (size_t) -1;
+                       }
+                  }
+               
+               }
+               else {
+                       *outbuf = *inbuf;
+                       outbuf++;
+                       inbuf++;
+                       i_len--;
+                       o_len--;
+               }
+       }
+       
+       *outbuf = 0;
+       return dest_len - o_len;
+}
 
+size_t encode_cap ( charset_t mac_set, char* src, size_t src_len, char* dest, size_t dest_len)
+{
+       size_t i_len, o_len;
+       char* inbuf = src;
+       char* outbuf = dest;
+       char h[MAXPATHLEN];
+       char  *buf, *buf_save;
+       size_t buflen, hlen;
+       /* Convert new escape format to old style cap format */
+       
+       i_len = src_len;
+       o_len = dest_len;
+       
+       while ( i_len > 0 && o_len > 0)
+       {
+               if ( *inbuf == ':' ) {
+                   if ( i_len >= 5 && 
+                       isxdigit( *(inbuf+1)) && isxdigit( *(inbuf+2)) && isxdigit( *(inbuf+3)) && isxdigit( *(inbuf+4))) {
+                       hlen = 0;
+                       while ( *inbuf == ':' && i_len >=5 && 
+                               isxdigit( *(inbuf+1)) && isxdigit( *(inbuf+2)) && 
+                               isxdigit( *(inbuf+3)) && isxdigit( *(inbuf+4))) {
+                               if ( i_len < 5) {
+                                       errno = E2BIG;
+                                       return (size_t)-1;
+                               }
+                               inbuf++;
+                               h[hlen]   = hextoint( *inbuf ) << 4;
+                               inbuf++;
+                               h[hlen++] |= hextoint( *inbuf );                        
+                               inbuf++;
+                               h[hlen]   = hextoint( *inbuf ) << 4;
+                               inbuf++;
+                               h[hlen++] |= hextoint( *inbuf );
+                               inbuf++;
+                               i_len -= 5;
+                       }
+                       if ((size_t) -1 == (buflen = convert_string_allocate(CH_UCS2, mac_set, &h, hlen, (void**) &buf)) ) 
+                               return buflen;
+                       buf_save = buf;
+                       while (buflen > 0) {
+                               if ( o_len < 3) {
+                                       errno = E2BIG;
+                                       return (size_t) -1;
+                               }
+                               *outbuf++ = ':';
+                               *outbuf++ = hexdig[ ( *buf & 0xf0 ) >> 4 ];
+                               *outbuf++ = hexdig[ *buf & 0x0f ];
+                               buf++;
+                               o_len -= 3;
+                               buflen--;
+                       }
+                       SAFE_FREE(buf_save);
+                       buflen = 0;
+                   }
+                   else {
+                       /* We have an invalid :xxxx sequence, use as is */
+                       *outbuf = *inbuf;
+                       outbuf++;
+                       inbuf++;
+                       i_len--;
+                       o_len--;
+                   }
+               }
+               else {
+                       *outbuf = *inbuf;
+                       outbuf++;
+                       inbuf++;
+                       i_len--;
+                       o_len--;
+               }
+       }
+       *outbuf = 0;
+       return dest_len - o_len;
+}
diff --git a/libatalk/unicode/charsets/Makefile.am b/libatalk/unicode/charsets/Makefile.am
new file mode 100644 (file)
index 0000000..aefbc10
--- /dev/null
@@ -0,0 +1,22 @@
+# Makefile.am for libatalk/unicode/charsets
+
+noinst_LTLIBRARIES = libcharsets.la
+
+CFLAGS = -I$(top_srcdir)/sys @CFLAGS@
+LIBS = 
+
+libcharsets_la_SOURCES = \
+       mac_roman.c     \
+       mac_hebrew.c    \
+       mac_centraleurope.c     \
+       mac_turkish.c \
+       mac_cyrillic.c \
+       generic_mb.c
+
+noinst_HEADERS = \
+       mac_roman.h \
+       mac_centraleurope.h \
+       mac_hebrew.h \
+       mac_turkish.h \
+       mac_cyrillic.h \
+       generic_mb.h
diff --git a/libatalk/unicode/charsets/generic_mb.c b/libatalk/unicode/charsets/generic_mb.c
new file mode 100644 (file)
index 0000000..6e0896e
--- /dev/null
@@ -0,0 +1,110 @@
+/* 
+   Unix SMB/CIFS implementation.
+   minimal iconv implementation
+   Copyright (C) Andrew Tridgell 2001
+   Copyright (C) Jelmer Vernooij 2002,2003
+   
+   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.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+   
+   From samba 3.0 beta and GNU libiconv-1.8
+   It's bad but most of the time we can't use libc iconv service:
+   - it doesn't round trip for most encoding
+   - it doesn't know about Apple extension
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+#include <netatalk/endian.h>
+#include <atalk/unicode.h>
+#include <atalk/logger.h>
+#include <errno.h>
+
+#include "generic_mb.h"
+
+
+/* ------------------------ */
+
+size_t mb_generic_push( int (*char_func)(unsigned char *, ucs2_t), void *cd, char **inbuf, size_t *inbytesleft,
+                         char **outbuf, size_t *outbytesleft)
+{
+        int len = 0;
+       unsigned char *tmpptr = (unsigned char *) *outbuf;
+
+        while (*inbytesleft >= 2 && *outbytesleft >= 1) {
+
+               ucs2_t *inptr = (ucs2_t *) *inbuf;
+               if ( (char_func)( tmpptr, *inptr)) {
+                       (*inbuf) += 2;
+                       tmpptr++;
+                       len++;
+                       (*inbytesleft)  -= 2;
+                       (*outbytesleft) -= 1;
+               }
+               else    
+               {
+                       errno = EILSEQ;
+                       return (size_t) -1;     
+               }
+        }
+
+        if (*inbytesleft > 0) {
+                errno = E2BIG;
+                return -1;
+        }
+
+        return len;
+}
+
+/* ------------------------ */
+
+size_t mb_generic_pull ( int (*char_func)(ucs2_t *, const unsigned char *), void *cd, char **inbuf, size_t *inbytesleft,
+                         char **outbuf, size_t *outbytesleft)
+{
+       ucs2_t          *temp;
+       unsigned char   *inptr;
+        size_t  len = 0;
+
+        while (*inbytesleft >= 1 && *outbytesleft >= 2) {
+
+               inptr = (unsigned char *) *inbuf;
+               temp  = (ucs2_t*) *outbuf;      
+               if (char_func ( temp, inptr)) {
+                       (*inbuf)        +=1;
+                       (*outbuf)       +=2;
+                       (*inbytesleft) -=1;
+                       (*outbytesleft)-=2;
+                       len++;
+                       
+               }
+               else    
+               {
+                       errno = EILSEQ;
+                       return (size_t) -1;     
+               }
+        }
+
+        if (*inbytesleft > 0) {
+                errno = E2BIG;
+                return (size_t) -1;
+        }
+
+        return len;
+
+}
diff --git a/libatalk/unicode/charsets/generic_mb.h b/libatalk/unicode/charsets/generic_mb.h
new file mode 100644 (file)
index 0000000..64a40a7
--- /dev/null
@@ -0,0 +1,2 @@
+size_t   mb_generic_pull(int (*charfunc)(ucs2_t *, const unsigned char *), void *,char **, size_t *, char **, size_t *);
+size_t   mb_generic_push(int (*charfunc)(unsigned char *, ucs2_t), void *,char **, size_t *, char **, size_t *);
diff --git a/libatalk/unicode/charsets/mac_centraleurope.c b/libatalk/unicode/charsets/mac_centraleurope.c
new file mode 100644 (file)
index 0000000..a6397e8
--- /dev/null
@@ -0,0 +1,64 @@
+/* 
+   Unix SMB/CIFS implementation.
+   minimal iconv implementation
+   Copyright (C) Andrew Tridgell 2001
+   Copyright (C) Jelmer Vernooij 2002,2003
+   
+   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.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+   
+   From samba 3.0 beta and GNU libiconv-1.8
+   It's bad but most of the time we can't use libc iconv service:
+   - it doesn't round trip for most encoding
+   - it doesn't know about Apple extension
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+#include <stdlib.h>
+#include <netatalk/endian.h>
+#include <atalk/unicode.h>
+
+#include "mac_centraleurope.h"
+#include "generic_mb.h"
+
+static size_t   mac_centraleurope_pull(void *,char **, size_t *, char **, size_t *);
+static size_t   mac_centraleurope_push(void *,char **, size_t *, char **, size_t *);
+
+struct charset_functions charset_mac_centraleurope =
+{
+       "MAC_CENTRALEUROPE",
+       29,
+       mac_centraleurope_pull,
+       mac_centraleurope_push,
+       CHARSET_CLIENT | CHARSET_MULTIBYTE      
+};
+
+
+/* ------------------------ */
+
+static size_t mac_centraleurope_push( void *cd, char **inbuf, size_t *inbytesleft,
+                         char **outbuf, size_t *outbytesleft)
+{
+       return (size_t) mb_generic_push( char_ucs2_to_mac_centraleurope, cd, inbuf, inbytesleft, outbuf, outbytesleft);
+}
+
+/* ------------------------ */
+
+static size_t mac_centraleurope_pull ( void *cd, char **inbuf, size_t *inbytesleft,
+                         char **outbuf, size_t *outbytesleft)
+{
+       return (size_t) mb_generic_pull( char_mac_centraleurope_to_ucs2, cd, inbuf, inbytesleft, outbuf, outbytesleft);
+}
diff --git a/libatalk/unicode/charsets/mac_centraleurope.h b/libatalk/unicode/charsets/mac_centraleurope.h
new file mode 100644 (file)
index 0000000..dad99b0
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 1999-2001 Free Software Foundation, Inc.
+ * This file is part of the GNU LIBICONV Library.
+ *
+ * The GNU LIBICONV Library is free software; you can redistribute it
+ * and/or modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * The GNU LIBICONV Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with the GNU LIBICONV Library; see the file COPYING.LIB.
+ * If not, write to the Free Software Foundation, Inc., 59 Temple Place -
+ * Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * MacCentralEurope
+ */
+
+static const unsigned short mac_centraleurope_2uni[128] = {
+  /* 0x80 */
+  0x00c4, 0x0100, 0x0101, 0x00c9, 0x0104, 0x00d6, 0x00dc, 0x00e1,
+  0x0105, 0x010c, 0x00e4, 0x010d, 0x0106, 0x0107, 0x00e9, 0x0179,
+  /* 0x90 */
+  0x017a, 0x010e, 0x00ed, 0x010f, 0x0112, 0x0113, 0x0116, 0x00f3,
+  0x0117, 0x00f4, 0x00f6, 0x00f5, 0x00fa, 0x011a, 0x011b, 0x00fc,
+  /* 0xa0 */
+  0x2020, 0x00b0, 0x0118, 0x00a3, 0x00a7, 0x2022, 0x00b6, 0x00df,
+  0x00ae, 0x00a9, 0x2122, 0x0119, 0x00a8, 0x2260, 0x0123, 0x012e,
+  /* 0xb0 */
+  0x012f, 0x012a, 0x2264, 0x2265, 0x012b, 0x0136, 0x2202, 0x2211,
+  0x0142, 0x013b, 0x013c, 0x013d, 0x013e, 0x0139, 0x013a, 0x0145,
+  /* 0xc0 */
+  0x0146, 0x0143, 0x00ac, 0x221a, 0x0144, 0x0147, 0x2206, 0x00ab,
+  0x00bb, 0x2026, 0x00a0, 0x0148, 0x0150, 0x00d5, 0x0151, 0x014c,
+  /* 0xd0 */
+  0x2013, 0x2014, 0x201c, 0x201d, 0x2018, 0x2019, 0x00f7, 0x25ca,
+  0x014d, 0x0154, 0x0155, 0x0158, 0x2039, 0x203a, 0x0159, 0x0156,
+  /* 0xe0 */
+  0x0157, 0x0160, 0x201a, 0x201e, 0x0161, 0x015a, 0x015b, 0x00c1,
+  0x0164, 0x0165, 0x00cd, 0x017d, 0x017e, 0x016a, 0x00d3, 0x00d4,
+  /* 0xf0 */
+  0x016b, 0x016e, 0x00da, 0x016f, 0x0170, 0x0171, 0x0172, 0x0173,
+  0x00dd, 0x00fd, 0x0137, 0x017b, 0x0141, 0x017c, 0x0122, 0x02c7,
+};
+
+static int
+char_mac_centraleurope_to_ucs2 (ucs2_t *pwc, const unsigned char *s)
+{
+  unsigned char c = *s;
+  if (c < 0x80)
+    *pwc = (ucs2_t) c;
+  else
+    *pwc = (ucs2_t) mac_centraleurope_2uni[c-0x80];
+  return 1;
+}
+
+static const unsigned char mac_centraleurope_page00[224] = {
+  0xca, 0x00, 0x00, 0xa3, 0x00, 0x00, 0x00, 0xa4, /* 0xa0-0xa7 */
+  0xac, 0xa9, 0x00, 0xc7, 0xc2, 0x00, 0xa8, 0x00, /* 0xa8-0xaf */
+  0xa1, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa6, 0x00, /* 0xb0-0xb7 */
+  0x00, 0x00, 0x00, 0xc8, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+  0x00, 0xe7, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+  0x00, 0x83, 0x00, 0x00, 0x00, 0xea, 0x00, 0x00, /* 0xc8-0xcf */
+  0x00, 0x00, 0x00, 0xee, 0xef, 0xcd, 0x85, 0x00, /* 0xd0-0xd7 */
+  0x00, 0x00, 0xf2, 0x00, 0x86, 0xf8, 0x00, 0xa7, /* 0xd8-0xdf */
+  0x00, 0x87, 0x00, 0x00, 0x8a, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+  0x00, 0x8e, 0x00, 0x00, 0x00, 0x92, 0x00, 0x00, /* 0xe8-0xef */
+  0x00, 0x00, 0x00, 0x97, 0x99, 0x9b, 0x9a, 0xd6, /* 0xf0-0xf7 */
+  0x00, 0x00, 0x9c, 0x00, 0x9f, 0xf9, 0x00, 0x00, /* 0xf8-0xff */
+  /* 0x0100 */
+  0x81, 0x82, 0x00, 0x00, 0x84, 0x88, 0x8c, 0x8d, /* 0x00-0x07 */
+  0x00, 0x00, 0x00, 0x00, 0x89, 0x8b, 0x91, 0x93, /* 0x08-0x0f */
+  0x00, 0x00, 0x94, 0x95, 0x00, 0x00, 0x96, 0x98, /* 0x10-0x17 */
+  0xa2, 0xab, 0x9d, 0x9e, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+  0x00, 0x00, 0xfe, 0xae, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+  0x00, 0x00, 0xb1, 0xb4, 0x00, 0x00, 0xaf, 0xb0, /* 0x28-0x2f */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb5, 0xfa, /* 0x30-0x37 */
+  0x00, 0xbd, 0xbe, 0xb9, 0xba, 0xbb, 0xbc, 0x00, /* 0x38-0x3f */
+  0x00, 0xfc, 0xb8, 0xc1, 0xc4, 0xbf, 0xc0, 0xc5, /* 0x40-0x47 */
+  0xcb, 0x00, 0x00, 0x00, 0xcf, 0xd8, 0x00, 0x00, /* 0x48-0x4f */
+  0xcc, 0xce, 0x00, 0x00, 0xd9, 0xda, 0xdf, 0xe0, /* 0x50-0x57 */
+  0xdb, 0xde, 0xe5, 0xe6, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+  0xe1, 0xe4, 0x00, 0x00, 0xe8, 0xe9, 0x00, 0x00, /* 0x60-0x67 */
+  0x00, 0x00, 0xed, 0xf0, 0x00, 0x00, 0xf1, 0xf3, /* 0x68-0x6f */
+  0xf4, 0xf5, 0xf6, 0xf7, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+  0x00, 0x8f, 0x90, 0xfb, 0xfd, 0xeb, 0xec, 0x00, /* 0x78-0x7f */
+};
+static const unsigned char mac_centraleurope_page20[48] = {
+  0x00, 0x00, 0x00, 0xd0, 0xd1, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+  0xd4, 0xd5, 0xe2, 0x00, 0xd2, 0xd3, 0xe3, 0x00, /* 0x18-0x1f */
+  0xa0, 0x00, 0xa5, 0x00, 0x00, 0x00, 0xc9, 0x00, /* 0x20-0x27 */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+  0x00, 0xdc, 0xdd, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+};
+static const unsigned char mac_centraleurope_page22[32] = {
+  0x00, 0x00, 0xb6, 0x00, 0x00, 0x00, 0xc6, 0x00, /* 0x00-0x07 */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+  0x00, 0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+  0x00, 0x00, 0xc3, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+};
+static const unsigned char mac_centraleurope_page22_1[8] = {
+  0xad, 0x00, 0x00, 0x00, 0xb2, 0xb3, 0x00, 0x00, /* 0x60-0x67 */
+};
+
+static int
+char_ucs2_to_mac_centraleurope(unsigned char *r, ucs2_t wc)
+{
+  unsigned char c = 0;
+  if (wc < 0x0080) {
+    *r = wc;
+    return 1;
+  }
+  else if (wc >= 0x00a0 && wc < 0x0180)
+    c = mac_centraleurope_page00[wc-0x00a0];
+  else if (wc == 0x02c7)
+    c = 0xff;
+  else if (wc >= 0x2010 && wc < 0x2040)
+    c = mac_centraleurope_page20[wc-0x2010];
+  else if (wc == 0x2122)
+    c = 0xaa;
+  else if (wc >= 0x2200 && wc < 0x2220)
+    c = mac_centraleurope_page22[wc-0x2200];
+  else if (wc >= 0x2260 && wc < 0x2268)
+    c = mac_centraleurope_page22_1[wc-0x2260];
+  else if (wc == 0x25ca)
+    c = 0xd7;
+  if (c != 0) {
+    *r = c;
+    return 1;
+  }
+  return 0;
+}
diff --git a/libatalk/unicode/charsets/mac_cyrillic.c b/libatalk/unicode/charsets/mac_cyrillic.c
new file mode 100644 (file)
index 0000000..f344fe0
--- /dev/null
@@ -0,0 +1,65 @@
+/* 
+   Unix SMB/CIFS implementation.
+   minimal iconv implementation
+   Copyright (C) Andrew Tridgell 2001
+   Copyright (C) Jelmer Vernooij 2002,2003
+   
+   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.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+   
+   From samba 3.0 beta and GNU libiconv-1.8
+   It's bad but most of the time we can't use libc iconv service:
+   - it doesn't round trip for most encoding
+   - it doesn't know about Apple extension
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+#include <stdlib.h> /* for size_t */
+
+#include <netatalk/endian.h>
+#include <atalk/unicode.h>
+
+#include "mac_cyrillic.h"
+#include "generic_mb.h"
+
+static size_t   mac_cyrillic_pull(void *,char **, size_t *, char **, size_t *);
+static size_t   mac_cyrillic_push(void *,char **, size_t *, char **, size_t *);
+
+struct charset_functions charset_mac_cyrillic =
+{
+       "MAC_CYRILLIC",
+       7,
+       mac_cyrillic_pull,
+       mac_cyrillic_push,
+       CHARSET_CLIENT | CHARSET_MULTIBYTE      
+};
+
+
+/* ------------------------ */
+
+static size_t mac_cyrillic_push( void *cd, char **inbuf, size_t *inbytesleft,
+                         char **outbuf, size_t *outbytesleft)
+{
+      return (size_t) mb_generic_push( char_ucs2_to_mac_cyrillic, cd, inbuf, inbytesleft, outbuf, outbytesleft);
+}
+
+/* ------------------------ */
+
+static size_t mac_cyrillic_pull ( void *cd, char **inbuf, size_t *inbytesleft,
+                         char **outbuf, size_t *outbytesleft)
+{
+      return (size_t) mb_generic_pull( char_mac_cyrillic_to_ucs2, cd, inbuf, inbytesleft, outbuf, outbytesleft);
+}
diff --git a/libatalk/unicode/charsets/mac_cyrillic.h b/libatalk/unicode/charsets/mac_cyrillic.h
new file mode 100644 (file)
index 0000000..74c2140
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 1999-2001 Free Software Foundation, Inc.
+ * This file is part of the GNU LIBICONV Library.
+ *
+ * The GNU LIBICONV Library is free software; you can redistribute it
+ * and/or modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * The GNU LIBICONV Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with the GNU LIBICONV Library; see the file COPYING.LIB.
+ * If not, write to the Free Software Foundation, Inc., 59 Temple Place -
+ * Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * MacCyrillic
+ */
+
+static const unsigned short mac_cyrillic_2uni[128] = {
+  /* 0x80 */
+  0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417,
+  0x0418, 0x0419, 0x041a, 0x041b, 0x041c, 0x041d, 0x041e, 0x041f,
+  /* 0x90 */
+  0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427,
+  0x0428, 0x0429, 0x042a, 0x042b, 0x042c, 0x042d, 0x042e, 0x042f,
+  /* 0xa0 */
+  0x2020, 0x00b0, 0x0490, 0x00a3, 0x00a7, 0x2022, 0x00b6, 0x0406,
+  0x00ae, 0x00a9, 0x2122, 0x0402, 0x0452, 0x2260, 0x0403, 0x0453,
+  /* 0xb0 */
+  0x221e, 0x00b1, 0x2264, 0x2265, 0x0456, 0x00b5, 0x0491, 0x0408,
+  0x0404, 0x0454, 0x0407, 0x0457, 0x0409, 0x0459, 0x040a, 0x045a,
+  /* 0xc0 */
+  0x0458, 0x0405, 0x00ac, 0x221a, 0x0192, 0x2248, 0x2206, 0x00ab,
+  0x00bb, 0x2026, 0x00a0, 0x040b, 0x045b, 0x040c, 0x045c, 0x0455,
+  /* 0xd0 */
+  0x2013, 0x2014, 0x201c, 0x201d, 0x2018, 0x2019, 0x00f7, 0x201e,
+  0x040e, 0x045e, 0x040f, 0x045f, 0x2116, 0x0401, 0x0451, 0x044f,
+  /* 0xe0 */
+  0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437,
+  0x0438, 0x0439, 0x043a, 0x043b, 0x043c, 0x043d, 0x043e, 0x043f,
+  /* 0xf0 */
+  0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447,
+  0x0448, 0x0449, 0x044a, 0x044b, 0x044c, 0x044d, 0x044e, 0x20ac,
+};
+
+static int
+char_mac_cyrillic_to_ucs2 (ucs2_t *pwc, const unsigned char *s)
+{
+  unsigned char c = *s;
+  if (c >= 0x80)
+    *pwc = (ucs2_t) mac_cyrillic_2uni[c-0x80];
+  else
+    *pwc = (ucs2_t) c;
+  return 1;
+}
+
+static const unsigned char mac_cyrillic_page00[32] = {
+  0xca, 0x00, 0xa2, 0xa3, 0xff, 0x00, 0x00, 0xa4, /* 0xa0-0xa7 */
+  0x00, 0xa9, 0x00, 0xc7, 0xc2, 0x00, 0xa8, 0x00, /* 0xa8-0xaf */
+  0xa1, 0xb1, 0x00, 0x00, 0x00, 0xb5, 0xa6, 0x00, /* 0xb0-0xb7 */
+  0x00, 0x00, 0x00, 0xc8, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+};
+static const unsigned char mac_cyrillic_page04[96] = {
+  0x00, 0xdd, 0xab, 0xae, 0xb8, 0xc1, 0xa7, 0xba, /* 0x00-0x07 */
+  0xb7, 0xbc, 0xbe, 0xcb, 0xcd, 0x00, 0xd8, 0xda, /* 0x08-0x0f */
+  0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x10-0x17 */
+  0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x18-0x1f */
+  0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x20-0x27 */
+  0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x28-0x2f */
+  0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0x30-0x37 */
+  0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0x38-0x3f */
+  0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0x40-0x47 */
+  0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xdf, /* 0x48-0x4f */
+  0x00, 0xde, 0xac, 0xaf, 0xb9, 0xcf, 0xb4, 0xbb, /* 0x50-0x57 */
+  0xc0, 0xbd, 0xbf, 0xcc, 0xce, 0x00, 0xd9, 0xdb, /* 0x58-0x5f */
+};
+static const unsigned char mac_cyrillic_page20[24] = {
+  0x00, 0x00, 0x00, 0xd0, 0xd1, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+  0xd4, 0xd5, 0x00, 0x00, 0xd2, 0xd3, 0xd7, 0x00, /* 0x18-0x1f */
+  0xa0, 0x00, 0xa5, 0x00, 0x00, 0x00, 0xc9, 0x00, /* 0x20-0x27 */
+};
+static const unsigned char mac_cyrillic_page21[24] = {
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x00, /* 0x10-0x17 */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+  0x00, 0x00, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+};
+static const unsigned char mac_cyrillic_page22[104] = {
+  0x00, 0x00, 0xb6, 0x00, 0x00, 0x00, 0xc6, 0x00, /* 0x00-0x07 */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+  0x00, 0x00, 0xc3, 0x00, 0x00, 0x00, 0xb0, 0x00, /* 0x18-0x1f */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+  0xc5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+  0xad, 0x00, 0x00, 0x00, 0xb2, 0xb3, 0x00, 0x00, /* 0x60-0x67 */
+};
+
+static int
+char_ucs2_to_mac_cyrillic(unsigned char *r, ucs2_t wc)
+{
+  unsigned char c = 0;
+  if (wc < 0x0080) {
+    *r = wc;
+    return 1;
+  }
+  else if (wc >= 0x00a0 && wc < 0x00c0)
+    c = mac_cyrillic_page00[wc-0x00a0];
+  else if (wc == 0x00f7)
+    c = 0xd6;
+  else if (wc == 0x0192)
+    c = 0xc4;
+  else if (wc >= 0x0400 && wc < 0x0460)
+    c = mac_cyrillic_page04[wc-0x0400];
+  else if (wc >= 0x2010 && wc < 0x2028)
+    c = mac_cyrillic_page20[wc-0x2010];
+  else if (wc >= 0x2110 && wc < 0x2128)
+    c = mac_cyrillic_page21[wc-0x2110];
+  else if (wc >= 0x2200 && wc < 0x2268)
+    c = mac_cyrillic_page22[wc-0x2200];
+  if (c != 0) {
+    *r = c;
+    return 1;
+  }
+  return 0;
+}
diff --git a/libatalk/unicode/charsets/mac_hebrew.c b/libatalk/unicode/charsets/mac_hebrew.c
new file mode 100644 (file)
index 0000000..7db4940
--- /dev/null
@@ -0,0 +1,223 @@
+/* 
+   Unix SMB/CIFS implementation.
+   minimal iconv implementation
+   Copyright (C) Andrew Tridgell 2001
+   Copyright (C) Jelmer Vernooij 2002,2003
+   
+   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.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+   
+   From samba 3.0 beta and GNU libiconv-1.8
+   It's bad but most of the time we can't use libc iconv service:
+   - it doesn't round trip for most encoding
+   - it doesn't know about Apple extension
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+#include <stdlib.h>
+#include <string.h>
+
+#include <netatalk/endian.h>
+#include <atalk/unicode.h>
+
+
+#include <atalk/logger.h>
+#include <errno.h>
+
+#include <atalk/unicode.h>
+
+#include "mac_hebrew.h"
+
+static size_t   mac_hebrew_pull(void *,char **, size_t *, char **, size_t *);
+static size_t   mac_hebrew_push(void *,char **, size_t *, char **, size_t *);
+
+struct charset_functions charset_mac_hebrew =
+{
+       "MAC_HEBREW",
+       5,
+       mac_hebrew_pull,
+       mac_hebrew_push,
+       CHARSET_CLIENT | CHARSET_MULTIBYTE      
+};
+
+
+/* ------------------------ 
+ * from unicode to mac hebrew code page
+*/
+static int
+char_ucs2_to_mac_hebrew ( unsigned char *r, ucs2_t wc)
+{
+    unsigned char c = 0;
+    if (wc < 0x0080) {
+       *r = wc;
+       return 1;
+    }
+    else if (wc >= 0x00a0 && wc < 0x0100)
+        c = mac_hebrew_page00[wc-0x00a0];
+    else if (wc >= 0x05b0 && wc < 0x05f0)
+        c = mac_hebrew_page05[wc-0x05b0];
+    else if (wc >= 0x2010 && wc < 0x2028)
+        c = mac_hebrew_page20[wc-0x2010];
+    else if (wc == 0x20aa)
+        c = 0xa6;
+    else if (wc >= 0xfb18 && wc < 0xfb50)
+        c = mac_hebrew_pagefb[wc-0xfb18];
+    if (c != 0) {
+       *r = c;
+       return 1;
+    }
+    return 0;
+}
+
+static size_t mac_hebrew_push( void *cd, char **inbuf, size_t *inbytesleft,
+                         char **outbuf, size_t *outbytesleft)
+{
+    unsigned char c = 0;
+    int len = 0;
+    unsigned char *tmpptr = (unsigned char *) *outbuf;
+
+    while (*inbytesleft >= 2 && *outbytesleft >= 1) {
+        ucs2_t *inptr = (ucs2_t *) *inbuf;
+       if (*inptr == 0x05b8) {
+           (*inbuf) += 2;
+           (*inbytesleft)  -= 2;
+           if (*inbytesleft >= 2 && *((ucs2_t *)*inbuf) == 0xf87f ) {
+               (*inbuf) += 2;
+               (*inbytesleft)  -= 2;
+               c = 0xde;
+           }
+           else {
+               c = 0xcb;
+           }
+           *tmpptr = c; 
+       }
+       else if (*inptr == 0x05f2 && *inbytesleft >= 4 && *(inptr +1) == 0x05b7) {
+           (*inbuf) += 4;
+           (*inbytesleft)  -= 4;
+           *tmpptr = 0x81;
+       }
+       else if (*inptr == 0xf86a && *inbytesleft >= 6 && *(inptr +1) == 0x05dc && *(inptr +2) == 0x05b9) {
+           (*inbuf) += 6;
+           (*inbytesleft)  -= 6;
+           *tmpptr = 0xc0;
+       }
+       else if (char_ucs2_to_mac_hebrew ( tmpptr, *inptr)) {
+           (*inbuf) += 2;
+           (*inbytesleft)  -= 2;
+       }
+       else {
+           errno = EILSEQ;
+           return (size_t) -1;
+       }
+       (*outbytesleft) -= 1;
+       tmpptr++;
+       len++;
+    }
+
+    if (*inbytesleft > 0) {
+        errno = E2BIG;
+        return -1;
+    }
+
+    return len;
+}
+
+/* ------------------------ */
+static int
+char_mac_hebrew_to_ucs2 (ucs2_t *pwc, const unsigned char *s)
+{
+       unsigned char c = *s;
+       if (c < 0x80) {
+               *pwc = (ucs2_t) c;
+               return 1;
+       }
+       else {
+               unsigned short wc = mac_hebrew_2uni[c-0x80];
+               if (wc != 0xfffd) {
+                   *pwc = (ucs2_t) wc;
+                   return 1;
+               }
+       }
+       return 0;
+}
+
+static size_t mac_hebrew_pull ( void *cd, char **inbuf, size_t *inbytesleft,
+                         char **outbuf, size_t *outbytesleft)
+{
+    ucs2_t         *temp;
+    unsigned char  *inptr;
+    size_t         len = 0;
+
+    while (*inbytesleft >= 1 && *outbytesleft >= 2) {
+        inptr = (unsigned char *) *inbuf;
+       temp  = (ucs2_t*) *outbuf;      
+       if (char_mac_hebrew_to_ucs2 ( temp, inptr)) {
+           if (*temp == 1) {       /* 0x81 --> 0x05f2+0x05b7 */
+               if (*outbytesleft < 4) {
+                   errno = E2BIG;
+                   return (size_t) -1; 
+               }
+               *temp = 0x05f2;
+               *(temp +1) = 0x05b7;
+               (*outbuf)      +=4;
+               (*outbytesleft)-=4;
+               len += 2;
+           }
+           else if (*temp == 2) { /* 0xc0 -> 0xf86a 0x05dc 0x05b9*/
+               if (*outbytesleft < 6) {
+                   errno = E2BIG;
+                   return (size_t) -1; 
+               }
+               *temp = 0xf86a;
+               *(temp +1) = 0x05dc;
+               *(temp +2) = 0x05b9;
+               (*outbuf)      +=6;
+               (*outbytesleft)-=6;
+               len += 3;
+           }
+           else if (*temp == 3) { /* 0xde --> 0x05b8 0xf87f */
+               if (*outbytesleft < 4) {
+                   errno = E2BIG;
+                   return (size_t) -1; 
+               }
+               *temp = 0x05b8;
+               *(temp +1) = 0xf87f;
+               (*outbuf)      +=4;
+               (*outbytesleft)-=4;
+               len += 2;
+           }
+           else {
+               (*outbuf)      +=2;
+               (*outbytesleft)-=2;
+               len++;
+           }
+           (*inbuf)        +=1;
+           (*inbytesleft) -=1;
+       }
+       else    
+       {
+           errno = EILSEQ;
+           return (size_t) -1; 
+       }
+    }
+
+    if (*inbytesleft > 0) {
+        errno = E2BIG;
+        return (size_t) -1;
+    }
+    return len;
+}
+
diff --git a/libatalk/unicode/charsets/mac_hebrew.h b/libatalk/unicode/charsets/mac_hebrew.h
new file mode 100644 (file)
index 0000000..dbb55fe
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 1999-2001 Free Software Foundation, Inc.
+ * This file is part of the GNU LIBICONV Library.
+ *
+ * The GNU LIBICONV Library is free software; you can redistribute it
+ * and/or modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * The GNU LIBICONV Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with the GNU LIBICONV Library; see the file COPYING.LIB.
+ * If not, write to the Free Software Foundation, Inc., 59 Temple Place -
+ * Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * from libiconv
+ * modified for round trip by didier gautheron
+ * Reference
+ * http://www.unicode.org/Public/MAPPINGS/VENDORS/APPLE/
+ */
+
+/*
+ * MacHebrew
+ */
+
+static const unsigned short mac_hebrew_2uni[128] = {
+  /* 0x80 0x81 -> 0x05f2+0x05b7 was 0xfb1f */
+  0x00c4,     01, 0x00c7, 0x00c9, 0x00d1, 0x00d6, 0x00dc, 0x00e1,
+  0x00e0, 0x00e2, 0x00e4, 0x00e3, 0x00e5, 0x00e7, 0x00e9, 0x00e8,
+
+  /* 0x90 */
+  0x00ea, 0x00eb, 0x00ed, 0x00ec, 0x00ee, 0x00ef, 0x00f1, 0x00f3,
+  0x00f2, 0x00f4, 0x00f6, 0x00f5, 0x00fa, 0x00f9, 0x00fb, 0x00fc,
+
+  /* 0xa0 */
+  /* 0xffd move to right to left (not 0x20aa) */
+  0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x20aa, 0x0027,
+  0x0029, 0x0028, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
+  
+  /* 0xb0 */
+  0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+  0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
+
+  /* 0xc0 -> 0xf86a 0x05dc 0x05b9*/
+      02, 0x201e, 0xf89b, 0xf89c, 0xf89d, 0xf89e, 0x05bc, 0xfb4b,
+  0xfb35, 0x2026, 0x00a0, 0x05b8, 0x05b7, 0x05b5, 0x05b6, 0x05b4,
+
+  /* 0xd0 
+     0xde --> 0x05b8 0xf87f 
+  */
+  0x2013, 0x2014, 0x201c, 0x201d, 0x2018, 0x2019, 0xfb2a, 0xfb2b,
+  0x05bf, 0x05b0, 0x05b2, 0x05b1, 0x05bb, 0x05b9,     03, 0x05b3,
+  /* 0xe0 */
+  0x05d0, 0x05d1, 0x05d2, 0x05d3, 0x05d4, 0x05d5, 0x05d6, 0x05d7,
+  0x05d8, 0x05d9, 0x05da, 0x05db, 0x05dc, 0x05dd, 0x05de, 0x05df,
+  /* 0xf0 */
+  0x05e0, 0x05e1, 0x05e2, 0x05e3, 0x05e4, 0x05e5, 0x05e6, 0x05e7,
+  0x05e8, 0x05e9, 0x05ea, 0x007d, 0x005d, 0x007b, 0x005b, 0x007c,
+};
+
+/* (wc >= 0x00a0 && wc < 0x0100) */
+
+static const unsigned char mac_hebrew_page00[96] = {
+  0xca, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+  0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x82, /* 0xc0-0xc7 */
+  0x00, 0x83, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+  0x00, 0x84, 0x00, 0x00, 0x00, 0x00, 0x85, 0x00, /* 0xd0-0xd7 */
+  0x00, 0x00, 0x00, 0x00, 0x86, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+  0x88, 0x87, 0x89, 0x8b, 0x8a, 0x8c, 0x00, 0x8d, /* 0xe0-0xe7 */
+  0x8f, 0x8e, 0x90, 0x91, 0x93, 0x92, 0x94, 0x95, /* 0xe8-0xef */
+  0x00, 0x96, 0x98, 0x97, 0x99, 0x9b, 0x9a, 0x00, /* 0xf0-0xf7 */
+  0x00, 0x9d, 0x9c, 0x9e, 0x9f, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+/*  (wc >= 0x05b0 && wc < 0x05f0) */
+static const unsigned char mac_hebrew_page05[64] = {
+  0xd9, 0xdb, 0xda, 0xdf, 0xcf, 0xcd, 0xce, 0xcc, /* 0xb0-0xb7 */
+  0xcb, 0xdd, 0x00, 0xdc, 0xc6, 0x00, 0x00, 0xd8, /* 0xb8-0xbf */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+  0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xd0-0xd7 */
+  0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xd8-0xdf */
+  0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xe0-0xe7 */
+  0xf8, 0xf9, 0xfa, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+};
+
+/* (wc >= 0x2010 && wc < 0x2028) */
+static const unsigned char mac_hebrew_page20[24] = {
+  0x00, 0x00, 0x00, 0xd0, 0xd1, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+  0xd4, 0xd5, 0x00, 0x00, 0xd2, 0xd3, 0xc1, 0x00, /* 0x18-0x1f */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc9, 0x00, /* 0x20-0x27 */
+};
+
+/* (wc >= 0xfb18 && wc < 0xfb50) */
+static const unsigned char mac_hebrew_pagefb[56] = {
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, /* 0x18-0x1f */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+  0x00, 0x00, 0xd6, 0xd7, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0x00, 0x00, /* 0x30-0x37 */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+  0x00, 0x00, 0x00, 0xc7, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+};
+
diff --git a/libatalk/unicode/charsets/mac_roman.c b/libatalk/unicode/charsets/mac_roman.c
new file mode 100644 (file)
index 0000000..f1ab31e
--- /dev/null
@@ -0,0 +1,115 @@
+/* 
+   Unix SMB/CIFS implementation.
+   minimal iconv implementation
+   Copyright (C) Andrew Tridgell 2001
+   Copyright (C) Jelmer Vernooij 2002,2003
+   
+   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.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+   
+   From samba 3.0 beta and GNU libiconv-1.8
+   It's bad but most of the time we can't use libc iconv service:
+   - it doesn't round trip for most encoding
+   - it doesn't know about Apple extension
+
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+#include <stdlib.h>
+#include <netatalk/endian.h>
+#include <atalk/unicode.h>
+
+#include "mac_roman.h"
+#include "generic_mb.h"
+
+static size_t   mac_roman_pull(void *,char **, size_t *, char **, size_t *);
+static size_t   mac_roman_push(void *,char **, size_t *, char **, size_t *);
+
+struct charset_functions charset_mac_roman =
+{
+       "MAC_ROMAN",
+       0,
+       mac_roman_pull,
+       mac_roman_push,
+       CHARSET_CLIENT | CHARSET_MULTIBYTE | CHARSET_PRECOMPOSED
+};
+
+/* ------------------------ */
+static int
+char_ucs2_to_mac_roman ( unsigned char *r, ucs2_t wc)
+{
+       unsigned char c = 0;
+       if (wc < 0x0080) {
+               *r = wc;
+               return 1;
+       }
+       else if (wc >= 0x00a0 && wc < 0x0100)
+               c = mac_roman_page00[wc-0x00a0];
+       else if (wc >= 0x0130 && wc < 0x0198)
+               c = mac_roman_page01[wc-0x0130];
+       else if (wc >= 0x02c0 && wc < 0x02e0)
+               c = mac_roman_page02[wc-0x02c0];
+       else if (wc == 0x03c0)
+               c = 0xb9;
+       else if (wc >= 0x2010 && wc < 0x2048)
+               c = mac_roman_page20[wc-0x2010];
+       else if (wc >= 0x2120 && wc < 0x2128)
+               c = mac_roman_page21[wc-0x2120];
+       else if (wc >= 0x2200 && wc < 0x2268)
+               c = mac_roman_page22[wc-0x2200];
+       else if (wc == 0x25ca)
+               c = 0xd7;
+       else if (wc >= 0xfb00 && wc < 0xfb08)
+               c = mac_roman_pagefb[wc-0xfb00];
+       else if (wc == 0xf8ff)
+               c = 0xf0;
+
+       if (c != 0) {
+               *r = c;
+               return 1;
+       }
+       return 0;
+}
+
+static size_t mac_roman_push( void *cd, char **inbuf, size_t *inbytesleft,
+                         char **outbuf, size_t *outbytesleft)
+{
+       /* No special handling required */
+       return (size_t) mb_generic_push( char_ucs2_to_mac_roman, cd, inbuf, inbytesleft, outbuf, outbytesleft);
+}
+
+/* ------------------------ */
+static int
+char_mac_roman_to_ucs2 (ucs2_t *pwc, const unsigned char *s)
+{
+       unsigned char c = *s;
+       if (c < 0x80) {
+               *pwc = (ucs2_t) c;
+               return 1;
+       }
+       else {
+               unsigned short wc = mac_roman_2uni[c-0x80];
+               *pwc = (ucs2_t) wc;
+               return 1;
+       }
+       return 0;
+}
+
+static size_t mac_roman_pull ( void *cd, char **inbuf, size_t *inbytesleft,
+                         char **outbuf, size_t *outbytesleft)
+{
+       return (size_t) mb_generic_pull( char_mac_roman_to_ucs2, cd, inbuf, inbytesleft, outbuf, outbytesleft);
+}
diff --git a/libatalk/unicode/charsets/mac_roman.h b/libatalk/unicode/charsets/mac_roman.h
new file mode 100644 (file)
index 0000000..32a5257
--- /dev/null
@@ -0,0 +1,118 @@
+
+/*
+ * $Id: mac_roman.h,v 1.1.2.1 2003-09-09 16:42:22 didg Exp $
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * from GNU libiconv
+ * modified by Bjorn (Apple Logo 0xf0 to Apple unicode 0xf8ff )
+ */
+
+
+static const unsigned char mac_roman_page00[96] = {
+  0xca, 0xc1, 0xa2, 0xa3, 0xdb, 0xb4, 0x00, 0xa4, /* 0xa0-0xa7 */
+  0xac, 0xa9, 0xbb, 0xc7, 0xc2, 0x00, 0xa8, 0xf8, /* 0xa8-0xaf */
+  0xa1, 0xb1, 0x00, 0x00, 0xab, 0xb5, 0xa6, 0xe1, /* 0xb0-0xb7 */
+  0xfc, 0x00, 0xbc, 0xc8, 0x00, 0x00, 0x00, 0xc0, /* 0xb8-0xbf */
+  0xcb, 0xe7, 0xe5, 0xcc, 0x80, 0x81, 0xae, 0x82, /* 0xc0-0xc7 */
+  0xe9, 0x83, 0xe6, 0xe8, 0xed, 0xea, 0xeb, 0xec, /* 0xc8-0xcf */
+  0x00, 0x84, 0xf1, 0xee, 0xef, 0xcd, 0x85, 0x00, /* 0xd0-0xd7 */
+  0xaf, 0xf4, 0xf2, 0xf3, 0x86, 0x00, 0x00, 0xa7, /* 0xd8-0xdf */
+  0x88, 0x87, 0x89, 0x8b, 0x8a, 0x8c, 0xbe, 0x8d, /* 0xe0-0xe7 */
+  0x8f, 0x8e, 0x90, 0x91, 0x93, 0x92, 0x94, 0x95, /* 0xe8-0xef */
+  0x00, 0x96, 0x98, 0x97, 0x99, 0x9b, 0x9a, 0xd6, /* 0xf0-0xf7 */
+  0xbf, 0x9d, 0x9c, 0x9e, 0x9f, 0x00, 0x00, 0xd8, /* 0xf8-0xff */
+};
+static const unsigned char mac_roman_page01[104] = {
+  0x00, 0xf5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+  0x00, 0x00, 0xce, 0xcf, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+  0xd9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+  0x00, 0x00, 0xc4, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+};
+static const unsigned char mac_roman_page02[32] = {
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf6, 0xff, /* 0xc0-0xc7 */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+  0xf9, 0xfa, 0xfb, 0xfe, 0xf7, 0xfd, 0x00, 0x00, /* 0xd8-0xdf */
+};
+static const unsigned char mac_roman_page20[56] = {
+  0x00, 0x00, 0x00, 0xd0, 0xd1, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+  0xd4, 0xd5, 0xe2, 0x00, 0xd2, 0xd3, 0xe3, 0x00, /* 0x18-0x1f */
+  0xa0, 0xe0, 0xa5, 0x00, 0x00, 0x00, 0xc9, 0x00, /* 0x20-0x27 */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+  0xe4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+  0x00, 0xdc, 0xdd, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+  0x00, 0x00, 0x00, 0x00, 0xda, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+};
+static const unsigned char mac_roman_page21[8] = {
+  0x00, 0x00, 0xaa, 0x00, 0x00, 0x00, 0xbd, 0x00, /* 0x20-0x27 */
+};
+static const unsigned char mac_roman_page22[104] = {
+  0x00, 0x00, 0xb6, 0x00, 0x00, 0x00, 0xc6, 0x00, /* 0x00-0x07 */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, /* 0x08-0x0f */
+  0x00, 0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+  0x00, 0x00, 0xc3, 0x00, 0x00, 0x00, 0xb0, 0x00, /* 0x18-0x1f */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+  0x00, 0x00, 0x00, 0xba, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+  0xc5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+  0xad, 0x00, 0x00, 0x00, 0xb2, 0xb3, 0x00, 0x00, /* 0x60-0x67 */
+};
+static const unsigned char mac_roman_pagefb[8] = {
+  0x00, 0xde, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+};
+
+
+
+
+static const unsigned short mac_roman_2uni[128] = {
+  /* 0x80 */
+  0x00c4, 0x00c5, 0x00c7, 0x00c9, 0x00d1, 0x00d6, 0x00dc, 0x00e1,
+  0x00e0, 0x00e2, 0x00e4, 0x00e3, 0x00e5, 0x00e7, 0x00e9, 0x00e8,
+  /* 0x90 */
+  0x00ea, 0x00eb, 0x00ed, 0x00ec, 0x00ee, 0x00ef, 0x00f1, 0x00f3,
+  0x00f2, 0x00f4, 0x00f6, 0x00f5, 0x00fa, 0x00f9, 0x00fb, 0x00fc,
+  /* 0xa0 */
+  0x2020, 0x00b0, 0x00a2, 0x00a3, 0x00a7, 0x2022, 0x00b6, 0x00df,
+  0x00ae, 0x00a9, 0x2122, 0x00b4, 0x00a8, 0x2260, 0x00c6, 0x00d8,
+  /* 0xb0 */
+  0x221e, 0x00b1, 0x2264, 0x2265, 0x00a5, 0x00b5, 0x2202, 0x2211,
+  0x220f, 0x03c0, 0x222b, 0x00aa, 0x00ba, 0x2126, 0x00e6, 0x00f8,
+  /* 0xc0 */
+  0x00bf, 0x00a1, 0x00ac, 0x221a, 0x0192, 0x2248, 0x2206, 0x00ab,
+  0x00bb, 0x2026, 0x00a0, 0x00c0, 0x00c3, 0x00d5, 0x0152, 0x0153,
+  /* 0xd0 */
+  0x2013, 0x2014, 0x201c, 0x201d, 0x2018, 0x2019, 0x00f7, 0x25ca,
+  0x00ff, 0x0178, 0x2044, 0x00a4, 0x2039, 0x203a, 0xfb01, 0xfb02,
+  /* 0xe0 */
+  0x2021, 0x00b7, 0x201a, 0x201e, 0x2030, 0x00c2, 0x00ca, 0x00c1,
+  0x00cb, 0x00c8, 0x00cd, 0x00ce, 0x00cf, 0x00cc, 0x00d3, 0x00d4,
+  /* 0xf0 */
+  0xf8ff, 0x00d2, 0x00da, 0x00db, 0x00d9, 0x0131, 0x02c6, 0x02dc,
+  0x00af, 0x02d8, 0x02d9, 0x02da, 0x00b8, 0x02dd, 0x02db, 0x02c7,
+};
diff --git a/libatalk/unicode/charsets/mac_turkish.c b/libatalk/unicode/charsets/mac_turkish.c
new file mode 100644 (file)
index 0000000..5406ab0
--- /dev/null
@@ -0,0 +1,62 @@
+/* 
+   Unix SMB/CIFS implementation.
+   minimal iconv implementation
+   Copyright (C) Andrew Tridgell 2001
+   Copyright (C) Jelmer Vernooij 2002,2003
+   
+   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.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+   
+   From samba 3.0 beta and GNU libiconv-1.8
+   It's bad but most of the time we can't use libc iconv service:
+   - it doesn't round trip for most encoding
+   - it doesn't know about Apple extension
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+#include <stdlib.h>
+#include <netatalk/endian.h>
+#include <atalk/unicode.h>
+
+#include "mac_turkish.h"
+#include "generic_mb.h"
+
+static size_t   mac_turkish_pull(void *,char **, size_t *, char **, size_t *);
+static size_t   mac_turkish_push(void *,char **, size_t *, char **, size_t *);
+
+struct charset_functions charset_mac_turkish =
+{
+       "MAC_TURKISH",
+       35,
+       mac_turkish_pull,
+       mac_turkish_push,
+       CHARSET_CLIENT | CHARSET_MULTIBYTE      
+};
+
+static size_t mac_turkish_push( void *cd, char **inbuf, size_t *inbytesleft,
+                         char **outbuf, size_t *outbytesleft)
+{
+       return (size_t) mb_generic_push( char_ucs2_to_mac_turkish, cd, inbuf, inbytesleft, outbuf, outbytesleft);
+}
+
+/* ------------------------ */
+
+static size_t mac_turkish_pull ( void *cd, char **inbuf, size_t *inbytesleft,
+                         char **outbuf, size_t *outbytesleft)
+{
+       return (size_t) mb_generic_pull( char_mac_turkish_to_ucs2, cd, inbuf, inbytesleft, outbuf, outbytesleft);
+
+}
diff --git a/libatalk/unicode/charsets/mac_turkish.h b/libatalk/unicode/charsets/mac_turkish.h
new file mode 100644 (file)
index 0000000..66d22f8
--- /dev/null
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 1999-2001 Free Software Foundation, Inc.
+ * This file is part of the GNU LIBICONV Library.
+ *
+ * The GNU LIBICONV Library is free software; you can redistribute it
+ * and/or modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * The GNU LIBICONV Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with the GNU LIBICONV Library; see the file COPYING.LIB.
+ * If not, write to the Free Software Foundation, Inc., 59 Temple Place -
+ * Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * MacTurkish
+ */
+
+static const unsigned short mac_turkish_2uni[128] = {
+  /* 0x80 */
+  0x00c4, 0x00c5, 0x00c7, 0x00c9, 0x00d1, 0x00d6, 0x00dc, 0x00e1,
+  0x00e0, 0x00e2, 0x00e4, 0x00e3, 0x00e5, 0x00e7, 0x00e9, 0x00e8,
+  /* 0x90 */
+  0x00ea, 0x00eb, 0x00ed, 0x00ec, 0x00ee, 0x00ef, 0x00f1, 0x00f3,
+  0x00f2, 0x00f4, 0x00f6, 0x00f5, 0x00fa, 0x00f9, 0x00fb, 0x00fc,
+  /* 0xa0 */
+  0x2020, 0x00b0, 0x00a2, 0x00a3, 0x00a7, 0x2022, 0x00b6, 0x00df,
+  0x00ae, 0x00a9, 0x2122, 0x00b4, 0x00a8, 0x2260, 0x00c6, 0x00d8,
+  /* 0xb0 */
+  0x221e, 0x00b1, 0x2264, 0x2265, 0x00a5, 0x00b5, 0x2202, 0x2211,
+  0x220f, 0x03c0, 0x222b, 0x00aa, 0x00ba, 0x2126, 0x00e6, 0x00f8,
+  /* 0xc0 */
+  0x00bf, 0x00a1, 0x00ac, 0x221a, 0x0192, 0x2248, 0x2206, 0x00ab,
+  0x00bb, 0x2026, 0x00a0, 0x00c0, 0x00c3, 0x00d5, 0x0152, 0x0153,
+  /* 0xd0 */
+  0x2013, 0x2014, 0x201c, 0x201d, 0x2018, 0x2019, 0x00f7, 0x25ca,
+  0x00ff, 0x0178, 0x011e, 0x011f, 0x0130, 0x0131, 0x015e, 0x015f,
+  /* 0xe0 */
+  0x2021, 0x00b7, 0x201a, 0x201e, 0x2030, 0x00c2, 0x00ca, 0x00c1,
+  0x00cb, 0x00c8, 0x00cd, 0x00ce, 0x00cf, 0x00cc, 0x00d3, 0x00d4,
+  /* 0xf0 */
+  0xf8ff, 0x00d2, 0x00da, 0x00db, 0x00d9, 0xf8a0, 0x02c6, 0x02dc,
+  0x00af, 0x02d8, 0x02d9, 0x02da, 0x00b8, 0x02dd, 0x02db, 0x02c7,
+};
+
+static int
+char_mac_turkish_to_ucs2 (ucs2_t *pwc, const unsigned char *s)
+{
+  unsigned char c = *s;
+  if (c < 0x80) {
+    *pwc = (ucs2_t) c;
+    return 1;
+  }
+  else {
+    unsigned short wc = mac_turkish_2uni[c-0x80];
+    if (wc != 0xfffd) {
+      *pwc = (ucs2_t) wc;
+      return 1;
+    }
+  }
+  return 0;
+}
+
+static const unsigned char mac_turkish_page00[96] = {
+  0xca, 0xc1, 0xa2, 0xa3, 0x00, 0xb4, 0x00, 0xa4, /* 0xa0-0xa7 */
+  0xac, 0xa9, 0xbb, 0xc7, 0xc2, 0x00, 0xa8, 0xf8, /* 0xa8-0xaf */
+  0xa1, 0xb1, 0x00, 0x00, 0xab, 0xb5, 0xa6, 0xe1, /* 0xb0-0xb7 */
+  0xfc, 0x00, 0xbc, 0xc8, 0x00, 0x00, 0x00, 0xc0, /* 0xb8-0xbf */
+  0xcb, 0xe7, 0xe5, 0xcc, 0x80, 0x81, 0xae, 0x82, /* 0xc0-0xc7 */
+  0xe9, 0x83, 0xe6, 0xe8, 0xed, 0xea, 0xeb, 0xec, /* 0xc8-0xcf */
+  0x00, 0x84, 0xf1, 0xee, 0xef, 0xcd, 0x85, 0x00, /* 0xd0-0xd7 */
+  0xaf, 0xf4, 0xf2, 0xf3, 0x86, 0x00, 0x00, 0xa7, /* 0xd8-0xdf */
+  0x88, 0x87, 0x89, 0x8b, 0x8a, 0x8c, 0xbe, 0x8d, /* 0xe0-0xe7 */
+  0x8f, 0x8e, 0x90, 0x91, 0x93, 0x92, 0x94, 0x95, /* 0xe8-0xef */
+  0x00, 0x96, 0x98, 0x97, 0x99, 0x9b, 0x9a, 0xd6, /* 0xf0-0xf7 */
+  0xbf, 0x9d, 0x9c, 0x9e, 0x9f, 0x00, 0x00, 0xd8, /* 0xf8-0xff */
+};
+static const unsigned char mac_turkish_page01[128] = {
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xda, 0xdb, /* 0x18-0x1f */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+  0xdc, 0xdd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+  0x00, 0x00, 0xce, 0xcf, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xde, 0xdf, /* 0x58-0x5f */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+  0xd9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+  0x00, 0x00, 0xc4, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+};
+static const unsigned char mac_turkish_page02[32] = {
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf6, 0xff, /* 0xc0-0xc7 */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+  0xf9, 0xfa, 0xfb, 0xfe, 0xf7, 0xfd, 0x00, 0x00, /* 0xd8-0xdf */
+};
+static const unsigned char mac_turkish_page20[40] = {
+  0x00, 0x00, 0x00, 0xd0, 0xd1, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+  0xd4, 0xd5, 0xe2, 0x00, 0xd2, 0xd3, 0xe3, 0x00, /* 0x18-0x1f */
+  0xa0, 0xe0, 0xa5, 0x00, 0x00, 0x00, 0xc9, 0x00, /* 0x20-0x27 */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+  0xe4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+};
+static const unsigned char mac_turkish_page21[8] = {
+  0x00, 0x00, 0xaa, 0x00, 0x00, 0x00, 0xbd, 0x00, /* 0x20-0x27 */
+};
+static const unsigned char mac_turkish_page22[104] = {
+  0x00, 0x00, 0xb6, 0x00, 0x00, 0x00, 0xc6, 0x00, /* 0x00-0x07 */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, /* 0x08-0x0f */
+  0x00, 0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+  0x00, 0x00, 0xc3, 0x00, 0x00, 0x00, 0xb0, 0x00, /* 0x18-0x1f */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+  0x00, 0x00, 0x00, 0xba, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+  0xc5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+  0xad, 0x00, 0x00, 0x00, 0xb2, 0xb3, 0x00, 0x00, /* 0x60-0x67 */
+};
+
+static int
+char_ucs2_to_mac_turkish (unsigned char *r, ucs2_t wc)
+{
+  unsigned char c = 0;
+  if (wc < 0x0080) {
+    *r = wc;
+    return 1;
+  }
+  else if (wc >= 0x00a0 && wc < 0x0100)
+    c = mac_turkish_page00[wc-0x00a0];
+  else if (wc >= 0x0118 && wc < 0x0198)
+    c = mac_turkish_page01[wc-0x0118];
+  else if (wc >= 0x02c0 && wc < 0x02e0)
+    c = mac_turkish_page02[wc-0x02c0];
+  else if (wc == 0x03c0)
+    c = 0xb9;
+  else if (wc >= 0x2010 && wc < 0x2038)
+    c = mac_turkish_page20[wc-0x2010];
+  else if (wc >= 0x2120 && wc < 0x2128)
+    c = mac_turkish_page21[wc-0x2120];
+  else if (wc >= 0x2200 && wc < 0x2268)
+    c = mac_turkish_page22[wc-0x2200];
+  else if (wc == 0x25ca)
+    c = 0xd7;
+  else if (wc == 0xf8ff) /* Apple Logo */
+    c = 0xf0;
+  else if (wc == 0xf8a0) /* undefinded1, roundtrip only */
+    c = 0xf5;
+  if (c != 0) {
+    *r = c;
+    return 1;
+  }
+  return 0;
+}
index e415be8dfe80593e2c83a9bbec6704a0a5277198..a6392aba652cd818faf0d64e2a072ea9cbb51b90 100644 (file)
@@ -32,6 +32,7 @@
 #include <stdlib.h>
 #include <unistd.h>
 #include <string.h>
+#include <ctype.h>
 #include <sys/param.h>
 #include <sys/stat.h>
 #include <atalk/logger.h>
@@ -45,9 +46,6 @@
 #endif
 
 
-#include "mac_roman.h"
-#include "mac_hebrew.h"
-
 /**
  * @file
  *
  *
  * @sa Samba Developers Guide
  **/
+#define CHARSET_WIDECHAR    32
 
 static size_t ascii_pull(void *,char **, size_t *, char **, size_t *);
 static size_t ascii_push(void *,char **, size_t *, char **, size_t *);
-static size_t  utf8_pull(void *,char **, size_t *, char **, size_t *);
-static size_t  utf8_push(void *,char **, size_t *, char **, size_t *);
 static size_t iconv_copy(void *,char **, size_t *, char **, size_t *);
 
-static size_t   mac_pull(void *,char **, size_t *, char **, size_t *);
-static size_t   mac_push(void *,char **, size_t *, char **, size_t *);
+static char hexdig[] = "0123456789abcdef";
+#define hextoint( c )   ( isdigit( c ) ? c - '0' : c + 10 - 'a' )
+
+struct charset_functions charset_ucs2 =
+{
+        "UCS-2LE",
+        0,
+        iconv_copy,
+        iconv_copy,
+        CHARSET_WIDECHAR
+};
+
+struct charset_functions charset_ascii =
+{
+        "ASCII",
+        0,
+        ascii_pull,
+        ascii_push,
+        CHARSET_MULTIBYTE | CHARSET_PRECOMPOSED 
+};
+
+struct charset_functions charset_iconv =
+{
+       NULL,
+       0,
+       NULL,
+       NULL,
+       CHARSET_ICONV | CHARSET_PRECOMPOSED
+};
+
+
+extern  struct charset_functions charset_mac_roman;
+extern  struct charset_functions charset_mac_hebrew;
+extern  struct charset_functions charset_mac_centraleurope;
+extern  struct charset_functions charset_mac_cyrillic;
+extern  struct charset_functions charset_mac_turkish;
+extern  struct charset_functions charset_utf8;
+extern  struct charset_functions charset_utf8_mac;
 
-static size_t   mac_hebrew_pull(void *,char **, size_t *, char **, size_t *);
-static size_t   mac_hebrew_push(void *,char **, size_t *, char **, size_t *);
 
 static struct charset_functions builtin_functions[] = {
-       {"UCS-2LE",   iconv_copy, iconv_copy},
-       {"UTF8",      utf8_pull,  utf8_push},
-       {"UTF-8",     utf8_pull,  utf8_push},
-       {"ASCII",     ascii_pull, ascii_push},
-       {"MAC",       mac_pull,  mac_push},
-       {"MAC-HEBR",  mac_hebrew_pull,  mac_hebrew_push},
-       {NULL, NULL, NULL}
+       {"UCS-2LE",   0, iconv_copy, iconv_copy, CHARSET_WIDECHAR},
+       {"ASCII",     0, ascii_pull, ascii_push, CHARSET_MULTIBYTE | CHARSET_PRECOMPOSED},
+       {NULL, 0, NULL, NULL, 0}
 };
 
+
 #define DLIST_ADD(list, p) \
 { \
         if (!(list)) { \
@@ -106,11 +134,9 @@ static struct charset_functions builtin_functions[] = {
         }\
 }
 
-
-
 static struct charset_functions *charsets = NULL;
 
-static struct charset_functions *find_charset_functions(const char *name) 
+struct charset_functions *find_charset_functions(const char *name) 
 {
        struct charset_functions *c = charsets;
 
@@ -130,7 +156,6 @@ int atalk_register_charset(struct charset_functions *funcs)
                return -1;
        }
 
-       LOG(log_debug, logtype_default, "Attempting to register new charset %s", funcs->name);
        /* Check whether we already have this charset... */
        if (find_charset_functions(funcs->name)) {
                LOG (log_debug, logtype_default, "Duplicate charset %s, not registering", funcs->name);
@@ -138,7 +163,6 @@ int atalk_register_charset(struct charset_functions *funcs)
        }
 
        funcs->next = funcs->prev = NULL;
-       LOG(log_debug, logtype_default, "Registered charset %s", funcs->name);
        DLIST_ADD(charsets, funcs);
        return 0;
 }
@@ -152,6 +176,15 @@ void lazy_initialize_iconv(void)
                initialized = 1;
                for(i = 0; builtin_functions[i].name; i++) 
                        atalk_register_charset(&builtin_functions[i]);
+
+               /* register additional charsets */
+               atalk_register_charset(&charset_utf8);
+               atalk_register_charset(&charset_utf8_mac);
+               atalk_register_charset(&charset_mac_roman);
+               atalk_register_charset(&charset_mac_hebrew);
+               atalk_register_charset(&charset_mac_turkish);
+               atalk_register_charset(&charset_mac_centraleurope);
+               atalk_register_charset(&charset_mac_cyrillic);
        }
 }
 
@@ -227,6 +260,25 @@ size_t atalk_iconv_ignore(atalk_iconv_t cd,
        size_t outlen = *outbytesleft;
        char *o_save;
        
+       /* in many cases we can go direct */
+       if (cd->direct) {
+       o_save = *outbuf;
+direct_loop:           
+               if ((size_t)-1 == cd->direct(cd->cd_direct, (char **)inbuf, inbytesleft, outbuf, outbytesleft)) {
+                       if (errno == EILSEQ) {
+                               o_save[outlen-*outbytesleft] = '_';
+                               (*outbuf) = o_save + outlen-*outbytesleft+1;
+                               (*outbytesleft) -=1;
+                               (*inbuf) += 2;
+                               (*inbytesleft) -= 2;
+                               *ignore = 1;
+                               goto direct_loop;
+                   }
+                   else
+                       return (size_t)(-1);
+               }
+       }
+       
        /* we have to do it chunks at a time */
        while (*inbytesleft > 0) {
                bufp = cvtbuf;
@@ -251,7 +303,6 @@ convert_push:
                        (*outbytesleft) -=1;
                        bufp += 2;
                        bufsize -= 2;
-                       //outlen=*outbytesleft;
                        *ignore = 1;
                        goto convert_push;
                    }
@@ -448,391 +499,3 @@ static size_t iconv_copy(void *cd, char **inbuf, size_t *inbytesleft,
 }
 
 /* ------------------------ */
-static size_t utf8_pull(void *cd, char **inbuf, size_t *inbytesleft,
-                        char **outbuf, size_t *outbytesleft)
-{
-       while (*inbytesleft >= 1 && *outbytesleft >= 2) {
-               unsigned char *c = (unsigned char *)*inbuf;
-               unsigned char *uc = (unsigned char *)*outbuf;
-               int len = 1;
-
-               if ((c[0] & 0x80) == 0) {
-                       uc[0] = c[0];
-                       uc[1] = 0;
-               } else if ((c[0] & 0xf0) == 0xe0) {
-                       if (*inbytesleft < 3) {
-                               LOG(log_debug, logtype_default, "short utf8 char\n");
-                               goto badseq;
-                       }
-                       uc[1] = ((c[0]&0xF)<<4) | ((c[1]>>2)&0xF);
-                       uc[0] = (c[1]<<6) | (c[2]&0x3f);
-                       len = 3;
-               } else if ((c[0] & 0xe0) == 0xc0) {
-                       if (*inbytesleft < 2) {
-                               LOG(log_debug, logtype_default, "short utf8 char\n");
-                               goto badseq;
-                       }
-                       uc[1] = (c[0]>>2) & 0x7;
-                       uc[0] = (c[0]<<6) | (c[1]&0x3f);
-                       len = 2;
-               }
-
-               (*inbuf)  += len;
-               (*inbytesleft)  -= len;
-               (*outbytesleft) -= 2;
-               (*outbuf) += 2;
-       }
-
-       if (*inbytesleft > 0) {
-               errno = E2BIG;
-               return -1;
-       }
-       
-       return 0;
-
-badseq:
-       errno = EINVAL;
-       return -1;
-}
-
-/* ------------------------ */
-static size_t utf8_push(void *cd, char **inbuf, size_t *inbytesleft,
-                        char **outbuf, size_t *outbytesleft)
-{
-       while (*inbytesleft >= 2 && *outbytesleft >= 1) {
-               unsigned char *c = (unsigned char *)*outbuf;
-               unsigned char *uc = (unsigned char *)*inbuf;
-               int len=1;
-
-               if (uc[1] & 0xf8) {
-                       if (*outbytesleft < 3) {
-                               LOG(log_debug, logtype_default, "short utf8 write\n");
-                               goto toobig;
-                       }
-                       c[0] = 0xe0 | (uc[1]>>4);
-                       c[1] = 0x80 | ((uc[1]&0xF)<<2) | (uc[0]>>6);
-                       c[2] = 0x80 | (uc[0]&0x3f);
-                       len = 3;
-               } else if (uc[1] | (uc[0] & 0x80)) {
-                       if (*outbytesleft < 2) {
-                               LOG(log_debug, logtype_default, "short utf8 write\n");
-                               goto toobig;
-                       }
-                       c[0] = 0xc0 | (uc[1]<<2) | (uc[0]>>6);
-                       c[1] = 0x80 | (uc[0]&0x3f);
-                       len = 2;
-               } else {
-                       c[0] = uc[0];
-               }
-
-
-               (*inbytesleft)  -= 2;
-               (*outbytesleft) -= len;
-               (*inbuf)  += 2;
-               (*outbuf) += len;
-       }
-
-       if (*inbytesleft == 1) {
-               errno = EINVAL;
-               return -1;
-       }
-
-       if (*inbytesleft > 1) {
-               errno = E2BIG;
-               return -1;
-       }
-       
-       return 0;
-
-toobig:
-       errno = E2BIG;
-       return -1;
-}
-
-/* ------------------------ */
-static int
-char_ucs2_to_mac_roman ( unsigned char *r, ucs2_t wc)
-{
-       unsigned char c = 0;
-       if (wc < 0x0080) {
-               *r = wc;
-               return 1;
-       }
-       else if (wc >= 0x00a0 && wc < 0x0100)
-               c = mac_roman_page00[wc-0x00a0];
-       else if (wc >= 0x0130 && wc < 0x0198)
-               c = mac_roman_page01[wc-0x0130];
-       else if (wc >= 0x02c0 && wc < 0x02e0)
-               c = mac_roman_page02[wc-0x02c0];
-       else if (wc == 0x03c0)
-               c = 0xb9;
-       else if (wc >= 0x2010 && wc < 0x2048)
-               c = mac_roman_page20[wc-0x2010];
-       else if (wc >= 0x2120 && wc < 0x2128)
-               c = mac_roman_page21[wc-0x2120];
-       else if (wc >= 0x2200 && wc < 0x2268)
-               c = mac_roman_page22[wc-0x2200];
-       else if (wc == 0x25ca)
-               c = 0xd7;
-       else if (wc >= 0xfb00 && wc < 0xfb08)
-               c = mac_roman_pagefb[wc-0xfb00];
-       else if (wc == 0xf8ff)
-               c = 0xf0;
-
-       if (c != 0) {
-               *r = c;
-               return 1;
-       }
-       return 0;
-}
-
-static size_t mac_push( void *cd, char **inbuf, size_t *inbytesleft,
-                         char **outbuf, size_t *outbytesleft)
-{
-        int len = 0;
-       unsigned char *tmpptr = (unsigned char *) *outbuf;
-
-        while (*inbytesleft >= 2 && *outbytesleft >= 1) {
-
-               ucs2_t *inptr = (ucs2_t *) *inbuf;
-               if (char_ucs2_to_mac_roman ( tmpptr, *inptr)) {
-                       (*inbuf) += 2;
-                       tmpptr++;
-                       len++;
-                       (*inbytesleft)  -= 2;
-                       (*outbytesleft) -= 1;
-               }
-               else    
-               {
-                       errno = EILSEQ;
-                       return (size_t) -1;     
-               }
-        }
-
-        if (*inbytesleft > 0) {
-                errno = E2BIG;
-                return -1;
-        }
-
-        return len;
-}
-
-/* ------------------------ */
-static int
-char_mac_roman_to_ucs2 (ucs2_t *pwc, const unsigned char *s)
-{
-       unsigned char c = *s;
-       if (c < 0x80) {
-               *pwc = (ucs2_t) c;
-               return 1;
-       }
-       else {
-               unsigned short wc = mac_roman_2uni[c-0x80];
-               *pwc = (ucs2_t) wc;
-               return 1;
-       }
-       return 0;
-}
-
-static size_t mac_pull ( void *cd, char **inbuf, size_t *inbytesleft,
-                         char **outbuf, size_t *outbytesleft)
-{
-       ucs2_t          *temp;
-       unsigned char   *inptr;
-        size_t  len = 0;
-
-        while (*inbytesleft >= 1 && *outbytesleft >= 2) {
-
-               inptr = (unsigned char *) *inbuf;
-               temp  = (ucs2_t*) *outbuf;      
-               if (char_mac_roman_to_ucs2 ( temp, inptr)) {
-                       (*inbuf)        +=1;
-                       (*outbuf)       +=2;
-                       (*inbytesleft) -=1;
-                       (*outbytesleft)-=2;
-                       len++;
-                       
-               }
-               else    
-               {
-                       errno = EILSEQ;
-                       return (size_t) -1;     
-               }
-        }
-
-        if (*inbytesleft > 0) {
-                errno = E2BIG;
-                return (size_t) -1;
-        }
-
-        return len;
-
-}
-
-/* ------------------------ 
- * from unicode to mac hebrew code page
-*/
-static int
-char_ucs2_to_mac_hebrew ( unsigned char *r, ucs2_t wc)
-{
-    unsigned char c = 0;
-    if (wc < 0x0080) {
-       *r = wc;
-       return 1;
-    }
-    else if (wc >= 0x00a0 && wc < 0x0100)
-        c = mac_hebrew_page00[wc-0x00a0];
-    else if (wc >= 0x05b0 && wc < 0x05f0)
-        c = mac_hebrew_page05[wc-0x05b0];
-    else if (wc >= 0x2010 && wc < 0x2028)
-        c = mac_hebrew_page20[wc-0x2010];
-    else if (wc == 0x20aa)
-        c = 0xa6;
-    else if (wc >= 0xfb18 && wc < 0xfb50)
-        c = mac_hebrew_pagefb[wc-0xfb18];
-    if (c != 0) {
-       *r = c;
-       return 1;
-    }
-    return 0;
-}
-
-static size_t mac_hebrew_push( void *cd, char **inbuf, size_t *inbytesleft,
-                         char **outbuf, size_t *outbytesleft)
-{
-    unsigned char c = 0;
-    int len = 0;
-    unsigned char *tmpptr = (unsigned char *) *outbuf;
-
-    while (*inbytesleft >= 2 && *outbytesleft >= 1) {
-        ucs2_t *inptr = (ucs2_t *) *inbuf;
-       if (*inptr == 0x05b8) {
-           (*inbuf) += 2;
-           (*inbytesleft)  -= 2;
-           if (*inbytesleft >= 2 && *((ucs2_t *)*inbuf) == 0xf87f ) {
-               (*inbuf) += 2;
-               (*inbytesleft)  -= 2;
-               c = 0xde;
-           }
-           else {
-               c = 0xcb;
-           }
-           *tmpptr = c; 
-       }
-       else if (*inptr == 0x05f2 && *inbytesleft >= 4 && *(inptr +1) == 0x05b7) {
-           (*inbuf) += 4;
-           (*inbytesleft)  -= 4;
-           *tmpptr = 0x81;
-       }
-       else if (*inptr == 0xf86a && *inbytesleft >= 6 && *(inptr +1) == 0x05dc && *(inptr +2) == 0x05b9) {
-           (*inbuf) += 6;
-           (*inbytesleft)  -= 6;
-           *tmpptr = 0xc0;
-       }
-       else if (char_ucs2_to_mac_hebrew ( tmpptr, *inptr)) {
-           (*inbuf) += 2;
-           (*inbytesleft)  -= 2;
-       }
-       else {
-           errno = EILSEQ;
-           return (size_t) -1;
-       }
-       (*outbytesleft) -= 1;
-       tmpptr++;
-       len++;
-    }
-
-    if (*inbytesleft > 0) {
-        errno = E2BIG;
-        return -1;
-    }
-
-    return len;
-}
-
-/* ------------------------ */
-static int
-char_mac_hebrew_to_ucs2 (ucs2_t *pwc, const unsigned char *s)
-{
-       unsigned char c = *s;
-       if (c < 0x80) {
-               *pwc = (ucs2_t) c;
-               return 1;
-       }
-       else {
-               unsigned short wc = mac_hebrew_2uni[c-0x80];
-               if (wc != 0xfffd) {
-                   *pwc = (ucs2_t) wc;
-                   return 1;
-               }
-       }
-       return 0;
-}
-
-static size_t mac_hebrew_pull ( void *cd, char **inbuf, size_t *inbytesleft,
-                         char **outbuf, size_t *outbytesleft)
-{
-    ucs2_t         *temp;
-    unsigned char  *inptr;
-    size_t         len = 0;
-
-    while (*inbytesleft >= 1 && *outbytesleft >= 2) {
-        inptr = (unsigned char *) *inbuf;
-       temp  = (ucs2_t*) *outbuf;      
-       if (char_mac_hebrew_to_ucs2 ( temp, inptr)) {
-           if (*temp == 1) {       /* 0x81 --> 0x05f2+0x05b7 */
-               if (*outbytesleft < 4) {
-                   errno = EILSEQ;
-                   return (size_t) -1; 
-               }
-               *temp = 0x05f2;
-               *(temp +1) = 0x05b7;
-               (*outbuf)      +=4;
-               (*outbytesleft)-=4;
-               len += 2;
-           }
-           else if (*temp == 2) { /* 0xc0 -> 0xf86a 0x05dc 0x05b9*/
-               if (*outbytesleft < 6) {
-                   errno = EILSEQ;
-                   return (size_t) -1; 
-               }
-               *temp = 0xf86a;
-               *(temp +1) = 0x05dc;
-               *(temp +2) = 0x05b9;
-               (*outbuf)      +=6;
-               (*outbytesleft)-=6;
-               len += 3;
-           }
-           else if (*temp == 3) { /* 0xde --> 0x05b8 0xf87f */
-               if (*outbytesleft < 4) {
-                   errno = EILSEQ;
-                   return (size_t) -1; 
-               }
-               *temp = 0x05b8;
-               *(temp +1) = 0xf87f;
-               (*outbuf)      +=4;
-               (*outbytesleft)-=4;
-               len += 2;
-           }
-           else {
-               (*outbuf)      +=2;
-               (*outbytesleft)-=2;
-               len++;
-           }
-           (*inbuf)        +=1;
-           (*inbytesleft) -=1;
-       }
-       else    
-       {
-           errno = EILSEQ;
-           return (size_t) -1; 
-       }
-    }
-
-    if (*inbytesleft > 0) {
-        errno = E2BIG;
-        return (size_t) -1;
-    }
-    return len;
-}
-
diff --git a/libatalk/unicode/utf8.c b/libatalk/unicode/utf8.c
new file mode 100644 (file)
index 0000000..ae1c8cd
--- /dev/null
@@ -0,0 +1,163 @@
+/* 
+   Unix SMB/CIFS implementation.
+   minimal iconv implementation
+   Copyright (C) Andrew Tridgell 2001
+   Copyright (C) Jelmer Vernooij 2002,2003
+   
+   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.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+   
+   From samba 3.0 beta and GNU libiconv-1.8
+   It's bad but most of the time we can't use libc iconv service:
+   - it doesn't round trip for most encoding
+   - it doesn't know about Apple extension
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+#include <stdlib.h>
+
+#include <netatalk/endian.h>
+#include <atalk/unicode.h>
+
+
+#include <atalk/logger.h>
+#include <errno.h>
+
+#include <atalk/unicode.h>
+
+
+static size_t   utf8_pull(void *,char **, size_t *, char **, size_t *);
+static size_t   utf8_push(void *,char **, size_t *, char **, size_t *);
+
+struct charset_functions charset_utf8 =
+{
+       "UTF8",
+       0x08000103,
+       utf8_pull,
+       utf8_push,
+       CHARSET_VOLUME | CHARSET_MULTIBYTE | CHARSET_PRECOMPOSED
+};
+
+struct charset_functions charset_utf8_mac =
+{
+       "UTF8-MAC",
+       0x08000103,
+       utf8_pull,
+       utf8_push,
+       CHARSET_VOLUME | CHARSET_CLIENT | CHARSET_MULTIBYTE | CHARSET_DECOMPOSED
+};
+
+/* ------------------------ */
+static size_t utf8_pull(void *cd, char **inbuf, size_t *inbytesleft,
+                        char **outbuf, size_t *outbytesleft)
+{
+       while (*inbytesleft >= 1 && *outbytesleft >= 2) {
+               unsigned char *c = (unsigned char *)*inbuf;
+               unsigned char *uc = (unsigned char *)*outbuf;
+               int len = 1;
+
+               if ((c[0] & 0x80) == 0) {
+                       uc[0] = c[0];
+                       uc[1] = 0;
+               } else if ((c[0] & 0xf0) == 0xe0) {
+                       if (*inbytesleft < 3) {
+                               LOG(log_debug, logtype_default, "short utf8 char\n");
+                               goto badseq;
+                       }
+                       uc[1] = ((c[0]&0xF)<<4) | ((c[1]>>2)&0xF);
+                       uc[0] = (c[1]<<6) | (c[2]&0x3f);
+                       len = 3;
+               } else if ((c[0] & 0xe0) == 0xc0) {
+                       if (*inbytesleft < 2) {
+                               LOG(log_debug, logtype_default, "short utf8 char\n");
+                               goto badseq;
+                       }
+                       uc[1] = (c[0]>>2) & 0x7;
+                       uc[0] = (c[0]<<6) | (c[1]&0x3f);
+                       len = 2;
+               }
+
+               (*inbuf)  += len;
+               (*inbytesleft)  -= len;
+               (*outbytesleft) -= 2;
+               (*outbuf) += 2;
+       }
+
+       if (*inbytesleft > 0) {
+               errno = E2BIG;
+               return -1;
+       }
+       
+       return 0;
+
+badseq:
+       errno = EINVAL;
+       return -1;
+}
+
+/* ------------------------ */
+static size_t utf8_push(void *cd, char **inbuf, size_t *inbytesleft,
+                        char **outbuf, size_t *outbytesleft)
+{
+       while (*inbytesleft >= 2 && *outbytesleft >= 1) {
+               unsigned char *c = (unsigned char *)*outbuf;
+               unsigned char *uc = (unsigned char *)*inbuf;
+               int len=1;
+
+               if (uc[1] & 0xf8) {
+                       if (*outbytesleft < 3) {
+                               LOG(log_debug, logtype_default, "short utf8 write\n");
+                               goto toobig;
+                       }
+                       c[0] = 0xe0 | (uc[1]>>4);
+                       c[1] = 0x80 | ((uc[1]&0xF)<<2) | (uc[0]>>6);
+                       c[2] = 0x80 | (uc[0]&0x3f);
+                       len = 3;
+               } else if (uc[1] | (uc[0] & 0x80)) {
+                       if (*outbytesleft < 2) {
+                               LOG(log_debug, logtype_default, "short utf8 write\n");
+                               goto toobig;
+                       }
+                       c[0] = 0xc0 | (uc[1]<<2) | (uc[0]>>6);
+                       c[1] = 0x80 | (uc[0]&0x3f);
+                       len = 2;
+               } else {
+                       c[0] = uc[0];
+               }
+
+
+               (*inbytesleft)  -= 2;
+               (*outbytesleft) -= len;
+               (*inbuf)  += 2;
+               (*outbuf) += len;
+       }
+
+       if (*inbytesleft == 1) {
+               errno = EINVAL;
+               return -1;
+       }
+
+       if (*inbytesleft > 1) {
+               errno = E2BIG;
+               return -1;
+       }
+       
+       return 0;
+
+toobig:
+       errno = E2BIG;
+       return -1;
+}
index 8edaef3a9e20528ee247a412de1ccad0bbd1ea29..447cf72ff00250edf90abec42fcd7b378d687c02 100644 (file)
@@ -159,6 +159,7 @@ ucs2_t *strchr_w(const ucs2_t *s, ucs2_t c)
 ucs2_t *strcasechr_w(const ucs2_t *s, ucs2_t c)
 {
        while (*s != 0) {
+/*             LOG(log_debug, logtype_default, "Comparing %X to %X (%X - %X)", c, *s, toupper_w(c), toupper_w(*s));*/
                if (toupper_w(c) == toupper_w(*s)) return (ucs2_t *)s;
                s++;
        }
@@ -374,95 +375,112 @@ u_int32_t do_decomposition(ucs2_t base)
        return 0;
 }
 
+/* we can't use static, this stuff needs to be reentrant */
+/* static char comp[MAXPATHLEN +1]; */
 
-static char comp[MAXPATHLEN +1];
-
-char *precompose_w (ucs2_t *name, size_t inplen, size_t *outlen)
+size_t precompose_w (ucs2_t *name, size_t inplen, ucs2_t *comp, size_t *outlen)
 {
        size_t i;
        ucs2_t base, comb;
        ucs2_t *in, *out;
        ucs2_t result;
+       size_t o_len = *outlen;
 
-       if (!inplen || (inplen & 1) || inplen > sizeof(comp)/sizeof(u_int16_t))
-               return NULL;
+//     if (!inplen || (inplen & 1) || inplen > sizeof(comp)/sizeof(u_int16_t))
+       if (!inplen || (inplen & 1) || inplen > o_len)
+               return (size_t)-1;
        i = 0;
        in  = name;
        out = (ucs2_t *)comp;
-       *outlen = 0;
     
        base = *in;
-       while (1) {
+       while (*outlen > 2) {
                i += 2;
                in++;
                if (i == inplen) {
-                       *out = base;
-                       *outlen += 2;
-                       return comp;
+                       *out++ = base;
+                       *out = 0;
+                       *outlen -= 2;
+                       return o_len - *outlen;
                }
                comb = *in;
                if (comb >= 0x300 && (result = do_precomposition(base, comb))) {
                        *out = result;
                        out++;
-                       *outlen += 2;
+                       *outlen -= 2;
                        i += 2;
                        in++;
-                       if (i == inplen) 
-                               return comp;
+                       if (i == inplen) {
+                               *out = 0;
+                               *outlen -= 2;
+                               return o_len - *outlen;
+                       }
                        base = *in;
                }
                else {
                        *out = base;
                        out++;
-                       *outlen += 2;
+                       *outlen -= 2;
                        base = comb;
                }
        }
+       
+       errno = E2BIG;
+       return (size_t)-1;
 }
 
 /* --------------- */
 
-char *decompose_w (ucs2_t *name, size_t inplen, size_t *outlen)
+//char *decompose_w (ucs2_t *name, size_t inplen, size_t *outlen)
+size_t decompose_w (ucs2_t *name, size_t inplen, ucs2_t *comp, size_t *outlen)
 {
        size_t i;
        ucs2_t base;
        ucs2_t *in, *out;
        unsigned int result;
+       size_t o_len = *outlen;
 
        if (!inplen || (inplen & 1))
-               return NULL;
+               return (size_t)-1;
        i = 0;
        in  = name;
        out = (ucs2_t *)comp;
-       *outlen = 0;
     
        while (i < inplen) {
-               if (*outlen >= sizeof(comp)/sizeof(u_int16_t) +2) {
-                       return NULL;
+               //if (*outlen >= o_len/sizeof(u_int16_t) +2) {
+               if (*outlen < 2) {
+                       errno = E2BIG;
+                       return (size_t)-1;
                }
                base = *in;
                if ((result = do_decomposition(base))) {
+                       if ( *outlen < 4 ) {
+                               errno = E2BIG;
+                               return (size_t)-1;
+                       }
                        *out = result  >> 16;
                        out++;
-                       *outlen += 2;
+                       *outlen -= 2;
                        *out = result & 0xffff;
                        out++;
-                       *outlen += 2;
+                       *outlen -= 2;
                }
                else {
                        *out = base;
                        out++;
-                       *outlen += 2;
+                       *outlen -= 2;
                }
                i += 2;
                in++;
        }
-       return comp;
+
+       *out = 0;
+       *outlen -= 2;
+       return o_len-*outlen;
 }
 
 size_t utf8_charlen ( char* utf8 )
 {
-       size_t len;
         unsigned char *p;
 
         p = (unsigned char*) utf8;
index 21ae9e822a0a752ec386117551577bc054aabc1b..0b241b9b69c821380f2159acd5290843affe6c7c 100644 (file)
@@ -14,6 +14,7 @@ libutil_la_SOURCES = \
        server_ipc.c    \
        server_lock.c   \
        strcasestr.c    \
-       strdicasecmp.c  
+       strdicasecmp.c  \
+       fault.c
 
 #      util_unicode.c
diff --git a/libatalk/util/fault.c b/libatalk/util/fault.c
new file mode 100644 (file)
index 0000000..43ebddc
--- /dev/null
@@ -0,0 +1,198 @@
+/* 
+   Unix SMB/CIFS implementation.
+   Critical Fault handling
+   Copyright (C) Andrew Tridgell 1992-1998
+   
+   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.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/types.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+#include <execinfo.h>
+
+#include <atalk/logger.h>
+
+#ifndef SIGNAL_CAST
+#define SIGNAL_CAST (RETSIGTYPE (*)(int))
+#endif
+#ifndef SAFE_FREE /* Oh no this is also defined in tdb.h */
+#define SAFE_FREE(x) do { if ((x) != NULL) {free(x); x=NULL;} } while(0)
+#endif
+#define BACKTRACE_STACK_SIZE 64
+
+static void (*cont_fn)(void *);
+
+/*******************************************************************
+ Catch a signal. This should implement the following semantics:
+
+ 1) The handler remains installed after being called.
+ 2) The signal should be blocked during handler execution.
+********************************************************************/
+
+static void (*CatchSignal(int signum,void (*handler)(int )))(int)
+{
+#ifdef HAVE_SIGACTION
+       struct sigaction act;
+       struct sigaction oldact;
+
+       ZERO_STRUCT(act);
+
+       act.sa_handler = handler;
+#if 0 
+       /*
+        * We *want* SIGALRM to interrupt a system call.
+        */
+       if(signum != SIGALRM)
+               act.sa_flags = SA_RESTART;
+#endif
+       sigemptyset(&act.sa_mask);
+       sigaddset(&act.sa_mask,signum);
+       sigaction(signum,&act,&oldact);
+       return oldact.sa_handler;
+#else /* !HAVE_SIGACTION */
+       /* FIXME: need to handle sigvec and systems with broken signal() */
+       return signal(signum, handler);
+#endif
+}
+
+/*******************************************************************
+ Something really nasty happened - panic !
+********************************************************************/
+
+static void smb_panic(const char *why)
+{
+       char *cmd;
+       int result;
+#ifdef HAVE_BACKTRACE_SYMBOLS
+       void *backtrace_stack[BACKTRACE_STACK_SIZE];
+       size_t backtrace_size;
+       char **backtrace_strings;
+#endif
+
+#ifdef DEVELOPER
+       {
+               extern char *global_clobber_region_function;
+               extern unsigned int global_clobber_region_line;
+
+               if (global_clobber_region_function) {
+                       DEBUG(0,("smb_panic: clobber_region() last called from [%s(%u)]\n",
+                                        global_clobber_region_function,
+                                        global_clobber_region_line));
+               } 
+       }
+#endif
+
+#if 0
+       cmd = lp_panic_action();
+       if (cmd && *cmd) {
+               DEBUG(0, ("smb_panic(): calling panic action [%s]\n", cmd));
+               result = system(cmd);
+
+               if (result == -1)
+                       DEBUG(0, ("smb_panic(): fork failed in panic action: %s\n",
+                                         strerror(errno)));
+               else
+                       DEBUG(0, ("smb_panic(): action returned status %d\n",
+                                         WEXITSTATUS(result)));
+       }
+       DEBUG(0,("PANIC: %s\n", why));
+#endif
+
+#ifdef HAVE_BACKTRACE_SYMBOLS
+       /* get the backtrace (stack frames) */
+       backtrace_size = backtrace(backtrace_stack,BACKTRACE_STACK_SIZE);
+       backtrace_strings = backtrace_symbols(backtrace_stack, backtrace_size);
+
+       LOG(log_error, logtype_default, "BACKTRACE: %d stack frames:\n", backtrace_size);
+       
+       if (backtrace_strings) {
+               size_t i;
+
+               for (i = 0; i < backtrace_size; i++)
+                       LOG(log_error, logtype_default, " #%u %s", i, backtrace_strings[i]);
+
+               SAFE_FREE(backtrace_strings);
+       }
+
+#endif
+
+}
+
+
+/*******************************************************************
+report a fault
+********************************************************************/
+static void fault_report(int sig)
+{
+       static int counter;
+
+       if (counter) _exit(1);
+
+       counter++;
+
+       LOG(log_error, logtype_default, "===============================================================");
+       LOG(log_error, logtype_default, "INTERNAL ERROR: Signal %d in pid %d (%s)",sig,(int)getpid(),VERSION);
+       LOG(log_error, logtype_default, "===============================================================");
+  
+       smb_panic("internal error");
+
+       if (cont_fn) {
+               cont_fn(NULL);
+#ifdef SIGSEGV
+               CatchSignal(SIGSEGV,SIGNAL_CAST SIG_DFL);
+#endif
+#ifdef SIGBUS
+               CatchSignal(SIGBUS,SIGNAL_CAST SIG_DFL);
+#endif
+               return; /* this should cause a core dump */
+       }
+       exit(1);
+}
+
+/****************************************************************************
+catch serious errors
+****************************************************************************/
+static void sig_fault(int sig)
+{
+       fault_report(sig);
+}
+
+/*******************************************************************
+setup our fault handlers
+********************************************************************/
+void fault_setup(void (*fn)(void *))
+{
+       cont_fn = fn;
+
+#ifdef SIGSEGV
+       CatchSignal(SIGSEGV,SIGNAL_CAST sig_fault);
+#endif
+#ifdef SIGBUS
+       CatchSignal(SIGBUS,SIGNAL_CAST sig_fault);
+#endif
+}
+
+
+
index 4dc47afae05dc0ccc8825e2052ea973c1491411f..0cc5674637b071f0e35949ae39d6a2d8ef8aa2a1 100644 (file)
@@ -235,12 +235,14 @@ bool log_setup(char *filename, enum loglevels loglevel, enum logtypes logtype,
 {
 #ifndef DISABLE_LOGGER
 
+#ifdef CHECK_STAT_ON_NEW_FILES
   struct stat statbuf;
   int firstattempt;
   int retval;
   gid_t gid;
   uid_t uid;
   int access;
+#endif
   char lastchar[2];
 
   log_file_data_pair *logs;
diff --git a/macros/gssapi-check.m4 b/macros/gssapi-check.m4
new file mode 100644 (file)
index 0000000..aedf733
--- /dev/null
@@ -0,0 +1,146 @@
+dnl $Id: gssapi-check.m4,v 1.1.2.1 2003-09-09 16:42:22 didg Exp $
+dnl Autoconf macro to check for kerberos
+
+AC_DEFUN([NETATALK_GSSAPI_CHECK], 
+[
+       FOUND_GSSAPI=no
+       GSSAPI_LIBS=""
+       GSSAPI_CFLAGS=""
+
+        AC_ARG_ENABLE(gssapi,
+                [  --enable-gssapi[=DIR]     compile Kerberos V UAM],
+                [compilegssapi=$enableval],
+                [compilegssapi=no]
+        )
+
+       if test x"$compilegssapi" != x"no"; then
+
+                if test "x$compilegssapi" != "xyes"; then
+                       GSSAPI_CFLAGS="-I$withval/include"
+                       GSSAPI_CPPFLAGS="-I$withval/include"
+                       GSSAPI_LDFLAGS="-L$withval/lib"
+                       FOUND_GSSAPI=yes
+                       AC_MSG_CHECKING([checking for GSSAPI support in])
+                       AC_MSG_RESULT([$compilegssapi])
+                fi
+
+
+       # Do no harm to the values of CFLAGS and LIBS while testing for
+       # Kerberos support.
+
+               ac_save_CFLAGS=$CFLAGS
+               ac_save_CPPFLAGS=$CPPFLAGS
+               ac_save_LDFLAGS=$LDFLAGS
+               ac_save_LIBS=$LIBS
+
+               if test x$FOUND_GSSAPI = x"no"; then
+       #################################################
+       # check for krb5-config from recent MIT and Heimdal kerberos 5
+       AC_PATH_PROG(KRB5_CONFIG, krb5-config)
+       AC_MSG_CHECKING(for working krb5-config)
+       if test -x "$KRB5_CONFIG"; then
+         ac_save_CFLAGS=$CFLAGS
+         CFLAGS="";export CFLAGS
+         ac_save_LDFLAGS=$LDFLAGS
+         LDFLAGS="";export LDFLAGS
+         GSSAPI_LIBS="`$KRB5_CONFIG --libs gssapi`"
+         GSSAPI_CFLAGS="`$KRB5_CONFIG --cflags | sed s/@INCLUDE_des@//`"
+         GSSAPI_CPPFLAGS="`$KRB5_CONFIG --cflags | sed s/@INCLUDE_des@//`"
+         CFLAGS=$ac_save_CFLAGS;export CFLAGS
+         LDFLAGS=$ac_save_LDFLAGS;export LDFLAGS
+         FOUND_GSSAPI=yes
+         AC_MSG_RESULT(yes)
+       else
+         AC_MSG_RESULT(no. Fallback to previous krb5 detection strategy)
+       fi
+       fi
+
+       if test x$FOUND_GSSAPI = x"no"; then
+       #################################################
+       # see if this box has the SuSE location for the heimdal krb implementation
+       AC_MSG_CHECKING(for /usr/include/heimdal)
+       if test -d /usr/include/heimdal; then
+         if test -f /usr/lib/heimdal/lib/libkrb5.a; then
+               GSSAPI_CFLAGS="-I/usr/include/heimdal"
+               GSSAPI_CPPFLAGS="-I/usr/include/heimdal"
+               GSSAPI_LDFLAGS="-L/usr/lib/heimdal/lib"
+               AC_MSG_RESULT(yes)
+               FOUND_GSSAPI=yes
+         else
+               GSSAPI_CFLAGS="-I/usr/include/heimdal"
+               GSSAPI_CPPFLAGS="-I/usr/include/heimdal"
+               AC_MSG_RESULT(yes)
+               FOUND_GSSAPI=yes
+         fi
+       else
+         AC_MSG_RESULT(no)
+       fi
+       fi
+
+  if test x$FOUND_GSSAPI = x"no"; then
+    #################################################
+    # see if this box has the RedHat location for kerberos
+    AC_MSG_CHECKING(for /usr/kerberos)
+    if test -d /usr/kerberos -a -f /usr/kerberos/lib/libkrb5.a; then
+      GSSAPI_LDFLAGS="-L/usr/kerberos/lib"
+      GSSAPI_CFLAGS="-I/usr/kerberos/include"
+      GSSAPI_CPPFLAGS="-I/usr/kerberos/include"
+      AC_MSG_RESULT(yes)
+    else
+      AC_MSG_RESULT(no)
+    fi
+  fi
+
+  CFLAGS="$CFLAGS $GSSAPI_CFLAGS"
+  CPPFLAGS="$CPPFLAGS $GSSAPI_CPPFLAGS"
+  LDFLAGS="$LDFLAGS $GSSAPI_LDFLAGS"
+               LIBS="$GSSAPI_LIBS"
+
+
+               # check for gssapi headers
+
+               gss_headers_found=no
+               AC_CHECK_HEADERS(gssapi.h gssapi/gssapi_generic.h gssapi/gssapi.h gssapi/gssapi_krb5.h,[gss_headers_found=yes],[],[])
+               if test x"$gss_headers_found" = x"no"; then
+                       AC_MSG_ERROR([GSSAPI installation not found, headers missing])
+               fi
+
+               # check for libs
+
+               AC_CHECK_LIB(gssapi, gss_display_status) 
+               AC_CHECK_LIB(gssapi_krb5, gss_display_status) 
+
+               # check for functions
+
+               AC_CHECK_FUNC(gss_acquire_cred,[],[AC_MSG_ERROR([GSSAPI: required function gss_acquire_cred missing])])
+
+               # Heimdal/MIT compatibility fix
+  if test "$ac_cv_header_gssapi_h" = "yes"; then
+    AC_EGREP_HEADER(GSS_C_NT_HOSTBASED_SERVICE, gssapi.h, AC_DEFINE(HAVE_GSS_C_NT_HOSTBASED_SERVICE,1,[Wheter GSS_C_NT_HOSTBASED_SERVICE is in gssapi.h]))
+  else
+    AC_EGREP_HEADER(GSS_C_NT_HOSTBASED_SERVICE, gssapi/gssapi.h, AC_DEFINE(HAVE_GSS_C_NT_HOSTBASED_SERVICE,1,[Wheter GSS_C_NT_HOSTBASED_SERVICE is in gssapi.h]))
+  fi
+
+
+    AC_MSG_CHECKING(whether GSSAPI support is used)
+               if test x"$ac_cv_lib_gssapi_gss_display_status" = x"yes" || test x"$ac_cv_lib_gssapi_krb5_gss_display_status" = x"yes"; then
+                       AC_DEFINE(HAVE_GSSAPI,1,[Whether to enable GSSAPI support])
+                       AC_MSG_RESULT([yes])
+                       GSSAPI_LIBS="$LIBS $LDLAGS"
+  else
+                       AC_MSG_RESULT([no])
+                       AC_MSG_ERROR([GSSAPI installation not found])
+    GSSAPI_LIBS=""
+  fi
+
+  LIBS="$ac_save_LIBS"
+  CFLAGS="$ac_save_CFLAGS"
+  LDFLAGS="$ac_save_LDFLAGS"
+  CPPFLAGS="$ac_save_CPPFLAGS"
+       fi
+
+       AM_CONDITIONAL(USE_GSSAPI, test x"$ac_cv_lib_gssapi_gss_display_status" = x"yes")
+  AC_SUBST(GSSAPI_LIBS)
+  AC_SUBST(GSSAPI_CFLAGS)
+
+])
index 738c60de026258ebab7935a2cf31a199f0ae22c4..5c37287fb08b4e18f577be8d232de7d4c0189136 100644 (file)
@@ -28,6 +28,9 @@ dnl   # check for libiconv support
          esac ],
          AC_MSG_RESULT(no)
        )
+
+       CFLAGS_REMOVE_USR_INCLUDE(ICONV_CFLAGS)
+       LIB_REMOVE_USR_LIB(ICONV_LIBS)
        AC_SUBST(ICONV_CFLAGS)
        AC_SUBST(ICONV_LIBS)
 
index 8a9ef9b3f63935b3bdec987f725ec0bcef2b048f..04ba343efcfbe19fbfbe6c04f48e760e1a957ff6 100644 (file)
@@ -1,4 +1,4 @@
-dnl $Id: ssl-check.m4,v 1.8 2003-01-29 00:16:31 srittau Exp $
+dnl $Id: ssl-check.m4,v 1.8.6.1 2003-09-09 16:42:22 didg Exp $
 dnl Autoconf macro to check for SSL or OpenSSL
 
 AC_DEFUN([AC_PATH_SSL], [
@@ -20,6 +20,7 @@ AC_DEFUN([AC_PATH_SSL], [
 
        SSL_CFLAGS=""
        SSL_LIBS=""
+       saved_LIBS=$LIBS
        compile_ssl=no
 
        if test "$tryssl" = "yes"; then
@@ -49,6 +50,9 @@ dnl FIXME: The following looks crude and probably doesn't work properly.
                        AC_MSG_RESULT([no])
                fi
        fi
+       CFLAGS_REMOVE_USR_INCLUDE(SSL_CFLAGS)
+       LIB_REMOVE_USR_LIB(SSL_LIBS)
        AC_SUBST(SSL_CFLAGS)
        AC_SUBST(SSL_LIBS)
+       LIBS=$saved_LIBS
 ])
diff --git a/macros/tcp-wrappers.m4 b/macros/tcp-wrappers.m4
new file mode 100644 (file)
index 0000000..645a7b9
--- /dev/null
@@ -0,0 +1,41 @@
+dnl $Id: tcp-wrappers.m4,v 1.1.4.1 2003-09-09 16:42:22 didg Exp $
+
+AC_DEFUN([NETATALK_TCP_WRAPPERS], [
+       check=maybe
+       AC_ARG_ENABLE(tcp-wrappers,
+               [  --disable-tcp-wrappers  disable TCP wrappers support],
+               [
+                       if test "x$enableval" == "xno"; then
+                               check=no
+                       else
+                               check=yes
+                       fi
+               ]
+       )
+
+       enable=no
+       if test "x$check" != "xno"; then
+               AC_CHECK_LIB(wrap, tcpd_warn, enable=yes)
+       fi
+       if test "x$enable" == "xyes"; then
+               AC_CHECK_HEADERS(tcpd.h)
+               if test "x$ac_cv_header_tcpd_h" != "xyes"; then
+                       enable=no
+               fi
+       fi
+
+       AC_MSG_CHECKING([whether to enable the TCP wrappers])
+       if test "x$enable" == "xyes"; then
+               AC_DEFINE(TCPWRAP, 1, [Define if TCP wrappers should be used])
+               WRAP_LIBS="-lwrap"
+               AC_MSG_RESULT([yes])
+       else
+               if test "x$check" == "xyes"; then
+                       AC_MSG_ERROR([libwrap not found])
+               else
+                       AC_MSG_RESULT([no])
+               fi
+       fi
+
+       AC_SUBST(WRAP_LIBS)
+])
diff --git a/macros/util.m4 b/macros/util.m4
new file mode 100644 (file)
index 0000000..0274029
--- /dev/null
@@ -0,0 +1,24 @@
+dnl Removes -I/usr/include/? from given variable
+AC_DEFUN(CFLAGS_REMOVE_USR_INCLUDE,[
+  ac_new_flags=""
+  for i in [$]$1; do
+    case [$]i in
+    -I/usr/include|-I/usr/include/) ;;
+    *) ac_new_flags="[$]ac_new_flags [$]i" ;;
+    esac
+  done
+  $1=[$]ac_new_flags
+])
+
+dnl Removes -L/usr/lib/? from given variable
+AC_DEFUN(LIB_REMOVE_USR_LIB,[
+  ac_new_flags=""
+  for i in [$]$1; do
+    case [$]i in
+    -L/usr/lib|-L/usr/lib/) ;;
+    *) ac_new_flags="[$]ac_new_flags [$]i" ;;
+    esac
+  done
+  $1=[$]ac_new_flags
+])
+
index 5aa4ca15163871e1c3ce9da6904be9e6f70f4459..b0748bb5b4faad5d60fa4a88f4c5a981d1ef0a03 100644 (file)
@@ -10,6 +10,7 @@ SUFFIXES = .tmpl .
            -e s@:ETCDIR:@${pkgconfdir}@ \
            -e s@:LIBDIR:@${libdir}@ \
            -e s@:LIBEXECDIR:@${libexecdir}@ \
+           -e s@:NETATALK_VERSION:@${NETATALK_VERSION}@ \
            <$< >$@
 
 NONGENERATED_MANS = timelord.8
index a17e1fa8c0ae959074cf9b8e5e5eb29c42834d8a..2fb28f7d2b0ab67dcf7cae2016808c85f5806bfa 100644 (file)
@@ -1,4 +1,4 @@
-.TH AFPD 8 "23 Feb 1999" "netatalk 1.4b2/asun 2.1.3"
+.TH AFPD 8 "23 Feb 1999" ":NETATALK_VERSION:"
 
 .SH NAME
 afpd \- AppleTalk Filing Protocol daemon