EXTRA_DIST = cnid_maint.in
-if COMPILE_CNID
+#if COMPILE_CNID
bin_SCRIPTS = cnid_maint
-else
-bin_SCRIPTS =
-endif
+#else
+#bin_SCRIPTS =
+#endif
-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)
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
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
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:
AM_ICONV
AC_SYS_LARGEFILE
fi
+NETATALK_GSSAPI_CHECK
dnl ----------- A NOTE ABOUT DROPKLUDGE
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!])])
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"
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 ],
fi
dnl -- look for openssl
+AC_MSG_RESULT([ LIBS = $LIBS])
AC_PATH_SSL
dnl --------------------- check for building PGP UAM module
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
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
[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])
+
+
# Makefile.am for etc/
-SUBDIRS = afpd atalkd papd psf uams
+SUBDIRS = afpd cnid_dbd atalkd papd psf uams
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@ \
/*
- * $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.
{
ASP asp = obj->handle;
+ close_all_vol();
if (obj->options.authprintdir) afp_authprint_remove(obj);
if (obj->logout)
}
}
+/* ---------------------- */
+#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;
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,
/*
- * $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.
{
DSI *dsi = obj->handle;
+ close_all_vol();
if (obj->logout)
(*obj->logout)();
#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 */
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;
/*
- * $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.
#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
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 */
#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
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)))
}
}
+ /* 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")))
}
}
+ 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;
}
#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>
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;
if (!isdir && (of = of_findname(path))) {
adp = of->of_ad;
} else {
- memset(&ad, 0, sizeof(ad));
+ ad_init(&ad, vol->v_adouble);
adp = &ad;
}
*/
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)) {
/* 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;
} /* 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)) {
/* 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;
/* 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;
/* 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;
/* 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;
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)
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;
}
/* 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;
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) {
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));
/* 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);
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));
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;
/*
- * $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.
*
#include "globals.h"
#include "desktop.h"
-#ifdef FILE_MANGLING
#include "mangle.h"
-#endif /* CNID_DB */
#ifdef AFP3x
#include <iconv.h>
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);
}
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;
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;
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;
/*
- * $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.
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) ? \
/*
- * $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.
#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>
#include "globals.h"
#include "unix.h"
+#include "mangle.h"
+
struct dir *curdir;
int afp_errno;
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;
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;
}
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;
/* cname is not efficient */
if (cname( vol, ret, &ptr ) == NULL )
return NULL;
-#endif
+
return dirsearch(vol, did);
}
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) {
ret.dir = dir;
}
return &ret;
- }
+ } /* if (len == 0) */
if (*data == sep ) {
data++;
*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) {
} else {
cdir = extenddir( vol, dir, &ret );
- }
+ } /* if (!extend) */
if ( cdir == NULL ) {
dir = cdir;
*path = '\0';
}
- }
- }
+ } /* if (p != path) */
+ } /* for (;;) */
}
/*
(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;
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 );
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) {
}
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 );
}
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))
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 );
}
}
- 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
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 ) {
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;
}
/*
- * $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.
#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"
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
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;
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;
}
*/
char *check_dirent(const struct vol *vol, char *name)
{
- char *m_name = NULL;
if (!strcmp(name, "..") || !strcmp(name, "."))
return NULL;
/* 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;
}
/* ----------------------------- */
return( AFPERR_NOOBJ );
}
sd.sd_last += len + 1;
- len = *(sd.sd_last)++;
- sd.sd_last += len + 1;
sd.sd_sindex++;
}
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;
*/
*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
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 );
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 );
/*
- * $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.
#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"
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);
/* ---------------------
*/
-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;
/* 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 {
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);
{
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) {
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;
}
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;
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;
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 :
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);
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;
}
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) {
if ((of = of_findname(path))) {
adp = of->of_ad;
} else {
- memset(&ad, 0, sizeof(ad));
+ ad_init(&ad, vol->v_adouble);
adp = &ad;
}
* 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 )) )
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;
/* 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:
}
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 */
}
/* ------------------------------------ */
-#ifdef CNID_DB
/* return a file id */
int afp_createid(obj, ibuf, ibuflen, rbuf, rbuflen )
AFPObj *obj;
return( AFPERR_PARAM);
}
- if (vol->v_db == NULL) {
+ if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
return AFPERR_NOOP;
}
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;
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];
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 */
}
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,
return( AFPERR_PARAM);
}
- if (vol->v_db == NULL) {
+ if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
return AFPERR_NOOP;
}
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;
}
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;
return err;
}
-#endif /* CNID_DB */
#define APPLETEMP ".AppleTempXXXXXX"
struct ofork *d_of;
int crossdev;
-#ifdef CNID_DB
int slen, dlen;
-#endif /* CNID_DB */
u_int32_t sid, did;
u_int16_t vid;
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 */
/* 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 */
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 */
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
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:
}
goto err_temp_to_dest;
}
-#endif /* CNID_DB */
#ifdef DEBUG
LOG(log_info, logtype_afpd, "ending afp_exchangefiles:");
/* 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);
/*
- * $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.
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));
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
/*
- * $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.
#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
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 */
}
}
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;
} 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;
/*
- * $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.
#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"
/*
- * $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.
#include <netatalk/at.h>
#include <atalk/afp.h>
#include <atalk/compat.h>
+#include <atalk/unicode.h>
/* test for inline */
#ifndef __inline__
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;
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 *));
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 *));
/*
- * $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.
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))
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. */
/*
- * $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 */
/*
- * $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 $
*
*/
#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 */
/*
- * $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] */
/* 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;
}
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) {
{
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));
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;
/*
- * $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.
/* 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. */
/*
- * $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.
const struct afp_options *options)
{
char *status;
- char *usersign, *ifaddr;
+ char *usersign;
int i;
u_int16_t offset, sigoff;
long hostid;
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));
/*
- * $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
void restore_uidgid ( pair )
uidgidset *pair;
{
- int uid, gid;
+ uid_t uid
+ gid_t gid;
uid = geteuid ();
gid = getegid ();
/*
- * $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.
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;
#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)
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;
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;
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;
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)
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);
volume->v_qfd = -1;
#endif /* __svr4__ */
volume->v_vid = lastvid++;
- volume->v_lastdid = 17;
/* handle options */
if (options) {
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);
* 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;
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, ",");
}
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);
* 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 ) {
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
{
struct stat st;
char *volname;
-#ifndef CNID_DB
char *p;
-#endif
struct vol *volume;
struct dir *dir;
int len, ret;
volume->max_filename = MACFILELEN;
}
-#ifdef CNID_DB
- volume->v_db = NULL;
-#endif
volume->v_dir = volume->v_root = NULL;
/* FIXME unix name != mac name */
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) {
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 );
}
}
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;
}
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);
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)
/*
- * $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.
#define AFPVOL_NAMELEN 27
+#include <atalk/cnid.h>
+
struct codepage_hash {
unsigned char *from, *to;
struct codepage_hash *next, *prev;
#endif /*__svr4__*/
char *v_gvs;
time_t v_time;
- int v_lastdid;
u_int16_t v_vid;
void *v_nfsclient;
int v_nfs;
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
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;
#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)
#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))
--- /dev/null
+# 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@
--- /dev/null
+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
--- /dev/null
+/*
+ * $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);
+ }
+}
--- /dev/null
+/*
+ * $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;
+}
+
+
--- /dev/null
+/*
+ * $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 */
+
+
+
+
+
+
--- /dev/null
+/*
+ * $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(¶ms, 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 ¶ms;
+ }
+ } 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 ¶ms;
+ else
+ return NULL;
+}
+
+
+
--- /dev/null
+/*
+ * $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 */
+
--- /dev/null
+/*
+ * $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 */
--- /dev/null
+/*
+ * $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;
+}
--- /dev/null
+/*
+ * $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;
+}
--- /dev/null
+/*
+ * $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;
+}
--- /dev/null
+/*
+ * $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;
+}
--- /dev/null
+/*
+ * $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;
+}
--- /dev/null
+/*
+ * $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;
+}
--- /dev/null
+/*
+ * $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 */
+
--- /dev/null
+/*
+ * $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
--- /dev/null
+/*
+ * $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);
+ }
+}
--- /dev/null
+/*
+ * $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;
+}
--- /dev/null
+/*
+ * $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 */
--- /dev/null
+/*
+ * $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;
+}
--- /dev/null
+/*
+ * $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 */
-D_PATH_PAPDCONF=\"$(pkgconfdir)/papd.conf\" \
-D_PATH_PAPDUAMPATH=\"$(UAMS_PATH)/\"
-LIBS = @PAM_LIBS@
+#LIBS = @PAM_LIBS@
# 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
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
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
/*
- * $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)
#include <atalk/afp.h>
#include <atalk/uam.h>
+#include <atalk/unicode.h>
#define KEYSIZE 16
#define PASSWDLEN 64
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;
}
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));
}
--- /dev/null
+/*\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
/*
- * $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)
#include <atalk/logger.h>
#include <security/pam_appl.h>
+#include <atalk/unicode.h>
#include <atalk/afp.h>
#include <atalk/uam.h>
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.
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));
}
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));
}
# 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
/*
- * $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.
*
#define HAVE_SENDFILE_READ
#endif
+/* version info */
+#define AD_VERSION1 0x00010000
+#define AD_VERSION2 0x00020000
+#define AD_VERSION AD_VERSION2
+
/*
* AppleDouble entry IDs.
*/
#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
#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 */
#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 */
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),
*/
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));
/*
- * 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 */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/* 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
--- /dev/null
+#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 */
#ifndef _ATALK_UNICODE_H
#define _ATALK_UNICODE_H 1
-
+#include <atalk/list.h>
#define ucs2_t u_int16_t
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
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;
};
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));
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 *));
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));
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));
/*
- * $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
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
# 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
nbp/libnbp.la \
netddp/libnetddp.la \
util/libutil.la \
+ tdb/libtdb.la \
unicode/libunicode.la
libatalk_la_SOURCES = dummy.c
/*
- * $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
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
/*
- * $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)
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 );
/*
- * $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.
#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. */
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},
{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;
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
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 *)
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;
/* 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 );
{
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 */
}
* 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 */
/* ----------------
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;
#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.
*/
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;
}
/* 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,
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
-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
+
--- /dev/null
+# 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
--- /dev/null
+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.
--- /dev/null
+/*
+ * 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 */
+
--- /dev/null
+/*
+ * $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 */
--- /dev/null
+/*
+ * $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 */
--- /dev/null
+/*
+ * $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 */
--- /dev/null
+/*
+ * $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 */
--- /dev/null
+/*
+ * $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 */
--- /dev/null
+/*
+ * $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
+ *
+ */
--- /dev/null
+/*
+ * $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)
+
--- /dev/null
+/*
+ * $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
--- /dev/null
+
+/*
+ * $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 */
--- /dev/null
+/*
+ * $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 */
--- /dev/null
+/*
+ * $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
--- /dev/null
+/*
+ * $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
--- /dev/null
+/*
+ * $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;
+}
+
+
--- /dev/null
+
+/*
+ * $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
+}
--- /dev/null
+# 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
--- /dev/null
+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.
--- /dev/null
+/*
+ * 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 */
+
--- /dev/null
+/*
+ * $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 */
--- /dev/null
+/*
+ * $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 */
--- /dev/null
+/*
+ * $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 */
--- /dev/null
+/*
+ * $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 */
--- /dev/null
+
+/*
+ * $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 */
--- /dev/null
+/*
+ * $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
+ *
+ */
--- /dev/null
+/*
+ * $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)
+
--- /dev/null
+/*
+ * $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 */
--- /dev/null
+
+/*
+ * $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 */
--- /dev/null
+/*
+ * $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 */
--- /dev/null
+/*
+ * $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 */
--- /dev/null
+/*
+ * $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 */
--- /dev/null
+# 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
+
--- /dev/null
+/*
+ * $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 */
+
--- /dev/null
+/*
+ * $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 */
+
--- /dev/null
+# 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
--- /dev/null
+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.
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * $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 */
--- /dev/null
+/*
+ * $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 */
--- /dev/null
+/*
+ * $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 */
--- /dev/null
+/*
+ * $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 */
--- /dev/null
+/*
+ * $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 */
--- /dev/null
+/*
+ * $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 */
--- /dev/null
+/*
+ * $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 */
--- /dev/null
+/*
+ * $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 */
--- /dev/null
+/*
+ * $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 */
--- /dev/null
+# 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
--- /dev/null
+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.
--- /dev/null
+
+/*
+ * $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 */
--- /dev/null
+
+/*
+ * 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 */
--- /dev/null
+# 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
--- /dev/null
+There are still things to do. See ../last/README for details.
--- /dev/null
+
+/*
+ * $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 */
--- /dev/null
+
+/*
+ * 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 */
--- /dev/null
+# 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
--- /dev/null
+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.
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * $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
--- /dev/null
+/*
+ * $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
--- /dev/null
+/*
+ * $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
--- /dev/null
+/*
+ * $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
--- /dev/null
+/*
+ * $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
--- /dev/null
+/*
+ * $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
--- /dev/null
+/*
+ * $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
--- /dev/null
+/*
+ * $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
--- /dev/null
+/*
+ * $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
# 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
/*
- * $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.
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)
{
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];
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));
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@
#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().
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;
{
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 */
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);
}
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);
}
}
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;
}
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;
size = convert_string_allocate(CH_UTF8, CH_UCS2, src, srclen,
(void **) &buffer);
- if (size == -1) {
+ if (size == (size_t) -1) {
free(buffer);
return size;
}
size = convert_string_allocate(CH_UTF8, CH_UCS2, src, srclen,
(void **) &buffer);
- if (size == -1) {
+ if (size == (size_t)-1) {
free(buffer);
return size;
}
size = convert_string_allocate(CH_MAC, CH_UCS2, src, srclen,
(void **) &buffer);
- if (size == -1) {
+ if (size == (size_t)-1) {
free(buffer);
return size;
}
size = convert_string_allocate(CH_MAC, CH_UCS2, src, srclen,
(void **) &buffer);
- if (size == -1) {
+ if (size == (size_t)-1) {
free(buffer);
return size;
}
* @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)
{
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)
{
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;
+}
--- /dev/null
+# 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
--- /dev/null
+/*
+ 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;
+
+}
--- /dev/null
+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 *);
--- /dev/null
+/*
+ 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);
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ 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);
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ 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;
+}
+
--- /dev/null
+/*
+ * 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 */
+};
+
--- /dev/null
+/*
+ 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);
+}
--- /dev/null
+
+/*
+ * $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,
+};
--- /dev/null
+/*
+ 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);
+
+}
--- /dev/null
+/*
+ * 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;
+}
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
+#include <ctype.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <atalk/logger.h>
#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)) { \
}\
}
-
-
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;
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);
}
funcs->next = funcs->prev = NULL;
- LOG(log_debug, logtype_default, "Registered charset %s", funcs->name);
DLIST_ADD(charsets, funcs);
return 0;
}
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);
}
}
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;
(*outbytesleft) -=1;
bufp += 2;
bufsize -= 2;
- //outlen=*outbytesleft;
*ignore = 1;
goto convert_push;
}
}
/* ------------------------ */
-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;
-}
-
--- /dev/null
+/*
+ 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;
+}
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++;
}
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;
server_ipc.c \
server_lock.c \
strcasestr.c \
- strdicasecmp.c
+ strdicasecmp.c \
+ fault.c
# util_unicode.c
--- /dev/null
+/*
+ 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
+}
+
+
+
{
#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;
--- /dev/null
+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)
+
+])
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)
-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], [
SSL_CFLAGS=""
SSL_LIBS=""
+ saved_LIBS=$LIBS
compile_ssl=no
if test "$tryssl" = "yes"; then
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
])
--- /dev/null
+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)
+])
--- /dev/null
+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
+])
+
-e s@:ETCDIR:@${pkgconfdir}@ \
-e s@:LIBDIR:@${libdir}@ \
-e s@:LIBEXECDIR:@${libexecdir}@ \
+ -e s@:NETATALK_VERSION:@${NETATALK_VERSION}@ \
<$< >$@
NONGENERATED_MANS = timelord.8
-.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