]> arthur.barton.de Git - netatalk.git/commitdiff
- merge branch-netatalk-afp-3x-dev, HEAD was tagged before
authorbfernhomberg <bfernhomberg>
Thu, 28 Apr 2005 20:49:17 +0000 (20:49 +0000)
committerbfernhomberg <bfernhomberg>
Thu, 28 Apr 2005 20:49:17 +0000 (20:49 +0000)
461 files changed:
.cvsignore
CONTRIBUTORS
ChangeLog [deleted file]
Makefile.am
NEWS
README
TODO
VERSION
bin/Makefile.am
bin/adv1tov2/adv1tov2.c
bin/aecho/aecho.c
bin/afppasswd/Makefile.am
bin/afppasswd/afppasswd.c
bin/cnid/.cvsignore
bin/cnid/Makefile.am
bin/cnid/cnid2_create.in [new file with mode: 0755]
bin/cnid/cnid_index.c [new file with mode: 0644]
bin/getzones/getzones.c
bin/megatron/Makefile.am
bin/megatron/asingle.c
bin/megatron/asingle.h
bin/megatron/hqx.c
bin/megatron/macbin.c
bin/megatron/megatron.c
bin/megatron/nad.c
bin/megatron/nad.h
bin/nbp/nbplkup.c
bin/nbp/nbprgstr.c
bin/nbp/nbpunrgstr.c
bin/pap/pap.c
bin/pap/papstatus.c
bin/uniconv/.cvsignore [new file with mode: 0644]
bin/uniconv/Makefile.am [new file with mode: 0644]
bin/uniconv/iso8859_1_adapted.c [new file with mode: 0644]
bin/uniconv/uniconv.c [new file with mode: 0644]
config/AppleVolumes.default [deleted file]
config/AppleVolumes.default.tmpl [new file with mode: 0644]
config/AppleVolumes.system
config/Makefile.am
config/afpd.conf.tmpl
config/netatalk.conf
config/netatalk.conf.cobalt
configure.in
contrib/Makefile.am
contrib/a2boot/Makefile.am
contrib/patches/README [new file with mode: 0644]
contrib/patches/patch.afp_vfs [new file with mode: 0644]
contrib/patches/patch.mangled_trash_with_ip [new file with mode: 0644]
contrib/patches/patch.samba.3.0.5pre2-SVN [new file with mode: 0644]
contrib/patches/patch.samba.3.0a20 [new file with mode: 0644]
contrib/patches/patch.vfs [new file with mode: 0644]
contrib/printing/timeout.c
contrib/shell_utils/.cvsignore
contrib/shell_utils/Makefile.am
contrib/shell_utils/asip-status.pl.in [new file with mode: 0755]
contrib/shell_utils/lp2pap.sh.in [deleted file]
contrib/shell_utils/lp2pap.sh.tmpl [new file with mode: 0755]
contrib/shell_utils/netatalkshorternamelinks.pl.in [deleted file]
contrib/timelord/Makefile.am
contrib/timelord/timelord.c
distrib/debian/netatalk.examples
distrib/initscripts/Makefile.am
distrib/initscripts/rc.atalk.bsd.tmpl
distrib/initscripts/rc.atalk.cobalt
distrib/initscripts/rc.atalk.debian.tmpl [new file with mode: 0644]
distrib/initscripts/rc.atalk.gentoo.tmpl [new file with mode: 0644]
distrib/initscripts/rc.atalk.redhat.tmpl
distrib/initscripts/rc.atalk.suse.tmpl
distrib/initscripts/rc.atalk.sysv [deleted file]
distrib/initscripts/rc.atalk.sysv.tmpl [new file with mode: 0755]
distrib/initscripts/rc.atalk.tru64.tmpl
distrib/initscripts/rc.cnid_metad.netbsd.tmpl [new file with mode: 0644]
distrib/m4/netatalk.m4
doc/CONFIGURE [deleted file]
doc/DEVELOPER
doc/INSTALL [deleted file]
doc/README.documentation [new file with mode: 0644]
doc/README.ids
doc/README.platforms
doc/README.veto [deleted file]
etc/Makefile.am
etc/afpd/Makefile.am
etc/afpd/afp_asp.c
etc/afpd/afp_config.c
etc/afpd/afp_config.h
etc/afpd/afp_dsi.c
etc/afpd/afp_options.c
etc/afpd/afp_util.c
etc/afpd/afp_vfs.h [new file with mode: 0644]
etc/afpd/afprun.c [new file with mode: 0644]
etc/afpd/afs.c
etc/afpd/appl.c
etc/afpd/auth.c
etc/afpd/auth.h
etc/afpd/catsearch.c
etc/afpd/codepage.c [deleted file]
etc/afpd/codepage.h [deleted file]
etc/afpd/desktop.c
etc/afpd/desktop.h
etc/afpd/directory.c
etc/afpd/directory.h
etc/afpd/enumerate.c
etc/afpd/file.c
etc/afpd/file.h
etc/afpd/filedir.c
etc/afpd/fork.c
etc/afpd/fork.h
etc/afpd/globals.h
etc/afpd/main.c
etc/afpd/mangle.c
etc/afpd/mangle.h
etc/afpd/messages.c
etc/afpd/nfsquota.c
etc/afpd/nls/.cvsignore [deleted file]
etc/afpd/nls/Makefile.am [deleted file]
etc/afpd/nls/makecode.c [deleted file]
etc/afpd/nls/parsecode.c [deleted file]
etc/afpd/ofork.c
etc/afpd/precompose.c [deleted file]
etc/afpd/quota.c
etc/afpd/status.c
etc/afpd/status.h
etc/afpd/switch.c
etc/afpd/uam.c
etc/afpd/uam_auth.h
etc/afpd/uid.c
etc/afpd/unix.c
etc/afpd/unix.h
etc/afpd/vfs_adouble.c [new file with mode: 0644]
etc/afpd/volume.c
etc/afpd/volume.h
etc/atalkd/Makefile.am
etc/atalkd/atserv.h
etc/atalkd/config.c
etc/atalkd/interface.h
etc/atalkd/main.c
etc/atalkd/main.h
etc/atalkd/nbp.c
etc/atalkd/route.c
etc/atalkd/rtmp.c
etc/atalkd/zip.c
etc/cnid_dbd/.cvsignore [new file with mode: 0644]
etc/cnid_dbd/Makefile.am [new file with mode: 0644]
etc/cnid_dbd/README [new file with mode: 0644]
etc/cnid_dbd/cnid_metad.c [new file with mode: 0644]
etc/cnid_dbd/comm.c [new file with mode: 0644]
etc/cnid_dbd/comm.h [new file with mode: 0644]
etc/cnid_dbd/db_param.c [new file with mode: 0644]
etc/cnid_dbd/db_param.h [new file with mode: 0644]
etc/cnid_dbd/dbd.h [new file with mode: 0644]
etc/cnid_dbd/dbd_add.c [new file with mode: 0644]
etc/cnid_dbd/dbd_dbcheck.c [new file with mode: 0644]
etc/cnid_dbd/dbd_delete.c [new file with mode: 0644]
etc/cnid_dbd/dbd_get.c [new file with mode: 0644]
etc/cnid_dbd/dbd_getstamp.c [new file with mode: 0644]
etc/cnid_dbd/dbd_lookup.c [new file with mode: 0644]
etc/cnid_dbd/dbd_rebuild_add.c [new file with mode: 0644]
etc/cnid_dbd/dbd_resolve.c [new file with mode: 0644]
etc/cnid_dbd/dbd_update.c [new file with mode: 0644]
etc/cnid_dbd/dbif.c [new file with mode: 0644]
etc/cnid_dbd/dbif.h [new file with mode: 0644]
etc/cnid_dbd/main.c [new file with mode: 0644]
etc/cnid_dbd/pack.c [new file with mode: 0644]
etc/cnid_dbd/pack.h [new file with mode: 0644]
etc/cnid_dbd/usockfd.c [new file with mode: 0644]
etc/cnid_dbd/usockfd.h [new file with mode: 0644]
etc/papd/.cvsignore
etc/papd/Makefile.am
etc/papd/auth.c
etc/papd/file.h
etc/papd/headers.c
etc/papd/lp.c
etc/papd/lp.h
etc/papd/magics.c
etc/papd/main.c
etc/papd/ppd.c
etc/papd/print_cups.c [new file with mode: 0644]
etc/papd/print_cups.h [new file with mode: 0644]
etc/papd/printcap.c
etc/papd/printer.h
etc/papd/queries.c
etc/papd/session.c
etc/papd/showppd.c
etc/papd/uam.c
etc/psf/.cvsignore
etc/psf/Makefile.am
etc/psf/etc2ps.sh [new file with mode: 0644]
etc/psf/etc2ps.sh.in [deleted file]
etc/psf/psf.c
etc/uams/Makefile.am
etc/uams/crypt.c [deleted file]
etc/uams/crypt.h [deleted file]
etc/uams/uams_dhx_pam.c
etc/uams/uams_dhx_passwd.c
etc/uams/uams_gss.c
etc/uams/uams_guest.c
etc/uams/uams_krb4/uams_krb4.c
etc/uams/uams_pam.c
etc/uams/uams_passwd.c
etc/uams/uams_pgp.c
etc/uams/uams_randnum.c
include/atalk/Makefile.am
include/atalk/adouble.h
include/atalk/asp.h
include/atalk/cnid.h
include/atalk/cnid_dbd_private.h [new file with mode: 0644]
include/atalk/compat.h
include/atalk/dsi.h
include/atalk/list.h [new file with mode: 0644]
include/atalk/server_child.h
include/atalk/server_ipc.h
include/atalk/tdb.h [new file with mode: 0644]
include/atalk/uam.h
include/atalk/unicode.h [new file with mode: 0644]
include/atalk/util.h
include/atalk/volinfo.h [new file with mode: 0644]
libatalk/Makefile.am
libatalk/adouble/Makefile.am
libatalk/adouble/ad_attr.c
libatalk/adouble/ad_date.c
libatalk/adouble/ad_flush.c
libatalk/adouble/ad_lock.c
libatalk/adouble/ad_mmap.c
libatalk/adouble/ad_open.c
libatalk/adouble/ad_read.c
libatalk/adouble/ad_sendfile.c
libatalk/adouble/ad_size.c
libatalk/adouble/ad_write.c
libatalk/asp/Makefile.am
libatalk/asp/asp_getsess.c
libatalk/atp/Makefile.am
libatalk/atp/atp_sresp.c
libatalk/cnid/.cvsignore
libatalk/cnid/Makefile.am
libatalk/cnid/README
libatalk/cnid/cdb/.cvsignore [new file with mode: 0644]
libatalk/cnid/cdb/Makefile.am [new file with mode: 0644]
libatalk/cnid/cdb/README [new file with mode: 0644]
libatalk/cnid/cdb/cnid_cdb.h [new file with mode: 0644]
libatalk/cnid/cdb/cnid_cdb_add.c [new file with mode: 0644]
libatalk/cnid/cdb/cnid_cdb_close.c [new file with mode: 0644]
libatalk/cnid/cdb/cnid_cdb_delete.c [new file with mode: 0644]
libatalk/cnid/cdb/cnid_cdb_get.c [new file with mode: 0644]
libatalk/cnid/cdb/cnid_cdb_lookup.c [new file with mode: 0644]
libatalk/cnid/cdb/cnid_cdb_meta.c [new file with mode: 0644]
libatalk/cnid/cdb/cnid_cdb_meta.h [new file with mode: 0644]
libatalk/cnid/cdb/cnid_cdb_nextid.c [new file with mode: 0644]
libatalk/cnid/cdb/cnid_cdb_open.c [new file with mode: 0644]
libatalk/cnid/cdb/cnid_cdb_private.h [new file with mode: 0644]
libatalk/cnid/cdb/cnid_cdb_rebuild_add.c [new file with mode: 0644]
libatalk/cnid/cdb/cnid_cdb_resolve.c [new file with mode: 0644]
libatalk/cnid/cdb/cnid_cdb_update.c [new file with mode: 0644]
libatalk/cnid/cnid.c [new file with mode: 0644]
libatalk/cnid/cnid_add.c [deleted file]
libatalk/cnid/cnid_close.c [deleted file]
libatalk/cnid/cnid_delete.c [deleted file]
libatalk/cnid/cnid_get.c [deleted file]
libatalk/cnid/cnid_init.c [new file with mode: 0644]
libatalk/cnid/cnid_lookup.c [deleted file]
libatalk/cnid/cnid_mangle_add.c [deleted file]
libatalk/cnid/cnid_mangle_get.c [deleted file]
libatalk/cnid/cnid_meta.c [deleted file]
libatalk/cnid/cnid_meta.h [deleted file]
libatalk/cnid/cnid_nextid.c [deleted file]
libatalk/cnid/cnid_open.c [deleted file]
libatalk/cnid/cnid_private.h [deleted file]
libatalk/cnid/cnid_resolve.c [deleted file]
libatalk/cnid/cnid_update.c [deleted file]
libatalk/cnid/db3/.cvsignore [new file with mode: 0644]
libatalk/cnid/db3/Makefile.am [new file with mode: 0644]
libatalk/cnid/db3/README [new file with mode: 0644]
libatalk/cnid/db3/cnid_db3.h [new file with mode: 0644]
libatalk/cnid/db3/cnid_db3_add.c [new file with mode: 0644]
libatalk/cnid/db3/cnid_db3_close.c [new file with mode: 0644]
libatalk/cnid/db3/cnid_db3_delete.c [new file with mode: 0644]
libatalk/cnid/db3/cnid_db3_get.c [new file with mode: 0644]
libatalk/cnid/db3/cnid_db3_lookup.c [new file with mode: 0644]
libatalk/cnid/db3/cnid_db3_meta.c [new file with mode: 0644]
libatalk/cnid/db3/cnid_db3_meta.h [new file with mode: 0644]
libatalk/cnid/db3/cnid_db3_nextid.c [new file with mode: 0644]
libatalk/cnid/db3/cnid_db3_open.c [new file with mode: 0644]
libatalk/cnid/db3/cnid_db3_private.h [new file with mode: 0644]
libatalk/cnid/db3/cnid_db3_resolve.c [new file with mode: 0644]
libatalk/cnid/db3/cnid_db3_update.c [new file with mode: 0644]
libatalk/cnid/dbd/.cvsignore [new file with mode: 0644]
libatalk/cnid/dbd/Makefile.am [new file with mode: 0644]
libatalk/cnid/dbd/cnid_dbd.c [new file with mode: 0644]
libatalk/cnid/dbd/cnid_dbd.h [new file with mode: 0644]
libatalk/cnid/hash/.cvsignore [new file with mode: 0644]
libatalk/cnid/hash/Makefile.am [new file with mode: 0644]
libatalk/cnid/hash/README [new file with mode: 0644]
libatalk/cnid/hash/cnid_hash.h [new file with mode: 0644]
libatalk/cnid/hash/cnid_hash_add.c [new file with mode: 0644]
libatalk/cnid/hash/cnid_hash_close.c [new file with mode: 0644]
libatalk/cnid/hash/cnid_hash_delete.c [new file with mode: 0644]
libatalk/cnid/hash/cnid_hash_get.c [new file with mode: 0644]
libatalk/cnid/hash/cnid_hash_lookup.c [new file with mode: 0644]
libatalk/cnid/hash/cnid_hash_nextid.c [new file with mode: 0644]
libatalk/cnid/hash/cnid_hash_open.c [new file with mode: 0644]
libatalk/cnid/hash/cnid_hash_resolve.c [new file with mode: 0644]
libatalk/cnid/hash/cnid_hash_update.c [new file with mode: 0644]
libatalk/cnid/last/.cvsignore [new file with mode: 0644]
libatalk/cnid/last/Makefile.am [new file with mode: 0644]
libatalk/cnid/last/README [new file with mode: 0644]
libatalk/cnid/last/cnid_last.c [new file with mode: 0644]
libatalk/cnid/last/cnid_last.h [new file with mode: 0644]
libatalk/cnid/mtab/.cvsignore [new file with mode: 0644]
libatalk/cnid/mtab/Makefile.am [new file with mode: 0644]
libatalk/cnid/mtab/README [new file with mode: 0644]
libatalk/cnid/mtab/cnid_mtab.c [new file with mode: 0644]
libatalk/cnid/mtab/cnid_mtab.h [new file with mode: 0644]
libatalk/cnid/qdbm/.cvsignore [new file with mode: 0644]
libatalk/cnid/tdb/.cvsignore [new file with mode: 0644]
libatalk/cnid/tdb/Makefile.am [new file with mode: 0644]
libatalk/cnid/tdb/README [new file with mode: 0644]
libatalk/cnid/tdb/cnid_tdb.h [new file with mode: 0644]
libatalk/cnid/tdb/cnid_tdb_add.c [new file with mode: 0644]
libatalk/cnid/tdb/cnid_tdb_close.c [new file with mode: 0644]
libatalk/cnid/tdb/cnid_tdb_delete.c [new file with mode: 0644]
libatalk/cnid/tdb/cnid_tdb_get.c [new file with mode: 0644]
libatalk/cnid/tdb/cnid_tdb_lookup.c [new file with mode: 0644]
libatalk/cnid/tdb/cnid_tdb_nextid.c [new file with mode: 0644]
libatalk/cnid/tdb/cnid_tdb_open.c [new file with mode: 0644]
libatalk/cnid/tdb/cnid_tdb_resolve.c [new file with mode: 0644]
libatalk/cnid/tdb/cnid_tdb_update.c [new file with mode: 0644]
libatalk/compat/Makefile.am
libatalk/dsi/Makefile.am
libatalk/dsi/dsi_attn.c
libatalk/dsi/dsi_cmdreply.c
libatalk/dsi/dsi_getsess.c
libatalk/dsi/dsi_init.c
libatalk/dsi/dsi_read.c
libatalk/dsi/dsi_stream.c
libatalk/dsi/dsi_tcp.c
libatalk/dsi/dsi_tickle.c
libatalk/dsi/dsi_write.c
libatalk/nbp/Makefile.am
libatalk/netddp/Makefile.am
libatalk/netddp/netddp_open.c
libatalk/netddp/netddp_sendto.c
libatalk/pap/.cvsignore [new file with mode: 0644]
libatalk/tdb/.cvsignore [new file with mode: 0644]
libatalk/tdb/Makefile.am [new file with mode: 0644]
libatalk/tdb/spinlock.c [new file with mode: 0644]
libatalk/tdb/spinlock.h [new file with mode: 0644]
libatalk/tdb/tdb.c [new file with mode: 0644]
libatalk/unicode/.cvsignore [new file with mode: 0644]
libatalk/unicode/Makefile.am [new file with mode: 0644]
libatalk/unicode/byteorder.h [new file with mode: 0644]
libatalk/unicode/charcnv.c [new file with mode: 0644]
libatalk/unicode/charsets/.cvsignore [new file with mode: 0644]
libatalk/unicode/charsets/Makefile.am [new file with mode: 0644]
libatalk/unicode/charsets/generic_cjk.c [new file with mode: 0644]
libatalk/unicode/charsets/generic_cjk.h [new file with mode: 0644]
libatalk/unicode/charsets/generic_mb.c [new file with mode: 0644]
libatalk/unicode/charsets/generic_mb.h [new file with mode: 0644]
libatalk/unicode/charsets/mac_centraleurope.c [new file with mode: 0644]
libatalk/unicode/charsets/mac_centraleurope.h [new file with mode: 0644]
libatalk/unicode/charsets/mac_chinese_simp.c [new file with mode: 0644]
libatalk/unicode/charsets/mac_chinese_simp.h [new file with mode: 0644]
libatalk/unicode/charsets/mac_chinese_trad.c [new file with mode: 0644]
libatalk/unicode/charsets/mac_chinese_trad.h [new file with mode: 0644]
libatalk/unicode/charsets/mac_cyrillic.c [new file with mode: 0644]
libatalk/unicode/charsets/mac_cyrillic.h [new file with mode: 0644]
libatalk/unicode/charsets/mac_hebrew.c [new file with mode: 0644]
libatalk/unicode/charsets/mac_hebrew.h [new file with mode: 0644]
libatalk/unicode/charsets/mac_japanese.c [new file with mode: 0644]
libatalk/unicode/charsets/mac_japanese.h [new file with mode: 0644]
libatalk/unicode/charsets/mac_korean.c [new file with mode: 0644]
libatalk/unicode/charsets/mac_korean.h [new file with mode: 0644]
libatalk/unicode/charsets/mac_roman.c [new file with mode: 0644]
libatalk/unicode/charsets/mac_roman.h [new file with mode: 0644]
libatalk/unicode/charsets/mac_turkish.c [new file with mode: 0644]
libatalk/unicode/charsets/mac_turkish.h [new file with mode: 0644]
libatalk/unicode/iconv.c [new file with mode: 0644]
libatalk/unicode/precompose.h [new file with mode: 0644]
libatalk/unicode/ucs2_casetable.h [new file with mode: 0644]
libatalk/unicode/utf8.c [new file with mode: 0644]
libatalk/unicode/util_unistr.c [new file with mode: 0644]
libatalk/util/Makefile.am
libatalk/util/bprint.c
libatalk/util/fault.c [new file with mode: 0644]
libatalk/util/getiface.c
libatalk/util/logger.c
libatalk/util/server_child.c
libatalk/util/server_ipc.c
libatalk/util/server_lock.c
libatalk/util/strcasestr.c
libatalk/util/strlcpy.c [new file with mode: 0644]
libatalk/util/volinfo.c [new file with mode: 0644]
macros/Makefile.am
macros/admingrp-check.m4 [deleted file]
macros/afs-check.m4
macros/cnid-backend.m4 [new file with mode: 0644]
macros/config-checks.m4
macros/cups.m4 [new file with mode: 0644]
macros/db3-check.m4
macros/did-scheme.m4 [deleted file]
macros/gssapi-check.m4
macros/iconv.m4
macros/largefile-check.m4
macros/pam-check.m4
macros/quota-check.m4
macros/snprintf-check.m4
macros/srvloc.m4
macros/ssl-check.m4
macros/summary.m4 [new file with mode: 0644]
macros/tcp-wrappers.m4
macros/tex-check.m4 [deleted file]
macros/util.m4 [new file with mode: 0644]
man/man1/.cvsignore
man/man1/Makefile.am
man/man1/achfile.1
man/man1/acleandir.1
man/man1/aecho.1
man/man1/afile.1
man/man1/afppasswd.1
man/man1/apple_cp.1 [deleted file]
man/man1/apple_cp.1.tmpl [new file with mode: 0644]
man/man1/apple_mv.1 [deleted file]
man/man1/apple_mv.1.tmpl [new file with mode: 0644]
man/man1/apple_rm.1 [deleted file]
man/man1/apple_rm.1.tmpl [new file with mode: 0644]
man/man1/asip-status.pl.1.tmpl [new file with mode: 0644]
man/man1/getzones.1
man/man1/megatron.1
man/man1/nbp.1
man/man1/netatalk-config.1
man/man1/pap.1
man/man1/psorder.1
man/man1/timeout.1
man/man1/uniconv.1.tmpl [new file with mode: 0644]
man/man3/atalk_aton.3
man/man3/nbp_name.3
man/man4/atalk.4
man/man5/AppleVolumes.default.5.tmpl
man/man5/Makefile.am
man/man5/afpd.conf.5.tmpl
man/man5/atalkd.conf.5.tmpl
man/man5/netatalk.conf.5.tmpl
man/man5/papd.conf.5.tmpl
man/man8/Makefile.am
man/man8/afpd.8.tmpl
man/man8/atalkd.8.tmpl
man/man8/cnid_dbd.8.tmpl [new file with mode: 0644]
man/man8/cnid_metad.8.tmpl [new file with mode: 0644]
man/man8/papd.8.tmpl
man/man8/papstatus.8.tmpl
man/man8/psf.8.tmpl
man/man8/timelord.8
sys/netatalk/Makefile.am
sys/netatalk/at.h
sys/solaris/.cvsignore
sys/solaris/Makefile.am [deleted file]
sys/solaris/Makefile.in [new file with mode: 0644]
sys/solaris/Makefile.kernel.in [deleted file]
sys/solaris/aarp.c
sys/solaris/if.c
sys/solaris/if.h
sys/solaris/ioc.c
sys/solaris/tpi.c

index 40efb672a9e621ac460feda4b7c429b6a22c400a..f7e20ba48e34a12e846673388122bef8e26c9220 100644 (file)
@@ -12,6 +12,7 @@ depcomp
 compile
 missing
 mkinstalldirs
+install-sh
 aclocal.m4
 libtool
 ltconfig
index 103757ba5fe3ee8f6700dd7a2a627b63df8af1be..ad1434b0381d39e39cde69c47d7d461531d487c5 100644 (file)
@@ -24,7 +24,7 @@ Sourceforge Administration:
        Jeffrey Buchbinder <jeff@univrel.pr.uconn.edu>
        Matthew Keller <kellermg@potsdam.edu>
 
-Developers: Version 1.4.99 - 1.6
+Developers: Version 1.4.99 - 2.0
        Alain Richard <alain.richard@equation.fr>       
        David R Bosso <dbosso@ltsc.ucsb.edu>
        Joe Clarke <marcus@marcuscom.com>
@@ -49,6 +49,10 @@ Developers: Version 1.4.99 - 1.6
        Sumit Bose <sbose@hbv.de>
        Brandon Warren <bwarren@u.washington.edu>
        Dan Wilga <dwilga@mtholyoke.edu>
+       Rafal Lewczuk <rlewczuk@pronet.pl>
+       Didier Gautheron <dgautheron@magic.fr>
+       Joerg Lenneis <lenneis@wu-wien.ac.at>
+       Bjoern Fernhomberg <lists@fernhomberg.de>
 
 Webmin Module:
        Matthew Keller <kellermg@potsdam.edu>
@@ -61,7 +65,7 @@ Package Maintainers and Contributors:
 Sourceforge Website Maintainers:
        Andrew Morgan <morgan@orst.edu> 
 
-Documentation: Version 1.4.99 - 1.6
+Documentation: Version 1.4.99 - 2.0
        Steve Freitas <sflist@ihonk.com>
        Karen A Swanberg <swanberg@tc.umn.edu>
        Lance Levsen <l.levsen@printwest.com>
@@ -76,8 +80,9 @@ Documentation: Version 1.4.99 - 1.6
        Edmund Lam <epl@unimelb.edu.au>
        Sebastian Rittau <srittau@jroger.in-berlin.de>
        Chris Blake <Chris.Blake@anu.edu.au>
+       Thomas Kaiser <Thomas.Kaiser@phg-online.de>
 
-Bug Reports: Version 1.4.99 - 1.5
+Bug Reports: Version 1.4.99 - 2.0
        Ryan Dooley <dooleyr@missouri.edu>
        Don Jessup <DJessup@tricord.com>
        Kevin M. Myer <kevin_myer@iu13.k12.pa.us>
diff --git a/ChangeLog b/ChangeLog
deleted file mode 100644 (file)
index f62ad21..0000000
--- a/ChangeLog
+++ /dev/null
@@ -1,2654 +0,0 @@
-2003-01-16  Joe Marcus Clarke <marcus@marcuscom.com>
-       * Merge the relevant bits of README.cnid into Simon's README.ids, and
-         remove README.cnid.
-
-2003-01-15  Steven N. Hirsch <shirsch@adelphia.net>
-       * Fix the a2boot code on 64-bit platforms.
-
-2003-01-11  Steven N. Hirsch <shirsch@adelphia.net>
-       * Add Apple II boot support.
-       * Fix some build nits.
-       * Fix issues with building RPMs on RedHat 7.3 and 8.0.
-       * Fix issues with ProDOS attributes on files.
-
-2003-01-07  Rafal Marcin Lewczuk <rlewczuk@pronet.pl>
-       * Moving files between different directories on the same volume 
-         changes group of moved items if necessary (SGID bit set)
-       * Make FPCatSearch a bit more interactive (especially for MacOS 9)
-
-2003-01-04  Joe Marcus Clarke <marcus@marcuscom.com>
-       * Add a doc/README.cnid which talks about the CNID calculation
-         and persistence scheme.
-       * Change all references to db3/DB3 to BDB since we now support
-         Berkeley DB3 and DB4.
-       * Add DB 4.1.x support.
-
-2002-09-26  Andrew Morgan <morgan@orst.edu>
-       * Added syncmail script to CVSROOT so commits are logged to the
-       netatalk-cvs@lists.sourceforge.net mailing list.  You can subscribe
-       to this mailing list to keep track of cvs commits.
-
-2002-09-24  Sebastian Rittau  <srittau@jroger.in-berlin.de>
-
-       * NEWS: Catted CHANGES to the end of this file. Updated from the
-       stable branch.
-       * CHANGES: Removed.
-
-2002-02-14  andy m <morgan@orst.edu>
-       * etc/papd/queries.c: Added support for "ADOIsBinaryOK?" printer query
-       to papd.  We now respond with "True" instead of "unknown".
-
-2002-02-09  joe c  <marcus@marcuscom.com>
-       * etc/afpd/afp_options.c: Redo the -server_notif flag.  Now, server
-       notifications are enabled by default, and specifying the -client_polling
-       flag will disable them.
-
-2002-02-06  joe c  <marcus@marcuscom.com>
-       * etc/afpd/globals.h, etc/afpd/afp_options.c, etc/afpd/status.c
-       etc/afpd/volume.c: Add a new option -server_notif to specify that
-       a server supports server notifications.  If this flag is not specified
-       the client will poll the server every 10 seconds for directory changes.
-
-2002-02-03  andy m <morgan@orst.edu>
-       * bin/afppasswd/Makefile.am
-       Added an install-exec-hook to make the afppasswd binary suid root
-       after it is installed.  This lets local users change their afppasswd
-       password.
-
-2001-12-14  joe c   <marcus@marcuscom.com>
-       * etc/afpd/afp_options.c, etc/afpd/afp_dsi.c, etc/afpd/globals.h:
-       Add a new option to afpd called -timeout to specify the number of
-       server tickles to send before killing a AFPoTCP session.
-
-2001-12-10  joe c   <marcus@marcuscom.com>
-       * bin/cnid/cnid_didname_verify,c: Add a utility to verify the consistency
-       of didname.db.  Using the stock db_verify utility will fail as the sort
-       routine is unknown.
-
-2001-12-07  joe c   <marcus@marcuscom.com>
-       * libatalk/cnid/cnid_open.c: Re-enable synchronous transaction support
-       to try improve performance.
-
-2001-12-04  joe c   <marcus@marcuscom.com>
-       * etc/afpd/unix.c: Fix afpd sharing NFSv3 mounts (thanks to 
-       Pierre Beyssac <beyssac@enst.fr>)
-
-2001-12-03  joe c   <marcus@marcuscom.com>
-       * etc/afpd/*.[ch]: Big commit to clean up code with astyle (readable code 
-       is hackable code).  Also committed a fix to give CNID DB a shot in
-       production use.
-
-2001-11-27  joe c   <marcus@marcuscom.com>
-       * configure.in: Removed the --with-cnid-db option, and added
-         --with-did=cnid for consistency
-
-2001-11-19  pooba53 <bobo@bocklabs.wisc.edu>
-    * Modified distrib/initscripts/Makefile.am so
-      that SuSE init script ends up in the correct directory.
-
-2001-11-19  pooba53 <bobo@bocklabs.wisc.edu>
-       * modified config/AppleVolumes.default to not 
-          have the "/Home Directory" text in it as this is not the
-          proper way of allowing default Home directory access.
-
-2001-11-16  jnewman <jnewman@mudpup.com>
-       * macros/db3-check.m4: Prefer specific directories before general ones
-       
-2001-11-15  pooba53 <bobo@bocklabs.wisc.edu>
-        * Modified SuSE initscript, distrib/initscripts/rc.atalk.suse.tmpl
-
-2001-11-08  jeff b  <jeff@univrel.pr.uconn.edu>
-
-       * etc/afpd/uam.c, etc/uams/uams_pam.c, etc/uams/uams_dhx_pam.c,
-       include/atalk/uam.h: implemented patch #477640 for netatalk not
-       passing client name properly (thanks to Patrick Bihan-Faou
-       <pbf@users.sourceforge.net>)
-
-2001-11-04  joe c <marcus@marcuscom.com>
-
-       * libatalk/cnid/cnid_open.c: Re-added code to enable on-the-fly database
-       recovery
-
-2001-10-31  Dan <bobo@bocklabs.wisc.edu>
-        * Fixed bug in bin/afppasswd/Makefile.am causing compile problems
-          with SuSE distro.
-
-2001-10-24  joe  c  <marcus@marcuscom.com>
-
-       * etc/afpd/fork.c: Patch to add read-only locking support
-         (thanks to Miro Jurisic <meeroh@MIT.EDU>)
-
-2001-10-23  jeff b  <jeff@univrel.pr.uconn.edu>
-
-       * etc/afpd/{{afpd_options,filedir,main,unix}.c,
-       {filedir,globals,unix}.h}: patch from Edmund Lam to allow
-       perms masks
-
-2001-10-21  joe c <marcus@marcuscom.com>
-
-       * libatalk/cnid*.c: Big patch to improve transaction throughput
-         and database resiliency
-
-2001-10-19  Lance Levsen  <l.levsen@printwest.com>
-
-       * doc/FAQ: Thanks for the Patch Karen.
-
-       * doc/INSTALL: Thanks for the Patch Karen.
-
-       * CONTRIBUTORS (Developers): Thanks for the patch Brandon.
-
-       * configure.in: Fix db3 detection for db3 3.3.x users.  Thanks to
-         Jonathan Newman <jnewman@mudpup.com>
-
-2001-10-18  joe c <marcus@marcuscom.com>
-
-       * libatalk/cnid/cnid_add.c: Fix dancing icon problem
-       * bin/afile/achfile.c: Fix resource fork problem on littleendian
-         platforms.  Thanks to Brandon Warren <bwarren@u.washington.edu>.
-
-2001-10-17  joe c <marcus@marcuscom.com>
-
-       * libatalk/cnid/cnid_add.c: Fix deadlock problem when copying files to
-         netatalk server from multiple clients
-
-2001-10-16  Lance Levsen  <l.levsen@printwest.com>
-
-       * man/man1/apple_mv.1.tmpl: Added apple_mv man page.
-
-       * man/man1/apple_rm.1.tmpl: Added apple_rm man page.
-
-       * contrib/shell_utils/apple_mv: Updated perl. Added error check.
-
-       * config/Makefile.am: Change autoconf variable $(f) to shell
-       variable $$f.
-
-       * man/man1/Makefile.am: Modified to allow variable subs in man pages.
-
-       * contrib/shell_utils/apple_cp: Updated. Fixed file to file
-       copy.
-
-2001-10-15  Lance Levsen  <l.levsen@printwest.com>
-
-       * CONTRIBUTORS: Now up to date.
-
-       * doc/FAQ: Added Karen A Swanberg's FAQ additions.
-
-2001-10-14  Lance Levsen  <l.levsen@printwest.com>
-
-       * doc/INSTALL: Added some basic instructions. Filled in more of
-       the ./configure options.
-
-       * doc/DEVELOPER: Added BDB3 information 
-
-2001-10-11  joe  c  <marcus@marcuscom.com>
-
-       * configure.in: More PAM fixes
-
-2001-10-10  joe  c  <marcus@marcuscom.com>
-
-       * configure.in: More PAM fixes
-       * etc/uams/Makefile.am: Properly add -lpam (thanks, Sebastian)
-
-2001-10-09  joe  c  <marcus@marcuscom.com>
-
-       * configure.in: Fix problem with forced PAM
-       * etc/afpd/unix.c: Fix a problem setting directory perms on FreeBSD (thanks
-       to Glenn Trewitt <glenn@trewitt.org>)
-       * libatalk/cnid/cnid_close.c: Fix problem with .AppleDB contents showing
-       up in share window
-       * libatalk/cnid/cnid_update.c: memset more for cleanliness sake
-
-2001-10-04  jeff b  <jeff@univrel.pr.uconn.edu>
-
-       Released 1.5pre8
-
-2001-10-03  joe c   <marcus@marcuscom.com>
-       
-       * configure.in: Fix bug with PAM configuration
-       * etc/afpd/directory.c: Fix bug with unaccessible directories causing
-       afpd to erroneously return AFPERR_NOOBJ
-       * acinclude.m4: Fixed make problem on systems running libtool 1.3.x
-
-2001-09-28  joe c   <marcus@marcuscom.com>
-
-       * libatalk/cnid/cnid_close.c: Add more db3 3.3.x compatibility to CNID DB
-
-2001-09-27  joe c   <marcus@marcuscom.com>
-
-       * libatalk/cnid/cnid_open.c: Set internal deadlock detection
-
-2001-09-23  joe c   <marcus@marcuscom.com>
-
-       * libatalk/cnid/cnid_close.c, libatalk/cnid/cnid_resolve.c,
-       libatalk/cnid/cnid_open.c: More s/errno/rc fixes and some code
-       cleanup
-
-2001-09-22  joe c   <marcus@marcuscom.com>
-
-       * configure.in: Fix db3 compilation on Linux
-
-       * libatalk/cnid/cnid_get.c: Fix another potential deadlock problem by
-       replacing EAGAIN with DB_LOCK_DEADLOCK
-
-2001-09-21  joe c   <marcus@marcuscom.com>
-
-       * etc/afpd/desktop.c: Re-enable codepage translations (thanks to
-       Egon Niederacher <niederacher@fh-vorarlberg.ac.at>)
-
-       * libatalk/cnid/cnid_add.c, libatalk/cnid/cnid_get.c,
-       libatalk/cnid/cnid_lookup.c, libatalk/cnid/cnid_close.c,
-       libatalk/cnid/cnid_open.c, libatalk/cnid/cnid_update.c: Fixed bugs
-       with database contention and database corruption.
-
-2001-09-19  joe c   <marcus@marcuscom.com>
-
-       * etc/afpd/afp_config.c: Fixed a bug where SRVLOC services wouldn't
-       show up in OS 9.x
-
-       * libatalk/cnid/cnid_add.c: Fix a bug where some DBT data structures
-       were not being memset to NULL correctly.
-
-2001-09-18  joe c   <marcus@marcuscom.com>
-
-       * etc/afpd/afp_options.c: Fix a bug in the custom icon code (thanks to
-       Edmund Lam <epl@unimelb.edu.au> for finding this)
-
-       * libatalk/cnid/cnid_open.c: Added db3 version checking code
-
-       * config/afpd.conf.tmpl: Removed uams_guest.so from the default UAMs
-       list
-
-2001-09-17  jeff b  <jeff@univrel.pr.uconn.edu>
-
-       * acconfig.h, configure.in, etc/afpd/afp_config.c: SLP
-       support added (Joe Clarke)
-
-2001-09-14  jeff b  <jeff@univrel.pr.uconn.edu>
-
-       * sys/netatalk/endian.h: fix from Robert Cohen
-       <robert.cohen@anu.edu.au> for missing endif
-
-2001-09-13  joe c   <marcus@marcuscom.com>
-
-       * libatalk/util/getiface.c:
-       fix some malloc problems when no atalkd.conf file exists
-
-2001-09-10  joe c   <marcus@marcuscom.com>
-
-       * libatalk/util/getiface.c: up the new interface by one
-       each time instead of IFACE_NUM
-
-2001-09-10  jeff b  <jeff@univrel.pr.uconn.edu>
-
-       * etc/afpd/afp_options.c, etc/atalkd/main.c, etc/papd/main.c:
-       added version reporting with -v switch
-
-2001-09-06  jeff b  <jeff@univrel.pr.uconn.edu>
-
-       * etc/atalkd/main.c, etc/papd/main.c, etc/psf/psf.c,
-       libatalk/asp/asp_getsess.c, libatalk/dsi/dsi_getsess.c,
-       libatalk/pap/pap_slinit.c, libatalk/util/server_child.c:
-       autoconf POSIX.1 sys/wait.h check
-
-       * lots of files: AC_HEADER_STDC autoconf changes
-
-       * sys/netatalk/endian.h: used autoconf endian test instead
-       of manually checking every architecture
-
-2001-09-05  joe c <marcus@marcuscom.com>
-
-       * libatalk/cnid/cnid_open.c: comment out DB_JOINENV as this is not
-       supported in db3 3.1.17
-
-       * libatalk/cnid/cnid_add.c: fix my comments to properly explain the use
-       of rc over errno
-
-2001-09-04  jeff b  <jeff@univrel.pr.uconn.edu>
-
-       * etc/afpd/filedir.h: define veto_file() prototype (Edmund Lam)
-
-       * etc/uams/uams_dhx_pam.c: added quick Sun hack to seed openssl,
-       but it *really* needs something more elegant (#458433)
-
-2001-09-04  jeff b  <jeff@univrel.pr.uconn.edu>
-
-       * libatalk/cnid/cnid_add.c, libatalk/cnid/cnid_open.c: fixed
-       duplicate DID's being generated and FreeBSD db3 fix (Joe Clarke)
-
-       * doc/README.veto, etc/afpd/directory.c, etc/afpd/enumerate.c,
-       etc/afpd/file.c, etc/afpd/filedir.c, etc/afpd/volume.c,
-       etc/afpd/volume.h: adds Samba-style "veto file" support
-       (Edmund Lam)
-
-       * configure.in: properly checks for db3 headers (Joe Clarke)
-
-2001-08-31  jeff b  <jeff@univrel.pr.uconn.edu>
-
-       * libatalk/cnid/cnid_*.c: compilation fixes for those who don't
-       want to compile with CNID support (Edmund Lam)
-
-2001-08-28  Lance Levsen  <l.levsen@printwest.com>
-
-       * config/Makefile.am: Added a variable substitution from
-       configure.in to stop overwriting the config files.
-
-       * configure.in: Added --enable-overwrite flag that enables the
-       overwriting of configure files. Default is no overwrite, but does
-       check for missing files.
-       
-2001-08-27  jeff b  <jeff@univrel.pr.uconn.edu>
-
-       Released 1.5pre7
-
-2001-08-21  jeff b  <jeff@univrel.pr.uconn.edu>
-
-       * configure.in: now does rudimentary check for DB3 library
-       if CNID DB option (--enable-cnid-db) is given, with
-       option to specify path to DB3 (Jeff)
-
-2001-08-16  Uwe Hees <uwe.hees@rz-online.de>
-
-       * libatalk/cnid: replaced EAGAIN in db result checking with
-       DB_LOCK_DEADLOCK as appropriate for db-3.
-       * fixed a potential transaction problem in cnidd_add.
-
-2001-08-14  Sam Noble <ns@shadow.org>
-
-       * etc/afpd/directory.c: in afp_mapname and afp_mapid
-       convert uid/gid to/from network byte order before actually
-       using.  This should hopefully fix a long-standing bug in
-       the admin functionality.
-
-2001-08-14  jeff b  <jeff@univrel.pr.uconn.edu>
-
-       * acconfig.h, configure.in, etc/afpd/directory.c,
-       etc/afpd/enumerate.c, etc/afpd/file.c, etc/afpd/file.h,
-       etc/afpd/filedir.c, etc/afpd/fork.c, etc/afpd/volume.c,
-       etc/afpd/volume.h, libatalk/Makefile.am,
-       libatalk/cnid/cnid_add.c, libatalk/cnid/cnid_close.c,
-       libatalk/cnid/cnid_delete.c, libatalk/cnid/cnid_lookup.c,
-       libatalk/cnid/cnid_nextid.c, libatalk/cnid/cnid_open.c,
-       libatalk/cnid/cnid_private.h, libatalk/cnid/cnid_update.c:
-       DID database and reincluding libatalk/cnid back into
-       compiled tree (Uwe Hees)
-
-       * libatalk/cnid/.cvsignore: updated .cvsignore list for
-       CNID patch (Jeff)
-
-2001-08-09  Sam Noble <ns@shadow.org>
-
-       * configure.in, acconfig.h: Merged a patch from meeroh@mit.edu
-       to fix the kerberos uam build process.
-
-2001-08-08  jeff b  <jeff@univrel.pr.uconn.edu>
-
-       * etc/papd/session.c: prevents papd client from aborting
-       during the submission of a print job, therefore preventing
-       the job from hanging on the Mac (Michael Boers)
-
-2001-07-10  Lance Levsen  <lance@iworks.pwgroup.ca>
-
-       * man/man8/papd.8.tmpl: Fixed ftp URI for Adobe's PPD files.
-       
-2001-06-30  andy m  <morgan@orst.edu>
-
-       * etc/papd/ppd.c: "unquote" ppd values by removing leading
-       and trailing quote character. This should fix bug #426141.
-
-2001-06-27  jeff b  <jeff@univrel.pr.uconn.edu>
-
-       * many, many, files: more malformed ifdef correction, nicer
-       comments, etc, etc, etc (Jeff)
-
-       * etc/afpd/directory.c, etc/afpd/uid.c, etc/afpd/uid.h: fixes
-       for force-uidgid to compile properly. haven't tested it, but
-       no more compile errors. (Jeff)
-
-2001-06-27  uwe hees <hees@viva.de>
-
-       * etc/uams/uams_guest.c: fixed a typo.
-
-2001-06-26  andy m  <morgan@orst.edu>
-
-       * etc/papd/file.c: modified markline() to return 1 instead
-       of *linelength for successful completion. This should fix
-       the remaining binary printing problems in papd.  Thanks go
-       out to Dave Arnold <darn0ld@home.com> for getting me thinking
-       about the markline function.
-
-2001-06-25  jeff b  <jeff@univrel.pr.uconn.edu>
-
-       * etc/afpd/auth.c, etc/afpd/main.c, etc/afpd/uam.c,
-       etc/uams/uams_dhx_passwd.c, etc/uams/uams_passwd.c,
-       include/atalk/uam.h: TRU64 authentication patch to allow
-       any security scheme to be used on the TRU64 side (Burkhard
-       Schmidt)
-
-       * etc/afpd/uam.c, etc/papd/uam.c: fixed DISABLE_SHELLCHECK
-       support in both afpd and papd (Jason Keltz <jas@cs.yorku.ca>)
-
-       * etc/*/*.{c,h}: corrected malformed defines, nicer comments,
-       CVS Id tags (Jeff)
-
-2001-06-20  jeff b  <jeff@univrel.pr.uconn.edu>
-
-       * configure.in: check for linux/quota.h before enabling
-       QUOTACTL_WRAPPER (Joe Clarke) 
-
-       * acconfig.h, configure.in, include/atalk/util.h,
-       libatalk/util/module.c: removed NO_DLFCN_H in favor of
-       ifndef HAVE_DLFCN_H (Jeff)
-
-       * configure.in, etc/afpd/*.{c,h}, include/atalk/util.h:
-       major autoconf fixes for afpd, nicer commenting, etc (Jeff)
-
-2001-06-19  jeff b  <jeff@univrel.pr.uconn.edu>
-
-       * etc/afpd/file.c, etc/afpd/parse_mtab.c, etc/afpd/parse_mtab.h,
-       etc/atalkd/route.h, etc/atalkd/rtmp.c, etc/papd/headers.c,
-       etc/papd/magics.c, libatalk/asp/asp_tickle.c: patch for
-       fixed DID calculation in etc/afpd/file.c, FreeBSD errors and
-       other miscellany (Joe Clarke) 
-
-       * minor patches and fixes to the aforementioned files, warning
-       fixes with GCC, etc (Jeff)
-
-2001-06-18  jeff b  <jeff@univrel.pr.uconn.edu>
-
-       * configure.in, etc/uams/Makefile.am,
-       etc/uams/uams_krb4/Makefile.am: patch #433952 from Sebastian
-       Rittau to move UAM authentication to use libtool
-
-       * configure.in, bin/afppasswd/Makefile.am, config/Makefile.am,
-       contrib/shell_utils/Makefile.am, distrib/initscripts/Makefile.am,
-       etc/afpd/Makefile.am, etc/afpd/nls/Makefile.am,
-       etc/atalkd/Makefile.am, etc/papd/Makefile.am,
-       man/man5/Makefile.am, man/man8/Makefile.am: patch #433906
-       to move to pkgconfdir for package config files (Sebastian Rittau)
-
-       * configure.in: fixed error that caused --with-did not to function
-       properly
-
-2001-06-13  Sam Noble <ns@shadow.org>
-
-       * etc/papd/{printcap,ppd,lp,file,comment}.h:
-       added #include <sys/cdefs.h> to these headers so that __P gets
-       properly defined on platforms like TRU64
-
-2001-06-11  jeff b  <jeff@univrel.pr.uconn.edu>
-
-       * configure.in, include/atalk/adouble.h, libatalk/compat/flock.c:
-       patch #431859 to avoid ucbinclude on Solaris, with flock support,
-       thanks to Russ Allbery (rra@users.sourceforge.net)
-
-       * acconfig.h, configure.in, libatalk/util/server_child.c,
-       libatalk/util/server_lock.c, sys/netatalk/endian.h: patch #432052
-       for portability to IRIX, HP-UX, and AIX (Russ Allbery)
-
-       * etc/afpd/nls/makecode.c: patch #432137 to add codepage mapping
-       support for (C), (TM) and other characters to avoid losing them,
-       submitted by Andre Schild (aschild@users.sourceforge.net)
-
-       * configure.in: set sysconfdir as /etc/netatalk by default, and
-       uams path now pulls from sysconfdir instead of config_dir
-       (Sam Noble)
-
-2001-06-07  jeff b  <jeff@univrel.pr.uconn.edu>
-
-       * configure.in, bin/afppasswd/Makefile.am,
-       contrib/shell_utils/Makefile.am, distrib/initscripts/Makefile.am,
-       etc/afpd/Makefile.am, etc/afpd/nls/Makefile.am,
-       etc/atalkd/Makefile.am, etc/papd/Makefile.am,
-       man/man5/Makefile, man/man8/Makefile.am: patch #422872 from
-       Sebastian Rittau to move from CONFIG_DIR to sysconfdir
-
-       * etc/psf/Makefile.am, sys/solaris/Makefile: additional removal
-       of CONFIG_DIR in favor of sysconfdir, plus patch #422860 from
-       Sebastian Rittau to correct other problems
-
-       * config/Makefile.am, config/netatalk.pamd: patch #422856 from
-       Sebastian Rittau, moving to pam_unix.so and being more proper
-
-       * etc/afpd/Makefile.am, etc/afpd/main.c: added support for
-       ${sysconfdir}/afpd.mtab to be read into memory, so that mtab
-       DID support actually works...
-
-2001-06-06  jeff b  <jeff@univrel.pr.uconn.edu>
-
-       * etc/afpd/filedir.c, etc/afpd/unix.c: fixed dropkludge code
-       so that it properly compiles again, along with minor warning
-       fixen
-
-2001-06-05 Dan L. (pooba53)
-
-       * Modified configure.in so references made to $ac_prefix_default
-       listed at the beginning are correct. The previous references were
-       being made to $ac_default_prefix.
-
-2001-06-04  jeff b  <jeff@univrel.pr.uconn.edu>
-
-       * doc/README.TRU64: details about tru64 installations, from
-       Edmund Lam <epl@unimelb.edu.au> 
-
-       * etc/afpd/fork.c: implemented Sebastian Rittau's change to
-       avoid overwriting AppleDouble headers (finally)
-
-       * configure.in, etc/afpd/enumerate.c, etc/afpd/parse_mtab.c:
-       added initial support for mtab DID format. removed "lastdid"
-       configure option in favor of --with-did={last,mtab}
-
-2001-06-01  jeff b  <jeff@univrel.pr.uconn.edu>
-       * etc/afpd/quota.c: fix for Linux compile by Sam Noble
-       <ns@shadow.org>
-
-2001-05-25  jeff b  <jeff@univrel.pr.uconn.edu>
-       * etc/uams/uams_passwd.c: another Tru64 fix from Burkhard
-       Schmidt <bs@cpfs.mpg.de>
-
-       * configure.in, contrib/shell_utils/Makefile.am,
-       contrib/shell_utils/afpd-mtab.pl, doc/Makefile.am,
-       doc/COPYRIGHT.mtab, doc/README.mtab, doc/README.mtab.distribution,
-       etc/afpd/.cvsignore, etc/afpd/Makefile.am, etc/afpd/parse_mtab.c,
-       etc/afpd/parse_mtab.h, test_parse_mtab.c: experimental mtab
-       code from Bob Rogers to generate more persistant DIDs
-
-2001-05-22  jeff b  <jeff@univrel.pr.uconn.edu>
-       * configure.in, etc/afpd/unix.h: more portability fixes, and
-       integration of Tru64 build fix from Edmund Lam <epl@unimelb.edu.au>
-
-       * configure.in, bin/megatron/Makefile.am,
-       distrib/initscripts/Makefile.am, etc/afpd/main.c,
-       etc/afpd/quota.c, etc/afpd/unix.h,
-       etc/uams/uams_dhx_passwd.c, etc/uams/uams_passwd.c: Another
-       round of Tru64 patches from Burkhard Schmidt <bs@cpfs.mpg.de>
-
-2001-05-09  jeff b  <jeff@univrel.pr.uconn.edu>
-       * autogen.sh: added automake --include-deps to autogen.sh to
-       promote more portable Makefiles (thanks to Christian
-       Weisgerber <naddy@mips.inka.de> from OpenBSD)
-
-2001-05-08  jeff b  <jeff@univrel.pr.uconn.edu>
-
-       * bin/megatron/Makefile.am, etc/uams/Makefile.am: small Makefile fixes
-       from Olaf Hering <olh@suse.de>
-
-       * etc/uams/uams_dhx_passwd.c: Tru64 fixes from Burkhard Schmidt
-       <bs@cpfs.mpg.de>
-
-2001-05-07  jeff b  <jeff@univrel.pr.uconn.edu>
-
-       * contrib/shell_utils/netatalkshorternamelinks.pl: added script to
-       shorten names
-
-       * etc/afpd/quota.c, etc/uams/uams_passwd.c: patches from Burkhard
-       Schmidt <bs@cpfs.mpg.de> to fix typos
-
-2001-05-03  jeff b  <jeff@univrel.pr.uconn.edu>
-
-       * etc/afpd/quota.c, etc/afpd/unix.h, etc/afpd/main.c,
-       etc/uams/uams_passwd.c: Tru64 patch from Burkhard Schmidt <bs@cpfs.mpg.de>
-
-       * configure.in, etc/afpd/quota.c, etc/afpd/unix.h: fixes for USE_*_H
-       moving to autodetected HAVE_*_H from autoconf script
-
-2001-05-01  jeff b  <jeff@univrel.pr.uconn.edu>
-
-       * bin/aecho/aecho.c, bin/getzones/getzones.c, bin/megatron/asingle.c,
-       bin/megatron/hqx.c, bin/megatron/macbin.c, bin/megatron/megatron.c,
-       bin/megatron/nad.c, bin/megatron/updcrc.c, libatalk/atp/atp_bprint.c,
-       libatalk/util/getiface.c: warnings patch from Sebastian Rittau
-       <srittau@users.sourceforge.net> (#420300)
-
-       * bin/afile/*: replacement for old restrictive afile from Sebastian
-       Rittau <srittau@users.sourceforge.net> (#420302)
-
-       * distrib/initscripts/rc.atalk.redhat.tmpl: daemon-specific start and
-       stop messages to the redhat initscript. nbpregister and unregister
-       messages are also displayed. This patch also permits spaces in zone
-       and machine names to be used in the variables. From Ryan Cleary
-       <tryanc@users.sourceforge.net> (#418094)
-
-       * bin/megatron/Makefile.am: patch to properly create links for
-       megatron, from Sebastian Rittau <srittau@users.sourceforge.net>
-       (#420446)
-
-2001-04-25  morgan a <morgan@orst.edu>
-
-       * etc/afpd/unix.c: in setdirowner(), changed some of the syslog
-       statements from LOG_ERR to LOG_DEBUG.  Some common "soft errors"
-       were being logged and scaring users.  :)
-
-2001-04-24  jeff b  <jeff@univrel.pr.uconn.edu>  
-
-       * configure.in: fixed problem with tcp_wrappers support; it needed to
-       check for tcpd_warn
-
-2001-04-20  jeff b  <jeff@univrel.pr.uconn.edu>  
-
-       * configure.in, etc/afpd/Makefile.am, etc/papd/Makefile.am: added
-       AFPD_LIBS and PAPD_LIBS to cope with libraries that don't need to
-       be used for everything
-
-2001-04-16  jeff b  <jeff@univrel.pr.uconn.edu>  
-
-       * etc/afpd/directory.c, etc/afpd/messages.c, etc/uams/uams_dhx_pam.c:
-       merged patch from Heath Kehoe <hkehoe@users.sourceforge.net> #416371,
-       fixing an OSX issue, byteorder problems with uid/gid in directory.c,
-       and fixing the syslog()'s in uams_dhx_pam.c to not produce useless
-       errors
-
-2001-04-12  jeff b  <jeff@univrel.pr.uconn.edu>  
-
-       Released 1.5pre6
-
-2001-04-10  jeff b  <jeff@univrel.pr.uconn.edu>  
-
-       * configure.in, acconfig.h, etc/afpd/uam.c: patch submitted by Jason
-       Kelitz (jkeltz) to allow disabling of shell checking
-
-       * configure.in, contrib/Makefile.am: made timelord compilation
-       optional, disabled by default
-
-2001-04-03  jeff b  <jeff@univrel.pr.uconn.edu>  
-
-       * etc/afpd/file.c: merged patch from Soren Spies <sspies@apple.com>
-       at Apple, fixing server disconnect problem upon afp_createid() call
-
-2001-04-02  jeff b  <jeff@univrel.pr.uconn.edu>  
-
-       * contrib/shell_utils/Makefile.am, contrib/shell_utils/cleanappledouble.pl:
-       added cleanappledouble.pl script from Heath Kehoe <hakehoe@avalon.net>
-
-2001-03-26  jeff b  <jeff@univrel.pr.uconn.edu>  
-
-       * etc/afpd/quota.c: fix compile dbtob problem on Linux from Sam
-       Noble <ns@shadow.org>
-
-       * configure.in, etc/uams/Makefile.am, etc/uams/uams_krb4/Makefile.am:
-       moved -shared into LDSHAREDFLAGS to fix Solaris build problems
-       from Bob Rogers <rogers-netatalk-devel@rgrjr.dyndns.org> and
-       Akop Pogosian <akopps@csua.berkeley.edu>
-
-2001-03-22  Lance Levsen  <lance.l@dontspam.home.com>
-
-       * etc/uams/Makefile.am: Added $LDFLAGS to fix broken compile due
-       to inability to find libcrypto. libcrypto is defined in LDFLAGS as
-       "-L$ssldir/lib" in configure.
-
-2001-03-22 12:57 EST  jeff b  <jeff@univrel.pr.uconn.edu>  
-
-       * configure.in: patch for OpenBSD compile reported by Jean-Phillipe
-       Rey <jprey@ads.ecp.fr>
-
-2001-03-21 09:35 EST  jeff b  <jeff@univrel.pr.uconn.edu>  
-
-       * etc/afpd/ofork.c, include/atalk/adouble.h, libatalk/adouble/ad_open.c:
-       patch from Jonathan Paisley (jonp@chem.gla.ac.uk)
-
-2001-03-14 13:30 EST  jeff b  <jeff@univrel.pr.uconn.edu>  
-
-       * configure.in: patch from Yoshinobu Ishizaki to fix problems with
-       Linux 2.0.x builds (Patch #408256)
-
-       * etc/afpd/file.c: used patch at http://www.avalon.net/~hakehoe/
-       to fix deleting/emptying trash problems (Patch #408218)
-
-2001-03-14 11:00 EST  jeff b  <jeff@univrel.pr.uconn.edu>  
-
-       * libatalk/adouble/ad_open.c: fixed O_RDWR kludge in ad_mode call
-       which was causing file creation problems
-
-2001-03-09 09:42 EST  jeff b  <jeff@univrel.pr.uconn.edu>  
-
-       * sys/solaris/Makefile: fixed problems noted by Akop Pogosian in Solaris
-       build, most notably paths, and reference to lp2pap.sh in the wrong
-       place
-
-2001-03-07 15:30 EST  jeff b  <jeff@univrel.pr.uconn.edu>  
-
-       Released 1.5pre5
-
-       * distrib/rpm/netatalk-redhat.spec, distrib/rpm/netatalk-mandrake.spec:
-       updated for 1.5pre5 release
-
-2001-03-07 10:34 EST  jeff b  <jeff@univrel.pr.uconn.edu>  
-
-       * etc/afpd/volume.c: changed VOLOPT_MAX to be 9 if FORCE_UIDGID is not
-       defined (thanks to Axel Bringenberg <A.Bringenberg@srz-berlin.de>)
-
-2001-03-07 10:14 EST  jeff b  <jeff@univrel.pr.uconn.edu>  
-
-       * ChangeLog: started using timestamps in ChangeLog
-
-       * etc/uams/uams_krb4/Makefile.am: fixed reference to send_to_kdc.c typo
-       (thanks to Sebastian Rittau)
-
-2001-03-06 13:40  Lance Levsen <l.levsen@printwest.com>
-
-       * FAQ, README, README.ASUN, INSTALL.txt: Moved FAQ, AND READMEs to
-       docs/, where they should be.
-
-       * INSTALL/INSTALL.txt: Added ./INSTALL/INSTALL.txt
-
-       * INSTALL/FAQ, README, README.ASUN: Moved README.ASUN, README,
-       FAQ to ./INSTALL
-
-2001-03-06 11:47  Andrew Morgan <morgan@orst.edu>
-
-       * TODO: A few updates to papd entry.
-
-       * README.MORGAN: Removed README.MORGAN because that information in
-       now in papd's man page.
-
-       * man/man8/papd.8.tmpl: Updated papd man page to match current
-       code.  Added descriptions of authenticated printing and other new
-       papd options.
-
-2001-02-28 15:43  Marc J. Millar <itlm019@mailbox.ucdavis.edu>
-
-       * libatalk/adouble/ad_open.c: AppleDouble directory creation
-       debugging
-       
-2001-02-28  jeff b  <jeff@univrel.pr.uconn.edu>  
-
-       * etc/afpd/directory.c, etc/afpd/file.c, etc/afpd/filedir.c,
-       etc/afpd/unix.c, etc/afpd/unix.h, etc/afpd/volume.h,
-       etc/afpd/volume.c, man/man5/AppleVolumes.default.5.tmpl: added
-       "dropbox" to available option if DROPKLUDGE is used during
-       compile 
-
-2001-02-27  jeff b  <jeff@univrel.pr.uconn.edu>  
-
-       * README: updated 1.5+ install instructions to include list of
-       required and recommended packages
-
-       * etc/uams/uams_*.c: cleanups, addition of CVS Id tag to C source
-
-       * configure.in, acconfig.h: change USE_AFS to AFS to be the same as
-       all of the defines in the codebase
-
-       * etc/uams/uams_dhx_pam.c: fixed DHX login using this module (last
-       patch made with syslog()'s didn't include any brackets) 
-       (Bug #233756)
-
-       * distrib/initscripts/.cvsignore: removed pulling of atalk
-
-       * configure.in, etc/uams/Makefile.am: conditional compilation support
-       for PGP UAM module using --enable-pgp-uam
-
-       * configure.in, etc/uams/Makefile.am, etc/uams/uams_krb4/Makefile.am,
-       etc/uams/uams_krb4/.cvsignore, etc/uams/uams_krb4/*.c: modifications
-       for future Kerberos module reintegration
-
-2001-02-26  jeff b  <jeff@univrel.pr.uconn.edu>  
-
-       * configure.in: added /usr/local/ssl to list of SSL paths to check, to
-       help kludge compilation on Mac OS X from Marcel <lammerse@xs4all.nl>
-
-       * distrib/initscripts/rc.atalk.redhat.tmpl: adjusted to echo warning
-       instead of dumping out if appletalk module not present, from
-       Steven Karen <karelsf@users.sourceforge.net> (Bug #404087)
-
-       * configure.in, contrib/timelord/timelord.c: applied patch from Wes
-       Hardaker <hardaker@users.sourceforge.net> (Patch #402245), with
-       suitable configure.in fixes
-
-2001-02-23  jeff b  <jeff@univrel.pr.uconn.edu>  
-
-       * etc/afpd/desktop.c, etc/afpd/codepage.c, etc/afpd/nls/makecode.c:
-       patch from Axel Barnitzek <barney@users.sourceforge.net> to fix
-       broken codepage support.
-
-       * ChangeLog: started updaing ChangeLog with important patch/fix
-       information, as it is *never* up to date.
-
-       * configure.in, acconfig.h: implemented AFS configuration option
-       patch from Wes Hardaker <hardaker@users.sourceforge.net>
-
-       * VERSION: bumped up version to 1.5pre5, since 1.5pre4 was kind of
-       paperbag-ish
-
-       * autogen.sh: make libtoolize copy instead of linking files to
-       avoid problems, thanks to Wes Hardaker <hardaker@users.sourceforge.net>
-
-2001-02-20  jeff b  <jeff@univrel.pr.uconn.edu>
-
-       Released 1.5pre4
-       - Debian packaging in tree
-       - Numerous Makefile/build fixes
-       - .cvsignore implemented
-       - Solaris build fixes
-
-2001-01-02  jeff b  <jeff@univrel.pr.uconn.edu>
-
-       * etc/afpd/uid.c, etc/afpd/uid.h, ...: added support for forcing
-       uid/gid per volume for afpd
-
-2000-09-22  Roland Schulz <rdschulz@abarrach.franken.de>
-
-       * etc/afpd/volume.c (setvoltime): fix for multiple clients
-       writing to same volume.
-
-2000-02-28  a sun  <asun@asun.cobalt.com>
-
-       * etc/afpd/directory.h (CNID_INODE): xor the inode a little
-       differently. 
-
-2000-02-23  a sun  <asun@asun.cobalt.com>
-
-       * etc/afpd/volume.c (creatvol): / is a special case. you can't
-       share it unless you give it a name.
-
-2000-02-21  a sun  <asun@asun.cobalt.com>
-
-       * distrib/initscripts/rc.atalk.redhat/cobalt: added changes to
-       make redhat 6.x happier.
-
-2000-02-17  a sun  <asun@asun.cobalt.com>
-
-       * libatalk/adouble/ad_lock.c (adf_unlock): off-by-one error with
-       lock removal. this + the log right below fix ragtime.
-
-2000-02-16  a sun  <asun@asun.cobalt.com>
-
-       * etc/afpd/fork.c (afp_bytelock): only error on bytelocks
-       positioned at 0x7FFFFFFF if there's no resource fork.
-
-2000-02-14  a sun  <asun@asun.cobalt.com>
-
-       * libatalk/adouble/ad_lock.c: re-wrote locking bits so that
-       allocations happen in blocks. added missing case that omnis
-       database triggers.
-
-2000-02-07  a sun  <asun@asun.cobalt.com>
-
-       * bin/nbp/Makefile (install): make nbprgstr/nbpunrgstr with 700
-       permissions. 
-
-       * include/atalk/adouble.h (sendfile): change to deal with
-       <sys/sendfile.h> 
-
-2000-01-25  a sun  <asun@asun.cobalt.com>
-
-       * etc/afpd/ofork.c: keep track of oforks being used for each
-       directory so that we can update them if the directory tree gets
-       modified. 
-
-       * etc/afpd/directory.c (deletecurdir): remove dangling symlinks on
-       delete. 
-
-2000-01-24  a sun  <asun@asun.cobalt.com>
-
-       * etc/afpd/directory.h (CNID): moved cnid assignment here along
-       with helpful macros.
-
-       * etc/afpd/directory.c: changed directory search to use red-black
-       trees to improve balance. parent-child tree changed to circular
-       doubly-linked list to speed up insert/remove times.  there's still
-       one obstacle to actually freeing red-black tree entries. i need to
-       add an ofork list to struct dir to minimize search times.
-
-2000-01-18  a sun  <asun@asun.cobalt.com>
-
-       * etc/afpd/directory.c (dirinsert): detect attempts to add
-       pre-existing entries as just symbolic links. 
-
-       * etc/afpd/filedir.h (CNID): moved inode-cnid assignment here and
-       extended to directories.
-
-2000-01-03  a sun  <asun@asun.cobalt.com>
-
-       * etc/uams/uams_pam.c (PAM_conv): surround PAM_BINARY_PROMPT with
-       an #ifdef.
-
-       * etc/afpd/status.c (status_init): fixed a bunch of problems here
-       that manifested under solaris 7.
-
-       * etc/afpd/main.c (main): use FD_SETSIZE instead of FD_SETSIZE +
-       1.
-       
-
-1999-12-27  a sun  <asun@asun.cobalt.com>
-
-       * libatalk/util/getiface.c: moved interface detection code to here
-       so that i can use if_nameindex() or getifconf() depending upon
-       what's available.
-
-1999-12-13  a sun  <asun@asun.cobalt.com>
-
-       * libatalk/dsi/dsi_tcp.c (dsi_tcp_init): added if_nameindex()
-       based interface code.
-
-       * etc/afpd/afp_options.c (afp_options_parseline): added
-       -server_quantum as an option. using hex would be a good idea.
-
-       * libatalk/dsi/dsi_opensess.c (dsi_opensession): added bits to set
-       the server quantum. by default, the server quantum is limited to
-       1MB due to a bug in the os 9 appleshare client.
-
-       * distrib/initscripts/rc.atalk.{cobalt,redhat}: surround nbp stuff
-       with double quotes.
-
-       * etc/uams/uams_dhx_pam.c (pam_changepw): added dhx-based password
-       changing for pam.
-
-1999-12-06  a sun  <asun@asun.cobalt.com>
-
-       * etc/afpd/directory.c (setdirparams): don't error if we can't set
-       the desktop owner/permisssions.
-
-1999-11-04  a sun  <asun@asun.cobaltnet.com>
-
-       * etc/afpd/fork.c (afp_openfork): had the ordering wrong on an
-       openfork. 
-
-1999-11-02  a sun  <asun@asun.cobaltnet.com>
-
-       * etc/afpd/afp_dsi.c (afp_over_dsi): flush data for unknown dsi
-       commands. 
-
-1999-10-28  a sun  <asun@asun.cobaltnet.com>
-
-       * etc/uams/*.c: return FPError_PARAM if the user is unknown. 
-
-1999-10-27  a sun  <asun@asun.cobaltnet.com>
-
-       * etc/afpd/fork.c (afp_read): if sendfile isn't supported, use the
-       old looping method.
-
-1999-10-25  a sun  <asun@asun.cobaltnet.com>
-
-       * libatalk/nbp/nbp_unrgstr.c (nbp_unrgstr): fix nbp unregisters.
-
-1999-10-21  a sun  <asun@asun.cobaltnet.com>
-
-       * etc/afpd/Makefile (install): moved install of afpd earlier per
-       suggestion by steven michaud.
-
-1999-10-05  a sun  <asun@asun.cobaltnet.com>
-
-       * etc/uams/uams_randnum.c (afppasswd): for ~/.passwd's, turn
-       ourselves into the user so that nfs is happy.
-
-1999-09-19  a sun  <asun@adrian5>
-
-       * libatalk/netddp/netddp_open.c, nbp/*.c: only use the bcast stuff
-       if it's on an os x server machine.
-
-1999-09-15  a sun  <asun@adrian5>
-
-       * libatalk/nbp/nbp_unrgstr.c,nbp_lkup.c,nbp_rgstr.c: os x server
-       wants ATADDR_BCAST. that probably means that i need to do
-       multihoming appletalk a little differently. bleah.
-
-1999-09-09    <asun@asun.cobaltnet.com>
-
-       * etc/afpd/directory.c (getdirparams), libatalk/adouble/ad_open.c
-       (ad_open): mondo lameness. i forgot that directory lookups can be
-       done with "." as the directory name. that was auto-hiding
-       them. bleah. i also figured out which bit was the invisible bit
-       for finderinfo information.
-
-1999-09-06  Adrian Sun  <asun@glazed.cobaltnet.com>
-
-       * etc/afpd/desktop.c (mtoupath): fixed a bug in codepage support
-       that accidentally crept in.
-
-1999-08-31  Adrian Sun  <asun@glazed.cobaltnet.com>
-
-       * etc/afpd/quota.c (getfsquota): use group quotas in quota
-       calculations if the user belongs to a single group. just use the
-       user quotas if the user belongs to multiple groups.
-
-       * etc/afpd/volume.c (getvolspace): added an options:limitsize to
-       restrict the available space to 2GB. this is for macs running
-       older versions of the operating system with newer versions of the
-       appleshare client. weird huh?
-
-       * etc/afpd/quota.c (uquota_getvolspace): bleah. 64-bit shifts
-       don't get promoted in the same way as arithmetic operations. added
-       some more casts to deal with that issue.
-
-1999-08-24  Adrian Sun  <asun@glazed.cobaltnet.com>
-
-       * man/man?/Makefile: don't re-build .tmp files if they already
-       exist. this gets the install phase to work correctly.
-
-1999-08-13  a sun  <asun@hecate.darksunrising.blah>
-
-       * etc/afpd/directory.c, file.c, filedir.c: illegal characters get
-       AFPERR_PARAM. also, reject names with /'s in them if the nohex
-       option is used.
-
-1999-08-12  a sun  <asun@hecate.darksunrising.blah>
-
-       * etc/afpd/filedir.c,file.c,directory.c: changed error for
-       illegal filenames to AFPERR_EXIST.
-
-1999-08-11  a sun  <asun@hecate.darksunrising.blah>
-
-       * etc/afpd/desktop.h (validupath): if usedots is set, .Apple* and
-       .Parent files are no longer valid file names.
-
-       * etc/afpd/volume.c (volset): added usedots and nohex as
-       options. usedots stops :hex translation of . files while nohex
-       stops :hex translation of everything but . files. in addition,
-       . files created on the unix side are by default hidden.
-
-       * libatalk/adouble/ad_open.c: initialize more bits.
-
-1999-08-10  a sun  <asun@hecate.darksunrising.blah>
-
-       * distrib/initscripts/rc.atalk.redhat (WORKSTATION): use the
-       actual name for nbp registration rather than ATALK_NAME.
-
-       * sys/solaris/Makefile (kernel): make sure osdefs and machinedefs
-       get used when building the kernel module.
-
-       * sys/solaris: changed strings.h to string.h
-
-1999-08-08  a sun  <asun@hecate.darksunrising.blah>
-
-       * etc/afpd/volume.c (readvolfile): changed volume options into an
-       array of structs to ease maintenance.
-
-1999-08-05  a sun  <asun@hecate.darksunrising.blah>
-
-       * etc/afpd/status.c (status_init): change the default icon
-       depending upon whether or not it's an ASIP or an AppleTalk
-       connection. 
-
-1999-08-04  Adrian Sun  <asun@glazed.cobaltnet.com>
-
-       * etc/atalkd/main.c (setaddr): made a failure with setaddr a 
-       little more informative.
-
-1999-08-03  Adrian Sun  <asun@glazed.cobaltnet.com>
-
-       * yippee. someone figured what was happening with the installation
-       of the man pages. i got rid of a duplicate entry.
-
-1999-08-02  a sun  <asun@hecate.darksunrising.blah>
-
-       * etc/afpd/volume.c (readvolfile): added a per-file way of setting
-       default options. it keys in on a :DEFAULT: label.
-
-1999-07-30  a sun  <asun@hecate.darksunrising.blah>
-
-       * moved rc.atalk.* scripts to distrib/initscripts.
-
-1999-07-27  a sun  <asun@hecate.darksunrising.blah>
-
-       * contrib/printing: added patch from job@uchicago.edu
-
-       * etc/afpd/file.c: forgot to initialize struct ad in
-       some places.
-
-       * etc/afpd/nls/makecode.c: added an empty mapping.
-
-       * etc/psf/Makefile (install): well cp -d didn't work either. just
-       use tar.
-
-1999-07-26  a sun  <asun@hecate.darksunrising.blah>
-
-       * sys/solaris/tpi.c (tpi_attach): changed DDI_NT_NET to DDI_PSEUDO
-       (from denny@geekworld.com).
-
-       * distrib/rpm/netatalk-asun.spec (Summary): incorporated new spec
-       and patch files from inoue.
-
-       * sys/linux/Makefile (install-sysv): fixed up a bit.
-
-       * etc/psf/Makefile (install): use cp -d instead of cp -a to make
-       *bsd happier.
-
-       * etc/afpd/afp_options.c (afp_options_parseline): reversed meaning
-       of -icon. now it means to use the yucky bitmap instead of the
-       apple icon.
-
-       * bin/afppasswd/Makefile (all): add -Iinclude/openssl for
-       afppasswd as well. 
-
-1999-07-18  a sun  <asun@hecate.darksunrising.blah>
-
-       * create links/mangle files in the compile rather than the install
-       phase so that rpm will be happier.
-
-1999-07-17  a sun  <asun@hecate.darksunrising.blah>
-
-       * etc/afpd/file.c (afp_createfile), directory (afp_createdir),
-         filedir.c (afp_rename, afp_moveandrename): don't allow the
-         creation/renaming of names with certain characters if mswindows
-         compatibility is enabled.
-
-1999-07-16  a sun  <asun@hecate.darksunrising.blah>
-
-       * rc.atalk.redhat: incorporated chkconfig from inoue.
-
-1999-07-15  a sun  <asun@hecate.darksunrising.blah>
-
-       * etc/atalkd/config.c (getifconf): wrap check against
-       IFF_MULTICAST behind an #ifdef IFF_MULTICAST.
-
-       * sys/netbsd/Makefile (LDSHAREDFLAGS): key in on machine type.
-
-1999-07-11  a sun  <asun@hecate.darksunrising.blah>
-
-       * contrib/ICDumpSuffixMap: added internet config perl script from
-       inoue. 
-
-       * contrib/printing: added contributed solaris printing scripts
-       from job@uchicago.edu.
-
-1999-07-10  a sun  <asun@hecate.darksunrising.blah>
-
-       * etc/atalkd/interface.h, rtmp.h: prototyped functions.
-
-       * etc/atalkd/zip.c: converted bcopy's to memcpy's.
-
-       * etc/atalkd/nbp.c,rtmp.c: added checks for the interface for
-       dontroute cases.
-
-       * etc/atalkd/main.c: converted bzero/bcopy to memset/memcpy.
-
-1999-07-08  a sun  <asun@hecate.darksunrising.blah>
-
-       * libatalk/nbp/nbp_rgstr.c (nbp_rgstr): return EADDRINUSE if the
-       address already exists.
-
-1999-07-06  a sun  <asun@hecate.darksunrising.blah>
-
-       * rc.atalk.redhat: changed netatalk.config to netatalk.conf
-
-1999-07-05  a sun  <asun@hecate.darksunrising.blah>
-
-       * etc/atalkd/nbp.c (nbp_packet): add interface to nbp struct. this
-       is so that we can filter by interface in the future. however, it
-       doesn't seem to work that well right now. bleah. 
-
-       * etc/atalkd/main.c: fixed up dontroute option so that it doesn't
-       screw up atalkd.conf. also, we need to do a bootaddr if dontroute
-       is set. 
-
-       * libatalk/atp,nbp,netddp; bin/aecho,nbp,getzones,pap;
-       etc/papd,afpd: accept -A <ddp address> as an option so that you
-       can specify the address to be used on a multihomed server. for
-       papd, you use the 'pa' option in papd.conf.
-
-1999-07-04  a sun  <asun@hecate.darksunrising.blah>
-
-       * etc/atalkd/config.c (parseline): initialize parseline properly
-       so that we don't get extraneous junk.
-
-       * etc/afpd/afp_options.c (afp_options_parseline): do
-       gethostbyaddr/gethostbyname's for -ipaddr and -fqdn.
-
-       * etc/atalkd/config.c (getifconf/readconf): check to see if the
-       supported device can support appletalk addresses. either continue
-       or exit depending upon whether or not it's auto-configed.
-
-1999-07-03  a sun  <asun@hecate.darksunrising.blah>
-
-       * etc/afpd/afp_options.c (afp_options_parse): -I (-[no]icon) will
-       toggle the volume icon so that it uses the apple icon instead.
-
-       * etc/afpd/config.c (AFPConfigInit): added more logic for the
-       -proxy option. here are the rules: -proxy will always try to
-       create a DDP server instance. by default, the proxy server will
-       still allow you to login with an appletalk connection. to prevent
-       that, just set the uamlist to an empty string.
-
-1999-07-02  a sun  <asun@hecate.darksunrising.blah>
-
-       * etc/afpd/status.c (status_netaddress): added support for fqdn
-       (not available in the appleshare client yet).
-
-1999-07-01  a sun  <asun@hecate.darksunrising.blah>
-
-       * etc/afpd/config.c (DSIConfigInit): application code for proxy
-       setup. it's the -proxy option.
-
-       * libatalk/dsi/dsi_init/tcp.c (dsi_init/dsi_tcp_init): added
-       support for proxy setup.
-
-1999-06-30  a sun  <asun@hecate.darksunrising.blah>
-
-       * etc/afpd/filedir.c (afp_rename): fixed up some error
-       codes. quark express should be happier.
-
-       * etc/afpd/uam.c (uam_afpserver_option): added
-       UAM_OPTION_HOSTNAME. use this to set PAM_RHOST. i just got a
-       report that setting that fixes pam on solaris machines.
-
-1999-06-28  a sun  <asun@hecate.darksunrising.blah>
-
-       * etc/afpd/ofork.c (of_alloc): report out of forks in syslog..
-
-       * etc/afpd/enumerate.c (afp_enumerate): close an opendir leak. 
-
-       * include/atalk/{dsi,asp}.h: make cmdlen and datalen ints.
-
-       * etc/afpd/fork.c (afp_write): fixed up error condition.
-
-1999-06-26  a sun  <asun@hecate.darksunrising.blah>
-
-       * etc/uams/Makefile (install): changed install location of uams.
-
-       * sys/linux/Makefile (install-sysv): always install redhat
-       script. netatalk.config script only gets installed if it's not
-       there already.
-
-1999-06-23  a sun  <asun@hecate.darksunrising.blah>
-
-       * rc.atalk.redhat: merged in redhat contrib rpm rc.atalk script.
-
-       * etc/afpd/afp_options.c (afp_options_init): changed default
-       maxusers to 20.
-
-1999-06-22  a sun  <asun@hecate.darksunrising.blah>
-
-       * etc/afpd/config.c (DSIConfigInit): truncate options->server to
-       just the server name here.
-
-       * etc/afpd/volume.c (volxlate): made $s return something
-       meaningful no matter what.
-
-       * libatalk/adouble/ad_sendfile.c (ad_readfile): freebsd sendfile
-       wants an off_t.
-
-1999-06-20  a sun  <asun@hecate.darksunrising.blah>
-
-       * etc/afpd/volume.c (volxlate): added variable substitution. if it
-       doesn't understand the variable, it just spits it back out.
-       
-       (creatvol): display truncated volume name if it's too long.
-
-       * sys/{generic,solaris}/Makefile: added NO_CRYPTLIB option to deal
-       with oses that have -lcrypt but shouldn't use it.
-
-1999-06-11  a sun  <asun@hecate.darksunrising.blah>
-
-       * include/atalk/afp.h: added comments to FPErrors.
-
-       * etc/afpd/enumerate.c (afp_enumerate): make FPEnumerate do some
-       more error checking.
-
-       * include/atalk/util.h: server_lock() returns pid_t. 
-
-1999-06-10  a sun  <asun@hecate.darksunrising.blah>
-
-       * README.ASUN: added location for both ssleay and openssl.
-
-       * etc/uams: moved install to LIBDIR/uams. "uams_*" now means "uam
-       server." in the future, there will be "uamc_*." changed the shared
-       library names to match.
-
-       * include/atalk/atp.h,nbp.h: forgot to include <sys/cdefs.h>
-
-       * etc/uams/Makefile: openssl-0.9.3c uses <openssl/*.h> so add that
-       to the include path.
-
-       * sys/{solaris,ultrix}/Makefile: just use -I../sys/generic instead
-       of doing a link.
-
-       * include/atalk/uam.h, etc/uams/uam_*.c, etc/afpd/uam.c: added uam
-       type field. do type check.
-
-       * etc/uams/uam_*pam.c: added a couple more error codes. 
-
-1999-06-08  a sun  <asun@hecate.darksunrising.blah>
-
-       * etc/afpd/nls/Makefile (codepage.h): make sure that a link to
-       codepage.h gets made.
-
-       * libatalk/*/Makefile: make sure that the profiled directory gets
-       created.
-       
-       * etc/afpd/directory.c (afp_mapname): removed an extraneous line
-       that was causing mapname to fail.
-
-1999-06-07  a sun  <asun@hecate.darksunrising.blah>
-
-       * etc/atalkd/main.c (main): added a note to check the syslog if
-       atalkd can't be setup.
-
-       * sys/linux/Makefile: added -DNEED_QUOTACTL_WRAPPER to the list of
-       auto-detected #defines.
-
-1999-06-06  a sun  <asun@hecate.darksunrising.blah>
-
-       * etc/afpd/fork.c (afp_write): argh. i moved things around a
-       little too much and ended up with an uninitialized eid. strangely,
-       the compiler didn't complain. simplified bits a little as
-       well. also, FPWrite was returning the wrong error messages. on
-       64-bit filesystems, the offset can wraparound. so, report a disk
-       full error if that's going to happen. egcs-19990602 gets one
-       memcpy right and another wrong on my udb. bleah.
-       
-       (afp_read): fixed the error messages here as well.
-
-1999-06-05  a sun  <asun@hecate.darksunrising.blah>
-
-       * Makefile, sys/generic, sys/{ultrix,solaris}/Makefile: create
-       some links on the fly if they're missing.
-
-       * etc/afpd/directory.c (copydir): fixed a leaking opendir and
-       re-arranged a little.
-
-1999-06-04  a sun  <asun@hecate.darksunrising.blah>
-
-       * etc/afpd: prototyped everything here and moved the FP functions
-       into include files.
-
-       * libatalk/util/bprint.c: moved all of the bprints to here.
-
-       * libatalk/asp, include/atalk/asp.h: prototyped asp functions.
-
-       * include/atalk/atp.h, libatalk/atp: prototyped atp functions. 
-
-       * libatalk/nbp, include/atalk/nbp.h: added prototypes for nbp
-       functions. 
-
-       * bin/afppasswd/Makefile (afppasswd): fixed a misspelling in the
-       install phase.
-
-       * bin/afppasswd/afppasswd.c: added -a option so that root can add
-       new users. turned all of the options into bits. added newlines to
-        each entry.
-
-1999-06-03  a sun  <asun@hecate.darksunrising.blah>
-
-       * sys/freebsd/Makefile: turn on sendfile support if running on a
-       FreeBSD 3+ machine.
-
-1999-06-02  a sun  <asun@hecate.darksunrising.blah>
-
-       * etc/uams/uam_dhx_pam.c: fixed memory freeing part of pam
-       conversation function.
-
-       * sys/*/Makefile: check at make time to see if -lrpcsvc and
-       -lcrypt should be included in the appropriate places. 
-
-1999-05-28  a sun  <asun@hecate.darksunrising.blah>
-
-       * etc/afpd/file.c (deletefile): added more error checking here as
-       well. 
-
-       * etc/afpd/directory.c (renamedir): added a couple a few more
-       error bits. 
-
-       * sys/sunos/Makefile: sunos should really work now. 
-
-1999-05-27  a sun  <asun@hecate.darksunrising.blah>
-
-       * include/atalk/afp.h: added in a couple new error codes (one
-       deals with password setting policy, the other with maximum logins
-       by any user).
-
-       * etc/afpd/fork.c (afp_openfork): try to re-open files on
-       read-only volumes as read-only.
-
-1999-05-26  a sun  <asun@hecate.darksunrising.blah>
-
-       * sys/solaris/Makefile: fixed a few bobbles here. solaris uses
-       uname -p. other oses seem to use uname -m for the same information.
-
-       * etc/uams/uam_pam.c (pam_changepw): added check for same
-       password. 
-
-       * etc/uams/uam_randnum.c (randnum_changepw): added in cracklib and
-       same password checks.
-
-       * sys/osx/Makefile: moved the os x server stuff into its own build
-       directory. 
-
-       * sys/linux/Makefile, sys/solaris/Makefile: key in on OSVERSION
-       and MACHINETYPE for some stuff.  
-
-1999-05-25  a sun  <asun@hecate.darksunrising.blah>
-
-       * sys/sunos/Makefile: various bits to make stuff work with sunos
-       again. 
-
-1999-05-25  a sun  <asun@purgatorius.zoology.washington.edu>
-
-       * etc/afpd/file.c (copyfile): only copy the header file if newname
-       is specified. 
-
-       * etc/afpd/directory.c (copydir): make sure to balk if the
-       directory already exists. in addition, make sure to preserve the
-       timestamps. 
-
-1999-05-24  a sun  <asun@hecate.darksunrising.blah>
-
-       * bin/afppasswd/afppasswd.c: global password updating utility for
-       the randnum authentication method. 
-
-1999-05-22  a sun  <asun@hecate.darksunrising.blah>
-
-       * etc/uams/uam_randnum.c (afppasswd): added in global password
-       file for the randnum authentication method. it looks for a .key
-       file as well to handle encryption.
-
-       * etc/afpd/afp_options.c (afp_options_parseline): added
-       -passwdfile as an option so that you can specify a global randnum
-       password file if desired.
-
-       * etc/afpd/volume.c (readvolfile): we now have rwlist and rolist
-       as an AppleVolumes.* option. if the user is in the rolist, the
-       volume gets set as readonly. if there's a rwlist, and the user
-       isn't in it, the volume also gets set as readonly.
-
-1999-05-21  a sun  <asun@hecate.darksunrising.blah>
-
-       * libatalk/adouble/ad_lock.c (ad_fcntl_lock): plug a leak if we
-       can't allocate the reference counting variable.
-
-       * etc/uams/uam_*.c: make sure that uam_setup returns an error
-       code. 
-
-1999-05-19  a sun  <asun@hecate.darksunrising.blah>
-
-       * include/atalk/paths.h (_PATH_LOCKDIR): added os x server's
-       /var/run as the lock file directory.
-
-       * etc/afpd/fork.c (afp_write): kanehara@tpk.toppan.co.jp reported
-       a problem with FPWrite getting a request count of 0. that's
-       fixed. 
-
-       * etc/afpd/Makefile: bleah. for some reason, pam doesn't like to
-       load itself from a shared library. i've compensated by linking it
-       into afpd again.
-
-       * etc/uams/uam_dhx_passwd.c: okay. DHX now works. something's
-       still screwy with the dhx_pam stuff though.
-
-1999-05-18  a sun  <asun@hecate.darksunrising.blah>
-
-       * etc/afpd/uam.c (uam_getname): i forgot that getname modified the
-       username to fit what's in pw->pw_name if necessary.
-
-1999-05-16  a sun  <asun@hecate.darksunrising.blah>
-
-       * etc/uams/uam_dhx_passwd/pam.c: almost ready versions of the DHX
-       authentication method. i'm still missing a little info to get it
-       all right.
-
-       * bin/megatron/nad.c (nad_header_read): if there isn't a mac name,
-        create it from the unix name. 
-
-       * bin/megatron/megatron.c (megatron): oops. need to turn fdCreator
-       and fdType into strings.
-
-1999-05-16  a sun  <asun@pelvetia>
-
-       * etc/afpd/uam.c (uam_afpserver_option): changed the interface a
-       little. now, you pass in an int * if you want to either get/set
-       the size of the option. added in UAM_OPTION_RANDNUM for generic 
-        (4-byte granularity) random number generation.
-
-       * etc/afpd/switch.c: added afp_logout to preauth_switch.
-
-1999-05-15  a sun  <asun@hecate.darksunrising.blah>
-
-       * bin/megatron/macbin.c (bin_open): make error message for
-       macbinary files more informative.
-       
-       (test_header): added more macbinary tests. it now has a workaround
-       for apple's incorrectly generated macbinary files.
-
-1999-05-14  a sun  <asun@hecate.darksunrising.blah>
-
-       * sys/solaris/Makefile: added shared library generation bits.
-
-       * etc/uams: moved server-side uams here. 
-
-       * include/netatalk/endian.h: fixed some solaris bits. 
-
-       * etc/afpd/config.c (configfree): don't do an asp_close. instead,
-       do an atp_close and free the asp object. oh yeah, as afpd needs
-        to export symbols to its modules, make sure you don't do anything
-        more exciting than strip --strip-debug with it.
-
-1999-05-12  a sun  <asun@hecate.darksunrising.blah>
-
-       * various places that use sigaction: zero out struct sigaction so
-        that we don't send something confusing. also make sure that we
-        don't set a timer unless we already have a sigaction set.
-
-       * etc/afpd/fork.c (afp_openfork): don't error on trying to open an
-       empty resource fork read-only. also, added back in the bit of code
-       that prevented locks from being attempted on non-existent resource
-       forks.
-
-       * etc/afpd/afp_options.c (getoption): added a uamlist commandline
-       option (-U list). 
-
-       * libatalk/netddp/netddp_open.c: don't bind if nothing was passed
-       in. 
-
-       * libatalk/nbp/nbp_unrgstr.c (nbp_unrgstr): oops. forgot to
-       convert this over to use by the netddp interface.
-
-1999-05-12  a sun  <asun@pelvetia>
-
-       * etc/afpd/uam.c: os x server's runtime library loader is
-       braindead. as a result, i've switched to using an exported struct
-       with the uam's name.
-
-       * bin/aecho,getzones: changed these to use the netddp interface.
-
-       * libatalk/nbp/nbp_rgstr.c,unrgstr.c: fixed more leaky bits.
-
-       * libatalk/netddp: abstracted the ddp interface to netddp. besides
-       the prior socket-driven interface, there's now an os x server
-       interface. so, instead of calling socket/sendto/recvfrom, you call
-       netddp_open/netddp_sendto/netddp_recvfrom.
-
-1999-05-11  a sun  <asun@pelvetia>
-
-       * libatalk/nbp/nbp_lkup.c: oh my. nbp_lookup was fd leaky if there
-       was a problem.
-
-       * etc/atalkd/main.c (main): make sure that if -dontroute is
-       selected for all but one interface, that interface also gets
-       -dontroute set.
-
-1999-05-10  a sun  <asun@hecate.darksunrising.blah>
-
-       * etc/afpd/auth.c: re-wrote to deal with plug-in uams. it's much
-       smaller than it used to be.
-
-1999-05-09  a sun  <asun@hecate.darksunrising.blah>
-
-       * etc/afpd/uams/uam_guest.c, uam_pam.c, uam_passwd.c,
-       uam_randnum.c: uam modules. these should probably be moved out of
-       afpd (and into something like etc/uam_server) when the printing
-       stuff gets uam support.
-
-1999-05-08  a sun  <asun@hecate.darksunrising.blah>
-
-       * etc/afpd/uam.c: interface to user authentication modules.
-       it should eventually be moved to libatalk, but that's not
-       necessary until the printing uam stuff is done. everything is from
-       the server-side perspective, but that's only because there aren't
-       any client-side uses right now.
-
-       * libatalk/util/module.c: generic interface to run-time library
-       loading functions. right now, the dlfcn family and os x server's
-       NS-style way of doing things are the ones understood. in addition,
-       there's a DLSYM_PREPEND_UNDERSCORE for those systems that need it.
-
-       * libatalk/asp/asp_write.c (asp_wrtcont): log both the read and
-       write part of write continuations.
-
-1999-05-07  a sun  <asun@hecate.darksunrising.blah>
-
-       * etc/atalkd: added the ability to turn off routing for particular
-       interfaces. specify -dontroute for each interface that you don't
-       want to route.
-
-1999-05-06  a sun  <asun@hecate.darksunrising.blah>
-
-       * etc/afpd/auth.c: got rid of global clrtxtname and switched to
-       using obj->username.
-
-1999-05-04  a sun  <asun@hecate.darksunrising.blah>
-
-       * libatalk/dsi/dsi_write.c (dsi_write): dsi_write could loop
-       forever if there's a problem while it's being used. that's fixed.
-
-1999-05-01  a sun  <asun@hecate.darksunrising.blah>
-
-       * etc/afpd/directory.c (renamedir,copydir,deletedir): added bits
-       so that renaming a directory works across filesystems.
-
-1999-04-27  a sun  <asun@hecate.darksunrising.blah>
-
-       * etc/afpd/fork.c (getforkparams): report mtime if it's > than
-       what's stored in the header file.
-
-       * config/afpd.conf: incorporated a patch by Stefan Bethke to make
-       afpd.conf more understandable.
-
-       * sys/solaris/if.c: many of the firstnet/lastnet bits weren't
-       endian converted. that's fixed.
-
-       * libatalk/adouble/ad_lock.c (adf_find(x)lock): F_RD/WRLCK aren't
-       necessarily ORable, so use ADLOCK_RD/WR instead.
-       
-       (ad_fcntl_unlock): erk. fixed a typo that had the resource fork
-       unlock accidentally getting the data fork locks.
-
-1999-04-24  a sun  <asun@hecate.darksunrising.blah>
-
-       * etc/afpd/fork.c (afp_openfork): always try to create a resource
-       fork if asked.
-
-1999-04-21  a sun  <asun@hecate.darksunrising.blah>
-
-       * libatalk/adouble/ad_open.c, ad_read.c/ad_write.c, ad_flush.c:
-       turned the mmapped header stuff into and #ifdef
-       USE_MMAPPED_HEADERS option.
-
-       * libatalk/adouble/ad_open.c (ad_header_read): darn. i forgot that
-       the hfs fs doesn't currently have mmappable header files. rather
-       than implement that, i just reverted back to a modified version
-       of the old way of reading headers.
-
-1999-04-15  a sun  <asun@hecate.darksunrising.blah>
-
-       * etc/afpd/fork.c (afp_bytelock): byte locks become read locks on
-       read-only files.
-       
-       (afp_openfork): deal with read-only data forks that don't have
-       corresponding .AppleDouble files. we can't really do anything with
-       deny locks in this case. just make sure that read locks are set.
-
-       * etc/afpd/file.c (getfilparams): oops. got the parentheses wrong
-       around FILPBIT_FINFO. 
-
-       * etc/afpd/fork.c (afp_read): as we share open files now, check
-       for fork type against of_flags instead of just checking to see if
-       the file is open. this fixes a bug that caused resource forks to
-       get filled with data fork information.
-
-1999-04-09  a sun  <asun@porifera.zoology.washington.edu>
-
-       * sys/generic/Makefile: AFP/tcp now compiles on irix with quota
-       support.
-
-1999-04-09  a sun  <asun@mead1.u.washington.edu>
-
-       * sys/generic/Makefile: AFP/tcp now compiles on aix with quota
-       support.
-
-1999-04-09  a sun  <asun@saul6.u.washington.edu>
-
-       * sys/generic/Makefile: AFP/tcp part now compiles on digital unix
-       with quota support enabled.
-
-1999-04-08  a sun  <asun@hecate.darksunrising.blah>
-
-       * etc/afpd/volume.c, fork.c, file.c, directory.c, filedir.c,
-       config/AppleVolumes.default: added read-only volume option.
-
-       * etc/afpd/quota.c (uquota_getvolspace): modified for os x
-       server. 
-
-1999-04-03  a sun  <asun@hecate.darksunrising.blah>
-
-       * bin/megatron/macbin.c (bin_write): only pad if we need to do so 
-       (from <jk@espy.org>).   
-       (bin_header_write/read): fixed up screwed up file date
-       generation/reading with macbinary files. 
-
-       * bin/megatron: changed all of the bcopy/bzero/bcmp's to 
-       memcpy/memset/memcmp's. added macbinary III support.
-
-       * bin/megatron/macbin.c (bin_open): added --stdout as an option so
-       that we can stream macbinary file creation to stdout.
-
-       * bin/megatron/megatron.c: incorporated information patch (--header
-          and --macheader) from <fmorton@base2inc.com>.
-
-
-1999-04-02  a sun  <asun@hecate.darksunrising.blah>
-
-       * etc/afpd: whee! there are no more bcopy/bcmp's in this
-       directory. 
-
-       * libatalk: changed the bcopy/bzero's to memcpy/memset's. added in
-       dummy ints for some of the files that can get compiled to empty
-       objects. check for the type of msync() available as well.
-
-1999-03-31  a sun  <asun@hecate.darksunrising.blah>
-
-       * INSTALL/README.GENERIC: added information for a generic
-       architecture. It includes the information needed to get netatalk
-       to compile on a random unix platform.
-
-       * etc/afpd/quota.c: moved the quota stuff here so that we can
-       #ifdef it out on a machine without quota support.
-
-1999-03-30  a sun  <asun@hecate.darksunrising.blah>
-
-       * libatalk/adouble/ad_lock.c: reference count the locked ranges as
-       well. this prevents multiple read locks on the same byte range
-       from disappearing if one user disappears.
-       
-       (ad_fcntl_lock): here are the current rules for file
-       synchronization:
-          1) if there's a appledouble header, we use the beginning
-             of that for both data and resource forks.
-          2) if there isn't, we use the end of the data fork (or past the
-             end on 64-bit machines)
-       
-1999-03-28  a sun  <asun@hecate.darksunrising.blah>
-
-       * libatalk/adouble/ad_open.c (ad_refresh): okay. mmapping the
-       appledouble entry parts is done. 
-
-       * libatalk/cnid/cnid_add.c (cnid_add): prevent anyone from adding
-       in an illegal cnid.
-
-1999-03-27  a sun  <asun@hecate.darksunrising.blah>
-
-       * libatalk/adouble/ad_open.c (ad_refresh): started making the
-       appledouble header parsing more generic so that we can read in
-       arbitrary appledouble header files. i just mmap the parts that we
-       need. 
-
-1999-03-22  a sun  <asun@hecate.darksunrising.blah>
-
-       * etc/afpd/file.c (afp_copyfile): return the correct error
-       response on a failed copy. also, error if the file is already open
-       to prevent problems with locks. we really need to ad_lock
-        this during the copy
-
-1999-03-21  a sun  <asun@hecate.darksunrising.blah>
-
-       * etc/afpd/volume.c (readvolfile): switched volume options to
-       using ':' as a delimiter as that's one of the characters that's
-       not allowed as part of a mac filename.
-       (volset): changed access to allow/deny
-
-       * etc/afpd/auth.c (noauth_login): make sure that the username gets
-       set. 
-
-1999-03-17  a sun  <asun@hecate.darksunrising.blah>
-
-       * NOTE to myself: jeremy allison said that samba uses refcounts to
-       prevent close() from killing all the byte locks. so, i've started
-       converting afpd to using refcounting as well. luckily, we already
-       have of_findname, so we know when files are open. in cases where
-       files are already open, this will replace an ad_open with a lookup
-       into a hash table.
-
-       * etc/afpd/directory.c (getdirparams/getfilparams): check for
-       NULL names when getting directory/file names.
-
-       * etc/afpd/directory.{c,h} (DIRDID_ROOT/DIRDID_ROOT_PARENT): make
-       sure these are always in network byte order.
-
-1999-03-15  a sun  <asun@hecate.darksunrising.blah>
-
-       * etc/afpd/fork.c (afp_openfork): okay, fixed the file
-       synchronization bits. now, we use two bytes to do the read/write
-       stuff. when access is needed, a read lock is attempted. if a deny
-       lock is needed, a write lock is attempted. we even handle the
-       access None mode now by saving the access modes.
-
-       * etc/afpd/fork.h (AFPFORK_ACCMASK): started adding bits so that
-       we can obey all of the file synchronization rules.
-
-       * etc/afpd/fork.c (afp_bytelock): got the meaning of the clearbit
-       reversed. with helios lantest's lock/unlock 4000 times test, it
-       looks like i get <1 second overhead on my machine when using byte
-       locks. NOTE: this will get a little worse when serialization gets
-       added. in addition, 0x80000000 only works for 64-bit machines. i
-       reserve the last allowable bit for 32-bit machines. 
-
-       actually, both 64-bit machines and 32-bit machines use 0x7FFFFFFF
-       now as i'm able to trigger a kernel oops in linux with the 64-bit
-       code. 
-       
-       (afp_read/afp_write): make sure to use the same offset when doing
-       a tmplock.
-
-1999-03-14  a sun  <asun@hecate.darksunrising.blah>
-
-       * libatalk/adouble/ad_lock.c: i went and implemented a bunch of
-       stuff to get byte locks to work correctly (except for the
-       serialization) only to discover that files that use byte locks
-       also request a deny write mode. luckily, byte locks only cover up
-       to 0x7FFFFFFF. so, i'll just use 0x80000000 for the
-       synchronization locks.
-
-1999-03-08  a sun  <asun@hecate.darksunrising.blah>
-
-       * sys/{*bsd,ultrix,solaris,linux}/Makefile (depend): surround 
-       DEPS with double quotes so that multiple defines work.
-
-1999-03-06  a sun  <asun@hecate.darksunrising.blah>
-
-       * libatalk/adouble/ad_write.c, ad_read.c: make off off_t in size. 
-
-       * libatalk/adouble/ad_flush.c (adf_fcntl_relock), ad_lock.c
-       (adf_fcntl_locked): okay. fcntl locks now check against multiple
-       programs on the same machine opening the same file. current
-       problems with the mechanism that i don't want to fix unless
-       necessary: 
-               1) there's a race during the relock phase. serialization
-                  would solve that.
-               2) it assumes that each fd only locks a single contiguous
-                  range at a time. keeping a list of locked ranges would
-                  solve that. 
-       
-       also, i changed the default to using fcntl locks. if the above two
-       are really necessary, i'll probably switch to something a little
-       more featureful like the berkeley db's lock manager.
-
-       (note to myself: stuff new from asun2.1.3 from 1999-03-03)
-       
-1999-03-05  a sun  <asun@hecate.darksunrising.blah>
-
-       * libatalk/adouble/ad_lock.c: got rid of the endflag checks to
-       reduce system calls a little. 
-
-       * etc/afpd/auth.c (getname): do a case-insensitive compare on the
-       login name as well.
-
-       * sys/solaris/Makefile: added 64-bit solaris patch from
-       <jason@pattosoft.com.au>.
-
-1999-03-03  a sun  <asun@hecate.darksunrising.blah>
-
-       * include/netatalk/endian.h: make solaris 2.5 complain less.
-
-       * bin/adv1tov2/adv1tov2.c, libatalk/adouble/ad_open.c (ad_v1tov2):
-       fixed a couple problems with the adv1tov2 stuff.
-
-1999-02-26  a sun  <asun@hecate.darksunrising.blah>
-
-       * etc/afpd/volume.c (afp_openvol): erk. the volume password gets
-       aligned along an even boundary.
-
-1999-02-23  a sun  <asun@hecate.darksunrising.blah>
-
-       * etc/afpd/volume.c (readvolfile): added volume password support. 
-
-1999-02-14  a sun  <asun@hecate.darksunrising.blah>
-
-       * etc/atalkd/multicast.c (addmulti): added FreeBSD's data-link
-       layer multicast setting bits.
-
-       * libatalk/adouble/ad_open.c (ad_v1tov2): make sure to stick in
-       prodos field info when converting.
-
-       * rc.atalk.redhat: added pidof checking in case the machine
-       crashes. also added rc.atalk.wrapper to the redhat rc script
-       installation. 
-
-1999-02-07  a sun  <asun@hecate.darksunrising.blah>
-
-       * etc/afpd/fork.c (afp_setforkparams): make sure to do better
-       error detection here and more fully report error conditions.
-       
-       (flushfork): make sure to flush the header if necessary (rfork
-       length changed or modification date needs to be set).
-
-       (afp_write): ugh. this wasn't returning the right values for the
-       last byte written if the endflag was set. in addition, it was
-       setting the modification date. that should be left to FPCloseFork
-       and FPFlush(Fork). this fixes a problem that shows up with
-       QuarkXPress. 
-
-       NOTE: as of now, changes to the rfork info are the only things
-       that aren't flushed immediately when altered. 
-
-       * etc/afpd/fork.c (get/setforkparams), ofork.c: what ugliness. we
-       need to report bitmap errors if we try to fiddle with the wrong
-       fork. i added an of_flags field to keep things sorted.
-
-       * libatalk/adouble/ad_open.c (ad_v1tov2): oops. in all of the
-       movement, i forgot to make sure that the pre-asun2.2.0 features
-       still compile.
-
-1999-02-06  a sun  <asun@hecate.darksunrising.blah>
-
-       * etc/afpd/filedir.c (afp_moveandrename): make sure to save the
-       old name even when it's a directory.
-
-       * globals.h: added oldtmp and newtmp to AFPObj to reduce the
-       number of buffers used. use these when needed in afp_* calls.
-
-       * etc/afpd/directory.c (deletecurdir): delete stray .AppleDouble
-       files when deleting a directory.
-
-1999-02-05  a sun  <asun@hecate.darksunrising.blah>
-
-       * etc/afpd/file.c (afp_createfile): fixed a hard create error
-       check bug. 
-
-       * fixed up a few bobbles in the netatalk-990130 merge.
-
-       * the noadouble option should be pretty much implemented. here's
-       how it goes:
-               when a directory is created, the corresponding
-               .AppleDouble directory is not.
-               
-               comments, dates, and other file attributes will get
-               silently ignored and not result in the creation of a new
-               .AppleDouble directory.
-
-               however, if anything possessing a resource fork is copied
-               into that directory, the corresponding .AppleDouble
-               directory will be created. once this happens, any
-               other file in the directory can acquire an AppleDouble
-               header file in the future.
-               
-1999-02-03  a sun  <asun@hecate.darksunrising.blah>
-
-       * merged in the rest of netatalk-990130.
-
-       * sys/solaris: merged in netatalk-990130 changes.
-
-       * etc/afpd/file.c,fork.c,desktop.c libatalk/adouble/ad_sendfile.c:
-       tested and fixed the sendfile bits on linux. it looks like linux
-       doesn't permit socket -> file sendfiles yet.
-
-       * etc/afpd/fork.c (afp_read): we can't stream FPRead's with
-       newline character checking on.
-
-1999-02-02  a sun  <asun@hecate.darksunrising.blah>
-
-       * etc/afpd/fork.c (afp_flush), ofork.c (of_flush): FPFlush
-       operates on a per-volume basis.
-
-1999-01-31  a sun  <asun@hecate.darksunrising.blah>
-
-       * etc/afpd/file.c (copyfile): sendfile bits added here also.
-
-       * etc/afpd/desktop.c (afp_geticon): added sendfile bits here as
-       well. 
-
-       * libatalk/adouble/ad_sendfile.c (ad_writefile/ad_readfile):
-       implemented sendfile bits. currently, there's support for linux
-       and freebsd. unfortunately, freebsd's implementation doesn't allow
-       file->file or socket->file copies. bleah.
-
-1999-01-30  a sun  <asun@hecate.darksunrising.blah>
-
-       * etc/afpd/file.c (setfilparams), directory (setdirparams),
-       volume.c (volset): added in the beginnings of a NOADOUBLE option
-       for those that don't want AppleDouble headers to be created by
-       default. it doesn't really work that well right now.
-
-1999-01-29  a sun  <asun@hecate.darksunrising.blah>
-
-       * libatalk/adouble/ad_open.c (ad_v1tov2): separated v1tov2 bits
-       from ad_refresh. made broken v1 header checking the default. fixed
-       broken v1 date checking. now, it just checks to see if the v1
-       MDATE is > than st_mtime by 5 years.
-
-       * etc/afpd/directory.c: make date setting alter directory dates as
-       well. 
-
-1999-01-24  a sun  <asun@hecate.darksunrising.blah>
-
-       * etc/afpd/afp_dsi.c (alarm_handler,afp_over_dsi): added a
-       CHILD_RUNNING flag to prevent afpd from timing out on long copies.
-
-1999-01-21  a sun  <asun@hecate.darksunrising.blah>
-
-       * etc/afpd/volume.c (afp_openvol), libatalk/cnid/cnid_nextid.c:
-       shift the beginning of the fake did's if necessary.
-
-       * libatalk/adouble/ad_open.c (ad_refresh): fixed screwed-up date
-       detection code.
-
-       * libatalk/cnid/cnid_add.c,cnid_open.c,cnid_close.c: made some
-       changes so that the CNIDs will still work even when the .AppleDB
-       directory is read-only. if you're still allowed to create files on
-       these volumes, you'll get a temporary id for those.
-
-1999-01-20  a sun  <asun@hecate.darksunrising.blah>
-
-       * libatalk/cnid/{cnid_close.c,cnid_open.c}: added bits so that log
-       files get cleared out on cnid_close() if it's the last user for a
-       volume.
-
-1999-01-18  a sun  <asun@hecate.darksunrising.blah>
-
-       * etc/afpd/volume.c (afp_setvolparams): added FPSetVolParms. this
-       allows us to set the backup date on the server.
-
-       * etc/afpd/file.c (afp_exchangefiles): whee! we now have
-       FPExchangeFiles. we also have FPDeleteID, so that only leaves us
-       with FPCatSearch to do.
-
-1999-01-16  a sun  <asun@hecate.darksunrising.blah>
-
-       * sys/solaris/ddp.c (ddp_rput): added a couple htons()'s for the
-       net addresses.
-
-1999-01-11  a sun  <asun@hecate.darksunrising.blah>
-
-       * etc/afpd/volume.c (volset, afp_openvol): you can now specify a
-       dbpath= in AppleVolumes.* for the CNID database.
-
-       * libatalk/adouble/ad_open.c (ad_refresh): if we build in an
-       appledouble v1 environment, turn on v1compat by default.
-
-1999-01-10  a sun  <asun@hecate.darksunrising.blah>
-
-       * libatalk/adouble/ad_open.c (ad_refresh): added v1compat option
-       to handle broken ad headers.
-
-       * etc/afpd/file.c (setfilparams): we need to make sure that we
-       flush the file if we've created it even if there's an error.  the
-       magic number/version don't get saved if we don't.
-
-       * etc/afpd/appl.c, etc/afpd/directory.c, etc/afpd/desktop.c: added
-       DIRBITS to mkdirs.
-
-1998-12-30  a sun  <asun@hecate.darksunrising.blah>
-
-       * etc/afpd/volume.c (afp_openvol): got rid of unnecessary v_did.
-
-       * etc/afpd/file.c (afp_resolveid, afp_createid): added these two
-       in. 
-
-       * well, what do you know? the cnid stuff compiles in. 
-
-1998-12-29  a sun  <asun@hecate.darksunrising.blah>
-
-       * etc/afpd/fork.c, directory.c, file.c, filedir.c, volume.c,
-       enumerate.c: added in stubs for CNID database conditional on
-       AD_VERSION > AD_VERSION1.
-
-       * etc/afpd/nls/makecode.c: added iso8859-1 mapping.
-
-1998-12-27  a sun  <asun@hecate.darksunrising.blah>
-
-       * bin/adv1tov2/adv1tov2.c: turn non-printable ascii characters
-       into hex code as well.
-
-1998-12-21  a sun  <asun@hecate.darksunrising.blah>
-
-       * etc/afpd/auth.c: fixed FPChangePW for 2-way randnums.
-
-1998-12-15  a sun  <asun@hecate.darksunrising.blah>
-
-       * etc/afpd/fork.c (read_file/write_file): do crlf translation in
-       both directions so that we can recover from problems if
-       necessary. 
-
-1998-12-14  a sun  <asun@hecate.darksunrising.blah>
-
-       * bin/adv1tov2/adv1tov2.c: small utility program that recursively
-       descends a directory and converts everything it sees into
-       AppleDouble v2.
-
-1998-12-13  a sun  <asun@hecate.darksunrising.blah>
-
-       * libatalk/adouble/ad_flush.c (ad_rebuild_header): moved the
-       header rebuilding here so that ad_refresh can use it.
-
-       * libatalk/adouble/ad_open.c (ad_refresh): added locking to v1->v2
-       conversion.
-
-       * bin/megatron/asingle.c: yuk. removed all of
-       the duplicate stuff here and had it use the #defines in adouble.h.  
-
-       * libatalk/adouble/ad_open.c (ad_refresh): finished v1 -> v2
-       conversion routine. we still need a shortname creator and a cnid
-       database for the v2 features to be useful. 
-
-1998-12-11  a sun  <asun@hecate.darksunrising.blah>
-
-       * libatalk/adouble/ad_open.c (ad_refresh): punt if we get a file
-       that we don't understand.
-
-1998-12-10  a sun  <asun@hecate.darksunrising.blah>
-
-       * etc/afpd/desktop.c (utompath,mtoupath): simplified the codepage
-       stuff. also made sure to lower/upper the 8-bit characters as
-       well. 
-
-       * libatalk/util/strdicasecmp.c: the casemapping had a few wrong
-       characters. 
-
-       * etc/afpd/fork.c (getforkparams): make sure that the ROpen/DOpen
-       attribute bits are in the correct byte ordering.
-
-1998-12-09  a sun  <asun@hecate.darksunrising.blah>
-
-       * etc/afpd/volume.c (volset): made prodos an option to options=
-       flag. also added crlf as an option.
-
-       * libatalk/adouble/ad_open.c (ad_refresh): fix up times if
-       necessary. 
-       (ad_open): deal correctly with 0-length files by treating them as
-       newly created. 
-
-       * etc/afpd/volume.c (getvolparams), file.c (get/setfilparams),
-       fork.c (getforkparams), directory.c (get/setdirparams): finished
-       adding appledouble version 1 and 2 date conversion. also added
-       attribute setting. 
-       
-       * etc/afpd/volume.c (getvolparams): make sure to flush the header
-       file if we needed to fiddle with it. 
-
-       * libatalk/adouble/ad_date.c, ad_attr.c: date/attribute
-       setting/retrieval code. 
-
-       * libatalk/adouble/ad_open.c (ad_open): initialize date
-       structures here instead of elsewhere. 
-
-1998-12-07  a sun  <asun@hecate.darksunrising.blah>
-
-       * etc/afpd/directory.c, fork.c, volume.c, file.c: added unix<->afp
-       time conversion code. 
-
-1998-12-05  a sun  <asun@hecate.darksunrising.blah>
-
-       * etc/afpd/volume.c (volset): changed prodos setting to
-       prodos=true. 
-
-1998-12-04  a sun  <asun@hecate.darksunrising.blah>
-
-       * etc/afpd/volume.c (volset): okay. you now have the following
-       options to casefold: lowercase,uppercase,xlatelower,xlateupper
-               tolower    -> lowercases everything in both directions
-               toupper    -> uppercases everything in both directions
-               xlatelower -> client sees lowercase, server sees uppercase
-               xlateupper -> client sees uppercase, server sees lowercase
-
-       NOTE: you only should use this if you really need to do so. this
-       and the codepage option can cause mass confusion if applied
-       blindly to pre-existing directories.
-       
-1998-12-03  a sun  <asun@hecate.darksunrising.blah>
-
-       * etc/afpd/desktop.c (utompath,mtoupath), etc/afpd/volume.h: added
-       multiple options to casefold. bits 0 and 1 deal with MTOU, and
-       bits 2 and 3 deal with UTOM. i did it that way so that you can
-       casefold in one direction only or in both directions if
-       desired. needless to say, setting both bits for UTOM or MTOU
-       doesn't make any sense. right now, toupper takes precedence in
-       MTOU, and tolower takes precedence in UTOM.
-
-1998-12-02  a sun  <asun@hecate.darksunrising.blah>
-
-       * etc/afpd/afp_options.c (afp_options_*): added -uampath and
-       -codepagepath to the list of available options. they specify the
-       directories to look for uam modules and codepages,
-       respectively. currently, -uampath doesn't do anything.
-
-       * etc/afpd/volume.c (readvolfile): spruced up options to
-       AppleVolumes files. now you can have mtoufile=<codepage.x>,
-       utomfile=<codepage.y>, casefold=<num> for volumes.
-
-       * etc/afpd/desktop.c (utompath,mtoupath): added
-       codepage/casefolding support. casefold is currently an int that
-       could have multiple actions. right now, i just lowercase in
-       mtoupath and uppercase in utompath.
-
-       * etc/afpd/ofork.c (of_alloc, of_findname, of_rename): added vol
-       as an additional specifier so that we don't have problems with
-       the same path names on multiple volumes. 
-
-1998-11-29  a sun  <asun@purgatorius.zoology.washington.edu>
-
-       * etc/afpd/volume.c (getvolparams): added AFP2.1 volume attribute
-       bits. 
-
-1998-11-24  a sun  <asun@purgatorius.zoology.washington.edu>
-
-       * etc/atalkd/config.c (readconf, getifconf): added IFF_SLAVE to
-       prevent atalkd from trying to use a slave channel.
-
-1998-11-23  a sun  <asun@purgatorius.zoology.washington.edu>
-
-       * etc/afpd/volume.c (getvolparams): we shouldn't set the custom
-       icon bit by default on the root directory. that screws up pre-OS 8
-       systems.
-
-1998-11-19  a sun  <asun@purgatorius.zoology.washington.edu>
-
-       * libatalk/dsi/dsi_getsess.c (dsi_getsession): ignore SIGPIPE's
-       so that we can gracefully shut down the server side.
-
-       * etc/afpd/afp_dsi.c (afp_over_dsi), etc/afpd/afp_options.c,
-       libatalk/dsi/dsi_getsess.c (dsi_getsession),
-       libatalk/asp/asp_getsess.c (asp_getsession): made the tickle timer
-       interval an option (-tickleval <sec>).
-       
-       * etc/afpd/afp_dsi.c (afp_dsi_timedown): added child.die so that
-       we don't stomp on a shutdown timer. libatalk/dsi/dsi_read.c,
-       dsi_write.c both save/restore the old timer, so they don't really
-       care what the actual value is. 
-       
-1998-11-18  a sun  <asun@purgatorius.zoology.washington.edu>
-
-       * due to the recent obsession with bug fixing and low-level dsi
-       cleanups, i've decided that this should really be asun2.1.1
-       instead of asun2.1.0a.
-
-1998-11-17  a sun  <asun@purgatorius.zoology.washington.edu>
-
-       * libatalk/dsi/dsi_tcp.c (dsi_tcp_open): moved the afpd connection
-       announcement here from etc/afpd/afp_dsi.c. 
-       
-       * libatalk/dsi/dsi_stream.c: moved all of the read/write functions
-       into here as they're pretty generic. now, the protocol specific
-       stuff only handles open and close. 
-
-       * etc/afpd/fork.c (afp_read/write), desktop.c (afp_geticon),
-       file.c (copyfile), include/atalk/dsi.h (dsi_writefile/readfile):
-       added initial stubs for sendfile support. i still need to go
-       through and calculate the appropriate offsets to use. 
-
-       * libatalk/dsi/dsi_read.c, dsi_write.c: disable the interval timer
-       instead of just ignoring it.
-
-       * etc/afpd/desktop.c (afp_geticon), etc/afpd/fork.c (afp_read),
-       libatalk/dsi/dsi_read.c (dsi_readinit, dsi_readinit): modified the
-       dsi_read interface to return errors so that i can kill things
-       gracefully. 
-
-1998-11-16  a sun  <asun@purgatorius.zoology.washington.edu>
-
-       * libatalk/dsi/dsi_tcp.c (dsi_tcp_send/dsi_tcp_write): erk. read()
-       and write() treat a return of 0 differently. 
-
-1998-11-16  a sun  <asun@hecate.darksunrising.blah>
-
-       * libatalk/dsi/dsi_read.c (dsi_readinit): make sure to stick in
-       the error code.
-
-1998-11-15  a sun  <asun@purgatorius.zoology.washington.edu>
-
-       * etc/afpd/fork.c (afp_read): re-ordered some of the checks here
-       to return earlier on 0-sized files.
-
-1998-11-13  a sun  <asun@purgatorius.zoology.washington.edu>
-
-       * etc/afpd/afp_dsi.c (afp_over_dsi): moved the dsi->noreply toggle
-       check to here from dsi_cmdreply.
-
-1998-11-11  a sun  <asun@purgatorius.zoology.washington.edu>
-
-       * etc/atalkd/zip.c (zip_packet): make sure to copy multicast zone
-       back out. (reported by Michael Zuelsdorff <micha@dolbyco.han.de>)
-
-1998-11-09  a sun  <asun@purgatorius.zoology.washington.edu>
-
-       * etc/afpd/directory.c (getdirparams): changed unknown bit reply
-       code to AFPERR_BITMAP instead of AFPERR_PARAM.
-
-1998-11-06  a sun  <asun@purgatorius.zoology.washington.edu>
-
-       * etc/afpd/enumerate.c (afp_enumerate), directory.c (renamedir):
-       fixed a couple of failed realloc leaks.
-
-       * etc/afpd/filedir.c (afp_moveandrename, afp_rename): added bits
-       to deal with case-insensitive, case-preserving filesystems.
-
-1998-10-30  a sun  <asun@purgatorius.zoology.washington.edu>
-
-       * etc/afpd/auth.c: fixed randnum password changing check. 
-
-1998-10-27  a sun  <asun@purgatorius.zoology.washington.edu>
-
-       * etc/atalkd/main.c: add a check for SIOCATALKDIFADDR if
-       SIOCDIFADDR fails.
-       
-       * etc/afpd/volume.c (getvolparams): ad_open had the wrong
-       parameters. 
-
-       * etc/afpd/unix.c (setdeskowner): added a little extra space to
-       prevent buffer overflows here.
-
-1998-10-26  a sun  <asun@purgatorius.zoology.washington.edu>
-
-       * sys/linux/Makefile: fixed PAM message.
-
-       * sys/solaris/Makefile: make failure to ln -s a non-fatal error. 
-
-       * etc/papd/session.c, bin/pap/pap.c: changed sequence count to
-       wrap from 0 -> 1 instead of from 0xFFFF -> 1.
-
-       * etc/afpd/filedir.c (afp_rename, afp_moveandrename): actually, we
-       should check against the entire unix name.
-       
-1998-10-21  a sun  <asun@purgatorius.zoology.washington.edu>
-
-       * etc/afpd/filedir.c (afp_rename, afp_moveandrename): make sure
-       to check against mac name.
-
-1998-10-19  a sun  <asun@purgatorius.zoology.washington.edu>
-
-       * etc/afpd/auth.c (afp_changepw): make password changing deal
-       correctly with "real" user names. also, moved seteuid() to before
-       the pam_authenticate() bit as shadow passwords need that.
-
-       * etc/afpd/enumerate.c (afp_enumerate): make sure to check the mac
-       name against MACFILELEN.
-
-1998-10-16  a sun  <asun@purgatorius.zoology.washington.edu>
-
-       * etc/afpd/file.c (renamefile), filedir.c (afp_rename),
-       directory.c (renamedir): use strndiacasecmp() for AFPERR_SAMEOBJ
-       checks. also make sure test occurs before checking to see if the
-       destination exists.
-
-1998-10-15  a sun  <asun@purgatorius.zoology.washington.edu>
-
-       * etc/afpd/auth.c (afp_changepw): fixed a bit of brain damage. i
-       forgot that password changing needs root privileges to work.
-
-       * etc/afpd/auth.c (PAM_conversation): the supplied code was
-       incorrect. i cleaned it up a bit.
-
-       * sys/linux/Makefile: fixed the installation bits.
-
-1998-10-14  a sun  <asun@purgatorius.zoology.washington.edu>
-
-       * etc/afpd/auth.c (afp_changepw): don't kill the connection here
-       if there's a problem.
-
-1998-10-10  a sun  <asun@purgatorius.zoology.washington.edu>
-
-       * etc/afpd/enumerate.c, fork.c, ofork.c, file.c,
-       globals.h, directory.c, auth.c: #defined MACFILELEN and used
-       that. also made sure that files > MACFILELEN never show up.
-
-1998-09-25  a sun  <asun@purgatorius.zoology.washington.edu>
-
-       * etc/{afpd,papd,atalkd}/bprint.c (bprint): got rid of the
-       spurious pointer dereference.
-
-       * etc/afpd/ofork.c (of_alloc/of_rename): allocate the max mac file
-       length so that we don't need to realloc.
-
-       * etc/afpd/filedir.c (afp_rename, afp_moveandrename): make sure to
-       return AFPERR_BUSY if the dest has an ofork open.
-
-       * etc/afpd/file.c (renamefile), directory.c (renamedir), filedir.c
-       (afp_rename): return AFPERR_SAMEOBJ if source == dest
-
-1998-09-21  a sun  <asun@purgatorius.zoology.washington.edu>
-
-       * etc/afpd: went through and looked for places that needed to use
-       curdir instead of dir. i think i have them all right now.
-
-       * etc/afpd/filedir.c (afp_moveandrename): wasn't keeping track of
-       curdir correctly. what this really means is that cname should be
-       fixed to return everything it changes as opposed to changing a
-       global variable. 
-
-1998-09-19  a sun  <asun@purgatorius.zoology.washington.edu>
-
-       * etc/afpd/config.c (configinit): do the right thing if
-       AFPConfigInit fails.
-
-1998-09-18  a sun  <asun@purgatorius.zoology.washington.edu>
-
-       * etc/afpd/config.c (ASP/DSIConfigInit, configfree): how 
-       embarrassing. i wasn't doing refcounts correctly.
-
-1998-09-17  a sun  <asun@purgatorius.zoology.washington.edu>
-
-       * etc/afpd/nfsquota.c (getnfsquota): ultrix uses dqb_bwarn instead
-       of dqb_btimelimit.
-
-       * sys/ultrix/Makefile: ultrix understands the old rquota format. 
-
-       * etc/afpd/ofork.c (of_findname): erk. forgot to only search in
-       the current directory. 
-       (of_rename): erk. changed it to handle renaming a file that has
-       been opened multiple times.
-
-       * etc/atalkd: made sure that if you don't specify -router, things
-       are as they were before. 
-
-1998-09-13  a sun  <asun@purgatorius.zoology.washington.edu>
-
-       * etc/afpd/status.c (status_flags): forgot to turn on password
-       setting if randnum passwords are being used.
-
-1998-09-11  a sun  <asun@purgatorius.zoology.washington.edu>
-
-       * etc/afpd/unix.c (setdirmode): erk. make sure only to setgid on
-       directories. 
-
-       * bin/aecho/aecho.c (main): incorporated -c <num> (ala ping) patch
-       from "Fred Lindberg" <lindberg@id.wustl.edu>.
-
-1998-09-03  a sun  <asun@purgatorius.zoology.washington.edu>
-
-       * etc/afpd/directory.c (afp_closedir, afp_opendir): added these in
-       for more AFP 2.0 compliance. unfortunately, apple's appleshare
-       client doesn't like non-fixed directory ids.
-
-1998-08-31  a sun  <asun@purgatorius.zoology.washington.edu>
-
-       * etc/afpd/volume.c (accessvol): the accessible volume list can
-       now be controlled by groups and usernames. just use something of
-       the following form: @group,name,name2,@group2,name3
-
-       NOTE: you can't have any spaces, and the parser forces you to
-       include all options. in this case, there are some apple II options
-       that need to be entered. they need to go away soon anyway.
-
-       * etc/afpd/auth.c (getname): oops. i forgot to copy the gecos
-       field into a temporary buffer before calling strtok.
-
-1998-08-29  a sun  <asun@hecate.darksunrising.blah>
-
-       * etc/atalkd/main.c (as_timer), rtmp.c (rtmp_delzones): when the 
-       last router on an interface goes down, we need to delete the
-       interface's zone table.
-
-1998-08-28  a sun  <asun@purgatorius.zoology.washington.edu>
-
-       * etc/afpd/status.c (afp_getsrvrinfo): although it's never used,
-       i've added this in to increase AFP compliance.
-
-       * etc/afpd/auth.c (afp_getuserinfo): added FPGetUserInfo -- this
-       should make afpd compatible with OS 8.5's Nav Services.
-
-       * etc/atalkd/config.c,main.c: -router now specifies router mode
-       with any number of interfaces.
-
-1998-08-27  a sun  <asun@purgatorius.zoology.washington.edu>
-
-       * etc/atalkd/main.c (as_timer): well, i figured out how to set up
-       atalkd as a single-interface router. now, you can get zones with
-       only single interfaces! i'm only waiting on wes for the approved
-       configuration toggle.
-
-1998-08-26  a sun  <asun@purgatorius.zoology.washington.edu>
-
-       * libatalk/adouble/ad_lock.c, include/atalk/adouble.h: turned the
-       ADLOCK_* into real #defines and added translations in the
-       lock-type specific functions. this should make it easier to
-       recompile things without screwing up.
-
-1998-08-26  a sun  <asun@hecate.darksunrising.blah>
-
-       * etc/atalkd/nbp.c (nbp_packet): forgot to handle another local
-       zone case.
-
-1998-08-25  a sun  <asun@hecate.darksunrising.blah>
-
-       * etc/afpd/status.c (status_server): changed status_server to
-       use only the obj part of obj:type@zone-style names.
-
-       * etc/atalkd/nbp.c (nbp_packet): unregistering wasn't handling
-       zones properly. it was matching on anything but the actual zone.
-
-1998-08-18  a sun  <asun@purgatorius.zoology.washington.edu>
-
-       * etc/afpd/auth.c (clrtxt_login): added pam_set_time(PAM_TTY) so
-       that solaris' pam session setup doesn't crap out.
-
-1998-08-17  a sun  <asun@purgatorius.zoology.washington.edu>
-
-       * etc/atalkd/multicast.c (zone_bcast): fixed to do the right thing
-       with zip multicast info.
-
-1998-08-15  a sun  <asun@purgatorius.zoology.washington.edu>
-
-       * etc/afpd/nfsquota.c: made the old-style rquota fields dependent
-       upon -DUSE_OLD_RQUOTA and defined that for sunos. also included
-       <sys/time.h> for ultrix breakage.
-
-1998-08-13  a sun  <asun@purgatorius.zoology.washington.edu>
-
-       * etc/afpd/filedir.c (afp_rename), etc/afpd/ofork.c (of_rename): i
-       knew that speeding up of_findname would be useful. in any case, i
-       discovered the source of yet another small AFP non-compliance that
-       was confusing WordPerfect. on an afp_rename, we also need to
-       rename the corresponding ofork. i've added an of_rename() to do
-       this.
-
-1998-08-13  a sun  <asun@hecate>
-
-       * etc/afpd/ofork.c (of_dealloc,of_alloc): sped up dealloc by
-       sticking refnum in ofork.
-
-1998-08-12  a sun  <asun@hecate>
-
-       * etc/afpd/fork.c (afp_openfork): added already open attribute
-       bits.
-
-       * etc/afpd/ofork.c: added a hashed of_findname.
-
-1998-08-06  a sun  <asun@purgatorius.zoology.washington.edu>
-
-       * etc/afpd/fork.c (afp_openfork): fixed a problem with opening
-       forks from read-only non-appledouble media.
-
-1998-07-23  a sun  <asun@purgatorius.zoology.washington.edu>
-
-       * etc/afpd/afs.c (afs_getvolspace), etc/afpd/volume.c
-       (getvolspace): modified them to treak afs like the other
-       getvolspaces w.r.t. VolSpace.
-
-1998-07-21  a sun  <asun@purgatorius.zoology.washington.edu>
-
-       * etc/afpd/unix.c (mountp): erk. i forgot that symlinks are often
-       used for filesystems. nfs quotas sometimes failed as a
-       result. that's fixed now.
-
-1998-07-20  a sun  <asun@purgatorius.zoology.washington.edu>
-
-       * etc/afpd/auth.c (login): added a -DRUN_AS_USER #define so that
-       it's simple to run the server process as a non-root user.
-
-1998-07-17  a sun  <asun@purgatorius.zoology.washington.edu>
-
-       * etc/afpd/nfsquota.c (callaurpc, getnfsquota), volume.h: it turns
-       out that i was opening lots of sockets with callaurpc. now, the
-       socket gets saved and reused.
-
-       NOTE: quota-1.55-9 from redhat 5.x doesn't return the correct size
-       for rquota's bsize. unless fixed, rquota will report incorrect
-       values. 
-       
-1998-07-08  a sun  <asun@purgatorius.zoology.washington.edu>
-
-       * etc/afpd/uam/README: added some preliminary ideas on a
-       plug-in uam architecture. in addition, this should allow arbitrary
-       afp function replacement. eventually, auth.c should get a
-       bit cleaner.
-
-1998-07-07  a sun  <asun@purgatorius.zoology.washington.edu>
-
-       * etc/afpd/nfsquota.c: added headers and redefined a couple
-       structure fields so that sunos4 compiles.
-
-       * libatalk/compat/rquota_xdr.c: compile if we're using glibc <
-       2. this should get redhat 4.2 machines. NOTE: they're still
-       missing librpcsvc.a, so they'll need to remove that from the
-       etc/afpd/Makefile. 
-
-1998-07-06  a sun  <asun@purgatorius.zoology.washington.edu>
-
-       * libatalk/compat/rquota_xdr.c: it turns out that solaris is
-       missing a couple functions needed for rquota support. here they
-       are. 
-
-       * etc/afpd/unix.c (mountp): fixed the nfs detection for
-       solaris. we still need bsd and ultrix.
-
-1998-07-05  a sun  <asun@hecate>
-
-       * include/atalk/adouble.h: marked out space for appledouble v2. 
-
-1998-07-04  a sun  <asun@hecate>
-
-       * etc/afpd: plugged up some ad_open leaks. made sure that we don't
-       get negative numbers for length fields and such.
-       
-1998-07-04  a sun  <asun@hecate>
-
-       * etc/afpd/nfsquota.c (getnfsquota): added nfs rquota
-       support. Robert J. Marinchick <rjm8m@majink1.itc.virginia.edu>
-       provided the initial bits from the bsd quota program. 
-
-       * etc/afpd/unix.c (getquota): made getquota call getfsquota or
-       getnfsquota depending upon the type of fs. 
-
-       * etc/afpd/unix.c (mountp/special): munged mountp and
-       special to return either the nfs mount point or the fs
-       device. set the vol->v_nfs flag if it's nfs.
-
-       * etc/afpd/volume.c (getvolspace): xbfree and xbtotal will now
-       honor results returned from uquota_getvolspace.
-       
-1998-06-29  a sun  <asun@purgatorius.zoology.washington.edu>
-
-       * etc/afpd/file.c (copyfile): mmapping the file copy only helps on
-       multiple copies. as that's not the case here, i've reverted to
-       just doing read + write.
-       
-1998-06-28  a sun  <asun@purgatorius.zoology.washington.edu>
-
-       * sys/linux/Makefile: fixed the redhat-style atalk
-       installation. also, it doesn't over-write an existing
-       /etc/rc.d/init.d/atalk file.
-
-       * etc/afpd, libatalk/adouble/ad_write.c: removed <sys/file.h> and
-       </usr/ucbinclude/sys/file.h> so that we rely upon adouble.h.
-
-1998-06-19  a sun  <asun@purgatorius.zoology.washington.edu>
-
-       * changed sys/linux/Makefile to install a redhat-style sysv atalk
-       script instead of the bsd one.
-
-       * include/atalk/adouble.h: moved same-name list stub to struct
-       ad_adf. 
-       
-Thu Jun 18 18:20:28 1998  a sun  <asun@purgatorius>
-
-       * changed to asunx.y.z notation as i was getting tired of
-       increasing numbers. as this version is undergoing a fairly
-       substantial overhaul, i bumped it to 2.1.0. don't ask why asun1.0
-       never existed. i just started at 2.0.
-
-       * ofork (etc/afpd/{ofork.c,ofork.h,fork.c}: put in skeleton code
-       for hashed-by-name oforks and oforks which group by name to help
-       with byte locks and of_findname.
-
-       * adouble (include/atalk/adouble.h): started implementing
-       appledouble v2. mostly, i added bits to headers. v2 has wonderful
-       bits that should make prodos support much less clunky, allow
-       persistent dids, and allow msdos support.
-
-       * finder info: added bits to directory.c and file.c describing the
-       actual contents of finder info (from IM: Toolbox
-       Essentials). also, set default directory view to an allowed value
-       thanks to a suggestion from the appledouble v2 specs. that should
-       help with read-only media.
-
-       * etc/afpd/{directory.c,volume.c,afs.c,directory.h}: added
-       DIRDID_ROOT and DIRDID_ROOT_PARENT so people know that these did's
-       are reserved.
-       
-Wed Jun 17 11:54:49 1998  a sun  <asun@purgatorius>
-
-       * well, i'm starting a changelog as i keep forgetting what i've
-       done. 
-
-       * locks: revamped them to be more in line with what should
-       happen. currently, i've reverted back to flock-style locks as i'll
-       need to stick in more code to get fcntl-style locks to work
-       properly. specifically, i think modifying of_alloc/of_dealloc to
-       keep track of locks, fds, and names should solve the problem with
-       fcntl locks being process-specific and not fd specific.
-
index 15cf32b5099d3663024211278639c478e2f1cc57..1679f9dd453d75df6ee8bd4bf23c5e2a05c35843 100644 (file)
@@ -2,7 +2,7 @@
 
 SUBDIRS = libatalk bin config etc man contrib distrib include sys doc macros
 
-EXTRA_DIST = CONTRIBUTORS COPYRIGHT COPYING ChangeLog \
+EXTRA_DIST = CONTRIBUTORS COPYRIGHT COPYING NEWS\
        TODO VERSION services.atalk
 
 ACLOCAL_AMFLAGS = -I macros
diff --git a/NEWS b/NEWS
index c2f17d377cb2dde238aa21504d25e9b0dd3a9415..cfaa79a53b2f3093a176320d287c820282058226 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,205 @@
+Changes in 2.0.0
+================
+
+* UPD: afpd: add an error message if -ipaddr parameter cannot be parsed
+* UPD: updated documentation
+* FIX: afpd: fix a file descriptor and memory leak with OSX ._ resource fork
+* FIX: afpd: Prevent overwriting a file by renaming a file in the same 
+       directory to the same name. Won't work with OSX, the dest file gets 
+       deleted by OSX first.
+* FIX: sometimes '0' was used instead of 0 for creator/type
+* FIX: removed setpgrp check from configure, we don't use it anymore and
+       it doesn't work with cross compile.
+* FIX: fix for Solaris "make maintainer-clean", from Alexander Barton
+* FIX: fix username matching bug in afppasswd. from kanai at nadmin dot org
+* FIX: reworked username check a little. Depending on the UAM, the wrong
+       username _could_ have been selected.
+
+Changes in 2.0-rc2
+==================
+
+* UPD: use 0 0 for default creator/type rather than UNIX TEXT, from
+       Shlomi Yaakobovich.
+* UPD: updated documentation
+* UPD: change machine type from Macintosh to Netatalk in status reply
+* FIX: afpd: CopyFile only create a resource fork for destination if source
+       has one.
+* FIX: afpd: mangling: for utf8 --> max filename length is 255 bytes, else 31.
+* FIX: cnid_dbd: fix a signed/unsigned, 16/32 bits mismatch. from Burkhard
+       Schmidt, bs at cpfs.mpg.de.
+* FIX: afpd: After ad_setid don't flush resource fork if it has not been
+       modified.
+* FIX: NEWS: Fixed ancient NEWS entries. Removed umlauts
+* FIX: fix macname cache, SF bug 1021642
+* FIX: revert Makefile change from 2.0-rc1. We have to include BDB_CFLAGS
+       after CFLAGS
+
+Changes in 2.0-rc1
+==================
+
+* NEW: new manual page for asip-status.pl
+* UPD: updated documentation
+* UPD: uams: link uam_dhx_passwd.so to lcrypt before lcrypto. might help with
+       MD5 passwords
+* UPD: Improved BerkeleyDB detection
+* UPD: sys/solaris/Makefile.in: enable 'make check', from Alexander Barton
+* UPD: tcp wrappers detection should work on OpenBSD as well now
+* UPD: macbin: increase the maximum size of macbinary forks, as suggested by 
+       Sourceforge bug ID 829221
+* UPD: ASP: rework getstatus. use several ASP packets if the client allows
+       it, otherwise just send as much as we can
+* FIX: FreeBSD 5 build, from Alex Barton (alex at barton.de)
+* FIX: OSX 10.3 build
+* FIX: papd: workaround a problem with PJL before Postscript
+* FIX: afpd: make sure we only disconnect on old session if the users match
+* FIX: apfd: Quark6 mangled long filenames should work better now
+* FIX: enhance ADv1 to ADv2 conversion. Fixed a SIGSEGV reported by Mark Baker
+* FIX: better detection of invalid resource forks
+* FIX: fix some linking problems on OpenBSD
+* FIX: afpd: catsearch.c, filedir.c: fix bogus casts, from Olaf Hering 
+       (olh at suse.de)
+* FIX: afpd: don't try to create special folders and .volinfo on read-only
+       volumes
+* FIX: iconv/unicode enhancements. fixed a sigsegv on conversion error
+* FIX: configure.in: fix a typo, reported by Joerg Rossdeutscher
+* FIX: uniconv: enhanced uniconv behaviour
+* FIX: fixed some Solaris compilation problems
+* FIX: papd/Makefile.am: add a missing $DESTDIR, from Vlad Agranovsky
+* FIX: afpd: quota.c: remove a c99 declaration, from Yann Rouillard
+* FIX: configure.in: Solaris/gcc 3.0 fix, from Yann Rouillard
+* FIX: afpd: fix a SIGSEGV when sharing home dirs without any options in 
+       AppleVolumes.
+* FIX: numerous small bugfixes
+
+Changes in 2.0-beta2
+====================
+
+* NEW: atalkd, papd and npb tools now support nbpnames with extended
+       characters
+* NEW: integrated CUPS support for papd
+* NEW: optionally advertise SSH tunneling capabilties
+* NEW: automatic logfile removal for cnid_metad
+* NEW: asip-status.pl has been added to netatalk
+* UPD: updated documentation
+* UPD: we now require Berkeley DB >= 4.1
+* UPD: 64bit Linux fixes from Stew Benedict, Mandrakesoft
+* UPD: remove --enable-sendfile
+* UPD: more verbose error messages
+* FIX: better handling for resource forks without read access
+* FIX: Tru64 build, by Burkhard Schmidt
+* FIX: MIT Kerberos detection
+* FIX: varios *BSD compile problems
+* FIX: compile problem with libiconv, reported by Joe Marcus Clarke
+* FIX: adv1tov2: make it work with the new structure
+* FIX: afpd: filenames longer than 127 bytes were not enumerated correctly,
+       reported by Thies C. Arntzen
+* FIX: afpd: return IP before FQDN in status reply.
+* FIX: afpd: Mac chooser could crash on a codepage conversion error
+* FIX: afpd: KerberosV auth with Panther clients, make long AD tickets work,
+       reported by Andrew Smith
+* FIX: atalkd: could send invalid NBPLKUP replies, e.g with more than 15
+       printers. Reported by Almacha
+* FIX: papd: fix papd.conf parsing problems with consecutive ':' and missing 
+       newline. Reported by Craig White.
+* FIX: megatron: make megatron work with UTF-8 volumes
+* FIX: timeout: running timeout with commands which accept arguments, 
+       from Yuval Yeret.
+* FIX: uniconv: fix a SEGFAULT, reported by Matthew Geier
+* FIX: pam detection: PAM_C/LDFLAGS were always empty, from Alexander Barton
+* FIX: numerous small bugfixes.
+
+Changes in 2.0-beta1
+=====================
+
+* NEW: OSX style adouble scheme
+* NEW: japanese SHIFT_JIS codepage (iconv supplied)
+* NEW: Solaris kernel module build integrated with configure
+* NEW: Gentoo start scripts
+* NEW: cnid_dbd doesn't use transactions by default
+* FIX: afpd: the volume casefold option was broken
+* FIX: afpd: update AD2 headers and keep owner on file exchange
+* FIX: Solaris 9 and FreeBSD 4.9/5.2 compilation
+* FIX: free space reported with groups quotas on Linux
+* FIX: OS9/OS X didn't update free space
+* FIX: finder crash if folder opened got deleted by another process
+* FIX: randnum UAM wasn't AFP3 ready
+* FIX: numerous small bugfixes.
+
+Changes in 2.0-alpha2
+=====================
+
+* NEW: uniconv tool for converting volume encoding.
+* NEW: afpd: Make sure getstatus doesn't return loopback address as server IP.
+* NEW: afpd: Specify USEDOTS with MSWINDOWS implicitely.
+* NEW: afpd: SRVLOC register with IP address instead of hostname by default,
+       if -fqdn is specified register with FQDN.  Added extended character 
+       support for SLP, non ASCII characters are escaped Added ZONE to registration.
+* NEW: atalkd: Make atalkd set interfaces to ALLMULTI on linux by default.
+* NEW: cnid_metad: Use DB_PRIVATE attribute for dbd backend without transaction.
+* FIX: afpd: Partial workaround for an OSX client deadlock.
+* FIX: afpd: Reenumerate folder if db is out of sync in resolveID.
+* FIX: afpd: Don't modify modification date in copyfile.
+* FIX: afpd: Variable $v substitution: always use name defined in config files.
+* FIX: libatalk: Speed optimisation for byte locking was broken on resource fork.
+* FIX: Solaris 9 compilation.
+* FIX: Tru64 compilation fixes.
+* FIX: AFS compilation fixes.
+* FIX: strncpy bugfix.
+* FIX: configure, man pages update and small bugfixes.
+
+Changes in 2.0-alpha1
+=====================
+
+* NEW: afpd: We now support AFP 3.x, which features long filenames and 
+       large file support
+* NEW: CNID handling completely reworked. We now use per Volume configurable
+       CNID backends.
+* NEW: Two new daemons, cnid_metad and cnid_dbd to implement the dbd CNID backend.
+       Using Berkeley DB transactions with the CNID database should be safe now.
+* NEW: The on disk format of the CNID database has changed. We now support 8 byte
+       device and inode numbers and an additinal type field that should make 
+       detection of file/directory changes outside of afpd more robust. 
+       Changed from HASH to BTREE access which speeds things up in certain cases 
+       and reduces database file size.
+* NEW: Long file name mangling is now implemented using the CNID ID, so no database is 
+       required to map names to mangled names. This is the same method Mac OS X uses. 
+* NEW: New format (version 2) for Metadata in AppleDouble files. We record device and  
+       inode of the underlying file as well as the CNID. This can be used for recovery
+       and speeds up access to the CNID.
+* NEW: The old NLS codepage system has been removed. It was replaced by an iconv 
+       based conversion system, which provides much more flexibility.
+* NEW: You can safely use extended characters in volume names and for SIGUSR2 messaging.
+* NEW: The default volume encoding is UTF-8.
+* NEW: All documentation is now generated using DocBook. New or completely reworked 
+       sections about installing, setting up and upgrading Netatalk replace various 
+       README files in the doc directory.
+* FIX: Protect afpd better against unexpected signals during updates of the CNID
+       database with the cdb backend. This makes database corruption less likely.   
+* FIX: All manpages have been reviewed and should now be up to date.
+* FIX: Tons of bug fixes since 1.6.4. Please consults the CVS change log for details.
+
+Changes in 1.6.4
+================
+
+* NEW: afpd: Using the mswindows option now implicitly specifies usedots.
+  [Sam Noble]
+* UPD: afpd.8: Updated the option documentation.
+  [Thomas Kaiser, Sebastian Rittau]
+* FIX: configure: Removed broken --with-flock-locks option. [Bjoern Fernhomberg]
+* FIX: libatalk: Do not log network probe (OSX 10.3). [Didier Gautheron]
+* FIX: libatalk: Deadlock in signal handlers. [Didier]
+* FIX: libatalk: Compilation with Linux kernel 2.6 fixed. [Sebastian, Bjoern]
+* FIX: afpd: Solaris compile issues. [Bjoern]
+* FIX: afpd: If connection broke in dsi_tickle the child did never die. [Bjoern]
+* FIX: afpd: Catsearch, fixes a possible segmentation fault. [Bjoern]
+* FIX: afpd: Compilation issues. [Olaf Hering, Sebastian]
+* FIX: cnid: Fix compile problems on Tru64. [Burkhard Schmidt]
+* FIX: megatron: Fixed an uninitialized variable. [Olaf]
+* FIX: installation: Don't overwrite PAM file if --enable-overwrite configure
+       option is not set. [Sam, Ryan Cleary]
+* FIX: installation: Fixed BSD installation. [Toru TAKAMIZU]
+* FIX: docs: Removed ssl-dir/ssl-dirs confusion from doc/INSTALL. [Bjoern]
+
 Changes in 1.6.3
 ================
 
@@ -170,249 +372,255 @@ Changes in 1.5rc2
        and prior bounds checking.
 
 Changes from the 1.4b1 release:
+===============================
 
-    Fixed the maximum free/total volume size in afpd.
+*   Fixed the maximum free/total volume size in afpd.
 
-    Made ~ the default volume in afpd.
+*   Made ~ the default volume in afpd.
 
-    Fixed pid file handling and changed setpgrp() to setpgid() in afpd,
+*   Fixed pid file handling and changed setpgrp() to setpgid() in afpd,
     papd, and atalkd.
 
-    Added code to afpd to set the Unix file time stamps with utime().
+*   Added code to afpd to set the Unix file time stamps with utime().
 
-    Fixed a bug in papd's printcap code which limited it to 15 or so
+*   Fixed a bug in papd's printcap code which limited it to 15 or so
     printers.
 
-    Fixed papd's handling of piped printers.
+*   Fixed papd's handling of piped printers.
 
-    Fixed papd's handling of bad job names.
+*   Fixed papd's handling of bad job names.
 
-    Fixed atalkd to send NBP LKUP packets from NBP port.
+*   Fixed atalkd to send NBP LKUP packets from NBP port.
 
-    Added "sync;sync;sync" to Solaris kinstall to help with streams
+*   Added "sync;sync;sync" to Solaris kinstall to help with streams
     file corruption.
 
-    Added nlocalrts to streams ddp.conf.  Thanks Thomas Tornblom.
+*   Added nlocalrts to streams ddp.conf.  Thanks Thomas Tornblom.
 
-    Fixed signed extension infinite loop in Solaris module.
+*   Fixed signed extension infinite loop in Solaris module.
 
-    Moved all the config files to .../config.
+*   Moved all the config files to .../config.
 
 Changes from the 1.3.3 release:
+===============================
 
-    Added code from Sun Microsystems, Inc (OPCOM) for Solaris support.
+*   Added code from Sun Microsystems, Inc (OPCOM) for Solaris support.
     See COPYRIGHT.
 
-    Added support for FreeBSD, mostly changes by Mark Dawson and Julian
+*   Added support for FreeBSD, mostly changes by Mark Dawson and Julian
     Elischer.
 
-    All sorts of other stuff.
+*   All sorts of other stuff.
 
 Changes from the 1.3.1 release:
+===============================
 
-    Added options to psf's filter names to support accounting on HPs.
+*   Added options to psf's filter names to support accounting on HPs.
     !!! NOTE:  The location of the filters has changed, see the man
     page for where.
 
-    Added code from Alan Cox to support Linux.
+*   Added code from Alan Cox to support Linux.
 
-    Rewrote papd.  Now handles dropped connections better.
+*   Rewrote papd.  Now handles dropped connections better.
     Configuration has been modernized.  !!! NOTE: The format of the
     configuration file has changed, but NOT THE NAME.
 
-    Added Kerberos support to papd.
+*   Added Kerberos support to papd.
 
-    atalkd now removes routes on a SIGTERM.  Still can't just restart
+*   atalkd now removes routes on a SIGTERM.  Still can't just restart
     it, but it's closer.
 
-    Changed atalkd and the kernel driver to remove a hack added to
+*   Changed atalkd and the kernel driver to remove a hack added to
     support sending to 0.255.  Now the kernel will allow multiple open
     sockets with the same port, so long as the addess associated with
     the port is different.  atalkd now opens a socket for each port on
     each interface.
 
-    atalkd now rewrites its configuration file.  If no configuration
+*   atalkd now rewrites its configuration file.  If no configuration
     file is given, one will be generated.  Permissions on the new
     configuration file will be inherited from the old one.  If there is
     no old one, permissions default to 644.  Won't rewrite the file if
     the owner doesn't have write permission.
 
-    Removed support for the "AFS Kerberos UAM", in favor of the
+*   Removed support for the "AFS Kerberos UAM", in favor of the
     "AuthMan UAM".  Kerberos support should now be much more
     straight-forward.
 
-    Fixed a bug in afpd which would cause incorrect group calculations
+*   Fixed a bug in afpd which would cause incorrect group calculations
     on ultrix machines.
 
-    Fixed a bug in afpd which causes SimpleText and some other
+*   Fixed a bug in afpd which causes SimpleText and some other
     applications to silently fail to write.  There's also a bug in
     MacOS, but we can't fix that.
 
-    Fixed a bad interaction with afpd and AFS which would cause file
+*   Fixed a bad interaction with afpd and AFS which would cause file
     writes to not propogate between AFS clients.
 
-    !!! CHANGED the name(s) of afpd's config files.  The new files are
+*   !!! CHANGED the name(s) of afpd's config files.  The new files are
     AppleVolumes.system and AppleVolumes.default.  If AppleVolumes.system
     exists, it is always read, AppleVolumes.default is only read if the
     user has no AppleVolumes file.  Included a flag "-u" to indicate
     which file has precedence.  "-u" user wins, otherwise ".system"
     wins.
 
-    Rewrote the AppleVolumes parsing code.  Now works.
+*   Rewrote the AppleVolumes parsing code.  Now works.
 
-    Added a filename extension mapping to afpd.  User always takes
+*   Added a filename extension mapping to afpd.  User always takes
     precedence, regardless of the "-u" flag.  Code to change the type
     of all Unix files contributed by Kee Hinckley <nazgul@utopia.com>.
 
-    afpd now supports both UFS and AFS volumes simultaneously.  It also
+*   afpd now supports both UFS and AFS volumes simultaneously.  It also
     uses access() to attempt to calculate reasonable Mac permissions
     for AFS directories.
 
-    Changed reporting of file times.  Files that are written from Unix
+*   Changed reporting of file times.  Files that are written from Unix
     now update the Mac's idea of the files modification time.  Unix
     mtime is now reported instead of ctime.
 
-    Added support for a new UAM to afpd.  This requires that client
+*   Added support for a new UAM to afpd.  This requires that client
     Macs have MacTCP and AuthMan installed.  Should make running afpd
     for AFS easier.
 
-    Removed code so that otherwise valid volumes for which the mounting
+*   Removed code so that otherwise valid volumes for which the mounting
     user has no permission will appear in the volume selection dialog
     on the Mac gray-ed out.
 
-    Added code from Chris Metcalf of MIT to the AppleDouble library
+*   Added code from Chris Metcalf of MIT to the AppleDouble library
     which improves permission inheritance.
 
-    Added code from G. Paul Ziemba of Alantec, Inc to better report
+*   Added code from G. Paul Ziemba of Alantec, Inc to better report
     errors in psf.  Also changed psf to use syslog for errors that
     users aren't interested in.
 
-    Added information to psf's man page to better explain the
+*   Added information to psf's man page to better explain the
     interaction between psf, pap, and lpd.
 
-    Make psf/pap/psa do accounting when it's turnes on in
+*   Make psf/pap/psa do accounting when it's turnes on in
     /etc/printcap.
 
-    Changed pap's error message when there is no printer specified on
+*   Changed pap's error message when there is no printer specified on
     the command line and no .paprc is found.  Also heavily modified
     pap's man page to reflect changes in the "new" version of pap,
     including moving it from section 8 to section 1.
 
-    Fixed a byte-order bug in pap's sequence numbers.  Doubt if pap has
+*   Fixed a byte-order bug in pap's sequence numbers.  Doubt if pap has
     ever worked right on little endian machines!
 
-    Added a flag to pap to optionally close before receiving EOF from
+*   Added a flag to pap to optionally close before receiving EOF from
     the printer.  Off by default.  psf calls pap with this option on.
 
-    Added timeouts to the nbp library calls.  This means that processes
+*   Added timeouts to the nbp library calls.  This means that processes
     won't hang when atalkd dies during boot, thus hanging your
     machine.
 
 Changes from the 1.3 release:
+=============================
 
-    Fixed a bug in afpd which would cause APPL mappings to contain both
+*   Fixed a bug in afpd which would cause APPL mappings to contain both
     mac and unix path names.  The fixed code will handle the old
     (corrupted) database.
 
-    Fixed a *very* serious bug which would cause files to be corrupted
+*   Fixed a *very* serious bug which would cause files to be corrupted
     when copying to afpd.
 
-    Fixed a bug in afpd which would cause replies to icon writes to
+*   Fixed a bug in afpd which would cause replies to icon writes to
     contain the written icon.
 
-    Filled in the function code switch in afpd.  Previously, a hacker
+*   Filled in the function code switch in afpd.  Previously, a hacker
     could probably have used afpd to get unauthorized access to a
     machine running afpd.
 
-    Fixed a bug in the asp portion of libatalk.a which could cause the
+*   Fixed a bug in the asp portion of libatalk.a which could cause the
     malloc()/free() database to be corrupted.
 
-    Fixed a bug in atalkd's zip query code.  With this bug, only the
+*   Fixed a bug in atalkd's zip query code.  With this bug, only the
     first N % 255 nets get queried.  However, since nets bigger than
     255 are usually pretty unstable, the unqueried for nets will
     eventually get done, when N drops by one.
 
-    Suppressed a spurious error ("route: No such process") in atalkd.
+*   Suppressed a spurious error ("route: No such process") in atalkd.
 
 Changes from the 1.2.1 release:
+===============================
 
-    atalkd is completely rewritten for phase 2 support.  atalkd.conf
+*   atalkd is completely rewritten for phase 2 support.  atalkd.conf
     from previous version will not work!
 
-    afpd now has better AFS support.  In particular, the configuration
+*   afpd now has better AFS support.  In particular, the configuration
     for AFS was made much easier; a number of Kerberos-related
     byte-ordering and time problems were found; clear-text passwords
     were added (thanks to geeb@umich.edu).
 
-    afpd now handles Unix permissions much better (thanks to
+*   afpd now handles Unix permissions much better (thanks to
     metcalf@mit.edu).
 
-    There are many, many more changes, but most are small bug fixes.
+*   There are many, many more changes, but most are small bug fixes.
 
 Changes from the 1.2 release:
+=============================
 
-    The Sun support now uses loadable kernel modules (a la VDDRV)
+*   The Sun support now uses loadable kernel modules (a la VDDRV)
     instead of binary patches. As such, it should work on any sunos
     greater than 4.1, and is confirmed to work under 4.1.1 and 4.1.2.
 
-    The DEC support no longer requires source. It also runs under
+*   The DEC support no longer requires source. It also runs under
     ultrix 4.1 and 4.2. It still requires patching your kernel, but the
     patches are limited to those files available to binary-only sites
     -- primarily hooks for things like netatalk.
 
-    The etc.rc script now uses changes made to nbprgstr (see below).
+*   The etc.rc script now uses changes made to nbprgstr (see below).
 
-    aecho now takes machine names on the command line.
+*   aecho now takes machine names on the command line.
 
-    nbplkup now takes a command line argument specifying the number of
+*   nbplkup now takes a command line argument specifying the number of
     responses to accept. It also takes its defaults from the NBPLKUP
     environment variable.
 
-    nbprgstr may be used to register a name at any requested port.
+*   nbprgstr may be used to register a name at any requested port.
 
-    afpd now logs if an illegal shell is used during login, instead of
+*   afpd now logs if an illegal shell is used during login, instead of
     silently denying service.
 
-    A bug in afpd which caused position information for the directory
+*   A bug in afpd which caused position information for the directory
     children of the root of a volume to be ignored has been fixed.
 
-    Several typos in afpd which would cause include files necessary to
+*   Several typos in afpd which would cause include files necessary to
     ultrix to be skipped have been fixed.
 
-    atalkd will no long propagate routes to networks whose zone
+*   atalkd will no long propagate routes to networks whose zone
     it doesn't know.
 
-    atalkd no longer dumps core if it receives a ZIP GetMyZone request
+*   atalkd no longer dumps core if it receives a ZIP GetMyZone request
     from a network whose zone it doesn't know. (Since this currently
     can only happen from off net, it's not precisely a legal request.)
 
-    pap and papd (optionally) no longer check the connection id in PAP
+*   pap and papd (optionally) no longer check the connection id in PAP
     DATA responses. Both also maintain the function code in non-first-packet
     PAP DATA responses.  These changes are work-arounds to deal with
     certain AppleTalk printer cards, notably the BridgePort LocalTalk
     card for HP LJIIISIs.
 
-    pap no longer sends an EOF response to each PAP SENDDATA request,
+*   pap no longer sends an EOF response to each PAP SENDDATA request,
     only the first.
 
-    A bug in papd which would cause it to return a random value when
+*   A bug in papd which would cause it to return a random value when
     printing the procset to a piped printer has been fixed.
 
-    A bug relating to NBP on reverse-endian machines has been fixed.
+*   A bug relating to NBP on reverse-endian machines has been fixed.
 
-    atp_rsel() from libatalk now returns a correct value even if it
+*   atp_rsel() from libatalk now returns a correct value even if it
     hasn't recieved anything yet.
 
-    atalk_addr() from libatalk no longer accepts addresses in octal
+*   atalk_addr() from libatalk no longer accepts addresses in octal
     format, since AppleTalk addresses can have leading zeros. Also it
     checks that the separator character is a '.'.
 
-    Pseudo man pages for nbplkup, nbprgstr, and nbpunrgstr, have been
+*   Pseudo man pages for nbplkup, nbprgstr, and nbpunrgstr, have been
     added.
 
-    The example in the psf(8) man page is now correct.
+*   The example in the psf(8) man page is now correct.
 
-    The man pages for changed commands have been updated.
+*   The man pages for changed commands have been updated.
 
-    The README files for various machine have been updated
+*   The README files for various machine have been updated
     appropriately.
diff --git a/README b/README
index 33b000fcdc67fa396a428d373d1324c1412eabaf..0c228113a530150d25381c0bb83a9b42c4321646 100644 (file)
--- a/README
+++ b/README
@@ -1,9 +1,7 @@
 The documentation for Netatalk is arranged as follows:
 
-* doc/INSTALL
-  netatalk specific installation instructions
-* doc/CONFIGURE
-  how to set up the configuration files
+* doc/Netatalk-Manual(.pdf|.txt)
+  the Netatalk manual
 * doc/DEVELOPER 
   information for developers and additional requirements for compiling
 * doc/FAQ
diff --git a/TODO b/TODO
index af3e17e9dc235fd8683b068806ebc20908499b29..2c9540c6c7688380d6e2327bf152c0b3d048eda8 100644 (file)
--- a/TODO
+++ b/TODO
@@ -6,9 +6,7 @@ desired features (in no particular order):
                Add afp_fileid capabilities - done
                Add afp_catalogue
                afp_enumerate optimization
-               cname expansion to handle 8+3 and 255-unicode.
         server messages in useful places 
-        Other useful bits of AFP 2.0/2.1. are there any?
        change afp/ddp child handling to be in line w/ generic?
         administrative control program (using asip API?)
        appledouble v2 (gets us persistent DIDs). we'll need a did
@@ -44,8 +42,6 @@ desired features (in no particular order):
         
 things to fix:
         cleaner separation of layers.
-       fcntl-style byte locks - almost done. it just needs to do a
-               little sorting to get around a race condition.
        AFP <-> Unix permissions. there are a couple cases where they 
                don't map perfectly. in particular, gid == 0 means
                ignore group permissions while uid == 0 means anybody
@@ -57,11 +53,6 @@ things to fix:
                            read -> can see files.
                we need to map permissions so that these semantics get
                 followed.
-        real variable DIDs for now: it turns out that afpd lies about
-                this and says that it's doing fixed dids. bad bad
-                bad. i just have to implement Open/CloseDir and fiddle
-                a little with did assignment. argh. apple's appleshare
-               client doesn't like non-fixed directory ids. 
         support picking up items from dropboxes without linux-side superuser
                 intervention
         support for system-wide messages; send the main afpd process SIGUSR2
@@ -70,10 +61,7 @@ things to fix:
                 server messaging (currently replaces with a space)
 
 added features:
-       more of AFP 2.0!
        sped up of_findname and of_dealloc.
-       increased AFP compliance w.r.t. open forks and renames:
-               wordperfect and simpletext now both work!
         nfs quota support
        solaris beta STREAMS driver added.
        64-bit cleanup
@@ -84,13 +72,9 @@ added features:
        operate separately now (-T turns off tcp, -D turns off ddp).
        incorporated the netbsd patches 
                [source: wrstuden@loki.stanford.edu (Bill Studenmund)]
-       added/fixed quota support for linux/bsd4.4
-       codepage support/casefolding on a per volume basis.
-       expanded per-volume options
+       casefolding on a per volume basis.
        added "generic" platform support for AFP/tcp.
-       dynamically loaded uams 
        :ETCDIR:/afppasswd file for randnum passwds
-       can turn off .AppleDouble generation.
        AppleVolumes variable substitions
        atalkd: zones on single interfaces and the ability to control
                which interfaces get routes between them.
diff --git a/VERSION b/VERSION
index bc0ad689eba8a80209102ee9ceea8feb1d90313f..5ee09a8b300cd7831fd0d00defa62cba20dd3ab6 100644 (file)
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-1.7cvs
+2.1dev
index bd2db832f56ee858931a8d2103367032f6133150..73a109d4460db25ec4f487168bc24280f98e5ff0 100644 (file)
@@ -1,3 +1,3 @@
 # Makefile.am for bin/
 
-SUBDIRS = adv1tov2 aecho afile afppasswd cnid getzones megatron nbp pap psorder
+SUBDIRS = adv1tov2 aecho afile afppasswd cnid getzones megatron nbp pap psorder uniconv
index c52ff072e5264092963dae0f5da39dd6810d11bb..987599b9cb9557ca189274fcd8efa0359bcc88a6 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: adv1tov2.c,v 1.3 2001-06-29 14:14:46 rufustfirefly Exp $
+ * $Id: adv1tov2.c,v 1.4 2005-04-28 20:49:18 bfernhomberg Exp $
  * v1tov2: given a root directory, run down and convert all the
  * files/directories into appledouble v2.
  */
@@ -8,6 +8,7 @@
 #include "config.h"
 #endif /* HAVE_CONFIG_H */
 
+#include <atalk/adouble.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <dirent.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <sys/param.h>
+#include <errno.h>
+#include <string.h>
 
-#include <atalk/adouble.h>
+#include <atalk/util.h>
 
 #if AD_VERSION == AD_VERSION2
+#if 0
 /* translate characters */
-static int xlate(char *name, int flags) {
+static void xlate(char *name, int flags) {
   static const char hexdig[] = "0123456789abcdef";
   char upath[MAXPATHLEN + 1];
   char *m, *u;
@@ -52,7 +56,22 @@ static int xlate(char *name, int flags) {
       rename(ad_path(name, flags), ad_path(upath, flags)); /* rename rfork */
   }
 }
+#endif
+
+/* ----------------------------- */
+char *fullpathname(const char *name)
+{
+    static char wd[ MAXPATHLEN + 1];
 
+    if ( getcwd( wd , MAXPATHLEN) ) {
+        strlcat(wd, "/", MAXPATHLEN);
+        strlcat(wd, name, MAXPATHLEN);
+    }
+    else {
+        strlcpy(wd, name, MAXPATHLEN);
+    }
+    return wd;
+}
 
 #define MAXDESCEND 0xFFFF
 /* recursively descend subdirectories. 
@@ -61,12 +80,12 @@ void descend(DIR *dp)
 {
   DIR *dpnew;
   struct dirent *de;
-  unsigned char *m, *u;
   struct stat st;
   struct adouble ad;
   int flags;
   static int count = 0;
 
+  ad_init(&ad, AD_VERSION2, 0);
   if (count++ > MAXDESCEND) {
     fprintf(stderr, "FAILURE: too many subdirectories! possible infinite recursion.");
     return;
@@ -93,11 +112,11 @@ void descend(DIR *dp)
     }
 
     if (ad_open(de->d_name, flags, O_RDWR, 0, &ad) < 0) {
-      fprintf(stderr, "FAILURE: can't convert %s\n", de->d_name);
+      if (errno != ENOENT)
+          fprintf(stderr, "\nFAILURE: can't convert %s, %s\n", fullpathname(de->d_name), strerror(errno));
       continue;
     }
     ad_close(&ad, ADFLAGS_HF);
-    xlate(de->d_name, flags);
     fputc('.', stderr);
   }
   putc(')', stderr);
@@ -109,6 +128,7 @@ int main(int argc, char **argv)
   DIR           *dp;
   struct adouble ad;
  
+  ad_init(&ad, AD_VERSION2, 0);
   if (argc != 2) {
     fprintf(stderr, "%s <directory>\n", *argv);
     return -1;
@@ -132,7 +152,6 @@ int main(int argc, char **argv)
   closedir(dp);
   chdir("..");
 
-  xlate(argv[1], ADFLAGS_HF | ADFLAGS_DIR);
   putc('\n', stderr);
   return 0;
 }
index 7d02b8d116964a8b781bb7e307a30121df762e7c..fef8bc2b901c61d51525effba86a3fbfbf5930db 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: aecho.c,v 1.6 2003-06-06 19:35:15 srittau Exp $
+ * $Id: aecho.c,v 1.7 2005-04-28 20:49:18 bfernhomberg Exp $
  *
  * Copyright (c) 1990,1991 Regents of The University of Michigan.
  * All Rights Reserved.
 #endif /* ! SOCKLEN_T */
 
 struct sockaddr_at     target;
-int                    s, nsent = 0, nrecv = 0;
+int                    sock;
+unsigned int           nsent = 0, nrecv = 0;
 time_t                 totalms = 0, minms = -1, maxms = -1;
-static unsigned int     pings = 0;
+unsigned int           pings = 0;
 
 void usage(char *);
 
 void done()
 {
-    if ( nsent > 0 ) {
+    if ( nsent) {
        printf( "\n----%d.%d AEP Statistics----\n",
                ntohs( target.sat_addr.s_net ), target.sat_addr.s_node );
        printf( "%d packets sent, %d packets received, %d%% packet loss\n",
                nsent, nrecv, (( nsent - nrecv ) * 100 ) / nsent );
-       if ( nrecv > 0 ) {
+       if ( nrecv ) {
            printf( "round-trip (ms)  min/avg/max = %ld/%ld/%ld\n",
                    minms, totalms / nrecv, maxms );
        }       
@@ -101,7 +102,7 @@ void aep_send()
     memcpy( p, &tv, sizeof( struct timeval ));
     p += sizeof( struct timeval );
 
-    if ( netddp_sendto( s, buf, p - buf, 0, (struct sockaddr *) &target,
+    if ( netddp_sendto( sock, buf, p - buf, 0, (struct sockaddr *) &target,
            sizeof( struct sockaddr_at )) < 0 ) {
        perror( "sendto" );
        exit( 1 );
@@ -182,7 +183,7 @@ int main( ac, av )
     }
     target.sat_port = port;
 
-    if ((s = netddp_open(saddr.sat_addr.s_net || saddr.sat_addr.s_node ? 
+    if ((sock = netddp_open(saddr.sat_addr.s_net || saddr.sat_addr.s_node ? 
                         &saddr : NULL, NULL)) < 0) {
        perror("ddp_open");
        exit(1);
@@ -218,7 +219,7 @@ int main( ac, av )
 
     for (;;) {
        satlen = sizeof( struct sockaddr_at );
-       if (( cc = netddp_recvfrom( s, buf, sizeof( buf ), 0, 
+       if (( cc = netddp_recvfrom( sock, buf, sizeof( buf ), 0, 
                                    (struct sockaddr *) &sat,
                                    &satlen )) < 0 ) {
            if ( errno == EINTR ) {
index daff8d41b8edd4e5ba288a3941c47833a972aaf7..b9fad222a1e4d4f76243de6e9203b4d8df8c12f3 100644 (file)
@@ -1,6 +1,6 @@
 # Makefile.am for bin/afppasswd/
 
-pkgconfdir = $(PKGCONFDIR)
+pkgconfdir = @PKGCONFDIR@
 
 if USE_DHX
 bin_PROGRAMS = afppasswd
@@ -8,21 +8,13 @@ else
 bin_PROGRAMS =
 endif
 
-if HAVE_GCRYPT
-CRYPT_CFLAGS = $(GCRYPT_CFLAGS)
-CRYPT_LIBS = $(GCRYPT_LIBS)
-else
-CRYPT_CFLAGS = $(SSL_CFLAGS)
-CRYPT_LIBS = $(SSL_LIBS)
-endif
-
 afppasswd_SOURCES = afppasswd.c
-afppasswd_LDADD = $(top_builddir)/libatalk/libatalk.la $(CRYPT_LIBS)
+afppasswd_LDADD = $(top_builddir)/libatalk/libatalk.la @SSL_LIBS@
 
-INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/sys $(CRYPT_CFLAGS) \
-       -D_PATH_AFPDPWFILE=\"$(pkgconfdir)/afppasswd\"
+CFLAGS = @CFLAGS@ @SSL_CFLAGS@ -I$(top_srcdir)/sys \
+    -D_PATH_AFPDPWFILE=\"$(pkgconfdir)/afppasswd\"
 
 install-exec-hook:
 if USE_DHX
        chmod u+s $(DESTDIR)$(bindir)/afppasswd
-endif
+endif
\ No newline at end of file
index eb138c4f47f5c044df812d4657b38ac451707707..4c56875d1d59e07566bb69e5829ba7869bb99c35 100644 (file)
@@ -1,5 +1,5 @@
 /* 
- * $Id: afppasswd.c,v 1.18 2003-06-09 02:55:25 srittau Exp $
+ * $Id: afppasswd.c,v 1.19 2005-04-28 20:49:19 bfernhomberg Exp $
  *
  * Copyright 1999 (c) Adrian Sun (asun@u.washington.edu)
  * All Rights Reserved. See COPYRIGHT.
  */
 
 #ifdef HAVE_CONFIG_H
-#include <config.h>
+#include "config.h"
 #endif /* HAVE_CONFIG_H */
 
-#include <assert.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 
 #include <netatalk/endian.h>
 
-#if HAVE_GCRYPT
-#include <gcrypt.h>
-#define DES_KEY_SZ 8
-#else
 #include <des.h>
-#endif
 
 #ifdef USE_CRACKLIB
 #include <crack.h>
 #define OPTIONS "cafnu:p:"
 #define UID_START 100
 
-#define PASSWDLEN DES_KEY_SZ
-#define HEXPASSWDLEN (PASSWDLEN * 2)
+#define HEXPASSWDLEN 16
+#define PASSWDLEN 8
 
 static char buf[MAXPATHLEN + 1];
 
-/* FIXME: preparation for i18n */
-#ifndef _
-#define _(x) (x)
-#endif
-
-/* SRC and DST must not overlap. */
-static void hexify(u_int8_t *dst, const u_int8_t *src)
-{
-  int i, j;
-
-  for (i = j = 0; i < DES_KEY_SZ; i++, j += 2) {
-    static const unsigned char hextable[] = "0123456789ABCDEF";
-
-    dst[j]     = hextable[(src[i] & 0xF0) >> 4];
-    dst[j + 1] = hextable[(src[i] & 0x0F)];
-  }
-}
-
-/* SRC and DST can overlap. */
+/* if newpwd is null, convert buf from hex to binary. if newpwd isn't
+ * null, convert newpwd to hex and save it in buf. */
 #define unhex(x)  (isdigit(x) ? (x) - '0' : toupper(x) + 10 - 'A')
-static void unhexify(u_int8_t *dst, const u_int8_t *src)
-{
-  int i, j;
-
-  /* convert to binary */
-  for (i = j = 0; i < HEXPASSWDLEN; i += 2, j++)
-    dst[j] = (unhex(src[i]) << 4) | unhex(src[i + 1]);
-  if (j <= DES_KEY_SZ)
-    memset(dst + j, 0, HEXPASSWDLEN - j);
-}
-
-static u_int8_t *retrieve_key(int keyfd)
+static void convert_passwd(char *buf, char *newpwd, const int keyfd)
 {
-  static u_int8_t key[HEXPASSWDLEN];
-
-  if (lseek(keyfd, 0, SEEK_SET) == -1)
-    return NULL;
-  if (read(keyfd, key, sizeof(key)) < sizeof(key))
-    return NULL;
-
-  unhexify(key, key);
-
-  return key;
-}
+  u_int8_t key[HEXPASSWDLEN];
+  Key_schedule schedule;
+  unsigned int i, j;
+
+  if (!newpwd) {
+    /* convert to binary */
+    for (i = j = 0; i < sizeof(key); i += 2, j++)
+      buf[j] = (unhex(buf[i]) << 4) | unhex(buf[i + 1]);
+    if (j <= DES_KEY_SZ)
+      memset(buf + j, 0, sizeof(key) - j);
+  }
 
-static int decrypt_passwd(u_int8_t *dst, const u_int8_t *src, int keyfd)
-{
-  u_int8_t *key;
-  int err = 0;
-
-  key = retrieve_key(keyfd);
-  if (!key)
-    return 0;
-
-  {
-#if HAVE_GCRYPT
-    GcryCipherHd handle;
-
-    handle = gcry_cipher_open(GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0);
-    if (handle) {
-      int ret;
-
-      ret = gcry_cipher_setkey(handle, key, DES_KEY_SZ);
-      if (!ret)
-        ret = gcry_cipher_decrypt(handle, dst, 8, src, 8);
-      gcry_cipher_close(handle);
-      if (ret) {
-        fprintf(stderr, _("Decryption error: %s\n"), gcry_strerror(ret));
-        err = 1;
-      }
-      printf("pw: %s\n", buf); /* FIXME */
+  if (keyfd > -1) {
+    lseek(keyfd, 0, SEEK_SET);
+    read(keyfd, key, sizeof(key));
+    /* convert to binary */
+    for (i = j = 0; i < sizeof(key); i += 2, j++)
+      key[j] = (unhex(key[i]) << 4) | unhex(key[i + 1]);
+    if (j <= DES_KEY_SZ)
+      memset(key + j, 0, sizeof(key) - j);
+    key_sched((C_Block *) key, schedule);
+    memset(key, 0, sizeof(key));   
+    if (newpwd) {
+       ecb_encrypt((C_Block *) newpwd, (C_Block *) newpwd, schedule,
+                   DES_ENCRYPT);
     } else {
-      fprintf(stderr, _("Could not create crypt handle.\n"));
-      err = 1;
+      /* decrypt the password */
+      ecb_encrypt((C_Block *) buf, (C_Block *) buf, schedule, DES_DECRYPT);
     }
-#else
-    DES_key_schedule schedule;
-
-    DES_set_key_unchecked((DES_cblock *) key, &schedule);
-    DES_ecb_encrypt((DES_cblock *) src, (DES_cblock *) dst,
-                    &schedule, DES_DECRYPT);
-
-    memset(&schedule, 0, sizeof(schedule));
-#endif
+    memset(&schedule, 0, sizeof(schedule));      
   }
 
-  memset(key, 0, HEXPASSWDLEN);
-
-  return err;
-}
+  if (newpwd) {
+    const unsigned char hextable[] = "0123456789ABCDEF";
 
-static int encrypt_passwd(u_int8_t *dst, const u_int8_t *src, int keyfd)
-{
-  const u_int8_t *key;
-  int err = 0;
-
-  key = retrieve_key(keyfd);
-  if (!key)
-    return 0;
-
-  {
-#if HAVE_GCRYPT
-    GcryCipherHd handle;
-    int ret;
-                                                                                
-    handle = gcry_cipher_open(GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0);
-    if (handle) {
-      ret = gcry_cipher_setkey(handle, key, DES_KEY_SZ);
-      if (!ret)
-        ret = gcry_cipher_encrypt(handle, dst, 8, src, 0);
-      gcry_cipher_close(handle);
-      if (ret) {
-        fprintf(stderr, _("Encryption error: %s\n"), gcry_strerror(ret));
-        err = 1;
-      }
-    } else {
-      fprintf(stderr, _("Could not create crypt handle.\n"));
-      err = 1;
+    /* convert to hex */
+    for (i = j = 0; i < DES_KEY_SZ; i++, j += 2) {
+      buf[j] = hextable[(newpwd[i] & 0xF0) >> 4];
+      buf[j + 1] = hextable[newpwd[i] & 0x0F];
     }
-#else
-    DES_key_schedule schedule;
-
-    DES_set_key_unchecked((DES_cblock *) key, &schedule);
-    DES_ecb_encrypt((DES_cblock *) src, (DES_cblock *) dst,
-                    &schedule, DES_ENCRYPT);
-
-    memset(&schedule, 0, sizeof(schedule));      
-#endif
   }
-
-  return err;
 }
 
 /* this matches the code in uam_randnum.c */
@@ -211,12 +120,11 @@ static int update_passwd(const char *path, const char *name, int flags)
   char password[PASSWDLEN + 1], *p, *passwd;
   FILE *fp;
   off_t pos;
-  int found = 0;
   int keyfd = -1, err = 0;
 
   if ((fp = fopen(path, "r+")) == NULL) {
-    fprintf(stderr, _("Can't open password file %s: %s.\n"), path, strerror(errno));
-    return 1;
+    fprintf(stderr, "afppasswd: can't open %s\n", path);
+    return -1;
   }
 
   /* open the key file if it exists */
@@ -224,11 +132,6 @@ static int update_passwd(const char *path, const char *name, int flags)
   if (strlen(path) < sizeof(buf) - 5) {
     strcat(buf, ".key");
     keyfd = open(buf, O_RDONLY);
-    if (keyfd == -1 && errno != ENOENT) {
-      fprintf(stderr, _("Can't open key file %s: %s\n"), buf, strerror(errno));
-      err = 1;
-      goto update_done;
-    }
   } 
 
   pos = ftell(fp);
@@ -236,97 +139,77 @@ static int update_passwd(const char *path, const char *name, int flags)
   while (fgets(buf, sizeof(buf), fp)) {
     if ((p = strchr(buf, ':'))) {
       /* check for a match */
-      if (strncmp(buf, name, p - buf) == 0) {
+      if (strlen(name) == (p - buf) && 
+          strncmp(buf, name, p - buf) == 0) {
        p++;
        if (!(flags & OPT_ISROOT) && (*p == PASSWD_ILLEGAL)) {
-         fprintf(stderr, _("Your password is disabled. Please see your administrator.\n"));
+         fprintf(stderr, "Your password is disabled. Please see your administrator.\n");
          break;
        }
-       found = 1;
-       break;
+       goto found_entry;
       }
     }
     pos = ftell(fp);
     memset(buf, 0, sizeof(buf));
   }
 
-  if (!found) {
-    if ((flags & OPT_ISROOT) && (flags & OPT_ADDUSER)) {
-      strcpy(buf, name);
-      strcat(buf, FORMAT);
-      p = strchr(buf, ':') + 1;
-      fwrite(buf, strlen(buf), 1, fp);
-    } else {
-      fprintf(stderr, _("Can't find user %s in %s\n"), name, path);
-      err = 1;
-      goto update_done;
-    }
+  if (flags & OPT_ADDUSER) {
+    strcpy(buf, name);
+    strcat(buf, FORMAT);
+    p = strchr(buf, ':') + 1;
+    fwrite(buf, strlen(buf), 1, fp);
+  } else {
+    fprintf(stderr, "afppasswd: can't find %s in %s\n", name, path);
+    err = -1;
+    goto update_done;
   }
 
+found_entry:
   /* need to verify against old password */
   if ((flags & OPT_ISROOT) == 0) {
-    passwd = getpass(_("Enter OLD AFP password: "));
-    unhexify(p, p);
-    err = decrypt_passwd(p, p, keyfd);
-    if (err) {
-      memset(passwd, 0, strlen(passwd));
-      goto update_done;
-    }
+    passwd = getpass("Enter OLD AFP password: ");
+    convert_passwd(p, NULL, keyfd);
     if (strncmp(passwd, p, PASSWDLEN)) {
-      memset(passwd, 0, strlen(passwd));
-      fprintf(stderr, _("Wrong password.\n"));
-      err = 1;
+      fprintf(stderr, "afppasswd: invalid password.\n");
+      err = -1;
       goto update_done;
     }
-    memset(passwd, 0, strlen(passwd));
   }
 
   /* new password */
-  passwd = getpass(_("Enter NEW AFP password: "));
+  passwd = getpass("Enter NEW AFP password: ");
   memcpy(password, passwd, sizeof(password));
-  memset(passwd, 0, strlen(passwd));
   password[PASSWDLEN] = '\0';
 #ifdef USE_CRACKLIB
   if (!(flags & OPT_NOCRACK)) {
-    char *str;
-    if (str = FascistCheck(password, _PATH_CRACKLIB)) { 
-      memset(password, 0, PASSWDLEN);
-      fprintf(stderr, _("Error: %s\n"), str);
-      err = 1;
-      goto update_done;
+    if (passwd = FascistCheck(password, _PATH_CRACKLIB)) { 
+        fprintf(stderr, "Error: %s\n", passwd);
+        err = -1;
+        goto update_done;
     } 
   }
 #endif /* USE_CRACKLIB */
 
-  passwd = getpass(_("Enter NEW AFP password again: "));
+  passwd = getpass("Enter NEW AFP password again: ");
   if (strcmp(passwd, password) == 0) {
-    struct flock lock;
-    int fd = fileno(fp);
-
-    memset(passwd, 0, strlen(passwd));
-
-    err = encrypt_passwd(password, password, keyfd);
-    if (err)
-      goto update_done;
-    hexify(p, password);
-
-    lock.l_type = F_WRLCK;
-    lock.l_start = pos;
-    lock.l_len = 1;
-    lock.l_whence = SEEK_SET;
-    fseek(fp, pos, SEEK_SET);
-    fcntl(fd, F_SETLKW, &lock);
-    fwrite(buf, p - buf + HEXPASSWDLEN, 1, fp);
-    lock.l_type = F_UNLCK;
-    fcntl(fd, F_SETLK, &lock);
-    printf(_("Updated password.\n"));
-    memset(password, 0, PASSWDLEN);
+     struct flock lock;
+     int fd = fileno(fp);
+
+     convert_passwd(p, password, keyfd);
+     lock.l_type = F_WRLCK;
+     lock.l_start = pos;
+     lock.l_len = 1;
+     lock.l_whence = SEEK_SET;
+     fseek(fp, pos, SEEK_SET);
+     fcntl(fd, F_SETLKW, &lock);
+     fwrite(buf, p - buf + HEXPASSWDLEN, 1, fp);
+     lock.l_type = F_UNLCK;
+     fcntl(fd, F_SETLK, &lock);
+     printf("afppasswd: updated password.\n");
 
   } else {
-    memset(passwd, 0, strlen(passwd));
-    memset(password, 0, PASSWDLEN);
-    fprintf(stderr, _("Passwords don't match!\n"));
-    err = 1;
+    fprintf(stderr, "afppasswd: passwords don't match!\n");
+    err = -1;
   }
 
 update_done:
@@ -345,8 +228,8 @@ static int create_file(const char *path, uid_t minuid)
 
   
   if ((fd = open(path, O_CREAT | O_TRUNC | O_RDWR, 0600)) < 0) {
-    fprintf(stderr, _("Can't create password file %s: %s\n"), path, strerror(errno));
-    return 1;
+    fprintf(stderr, "afppasswd: can't create %s\n", path);
+    return -1;
   }
 
   setpwent();
@@ -360,9 +243,9 @@ static int create_file(const char *path, uid_t minuid)
     strcat(buf, FORMAT);
     len = strlen(buf);
     if (write(fd, buf, len) != len) {
-      fprintf(stderr, _("Problem writing to password file %s: %s\n"),
-             path, strerror(errno));
-      err = 1;
+      fprintf(stderr, "afppasswd: problem writing to %s: %s\n", path,
+             strerror(errno));
+      err = -1;
       break;
     }
   }
@@ -373,24 +256,6 @@ static int create_file(const char *path, uid_t minuid)
 }
 
 
-static void usage(void)
-{
-#ifdef USE_CRACKLIB
-    fprintf(stderr, _("Usage: afppasswd [-acfn] [-u minuid] [-p path] [username]\n"));
-#else /* USE_CRACKLIB */
-    fprintf(stderr, _("Usage: afppasswd [-acf] [-u minuid] [-p path] [username]\n"));
-#endif /* USE_CRACKLIB */
-    fprintf(stderr, _("  -a        add a new user\n"));
-    fprintf(stderr, _("  -c        create and initialize password file or specific user\n"));
-    fprintf(stderr, _("  -f        force an action\n"));
-#ifdef USE_CRACKLIB
-    fprintf(stderr, _("  -n        disable cracklib checking of passwords\n"));
-#endif /* USE_CRACKLIB */
-    fprintf(stderr, _("  -u uid    minimum uid to use, defaults to 100\n"));
-    fprintf(stderr, _("  -p path   path to afppasswd file\n"));
-}
-
-
 int main(int argc, char **argv)
 {
   struct stat st;
@@ -405,8 +270,16 @@ int main(int argc, char **argv)
   flags = ((uid = getuid()) == 0) ? OPT_ISROOT : 0;
 
   if (((flags & OPT_ISROOT) == 0) && (argc > 1)) {
-    usage();
-    return 1;
+    fprintf(stderr, "Usage: afppasswd [-acfn] [-u minuid] [-p path] [username]\n");
+    fprintf(stderr, "  -a        add a new user\n");
+    fprintf(stderr, "  -c        create and initialize password file or specific user\n");
+    fprintf(stderr, "  -f        force an action\n");
+#ifdef USE_CRACKLIB
+    fprintf(stderr, "  -n        disable cracklib checking of passwords\n");
+#endif /* USE_CRACKLIB */
+    fprintf(stderr, "  -u uid    minimum uid to use, defaults to 100\n");
+    fprintf(stderr, "  -p path   path to afppasswd file\n");
+    return -1;
   }
 
   while ((i = getopt(argc, argv, OPTIONS)) != EOF) {
@@ -439,28 +312,41 @@ int main(int argc, char **argv)
   
   if (err || (optind + ((flags & OPT_CREATE) ? 0 : 
                        (flags & OPT_ISROOT)) != argc)) {
-    usage();
-    return 1;
+#ifdef USE_CRACKLIB
+    fprintf(stderr, "Usage: afppasswd [-acfn] [-u minuid] [-p path] [username]\n");
+#else /* USE_CRACKLIB */
+    fprintf(stderr, "Usage: afppasswd [-acf] [-u minuid] [-p path] [username]\n");
+#endif /* USE_CRACKLIB */
+    fprintf(stderr, "  -a        add a new user\n");
+    fprintf(stderr, "  -c        create and initialize password file or specific user\n");
+    fprintf(stderr, "  -f        force an action\n");
+#ifdef USE_CRACKLIB
+    fprintf(stderr, "  -n        disable cracklib checking of passwords\n");
+#endif /* USE_CRACKLIB */
+    fprintf(stderr, "  -u uid    minimum uid to use, defaults to 100\n");
+    fprintf(stderr, "  -p path   path to afppasswd file\n");
+    return -1;
   }
 
+  i = stat(path, &st);
   if (flags & OPT_CREATE) {
     if ((flags & OPT_ISROOT) == 0) {
-      fprintf(stderr, _("Only root can create the password file.\n"));
-      return 1;
+      fprintf(stderr, "afppasswd: only root can create the password file.\n");
+      return -1;
     }
 
-    if (!stat(path, &st) && ((flags & OPT_FORCE) == 0)) {
-      fprintf(stderr, _("Password file already exists.\n"));
-      return 1;
+    if (!i && ((flags & OPT_FORCE) == 0)) {
+      fprintf(stderr, "afppasswd: password file already exists.\n");
+      return -1;
     }
     return create_file(path, uid_min);
 
   } else {
     struct passwd *pwd = NULL;
 
-    if (stat(path, &st) < 0) {
-      fprintf(stderr, _("Password file %s doesn't exist.\n"), path);
-      return 1;
+    if (i < 0) {
+      fprintf(stderr, "afppasswd: %s doesn't exist.\n", path);
+      return -1;
     }
     
     /* if we're root, we need to specify the username */
@@ -468,7 +354,7 @@ int main(int argc, char **argv)
     if (pwd)
       return update_passwd(path, pwd->pw_name, flags);
 
-    fprintf(stderr, _("Can't get password entry.\n"));
-    return 1;
+    fprintf(stderr, "afppasswd: can't get password entry.\n");
+    return -1;
   }
 }
index f7d5176ccde238782503cacc3c7da72aeef19f24..8834f14d3d78f223547e9e04920d284276f19fcb 100644 (file)
@@ -1,6 +1,7 @@
 Makefile
 Makefile.in
-cnid_didname_verify
+cnid2_create
 cnid_maint
+cnid_index
 .deps
 .libs
index c318a3b11a39b6bde81a55ac651773eae13efb30..21ed2fd55d63247a7f3baf23d65e49fb6d7b4ba6 100644 (file)
@@ -1,9 +1,19 @@
 # Makefile.am for bin/cnid/
 
-EXTRA_DIST = cnid_maint.in
+EXTRA_DIST = cnid_maint.in cnid2_create.in
+INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/sys
 
-if COMPILE_CNID
-bin_SCRIPTS = cnid_maint
-else
-bin_SCRIPTS = 
-endif
+#if COMPILE_CNID
+bin_SCRIPTS = cnid_maint cnid2_create
+bin_PROGRAMS = cnid_index
+#else
+#bin_SCRIPTS = 
+#endif
+
+cnid_index_SOURCES = cnid_index.c 
+
+cnid_index_LDADD = $(top_builddir)/libatalk/libatalk.la
+
+LIBS = @LIBS@ @BDB_LIBS@
+CFLAGS = @CFLAGS@ @BDB_CFLAGS@ 
diff --git a/bin/cnid/cnid2_create.in b/bin/cnid/cnid2_create.in
new file mode 100755 (executable)
index 0000000..e81ff1f
--- /dev/null
@@ -0,0 +1,362 @@
+#!@PERL@
+
+#
+# Upgrade version 1 CNID databases to version 2
+#
+# $Id: cnid2_create.in,v 1.2 2005-04-28 20:49:19 bfernhomberg Exp $
+#
+# Copyright (C) Joerg Lenneis 2003
+# All Rights Reserved.  See COPYING.
+#
+#
+
+use strict;
+
+
+### Globals
+
+my $toplevel = $ARGV[0];
+
+# Assume our current directory is .AppleDB in the share directory as the default. 
+
+$toplevel = ".." unless $toplevel;
+
+# Main file information data structure. Each entry in did_table points
+# to a list of hashes. Key is a DID and each list member is a hash
+# describing a file or directory in the directory corresponding to the
+# DID. n_entries is the number of items found, output_list contains
+# all entries that are eventually written to the output file.
+
+my %did_table;
+my $n_entries;
+my @output_list;
+
+# RootInfo values in the new format
+
+my $ri_cnid    = "00000000";
+my $ri_dev     = "1122334400000000";
+my $ri_ino     = "0000000000000000";
+my $ri_did     = "00000000";
+my $ri_hexname = "526f6f74496e666f00";  # RootInfo\0
+
+
+# Current CNID found in didname.db
+my $current_cnid;
+
+# Largest CNID from cnid.db, used if we cannot find the current CNID in didname.db 
+my $max_cnid;
+
+# Number of bogus/invalid entries found in the DB 
+my $errors_found;
+
+# Filenames
+
+my $didname_dump = "didname.dump";
+my $cnid_dump    = "cnid.dump";
+my $cnid2_dump   = "cnid2.dump";
+
+### Subroutines
+
+sub skip_header($)
+{
+    my $handle = shift;
+    my $header_ok;
+
+    while (<$handle>) {
+       chomp;
+       if ($_ eq "HEADER=END") {
+           $header_ok = 1;
+           last;
+       }
+    }
+    die "No valid header found, invalid input file?" unless $header_ok;
+}
+
+sub print_eentry($$)
+{
+    my $reason = shift;
+    my $entry  = shift;
+
+    printf "??:%s %-9s%-9s%-9s%-9s%s\n",
+    $reason,
+    $entry->{cnid},
+    $entry->{dev},
+    $entry->{ino},
+    $entry->{did},
+    $entry->{name};
+    
+    $errors_found++;
+}
+
+sub find_current_cnid()
+{
+    my $key;
+    my $val;
+    my $cnid;
+    my $compare = " " . $ri_did . $ri_hexname;
+
+    # get rid of "00" at the end, RootInfo in the old format does not have a trailing \0
+
+    $compare =~ s/00$//;
+    
+    open DIDNAME, "< $didname_dump" or die "Unable to open $didname_dump: $!";
+    skip_header(*DIDNAME);
+
+    while (1) {
+       $key = <DIDNAME>;
+       chomp $key;
+       last if $key eq "DATA=END";
+       $val = <DIDNAME>;
+       chomp $val;
+       last unless defined($key) and defined($val);    
+       if ($key eq $compare) {
+           # \00\00\00\00RootInfo
+           $val =~ s/^ //;
+           $cnid = $val;
+           last;
+       }       
+    }
+    close DIDNAME;
+    return $cnid;
+}
+
+sub verify_entry($)
+{
+    my $entry = shift;
+
+    if (length($entry->{cnid}) != 8 or length($entry->{name}) == 0) {
+       print_eentry("fmt", $entry);
+       return 0;
+    } else {
+       return 1;
+    }
+}
+
+sub create_did_table()
+{    
+    my $data_ok;
+    my $key;
+    my $val;
+    my $len;    
+    my $i;
+    my $name;
+    my $cmax;
+
+    open CNID, "< $cnid_dump" or die "Unable to open $cnid_dump: $!";
+    skip_header(*CNID);
+
+    while (1) {
+       $key = <CNID>;
+       chomp $key;
+       $key =~ s/^ //;
+       if ($key eq "DATA=END") {
+           $data_ok = 1;
+           last;
+       }
+       my $val = <CNID>;
+       chomp $val;
+       $val =~ s/^ //;
+
+       last unless defined($key) and defined($val);
+    
+       # We do not worry about converting any of the
+       # integer values into binary form. They are in network byte order, 
+       # so we know how to extend them. We just treat them as hexadecimal ASCII strings.
+       # The file name is also stored as a proper string, since we need to 
+       # look for it in the file system.
+
+       my $entry;
+    
+       $entry->{cnid}    = $key;
+       $entry->{dev}     = substr($val, 0,   8);
+       $entry->{ino}     = substr($val, 8,   8);
+       $entry->{did}     = substr($val, 16,  8);
+       $entry->{hexname} = substr($val, 24);
+    
+       $len = length($entry->{hexname}) - 2;
+       $i = 0;
+       $name = '';
+       while ($i < $len) {
+           $name .= chr(hex(substr($entry->{hexname}, $i, 2)));
+           $i += 2;
+       }
+       $entry->{name} = $name;
+
+       if (verify_entry($entry)) {
+           push @{$did_table{$entry->{did}}}, $entry;
+           $n_entries++;
+           $cmax = $entry->{cnid} if $entry->{cnid} gt $cmax;
+       }
+    }
+    close CNID;
+    die "No valid end of data found, invalid input file?" unless $data_ok;
+    return $cmax;
+}
+
+sub output_header($$$)
+{
+    my $handle = shift;
+    my $dbname = shift;
+    my $n      = shift;
+    
+    printf $handle "VERSION=3\nformat=bytevalue\ndatabase=%s\ntype=btree\nHEADER=END\n", $dbname;
+}
+
+sub expand_did_table($$)
+{
+    my $did = shift;
+    my $basename = shift;
+    my $entry;
+    my $name;
+
+    foreach $entry (@{$did_table{$did}}) {
+       $name = $basename . "/" . $entry->{name};
+
+       if ( -e $name ) { 
+           if ( -d $name ) { 
+               $entry->{type} = "00000001"; 
+           } else { 
+               $entry->{type} = "00000000"; 
+           } 
+       } else { 
+           
+            # The file/dir does not exist in the file system. This could result
+           # from a non-afpd rename that has not yet been picked up by afpd and is
+           # fixable. We need a guess at the type, though.
+           
+           if ($did_table{$entry->{cnid}} and scalar(@{$did_table{$entry->{cnid}}}) > 0) {
+
+               # We have entries hanging off this entry in our table,
+               # so this must be a directory
+               $entry->{type} = "00000001";
+           } else {
+               # If this is actually an empty directory that was renamed, 
+               # the entry will be deleted by afpd on the next access, 
+               # so this should be safe 
+               $entry->{type} = "00000000";            
+           }
+       }
+
+       $entry->{reached} = 1;
+       push @output_list, $entry;
+       expand_did_table($entry->{cnid}, $name);
+    }
+}
+
+sub find_unreachable()
+{
+    my $did;
+    my $list;
+    my $entry;
+
+    while (($did, $list) = each %did_table) {
+       foreach $entry (@{$list}) {
+           print_eentry("reach", $entry) unless $entry->{reached};
+       }
+    }
+}
+
+sub find_duplicates()
+{
+    my %seen_cnid;
+    my %seen_devino;
+    my %seen_didname;    
+    my $cnid;
+    my $devino;
+    my $didname;
+    my $err;
+    my $entry;
+    
+    for (my $i = 0; $i < scalar(@output_list); $i++) {
+       $err = 0;
+       $entry = $output_list[$i];
+       $cnid = $entry->{cnid};
+       $devino = $entry->{dev} . $entry->{ino};
+       $didname = $entry->{did} . $entry->{name};
+       if ($seen_cnid{$cnid}) {
+           print_eentry("exist_cnid", $entry);
+           $err++;
+       }
+       if ($seen_cnid{$cnid}) {
+           print_eentry("dupl_cnid", $entry);
+           $err++;
+       }
+       if ($seen_devino{$devino}) {
+           print_eentry("dupl_devino", $entry);
+           $err++;
+       }
+       if ($seen_didname{$didname}) {
+           print_eentry("dupl_didname", $entry);
+           $err++;
+       }
+       if ($err) {
+           splice(@output_list, $i, 1);
+       } else {
+           $seen_cnid{$cnid} = 1;
+           $seen_devino{$devino} = 1;
+           $seen_didname{$didname} = 1;
+       }
+    }
+}
+
+
+print "Finding the current CNID from $didname_dump\n";
+$current_cnid = find_current_cnid();
+print "Reading in entries from $cnid_dump\n";
+$max_cnid = create_did_table();
+print "Found $n_entries entries\n";
+
+if (not $current_cnid) {
+    print "Warning: could not find a valid entry for the current CNID in $didname_dump.\n";
+    print "Using maximum CNID value $max_cnid from $cnid_dump instead\n";
+    $current_cnid = $max_cnid;
+} else {
+    print "Current CNID is $current_cnid\n";
+}
+
+print "Building directory tree according to cnid.db\n";
+expand_did_table("00000002", $toplevel);
+
+if ($n_entries > scalar(@output_list)) {
+    print "Looking for unreachable nodes in the directory tree:\n";
+    find_unreachable();
+}
+
+print "Looking for duplicate entries\n";
+find_duplicates();
+
+print "Creating $cnid2_dump\n";
+open CNID2, "> $cnid2_dump" or die "Unable to open $cnid2_dump for writing: $!";
+output_header(*CNID2, "cnid2.db", scalar(@output_list) + 1);
+foreach my $entry (@output_list) {
+    print CNID2 " ", $entry->{cnid}, "\n";
+    print CNID2 " ", $entry->{cnid}, 
+                     "00000000", $entry->{dev}, "00000000", $entry->{ino},
+                     $entry->{type},
+                     $entry->{did}, $entry->{hexname}, "\n";
+}
+print CNID2 " ", $ri_cnid, "\n";
+print CNID2 " ", $ri_cnid, $ri_dev, $ri_ino, $current_cnid, $ri_did, $ri_hexname, "\n";
+print CNID2 "DATA=END\n";
+
+output_header(*CNID2, "devino.db", scalar(@output_list) + 1);
+foreach my $entry (@output_list) {
+    print CNID2 " ", "00000000", $entry->{dev}, "00000000", $entry->{ino}, "\n";
+    print CNID2 " ", $entry->{cnid}, "\n";
+}
+print CNID2 " ", $ri_dev, $ri_ino, "\n";
+print CNID2 " ", $ri_cnid, "\n";
+print CNID2 "DATA=END\n";
+
+output_header(*CNID2, "didname.db", scalar(@output_list) + 1);
+foreach my $entry (@output_list) {
+    print CNID2 " ", $entry->{did}, $entry->{hexname}, "\n";
+    print CNID2 " ", $entry->{cnid}, "\n";
+}
+print CNID2 " ", $ri_did, $ri_hexname, "\n";
+print CNID2 " ", $ri_cnid, "\n";
+print CNID2 "DATA=END\n";
+
+close CNID2;
+
+exit 0;
diff --git a/bin/cnid/cnid_index.c b/bin/cnid/cnid_index.c
new file mode 100644 (file)
index 0000000..42265a7
--- /dev/null
@@ -0,0 +1,589 @@
+/*
+ * $Id: cnid_index.c,v 1.2 2005-04-28 20:49:19 bfernhomberg Exp $
+ *
+ * All Rights Reserved.  See COPYING.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif /* HAVE_FCNTL_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 <sys/file.h>
+
+#include <netatalk/endian.h>
+#include <atalk/cnid_dbd_private.h>
+#include <atalk/logger.h>
+
+#define LOCKFILENAME  "lock"
+static int exit_sig = 0;
+
+/* Copy and past from etc/cnid_dbd/dbif.c */
+#include <db.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 | DB_PRIVATE) 
+#endif
+
+#define DBIF_DB_CNT 3
+
+#define DBIF_IDX_CNID      0
+#define DBIF_IDX_DEVINO    1
+#define DBIF_IDX_DIDNAME   2
+
+static struct db_table {
+     char            *name;
+     DB              *db;
+     u_int32_t       general_flags;
+     DBTYPE          type;
+} db_table[] =
+{
+     { "cnid2.db",       NULL,      0, DB_BTREE},
+     { "devino.db",      NULL,      0, DB_BTREE},
+     { "didname.db",     NULL,      0, DB_BTREE},
+};
+
+static char *old_dbfiles[] = {"cnid.db", NULL};
+
+/* --------------- */
+int didname(dbp, pkey, pdata, skey)
+DB *dbp _U_;
+const DBT *pkey _U_, *pdata;
+DBT *skey;
+{
+int len;
+    memset(skey, 0, sizeof(DBT));
+    skey->data = (char *)pdata->data + CNID_DID_OFS;
+    /* FIXME: At least DB 4.0.14 and 4.1.25 pass in the correct length of
+       pdata.size. strlen is therefore not needed. Also, skey should be zeroed
+       out already. */
+    len = strlen((char *)skey->data + CNID_DID_LEN);
+    skey->size = CNID_DID_LEN + len + 1;
+    return (0);
+}
+/* --------------- */
+int devino(dbp, pkey, pdata, skey)
+DB *dbp _U_;
+const DBT *pkey _U_, *pdata;
+DBT *skey;
+{
+    memset(skey, 0, sizeof(DBT));
+    skey->data = (char *)pdata->data + CNID_DEVINO_OFS;
+    skey->size = CNID_DEVINO_LEN;
+    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, db_txn, s, callback, flags);
+#else
+#if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR == 0)
+    return p->associate(p,       s, callback, flags);
+#else
+    return 0;
+#endif
+#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)
+    ret = db->open(db, db_txn, file, name, type, DB_CREATE, mode); 
+#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;
+    }
+}
+
+/* --------------- */
+static int dbif_open(int do_truncate)
+{
+    int ret;
+    int i;
+    u_int32_t count;
+
+    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 (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);
+
+        if (do_truncate && i > 0) {
+           if ((ret = db_table[i].db->truncate(db_table[i].db, db_txn, &count, 0))) {
+                LOG(log_error, logtype_cnid, "error truncating database %s: %s", 
+                    db_table[i].name, db_strerror(ret));
+                return -1;
+            }
+        }
+    }
+
+    /* 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, (do_truncate)?DB_CREATE: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, (do_truncate)?DB_CREATE:0)) != 0) {
+        LOG(log_error, logtype_cnid, "Failed to associate devino database: %s",db_strerror(ret));
+       return -1;
+    }
+
+    return 0;
+}
+
+/* ------------------------ */
+static int dbif_closedb(void)
+{
+    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 (err)
+        return -1;
+    return 0;
+}
+
+/* ------------------------ */
+static int dbif_close(void)
+{
+    int ret;
+    int err = 0;
+    
+    if (dbif_closedb()) 
+       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;
+    return 0;
+}
+/* --------------- */
+static int upgrade_required(void)
+{
+    int i;
+    int found = 0;
+    struct stat st;
+    
+    for (i = 0; old_dbfiles[i] != NULL; i++) {
+       if ( !(stat(old_dbfiles[i], &st) < 0) ) {
+           found++;
+           continue;
+       }
+       if (errno != ENOENT) {
+           LOG(log_error, logtype_cnid, "cnid_open: Checking %s gave %s", old_dbfiles[i], strerror(errno));
+           found++;
+       }
+    }
+    return found;
+}
+
+/* -------------------------- */
+static int dbif_sync(void)
+{
+    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;
+}
+
+/* -------------------------- */
+static int dbif_count(const int dbi, u_int32_t *count) 
+{
+    int ret;
+    DB_BTREE_STAT *sp;
+    DB *db = db_table[dbi].db;
+
+    ret = db->stat(db, &sp, 0);
+
+    if (ret) {
+        LOG(log_error, logtype_cnid, "error getting stat infotmation on database: %s", db_strerror(errno));
+        return -1;
+    }
+
+    *count = sp->bt_ndata;
+    free(sp);
+
+    return 0;
+}
+
+/* -------------------------- */
+static int dbd_check(char *dbdir)
+{
+    u_int32_t c_didname = 0, c_devino = 0, c_cnid = 0;
+
+    LOG(log_debug, logtype_cnid, "CNID database at `%s' is being checked (quick)", dbdir);
+
+    if (dbif_count(DBIF_IDX_CNID, &c_cnid)) 
+        return -1;
+
+    if (dbif_count(DBIF_IDX_DEVINO, &c_devino))
+        return -1;
+
+    /* bailout after the first error */
+    if ( c_cnid != c_devino) {
+        LOG(log_error, logtype_cnid, "CNID database at `%s' corrupted (%u/%u)", dbdir, c_cnid, c_devino);
+        return 1;
+    }
+
+    if (dbif_count(DBIF_IDX_DIDNAME, &c_didname)) 
+        return -1;
+
+    if ( c_cnid != c_didname) {
+        LOG(log_error, logtype_cnid, "CNID database at `%s' corrupted (%u/%u)", dbdir, c_cnid, c_didname);
+        return 1;
+    }
+
+    LOG(log_debug, logtype_cnid, "CNID database at `%s' seems ok, %u entries.", dbdir, c_cnid);
+    return 0;  
+}
+
+/* --------------- */
+/*
+ *  We assume our current directory is already the BDB homedir. Otherwise
+ *  opening the databases will not work as expected. If we use transactions,
+ *  dbif_env_init(), dbif_close() and dbif_stamp() are the only interface
+ *  functions that can be called without a valid transaction handle in db_txn.
+ */
+static int dbif_env_init(void)
+{
+    int ret;
+#ifdef CNID_BACKEND_DBD_TXN
+    char **logfiles = NULL;
+    char **file;
+#endif
+
+    /* Refuse to do anything if this is an old version of the CNID database */
+    if (upgrade_required()) {
+       LOG(log_error, logtype_cnid, "Found version 1 of the CNID database. Please upgrade to version 2");
+       return -1;
+    }
+
+    if ((db_errlog = fopen(DB_ERRLOGFILE, "a")) == NULL)
+        LOG(log_warning, logtype_cnid, "error creating/opening DB errlogfile: %s", strerror(errno));
+
+#ifdef CNID_BACKEND_DBD_TXN
+    if ((ret = db_env_create(&db_env, 0))) {
+        LOG(log_error, logtype_cnid, "error creating DB environment: %s", 
+            db_strerror(ret));
+        db_env = NULL;
+        return -1;
+    }    
+    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, ".", DBOPTIONS | DB_PRIVATE | DB_RECOVER, 0))) {
+        LOG(log_error, logtype_cnid, "error opening DB environment: %s", 
+            db_strerror(ret));
+        db_env->close(db_env, 0);
+        db_env = NULL;
+        return -1;
+    }
+
+    if (db_errlog != NULL)
+        fflush(db_errlog);
+
+    if ((ret = db_env->close(db_env, 0))) {
+        LOG(log_error, logtype_cnid, "error closing DB environment after recovery: %s", 
+            db_strerror(ret));
+        db_env = NULL;
+        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));
+        db_env = NULL;
+        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);
+        db_env = NULL;
+        return -1;      
+    }
+
+#ifdef CNID_BACKEND_DBD_TXN
+    if (db_env->log_archive(db_env, &logfiles, 0)) {
+       LOG(log_error, logtype_cnid, "error getting list of stale logfiles: %s",
+            db_strerror(ret));
+        db_env->close(db_env, 0);
+        db_env = NULL;
+        return -1;
+    }
+    if (logfiles != NULL) {
+       for (file = logfiles; *file != NULL; file++) {
+           if (unlink(*file) < 0)
+               LOG(log_warning, logtype_cnid, "Error removing stale logfile %s: %s", *file, strerror(errno));
+       }
+       free(logfiles);
+    }
+#endif
+    return 0;
+}
+
+
+static void sig_exit(int signo)
+{
+    exit_sig = signo;
+    return;
+}
+
+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;
+}
+
+/* ------------------------ */
+int get_lock(void)
+{
+    int lockfd;
+    struct flock lock;
+
+    if ((lockfd = open(LOCKFILENAME, O_RDWR | O_CREAT, 0644)) < 0) {
+       LOG(log_error, logtype_cnid, "main: error opening lockfile: %s", strerror(errno));
+       exit(1);
+    }
+    
+    lock.l_start  = 0;
+    lock.l_whence = SEEK_SET;
+    lock.l_len    = 0;
+    lock.l_type   = F_WRLCK;
+
+    if (fcntl(lockfd, F_SETLK, &lock) < 0) {
+       if (errno == EACCES || errno == EAGAIN) {
+           exit(0);
+       } else {
+           LOG(log_error, logtype_cnid, "main: fcntl F_WRLCK lockfile: %s", strerror(errno));
+           exit(1);
+       }
+    }
+    
+    return lockfd;
+}
+
+/* ----------------------- */
+void set_signal(void)
+{
+    struct sigaction sv;
+
+    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);
+    }
+}
+
+/* ----------------------- */
+void free_lock(int lockfd)
+{
+    struct flock lock;
+
+    lock.l_start  = 0;
+    lock.l_whence = SEEK_SET;
+    lock.l_len    = 0;
+    lock.l_type = F_UNLCK;
+    fcntl(lockfd, F_SETLK, &lock);
+    close(lockfd);
+}
+
+/* ------------------------ */
+int main(int argc, char *argv[])
+{
+#ifdef CNID_BACKEND_DBD_TXN
+
+    fprintf(stderr, "%s doesn't work with db transaction enabled\n", argv[0]);
+    exit (1);
+    
+#else
+    int err = 0;
+    int ret;
+    int lockfd;
+    char *dir;
+       
+    set_processname("cnid_index");
+    syslog_setup(log_debug, logtype_default, logoption_ndelay | logoption_pid, logfacility_daemon);
+    
+    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);
+    }
+    
+    /* Before we do anything else, check if there is an instance of cnid_dbd
+       running already and silently exit if yes. */
+    lockfd = get_lock();
+    
+    LOG(log_info, logtype_cnid, "Startup, DB dir %s", dir);
+    
+    set_signal();
+    
+    /* 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 (dbif_env_init() < 0)
+        exit(2); /* FIXME: same exit code as failure for dbif_open() */  
+    
+#ifdef CNID_BACKEND_DBD_TXN
+    if (dbif_txn_begin() < 0)
+       exit(6);
+#endif
+    
+    if (dbif_open(0) < 0) {
+#ifdef CNID_BACKEND_DBD_TXN
+       dbif_txn_abort();
+#endif
+        dbif_close();
+        exit(2);
+    }
+
+#ifndef CNID_BACKEND_DBD_TXN
+    if ((ret = dbd_check(dir))) {
+        if (ret < 0) {
+            dbif_close();
+            exit(2);
+        }
+        dbif_closedb();
+       LOG(log_info, logtype_cnid, "main: re-opening, secondaries will be rebuilt. This may take some time");
+        if (dbif_open(1) < 0) {
+           LOG(log_info, logtype_cnid, "main: re-opening databases failed");
+            dbif_close();
+            exit(2);
+        }
+       LOG(log_info, logtype_cnid, "main: rebuilt done");
+    }
+#endif
+
+#ifdef CNID_BACKEND_DBD_TXN
+    if (dbif_txn_commit() < 0)
+       exit(6);
+#endif
+
+#ifndef CNID_BACKEND_DBD_TXN
+    /* FIXME: Do we really need to sync before closing the DB? Just closing it
+       should be enough. */
+    if (dbif_sync() < 0)
+        err++;
+#endif
+
+    if (dbif_close() < 0)
+        err++;
+        
+    free_lock(lockfd);
+    
+    if (err)
+        exit(4);
+#endif
+    return 0;
+}
index db44f2b96de8a0a15f4d9125c3eb20ffcb5db59b..7b717386811baf2280d7bec8f7b5e46fd0102b7a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: getzones.c,v 1.6 2001-08-11 11:47:22 srittau Exp $
+ * $Id: getzones.c,v 1.7 2005-04-28 20:49:19 bfernhomberg Exp $
  */
 
 #ifdef HAVE_CONFIG_H
@@ -24,6 +24,7 @@
 #include <netatalk/at.h>
 #include <atalk/atp.h>
 #include <atalk/util.h>
+#include <atalk/unicode.h>
 #include <atalk/zip.h>
 
 void print_zones(short n, char *buf);
@@ -151,7 +152,22 @@ int main( argc, argv )
  */
 void print_zones( short n, char *buf )
 {
+    size_t zone_len;
+    char *zone;
+
     for ( ; n--; buf += (*buf) + 1 ) {
-       printf( "%.*s\n", *buf, buf+1 );
+
+        if ((size_t)(-1) == (zone_len = convert_string_allocate( CH_MAC,
+                       CH_UNIX, buf+1, *buf, &zone)) ) {
+            zone_len = *buf;
+            if (( zone = strdup(buf+1)) == NULL ) {
+               perror( "strdup" );
+               exit( 1 );
+            }
+        }
+
+       printf( "%.*s\n", (int)zone_len, zone );
+
+       free(zone);
     }
 }
index 1e1ef76233b801879bc85ce9e1a4d33ed5dcd09a..589303698dadfa5e7739f37e19a2d5306c9bda99 100644 (file)
@@ -16,3 +16,8 @@ install-exec-hook:
                rm -f $(DESTDIR)$(bindir)/$$LINK; \
                $(LN_S) megatron $(DESTDIR)$(bindir)/$$LINK; \
        done
+
+uninstall-hook:
+       @for LINK in $(LINKS); do \
+               rm -f $(DESTDIR)$(bindir)/$$LINK; \
+       done
index 6ef52b8606a066ec25adbdd27120d4ecb35329e9..0d2faea90bc1a10ea04248119942382a7897a8f8 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: asingle.c,v 1.9 2003-08-09 14:28:36 srittau Exp $
+ * $Id: asingle.c,v 1.10 2005-04-28 20:49:19 bfernhomberg Exp $
  */
 
 #ifdef HAVE_CONFIG_H
@@ -64,7 +64,7 @@ u_char                header_buf[ AD_HEADER_LEN ];
 
 int single_open( singlefile, flags, fh, options )
     char               *singlefile;
-    int                        flags, options;
+    int                        flags, options _U_;
     struct FHeader     *fh;
 {
     int                        rc;
@@ -268,7 +268,7 @@ int single_header_read( fh, version )
  * Unless I can't get the current date, in which case use time zero.
  */
     if (( date_entry < 7 ) || ( date_entry > 8 )) {
-       if (( time_seconds = time( NULL )) == -1 ) {
+       if (( time_seconds = time( NULL )) == (u_int32_t)-1 ) {
            time_seconds = AD_DATE_START;
        } else {
            time_seconds = AD_DATE_FROM_UNIX(time_seconds);
@@ -344,11 +344,11 @@ u_char            sixteennulls[] = { 0, 0, 0, 0, 0, 0, 0, 0,
 
 int single_header_test(void)
 {
-    int                        cc;
+    ssize_t            cc;
     u_int32_t          templong;
 
     cc = read( single.filed, (char *)header_buf, sizeof( header_buf ));
-    if ( cc < sizeof( header_buf )) {
+    if ( cc < (ssize_t)sizeof( header_buf )) {
        perror( "Premature end of file :" );
        return( -1 );
     }
@@ -398,7 +398,7 @@ int single_header_test(void)
 int single_read( fork, buffer, length )
     int                        fork;
     char               *buffer;
-    int                        length;
+    u_int32_t          length;
 {
     u_int32_t          entry_id;
     char               *buf_ptr;
@@ -418,9 +418,9 @@ int single_read( fork, buffer, length )
            break;
     }
 
-    if ( single.entry[ entry_id ].ade_len < 0 ) {
-       fprintf( stderr, "single_read: Trying to read past end of fork!\n" );
-       return( single.entry[ entry_id ].ade_len );
+    if (single.entry[entry_id].ade_len > length) {
+       fprintf(stderr, "single_read: Trying to read past end of fork!, length %d, ade_len == %u\n", length, single.entry[entry_id].ade_len);
+       return single.entry[entry_id].ade_len;
     }
     if ( single.entry[ entry_id ].ade_len == 0 ) {
        if ( fork == DATA ) {
index 44a3ab124b67843046e9b1a30a820a324f7ebf8e..557ba9d0a782dc02f485f87b55c2984189960464 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: asingle.h,v 1.2 2001-06-29 14:14:46 rufustfirefly Exp $
+ * $Id: asingle.h,v 1.3 2005-04-28 20:49:19 bfernhomberg Exp $
  */
 
 #ifndef _ASINGLE_H
@@ -12,6 +12,6 @@ int single_open(char *singlefile, int flags, struct FHeader *fh, int options);
 int single_close(int readflag);
 int single_header_read(struct FHeader *fh, int version);
 int single_header_test(void);
-int single_read(int fork, char *buffer, int length);
+int single_read(int fork, char *buffer, u_int32_t length);
 
 #endif /* _ASINGLE_H */
index 819f5ca727b5ff27e8898c95789b343abd533c2b..3f0406d55ade78b48eb394a5e24dff28b45e8787 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: hqx.c,v 1.13 2003-06-06 21:17:19 srittau Exp $
+ * $Id: hqx.c,v 1.14 2005-04-28 20:49:19 bfernhomberg Exp $
  */
 
 #ifdef HAVE_CONFIG_H
@@ -207,9 +207,9 @@ int hqx_read( fork, buffer, length )
     fprintf( stderr, "hqx_read: remaining length is %d\n", hqx.forklen[fork] );
 #endif /* DEBUG >= 3 */
 
-    if ( hqx.forklen[ fork ] < 0 ) {
-       fprintf( stderr, "This should never happen, dude!\n" );
-       return( hqx.forklen[ fork ] );
+    if (hqx.forklen[fork] > length) {
+       fprintf(stderr, "This should never happen, dude! length %d, fork length == %u\n", length, hqx.forklen[fork]);
+       return hqx.forklen[fork];
     }
 
     if ( hqx.forklen[ fork ] == 0 ) {
@@ -393,7 +393,7 @@ int hqx_header_read( fh )
  */
 
 int hqx_header_write( fh )
-    struct FHeader     *fh;
+    struct FHeader     *fh _U_;
 {
     return( -1 );
 }
index b98ef75720e658fd6d4a819b06c7c32560da3266..bf85a080b2fffc27e0e177e3e6e11709c4b6fab1 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: macbin.c,v 1.11 2003-12-15 05:27:24 srittau Exp $
+ * $Id: macbin.c,v 1.12 2005-04-28 20:49:19 bfernhomberg Exp $
  */
 
 #ifdef HAVE_CONFIG_H
@@ -85,12 +85,12 @@ int bin_open( binfile, flags, fh, options )
 
     /* call localtime so that we get the timezone offset */
     bin.gmtoff = 0;
-#ifdef HAVE_STRUCT_TM_TM_GMTOFF
+#ifndef NO_STRUCT_TM_GMTOFF
     time(&t);
     tp = localtime(&t);
     if (tp)
         bin.gmtoff = tp->tm_gmtoff;
-#endif /* HAVE_STRUCT_TM_TM_GMTOFF */
+#endif /* ! NO_STRUCT_TM_GMTOFF */
 
     if ( flags == O_RDONLY ) { /* input */
        if ( strcmp( binfile, STDIN ) == 0 ) {
@@ -185,9 +185,9 @@ int bin_read( fork, buffer, length )
     fprintf( stderr, "bin_read: remaining length is %d\n", bin.forklen[fork] );
 #endif /* DEBUG >= 3 */
 
-    if ( bin.forklen[ fork ] < 0 ) {
-       fprintf( stderr, "This should never happen, dude!\n" );
-       return( bin.forklen[ fork ] );
+    if (bin.forklen[fork] > length) {
+       fprintf(stderr, "This should never happen, dude! length %d, fork length == %u\n", length, bin.forklen[fork]);
+       return bin.forklen[fork];
     }
 
     if ( bin.forklen[ fork ] == 0 ) {
@@ -286,13 +286,14 @@ int bin_write( fork, buffer, length )
        perror( "Couldn't write to macbinary file:" );
        return( cc );
     }
-    bin.forklen[ fork ] -= length;
 
-    if ( bin.forklen[ fork ] < 0 ) {
-       fprintf( stderr, "This should never happen, dude!\n" );
-       return( bin.forklen[ fork ] );
+    if (length > bin.forklen[fork]) {
+       fprintf(stderr, "This should never happen, dude! length %d, fork length %u\n", length, bin.forklen[fork]);
+       return bin.forklen[fork];
     }
 
+    bin.forklen[fork] -= length;
+
 /*
  * add the padding at end of data and resource forks
  */
@@ -595,13 +596,14 @@ int test_header(void)
         return -1;
 
     /* macbinary forks aren't larger than 0x7FFFFF */
+    /* we allow forks to be larger, breaking the specs */
     memcpy(&cc, head_buf + 83, sizeof(cc));
     cc = ntohl(cc);
-    if (cc > 0x7FFFFF)
+    if (cc > 0x7FFFFFFF)
         return -1;
     memcpy(&cc, head_buf + 87, sizeof(cc));
     cc = ntohl(cc);
-    if (cc > 0x7FFFFF)
+    if (cc > 0x7FFFFFFF)
         return -1;
 
 
index 49223d203bbb83041c137ada48f1dc7738846515..09035f4c09050d24447c058402e87b76162dcacc 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: megatron.c,v 1.9 2002-04-29 01:52:49 morgana Exp $
+ * $Id: megatron.c,v 1.10 2005-04-28 20:49:20 bfernhomberg Exp $
  */
 
 #ifdef HAVE_CONFIG_H
@@ -191,7 +191,7 @@ int megatron( path, module, newname, flags )
     struct FHeader     fh;
     int                        bufc;
     int                        fork;
-    int                        forkred;
+    unsigned int       forkred;
 
 /*
  * If the source file is not stdin, make sure it exists and
index cb7ab5a2646a05216a29c6c11c191bbb0e0fda56..dac81a0982ea090d8f3e406cc8de984bffef21e0 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: nad.c,v 1.11 2002-04-29 01:52:50 morgana Exp $
+ * $Id: nad.c,v 1.12 2005-04-28 20:49:20 bfernhomberg Exp $
  */
 
 #ifdef HAVE_CONFIG_H
 #endif /* HAVE_FCNTL_H */
 
 #include <atalk/adouble.h>
+#include <atalk/util.h>
+#include <atalk/volinfo.h>
 #include <netatalk/endian.h>
 #include "megatron.h"
 #include "nad.h"
 
+struct volinfo vol;
 static char            hexdig[] = "0123456789abcdef";
 
 static char mtou_buf[MAXPATHLEN + 1], utom_buf[MAXPATHLEN + 1];
@@ -308,6 +311,83 @@ static char *utompathsjis( char *from)
 
     return utom_buf;
  }
+
+static char *utompathiconv(char *upath)
+{
+    char        *m, *u;
+    u_int16_t    flags = CONV_IGNORE | CONV_UNESCAPEHEX;
+    size_t       outlen;
+    static char         mpath[MAXPATHLEN];
+
+    m = mpath;
+    outlen = strlen(upath);
+
+#if 0
+    if (vol->v_casefold & AFPVOL_UTOMUPPER)
+        flags |= CONV_TOUPPER;
+    else if (vol->v_casefold & AFPVOL_UTOMLOWER)
+        flags |= CONV_TOLOWER;
+#endif
+
+    u = upath;
+
+    /* convert charsets */
+    if ((size_t)-1 == ( outlen = convert_charset ( vol.v_volcharset, vol.v_maccharset, vol.v_maccharset, u, outlen, mpath, MAXPATHLEN, &flags)) ) {
+        fprintf( stderr, "Conversion from %s to %s for %s failed.", vol.v_volcodepage, vol.v_maccodepage, u);
+        goto utompath_error;
+    }
+
+    mpath[outlen] = 0;
+    if (flags & CONV_REQMANGLE) 
+       goto utompath_error;
+
+    return(m);
+
+utompath_error:
+    return(utompathcap( upath ));
+}
+
+char *mtoupathiconv(char *mpath)
+{
+    char        *m, *u;
+    size_t       inplen;
+    size_t       outlen;
+    u_int16_t    flags = 0;
+    static char         upath[MAXPATHLEN];
+
+    if ( *mpath == '\0' ) {
+        return( "." );
+    }
+
+    /* set conversion flags */
+    if (!(vol.v_flags & AFPVOL_NOHEX))
+        flags |= CONV_ESCAPEHEX;
+    if (!(vol.v_flags & AFPVOL_USEDOTS))
+        flags |= CONV_ESCAPEDOTS;
+
+#if 0
+    if ((vol->v_casefold & AFPVOL_MTOUUPPER))
+        flags |= CONV_TOUPPER;
+    else if ((vol->v_casefold & AFPVOL_MTOULOWER))
+        flags |= CONV_TOLOWER;
+#endif
+
+    m = mpath;
+    u = upath;
+
+    inplen = strlen(m);
+    outlen = MAXPATHLEN;
+
+    if ((size_t)-1 == (outlen = convert_charset ( vol.v_maccharset, vol.v_volcharset, vol.v_maccharset, m, inplen, u, outlen, &flags)) ) {
+        fprintf (stderr, "conversion from %s to %s for %s failed.", vol.v_maccodepage, vol.v_volcodepage, mpath);
+        return(mtoupathcap( upath ));
+    }
+    upath[outlen] = 0;
+
+    return( upath );
+}
+
+
  
 char * (*_mtoupath) ( char *mpath) = mtoupathcap;
 char * (*_utompath) ( char *upath) = utompathcap;
@@ -340,6 +420,19 @@ struct nad_file_data {
     struct adouble     ad;
 } nad;
 
+static void initvol(char *path)
+{
+    if (!loadvolinfo(path, &vol)) {
+        vol_load_charsets(&vol);
+        ad_init(&nad.ad, vol.v_adouble, 0);
+        _mtoupath = mtoupathiconv;
+        _utompath = utompathiconv;
+    }
+    else
+        ad_init(&nad.ad, 0, 0);
+}
+
+
 int nad_open( path, openflags, fh, options )
     char               *path;
     int                        openflags, options;
@@ -355,10 +448,12 @@ int nad_open( path, openflags, fh, options )
  */
     select_charset( options);
     memset(&nad.ad, 0, sizeof(nad.ad));
+
     if ( openflags == O_RDONLY ) {
+       initvol(path);
        strcpy( nad.adpath[0], path );
        strcpy( nad.adpath[1], 
-               ad_path( nad.adpath[0], ADFLAGS_DF|ADFLAGS_HF ));
+               nad.ad.ad_path( nad.adpath[0], ADFLAGS_DF|ADFLAGS_HF ));
        for ( fork = 0 ; fork < NUMFORKS ; fork++ ) {
            if ( stat( nad.adpath[ fork ], &st ) < 0 ) {
                if ( errno == ENOENT ) {
@@ -382,10 +477,11 @@ int nad_open( path, openflags, fh, options )
        return( nad_header_read( fh ));
 
     } else {
+       initvol (".");
        strcpy( nad.macname, fh->name );
        strcpy( nad.adpath[0], mtoupath( nad.macname ));
        strcpy( nad.adpath[1], 
-               ad_path( nad.adpath[0], ADFLAGS_DF|ADFLAGS_HF ));
+               nad.ad.ad_path( nad.adpath[0], ADFLAGS_DF|ADFLAGS_HF ));
 #if DEBUG
     fprintf(stderr, "%s\n", nad.macname);
     fprintf(stderr, "%s is adpath[0]\n", nad.adpath[0]);
@@ -410,15 +506,25 @@ int nad_header_read( fh )
 {
     u_int32_t          temptime;
     struct stat                st;
+    char               *p;
 
+#if 0
     memcpy( nad.macname, ad_entry( &nad.ad, ADEID_NAME ), 
            ad_getentrylen( &nad.ad, ADEID_NAME ));
     nad.macname[ ad_getentrylen( &nad.ad, ADEID_NAME ) ] = '\0';
     strcpy( fh->name, nad.macname );
+#endif
 
     /* just in case there's nothing in macname */
-    if (*fh->name == '\0')
+    if (*fh->name == '\0') {
+      if ( NULL == (p = strrchr(nad.adpath[DATA], '/')) )
+        p = nad.adpath[DATA];
+      else p++;
+#if 0      
       strcpy(fh->name, utompath(nad.adpath[DATA]));
+#endif      
+      strcpy(fh->name, utompath(p));
+    }
 
     if ( stat( nad.adpath[ DATA ], &st ) < 0 ) {
        perror( "stat of datafork failed" );
index 9ce6aaf9ee4d64478c9378705724bc43b85136e0..b4b43ec0c8c51d816825607b6c48a1405ca5b849 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: nad.h,v 1.3 2003-06-06 21:17:20 srittau Exp $
+ * $Id: nad.h,v 1.4 2005-04-28 20:49:20 bfernhomberg Exp $
  */
 
 #ifndef _NAD_H
index b677e4600234e692c4572d559c9e2d0ad2c932f7..932b9e0f19948a2367ce278f1a28197700a2809d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: nbplkup.c,v 1.4 2001-06-29 14:14:46 rufustfirefly Exp $
+ * $Id: nbplkup.c,v 1.5 2005-04-28 20:49:20 bfernhomberg Exp $
  *
  * Copyright (c) 1990,1991 Regents of The University of Michigan.
  * All Rights Reserved.
 #include <atalk/util.h>
 #include <string.h>
 #include <stdio.h>
-#if !defined( sun ) || !defined( i386 )
+#ifdef HAVE_STDLIB_H
 #include <stdlib.h>
-#endif /* ! sun || ! i386 */
+#endif
+
+
+#include <atalk/unicode.h>
 
 char *Obj = "=";
 char *Type = "=";
@@ -53,7 +56,7 @@ void Usage( av0 )
        p++;
     }
 
-    printf( "Usage:\t%s [ -A address ] [ -r responses] [ obj:type@zone ]\n", p );
+    printf( "Usage:\t%s [ -A address ] [ -r responses] [-m Mac charset] [ obj:type@zone ]\n", p );
     exit( 1 );
 }
 
@@ -65,12 +68,16 @@ int main( ac, av )
     char               *name;
     int                        i, c, nresp = 1000;
     struct at_addr      addr;
+    char               *obj = NULL;
+    size_t             obj_len;
+    charset_t          chMac = CH_MAC;
+    char *             convname;
 
     extern char                *optarg;
     extern int         optind;
 
     memset(&addr, 0, sizeof(addr));
-    while (( c = getopt( ac, av, "r:A:" )) != EOF ) {
+    while (( c = getopt( ac, av, "r:A:m:" )) != EOF ) {
        switch ( c ) {
        case 'A':
            if (!atalk_aton(optarg, &addr)) {
@@ -81,6 +88,12 @@ int main( ac, av )
        case 'r' :
            nresp = atoi( optarg );
            break;
+        case 'm':
+            if ((charset_t)-1 == (chMac = add_charset(optarg)) ) {
+               fprintf(stderr, "Invalid Mac charset.\n");
+               exit(1);
+           }
+            break;
 
        default :
            Usage( av[ 0 ] );
@@ -137,7 +150,11 @@ int main( ac, av )
     }
 
     if ( ac - optind == 1 ) {
-       if ( nbp_name( av[ optind ], &Obj, &Type, &Zone )) {
+       if ((size_t)(-1) == convert_string_allocate( CH_UNIX, chMac,
+                           av[ optind ], strlen(av[optind]), &convname))
+            convname = av[ optind ];
+
+       if ( nbp_name( convname, &Obj, &Type, &Zone )) {
            Usage( av[ 0 ] );
            exit( 1 );
        }
@@ -148,13 +165,26 @@ int main( ac, av )
        exit( -1 );
     }
     for ( i = 0; i < c; i++ ) {
+       
+       if ((size_t)(-1) == (obj_len = convert_string_allocate( chMac, 
+                       CH_UNIX, nn[ i ].nn_obj, nn[ i ].nn_objlen, &obj)) ) {
+            obj_len = nn[ i ].nn_objlen;
+            if (( obj = strdup(nn[ i ].nn_obj)) == NULL ) {
+               perror( "strdup" );
+               exit( 1 );
+           }
+        }
+
        printf( "%31.*s:%-34.*s %u.%u:%u\n",
-               nn[ i ].nn_objlen, nn[ i ].nn_obj,
+               (int)obj_len, obj,
                nn[ i ].nn_typelen, nn[ i ].nn_type,
                ntohs( nn[ i ].nn_sat.sat_addr.s_net ),
                nn[ i ].nn_sat.sat_addr.s_node,
                nn[ i ].nn_sat.sat_port );
+
+       free(obj);
     }
 
+    free(nn);
     return 0;
 }
index b12039603b6b37c3995b1b4b528eef74853e0351..ca740577a64f55dc11ff7af3c8e56243fbc8c4ef 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: nbprgstr.c,v 1.4 2001-06-29 14:14:46 rufustfirefly Exp $
+ * $Id: nbprgstr.c,v 1.5 2005-04-28 20:49:20 bfernhomberg Exp $
  *
  * Copyright (c) 1990,1993 Regents of The University of Michigan.
  * All Rights Reserved.  See COPYRIGHT.
@@ -20,6 +20,7 @@
 #include <atalk/netddp.h>
 #include <atalk/nbp.h>
 #include <atalk/util.h>
+#include <atalk/unicode.h>
 
 void Usage( av0 )
     char       *av0;
@@ -32,7 +33,7 @@ void Usage( av0 )
        p++;
     }
 
-    fprintf( stderr, "Usage: %s [ -A address ] obj:type@zone\n", p );
+    fprintf( stderr, "Usage: %s [ -A address ] [-m Mac charset] [ -p port] obj:type@zone\n", p );
     exit( 1 );
 }
 
@@ -43,13 +44,15 @@ int main( ac, av )
     struct sockaddr_at addr;
     struct at_addr      ataddr;
     char               *Obj = 0, *Type = 0, *Zone = 0;
+    char               *convname = 0;
     int                        s, c, port = 0;
+    charset_t          chMac = CH_MAC;
     
     extern char                *optarg;
     extern int         optind;
 
     memset(&ataddr, 0, sizeof(ataddr));
-    while (( c = getopt( ac, av, "p:A:" )) != EOF ) {
+    while (( c = getopt( ac, av, "p:A:m:" )) != EOF ) {
        switch ( c ) {
        case 'A':
            if (!atalk_aton(optarg, &ataddr)) {
@@ -58,6 +61,13 @@ int main( ac, av )
            }
            break;
 
+        case 'm':
+            if ((charset_t)-1 == (chMac = add_charset(optarg)) ) {
+                fprintf(stderr, "Invalid Mac charset.\n");
+                exit(1);
+            }
+            break;
+
        case 'p' :
            port = atoi( optarg );
            break;
@@ -71,10 +81,15 @@ int main( ac, av )
        Usage( av[ 0 ] );
     }
 
+    /* Convert the name */
+    if ((size_t)(-1) == convert_string_allocate(CH_UNIX, chMac,
+                        av[optind], strlen(av[optind]), &convname))
+        convname = av[optind];
+
     /*
      * Get the name. If Type or Obj aren't specified, error.
      */
-    if ( nbp_name( av[ optind ], &Obj, &Type, &Zone ) || !Obj || !Type ) {
+    if ( nbp_name( convname, &Obj, &Type, &Zone ) || !Obj || !Type ) {
        Usage( av[ 0 ] );
     }
 
index 4cd68039596e14f5a15a1ca6484a33467d61c34b..aa69ae3b66f41ac656a1053e9c4f2c23492df996 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: nbpunrgstr.c,v 1.5 2001-07-31 19:49:02 srittau Exp $
+ * $Id: nbpunrgstr.c,v 1.6 2005-04-28 20:49:20 bfernhomberg Exp $
  *
  * Copyright (c) 1990,1991 Regents of The University of Michigan.
  * All Rights Reserved.
@@ -39,6 +39,8 @@
 #include <atalk/util.h>
 #include <atalk/nbp.h>
 
+#include <atalk/unicode.h>
+
 void Usage( av0 )
     char       *av0;
 {
@@ -50,7 +52,7 @@ void Usage( av0 )
        p++;
     }
 
-    fprintf( stderr, "Usage: %s [ -A address ] obj:type@zone\n", p );
+    fprintf( stderr, "Usage: %s [ -A address ] [ -m Mac charset] obj:type@zone\n", p );
     exit( 1 );
 }
 
@@ -59,14 +61,16 @@ int main( ac, av )
     char       **av;
 {
     char               *Obj = 0, *Type = 0, *Zone = 0;
+    char               *convname = 0;
     struct at_addr      addr;
     int                 c;
+    charset_t          chMac = CH_MAC;
 
     extern char                *optarg;
     extern int         optind;
     
     memset(&addr, 0, sizeof(addr));
-    while ((c = getopt(ac, av, "A:")) != EOF) {
+    while ((c = getopt(ac, av, "A:m:")) != EOF) {
       switch (c) {
       case 'A':
        if (!atalk_aton(optarg, &addr)) {
@@ -74,6 +78,13 @@ int main( ac, av )
          exit(1);
        }
        break;
+      case 'm':
+        if ((charset_t)-1 == (chMac = add_charset(optarg)) ) {
+          fprintf(stderr, "Invalid Mac charset.\n");
+          exit(1);
+        }
+        break;
+
       default:
        Usage(av[0]);
        break;
@@ -84,10 +95,15 @@ int main( ac, av )
        Usage( av[ 0 ] );
     }
 
+    /* Convert the name */
+    if ((size_t)(-1) == convert_string_allocate(CH_UNIX, chMac, 
+                        av[optind], strlen(av[optind]), &convname))
+        convname = av[optind]; 
+
     /*
      * Get the name. If Type or Obj aren't specified, error.
      */
-    if ( nbp_name( av[optind], &Obj, &Type, &Zone ) || !Obj || !Type ) {
+    if ( nbp_name( convname, &Obj, &Type, &Zone ) || !Obj || !Type ) {
        Usage( av[ 0 ] );
     }
 
index c0df79662c972472025729ff0a7c65a09ac77775..9679614da6f39a062fb70f807c0cbcf92d64b1ef 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: pap.c,v 1.9 2002-11-25 01:33:02 jmarcus Exp $
+ * $Id: pap.c,v 1.10 2005-04-28 20:49:20 bfernhomberg Exp $
  *
  * Copyright (c) 1990,1994 Regents of The University of Michigan.
  * All Rights Reserved.  See COPYRIGHT.
@@ -14,6 +14,7 @@
 #include <sys/uio.h>
 #include <netatalk/endian.h>
 #include <netatalk/at.h>
+#include <errno.h>
 #include <atalk/atp.h>
 #include <atalk/pap.h>
 #include <atalk/nbp.h>
@@ -25,7 +26,6 @@
 #include <string.h>
 #include <string.h>
 #include <stdlib.h>
-#include <errno.h>
 
 #define FUCKED
 
index 4536b6b7a2949c0a6ef6f6a5d46ecf3a78446a46..940463aa00f35a31f28e94313730c35e6ce19292 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: papstatus.c,v 1.4 2001-06-29 14:14:46 rufustfirefly Exp $
+ * $Id: papstatus.c,v 1.5 2005-04-28 20:49:20 bfernhomberg Exp $
  *
  * Copyright (c) 1990,1991 Regents of The University of Michigan.
  * All Rights Reserved.
@@ -33,6 +33,7 @@
 #include <sys/file.h>
 #include <netatalk/endian.h>
 #include <netatalk/at.h>
+#include <errno.h>
 #include <atalk/atp.h>
 #include <atalk/pap.h>
 #include <atalk/nbp.h>
@@ -40,7 +41,6 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <errno.h>
 
 #define _PATH_PAPRC    ".paprc"
 
diff --git a/bin/uniconv/.cvsignore b/bin/uniconv/.cvsignore
new file mode 100644 (file)
index 0000000..3ec17ea
--- /dev/null
@@ -0,0 +1,5 @@
+Makefile
+Makefile.in
+uniconv
+.deps
+.libs
diff --git a/bin/uniconv/Makefile.am b/bin/uniconv/Makefile.am
new file mode 100644 (file)
index 0000000..202e722
--- /dev/null
@@ -0,0 +1,8 @@
+# Makefile.am for bin/aecho/
+
+INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/sys
+
+bin_PROGRAMS = uniconv
+
+uniconv_SOURCES = uniconv.c iso8859_1_adapted.c
+uniconv_LDADD = $(top_builddir)/libatalk/cnid/libcnid.la $(top_builddir)/libatalk/libatalk.la
diff --git a/bin/uniconv/iso8859_1_adapted.c b/bin/uniconv/iso8859_1_adapted.c
new file mode 100644 (file)
index 0000000..38e7d33
--- /dev/null
@@ -0,0 +1,155 @@
+/* 
+   iso-8859-1.adapted conversion routines
+   Copyright (C) Bjoern Fernhomberg 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.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include <netatalk/endian.h>
+#include <atalk/unicode.h>
+#include <atalk/logger.h>
+
+#include "../../libatalk/unicode/byteorder.h"
+
+static size_t   iso8859_adapted_pull(void *,char **, size_t *, char **, size_t *);
+static size_t   iso8859_adapted_push(void *,char **, size_t *, char **, size_t *);
+
+struct charset_functions charset_iso8859_adapted =
+{
+       "ISO-8859-ADAPTED",
+       0,
+       iso8859_adapted_pull,
+       iso8859_adapted_push,
+       CHARSET_MULTIBYTE | CHARSET_PRECOMPOSED,
+       NULL,
+       NULL, NULL
+};
+
+
+/* ------------------------ 
+ * from unicode to iso8859_adapted code page
+*/
+
+static size_t iso8859_adapted_push( void *cd _U_, char **inbuf, size_t *inbytesleft,
+                         char **outbuf, size_t *outbytesleft)
+{
+    int len = 0;
+
+    while (*inbytesleft >= 2 && *outbytesleft >= 1) {
+       ucs2_t inptr = SVAL((*inbuf),0);
+        if ( inptr == 0x2122) {
+                SSVAL((*outbuf),0,0xAA);
+        }
+        else if ( inptr == 0x0192) {
+                SSVAL((*outbuf),0,0xC5);
+        }
+        else if ( inptr == 0x2014) {
+                SSVAL((*outbuf),0,0xD1);
+        }
+        else if ( inptr == 0x201C) {
+                SSVAL((*outbuf),0,0xD2);
+        }
+        else if ( inptr == 0x201D) {
+                SSVAL((*outbuf),0,0xD3);
+        }
+        else if ( inptr == 0x2018) {
+                SSVAL((*outbuf),0,0xD4);
+        }
+        else if ( inptr == 0x2019) {
+                SSVAL((*outbuf),0,0xD5);
+        }
+        else if ( inptr == 0x25CA) {
+                SSVAL((*outbuf),0,0xD7);
+        }
+       else if ( inptr > 0x0100) {
+               errno = EILSEQ;
+               return -1;
+        }
+       else {
+               SSVAL((*outbuf), 0, inptr);
+       }
+        (*inbuf)        +=2;
+        (*outbuf)       +=1;
+        (*inbytesleft) -=2;
+        (*outbytesleft)-=1;
+        len++;
+    }
+
+    if (*inbytesleft > 0) {
+        errno = E2BIG;
+        return -1;
+    }
+
+    return len;
+}
+
+/* ------------------------ */
+static size_t iso8859_adapted_pull ( void *cd _U_, char **inbuf, size_t *inbytesleft,
+                         char **outbuf, size_t *outbytesleft)
+{
+    unsigned char  *inptr;
+    size_t         len = 0;
+
+    while (*inbytesleft >= 1 && *outbytesleft >= 2) {
+        inptr = (unsigned char *) *inbuf;
+
+       if ( *inptr == 0xAA) {
+               SSVAL((*outbuf),0,0x2122);
+       }
+       else if ( *inptr == 0xC5) {
+               SSVAL((*outbuf),0,0x0192);
+       }
+       else if ( *inptr == 0xD1) {
+               SSVAL((*outbuf),0,0x2014);
+       }
+       else if ( *inptr == 0xD2) {
+               SSVAL((*outbuf),0,0x201C);
+       }
+       else if ( *inptr == 0xD3) {
+               SSVAL((*outbuf),0,0x201D);
+       }
+       else if ( *inptr == 0xD4) {
+               SSVAL((*outbuf),0,0x2018);
+       }
+       else if ( *inptr == 0xD5) {
+               SSVAL((*outbuf),0,0x2019);
+       }
+       else if ( *inptr == 0xD7) {
+               SSVAL((*outbuf),0,0x25CA);
+       }
+       else {
+               SSVAL((*outbuf),0,(*inptr));
+       }
+        (*outbuf)      +=2;
+       (*outbytesleft)-=2;
+        (*inbuf)        +=1;
+       (*inbytesleft) -=1;
+       len++;
+    }
+
+    if (*inbytesleft > 0) {
+        errno = E2BIG;
+        return (size_t) -1;
+    }
+    return len;
+}
+
diff --git a/bin/uniconv/uniconv.c b/bin/uniconv/uniconv.c
new file mode 100644 (file)
index 0000000..9955c2d
--- /dev/null
@@ -0,0 +1,556 @@
+/*
+   uniconv - convert volume encodings
+   Copyright (C) Bjoern Fernhomberg 2004
+
+   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 /* HAVE_CONFIG_H */
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <pwd.h>
+#include <dirent.h>
+#include <atalk/afp.h>
+#include <atalk/unicode.h>
+#include <atalk/util.h>
+#include <atalk/logger.h>
+
+#include "atalk/cnid.h"
+#ifndef MAXPATHLEN
+#define MAXPATHLEN 4096
+#endif
+
+static struct _cnid_db *cdb;
+static char curpath[MAXPATHLEN];
+static cnid_t cdir_id;
+static char db_stamp[ADEDLEN_PRIVSYN];
+
+static charset_t ch_from;
+char* from_charset;
+static charset_t ch_to;
+char* to_charset;
+static charset_t ch_mac;
+char* mac_charset;
+static int usedots = 0;
+static u_int16_t conv_flags = 0;
+static int dry_run = 0;
+static int verbose=0;
+char *cnid_type;
+
+char             Cnid_srv[256] = "localhost";
+int              Cnid_port = 4700;
+
+extern  struct charset_functions charset_iso8859_adapted;
+
+#ifndef MAX
+#define MAX(a,b) (((a)>(b))?(a):(b))
+#endif
+
+
+#define VETO "./../.AppleDB/.AppleDouble/.AppleDesktop/.Parent/"
+
+static int veto(const char *path)
+{
+    int i,j;
+    char *veto_str = VETO;
+    
+
+    if ((path == NULL))
+        return 0;
+
+    for(i=0, j=0; veto_str[i] != '\0'; i++) {
+        if (veto_str[i] == '/') {
+            if ((j>0) && (path[j] == '\0'))
+                return 1;
+            j = 0;
+        } else {
+            if (veto_str[i] != path[j]) {
+                while ((veto_str[i] != '/')
+                        && (veto_str[i] != '\0'))
+                    i++;
+                j = 0;
+                continue;
+            }
+            j++;
+        }
+    }
+    return 0;
+}
+
+
+static int do_rename( char* src, char *dst, struct stat *st)
+{
+    char        adsrc[ MAXPATHLEN + 1];
+    struct      stat tmp_st;
+
+    if (!stat(dst, &tmp_st)) {
+       fprintf (stderr, "error: cannot rename %s to %s, destination exists\n", src, dst);
+       return -1;
+    }
+
+    if ( rename( src, dst ) < 0 ) {
+       fprintf (stderr, "error: cannot rename %s to %s, %s\n", src, dst, strerror(errno));
+       return -1;
+    }
+
+    if (S_ISDIR(st->st_mode))
+       return 0;
+
+    strcpy( adsrc, ad_path( src, 0 ));
+
+    if (rename( adsrc, ad_path( dst, 0 )) < 0 ) {
+        struct stat ad_st;
+
+        if (errno == ENOENT) {
+            if (stat(adsrc, &ad_st)) /* source has no ressource fork, */
+               return 0;
+       }
+       else {
+               fprintf (stderr, "failed to rename resource fork, error: %s\n", strerror(errno));
+                return -1;
+       }       
+
+    }
+    return 0;
+}
+
+
+static char *convert_name(char *name, struct stat *st, cnid_t cur_did)
+{
+       static char   buffer[MAXPATHLEN];
+       size_t outlen = 0;
+       unsigned char *p,*q;
+       int require_conversion = 0;
+        u_int16_t    flags = conv_flags;
+       cnid_t id;
+
+       p = name;
+       q = buffer;
+
+       /* optimize for ascii case */
+       while (*p != 0) {
+               if ( *p >= 0x80 || *p == ':') {
+                       require_conversion = 1;
+                       break;
+               }
+               p++;
+       }
+
+       if (!require_conversion) {
+               if (verbose > 1)
+                   fprintf(stdout, "no conversion required\n");
+               return name;
+       }
+
+       /* convert charsets */
+       q=buffer;
+       p=name;
+
+       outlen = convert_charset(ch_from, ch_to, ch_mac, p, strlen(p), q, sizeof(buffer), &flags);
+       if ((size_t)-1 == outlen) {
+          if ( ch_to == CH_UTF8) {
+               /* maybe name is already in UTF8? */
+               flags = conv_flags;
+               q = (char*) buffer;
+               p = name;
+               outlen = convert_charset(ch_to, ch_to, ch_mac, p, strlen(p), q, sizeof(buffer), &flags);
+               if ((size_t)-1 == outlen) {
+                       /* it's not UTF8... */
+                       fprintf(stderr, "ERROR: conversion from '%s' to '%s' for '%s' in DID %u failed!!!\n", 
+                               from_charset, to_charset, name, ntohl(cur_did));
+                       return name;
+               }
+               buffer[outlen] = 0;
+
+               if (!strcmp(buffer, name)) {
+                       return name;
+               }
+           }
+          fprintf(stderr, "ERROR: conversion from '%s' to '%s' for '%s' in DID %u failed. Please check this!\n", 
+                       from_charset, to_charset, name, ntohl(cur_did));
+          return name;
+       }
+       buffer[outlen] = 0;
+       if (strcmp (name, buffer)) {
+           if (dry_run) {
+               fprintf(stdout, "dry_run: would rename %s to %s.\n", name, buffer);
+           }   
+           else if (!do_rename(name, buffer, st)) {
+               if (CNID_INVALID != (id = cnid_add(cdb, st, cur_did, buffer, strlen(buffer), 0))) 
+                               fprintf(stdout, "converted '%s' to '%s' (ID %u, DID %u).\n", 
+                                name, buffer, ntohl(id), ntohl(cur_did));
+           }
+       }
+       else if (verbose > 1)
+           fprintf(stdout, "no conversion required\n");
+       
+       return (buffer);
+}
+
+static int check_dirent(char** name, cnid_t cur_did)
+{
+       struct stat st;
+       int ret = 0;
+
+       if (veto(*name))
+               return 0;
+
+        if (stat(*name, &st) != 0) {
+               switch (errno) {
+                    case ELOOP:
+                    case ENOENT:
+                       return 0;
+                    default:
+                       return (-1);
+                }
+        }
+
+       if (S_ISDIR(st.st_mode)){
+               ret = 1;
+       } 
+
+       if (verbose > 1)
+           fprintf(stdout, "Checking: '%s' - ", *name);
+
+       *name = convert_name(*name, &st, cur_did);
+
+       return ret;
+}
+
+static int check_adouble(DIR *curdir, char * path _U_)
+{
+       DIR *adouble;
+       struct dirent* entry;
+       struct dirent* ad_entry;
+       int found = 0;
+
+       strlcat(curpath, "/", sizeof(curpath));
+       strlcat(curpath, ".AppleDouble", sizeof(curpath));
+
+       if (NULL == (adouble = opendir(curpath))) {
+               return(-1);
+       }
+
+       while (NULL != (ad_entry=readdir(adouble)) ) {
+               if (veto(ad_entry->d_name))
+                       break;
+               found = 0;
+               rewinddir(curdir);
+               while (NULL != (entry=readdir(curdir)) ) {
+                       if (!strcmp(ad_entry->d_name, entry->d_name)) {
+                               found = 1;
+                               break;
+                       }
+               }
+               if (!found) {
+                       fprintf (stderr, "found orphaned resource file %s", ad_entry->d_name);
+               }
+       }
+                       
+       rewinddir(curdir);
+       closedir(adouble);
+       return (0);
+}
+               
+static cnid_t add_dir_db(char *name, cnid_t cur_did)
+{
+       cnid_t id, did;
+       struct stat st;
+
+       if (CNID_INVALID != ( id = cnid_get(cdb, cur_did, name, strlen(name))) )
+           return id;
+
+       if (dry_run) {
+               return 0;
+       }
+
+        did = cur_did;
+       if (stat(name, &st)) {
+             fprintf( stderr, "dir '%s' cannot be stat'ed, error %u\n", name, errno);
+            return 0;
+        }
+
+        id = cnid_add(cdb, &st, did, name, strlen(name), 0);
+       
+       fprintf (stderr, "added '%s' to DID %u as %u\n", name, ntohl(did), ntohl(id));
+       return id;
+}
+
+static int getdir(DIR *curdir, char ***names)
+{
+       struct dirent* entry;
+       char **tmp = NULL, **new=NULL;
+       char *name;
+       int i=0;
+
+        while ((entry=readdir(curdir)) != NULL) {
+               new = (char **) realloc (tmp, (i+1) * sizeof(char*));
+               if (new == NULL) {
+                       fprintf(stderr, "out of memory");
+                       exit (-1);
+               }
+               tmp = new;
+               name = strdup(entry->d_name);
+               if (name == NULL) {
+                       fprintf(stderr, "out of memory");
+                       exit (-1);
+               }
+               tmp[i]= (char*) name;
+               i++;
+        };
+
+       *names = tmp;
+       return i;
+}
+
+static int checkdir(DIR *curdir, char *path, cnid_t cur_did)
+{
+       DIR* cdir;
+       int ret = 0;
+       cnid_t id;
+       char *name, *tmp;
+        int n;
+       size_t len=strlen(curpath);
+
+       char **names;
+
+       chdir(path);
+
+       check_adouble(curdir, path);
+       curpath[len] = 0;
+
+       if (verbose)
+           fprintf( stdout, "\nchecking DIR '%s' with ID %u\n", path, ntohl(cur_did));
+
+       n = getdir(curdir, &names);
+
+       while (n--) {
+               name = names[n];
+               tmp = strdup(name);
+                ret = check_dirent(&name, cur_did);
+               if (ret==1) {
+                    id = add_dir_db(name, cur_did);
+                   if ( id == 0 && !dry_run ) 
+                       continue;  /* skip, no ID */ 
+                   if ( dry_run )
+                       name = tmp;
+                    strlcat(curpath, "/", sizeof(curpath));
+                    strlcat(curpath, name, sizeof(curpath));
+                    cdir = opendir(curpath);
+                   if (cdir == NULL) {
+                       fprintf( stderr, "ERROR: cannot open DIR '%s' with ID %u\n", curpath, ntohl(cur_did));
+                       continue;
+                   }
+                    checkdir(cdir, curpath, id);
+                    closedir(cdir);
+                    curpath[len] = 0;
+                    chdir(path);
+                   if (verbose)
+                       fprintf( stdout, "returned to DIR '%s' with ID %u\n", path, ntohl(cur_did));
+                }
+                free(names[n]);
+               free(tmp);
+        }
+       free(names);
+       if (verbose)
+           fprintf( stdout, "leaving DIR '%s' with ID %u\n\n", path, ntohl(cur_did));
+
+       return 0;
+}
+
+static int init(char* path)
+{
+       DIR* startdir;
+
+        if (NULL == (cdb = cnid_open (path, 0, cnid_type, 0)) ) {
+                fprintf (stderr, "ERROR: cannot open CNID database in '%s'\n", path);
+                fprintf (stderr, "ERROR: check the logs for reasons, aborting\n");
+               return -1;
+        }
+        cnid_getstamp(cdb, db_stamp, sizeof(db_stamp));
+       cdir_id = htonl(2);
+
+       startdir = opendir(path);
+       strlcpy(curpath, path, sizeof(curpath));
+       checkdir (startdir, path, cdir_id);
+       closedir(startdir);
+
+       cnid_close(cdb);
+
+       return (0);
+}
+
+static void usage( char * name )
+{
+    fprintf( stderr, "usage:\t%s [-ndv] -c cnid -f fromcode -t tocode [-m maccode] path\n", name );
+    fprintf( stderr, "Try `%s -h' for more information.\n", name );
+    exit( 1 );
+}
+
+static void print_version ()
+{
+    fprintf( stderr, "uniconv - Netatalk %s\n", VERSION );
+}
+
+static void help ()
+{
+    fprintf (stdout, "\nuniconv, a tool to convert between various Netatalk volume encodings\n");
+    fprintf (stdout, "\nUsage:  uniconv [-ndv] -c cnid -f fromcode -t tocode [-m maccode] path\n\n");
+    fprintf (stdout, "Examples:\n");
+    fprintf (stdout, "     uniconv -c dbd -f ASCII -t UTF8 -m MAC_ROMAN /path/to/share\n");
+    fprintf (stdout, "     uniconv -c cdb -f ISO-8859-1 -t UTF8 -m MAC_ROMAN /path/to/share\n");
+    fprintf (stdout, "     uniconv -c cdb -f ISO-8859-ADAPTED -t ASCII -m MAC_ROMAN /path/to/share\n");
+    fprintf (stdout, "     uniconv -f UTF8 -t ASCII -m MAC_ROMAN /path/to/share\n\n");
+    fprintf (stdout, "Options:\n");
+    fprintf (stdout, "\t-f\tencoding to convert from, use ASCII for CAP encoded volumes\n");
+    fprintf (stdout, "\t-t\tvolume encoding to convert to, e.g. UTF8.\n");
+    fprintf (stdout, "\t-m\tMacintosh client codepage, required for CAP encoded volumes.\n");
+    fprintf (stdout, "\t\tDefaults to `MAC_ROMAN'\n");
+    fprintf (stdout, "\t-n\t`dry run', don't change anything.\n");
+    fprintf (stdout, "\t-d\tDon't CAP encode leading dots (:2e).\n");
+    fprintf (stdout, "\t-c\tCNID backend used on this volume, usually cdb or dbd.\n");
+    fprintf (stdout, "\t\tIf not specified, the default cnid backend `%s' is used\n", DEFAULT_CNID_SCHEME);
+    fprintf (stdout, "\t-v\tVerbose output, use twice for maximum logging.\n");
+    fprintf (stdout, "\t-V\tPrint version and exit\n");
+    fprintf (stdout, "\t-h\tThis help screen\n\n");
+    fprintf (stdout, "WARNING:\n");
+    fprintf (stdout, "     Setting the wrong options might render your data unusable!!!\n");
+    fprintf (stdout, "     Make sure you know what you are doing. Always backup your data first.\n\n");
+    fprintf (stdout, "     It is *strongly* recommended to do a `dry run' first and to check the\n");
+    fprintf (stdout, "     output for conversion errors.\n");
+    fprintf (stdout, "     USE AT YOUR OWN RISK!!!\n\n");
+
+}
+
+
+int main(int argc, char *argv[])
+{
+        char path[MAXPATHLEN];
+        int  c;
+
+       path[0]= 0;
+        conv_flags = CONV_UNESCAPEHEX | CONV_ESCAPEHEX | CONV_ESCAPEDOTS;
+
+#ifdef HAVE_SETLINEBUF
+        setlinebuf(stdout); 
+#endif        
+
+        while ((c = getopt (argc, argv, "f:m:t:c:nvVh")) != -1)
+        switch (c)
+        {
+       case 'f':
+               from_charset = strdup(optarg);
+               break;
+       case 't':
+               to_charset = strdup(optarg);
+               break;
+       case 'm':
+               mac_charset = strdup(optarg);
+               break;
+       case 'd':
+               conv_flags &= !CONV_ESCAPEDOTS;
+               usedots = 1;
+               break;
+       case 'n':
+               fprintf (stderr, "doing dry run, volume will *not* be changed\n");
+               dry_run = 1;
+               break;
+       case 'c':
+               cnid_type = strdup(optarg);
+               fprintf (stderr, "CNID backend set to: %s\n", cnid_type);
+               break;
+       case 'v':
+               verbose++;
+               break;
+       case 'V':
+               print_version();
+               exit (1);
+               break;
+        case 'h':
+               help();
+               exit(1);
+                break;
+        default:
+               break;
+        }
+
+        if ( argc - optind != 1 ) {
+            usage( argv[0] );
+            exit( 1 );
+        }
+        set_processname("uniconv");
+
+       if ( from_charset == NULL || to_charset == NULL) {
+               fprintf (stderr, "required charsets not specified\n");
+               exit(-1);
+       }
+
+       if ( mac_charset == NULL )
+               mac_charset = "MAC_ROMAN";
+
+       if ( cnid_type == NULL)
+               cnid_type = DEFAULT_CNID_SCHEME;
+       
+
+       /* get path */
+       strlcpy(path, argv[optind], sizeof(path));
+
+       /* deal with relative path */   
+       if (chdir(path)) {
+                fprintf (stderr, "ERROR: cannot chdir to '%s'\n", path);
+                return (-1);
+       }
+
+        if (NULL == (getcwd(path, sizeof(path))) ) {
+                fprintf (stderr, "ERROR: getcwd failed\n");
+                return (-1);
+        }
+
+       /* set charsets */
+       atalk_register_charset(&charset_iso8859_adapted);
+
+       if ( (charset_t) -1 == ( ch_from = add_charset(from_charset)) ) {
+               fprintf( stderr, "Setting codepage %s as source codepage failed", from_charset);
+               exit (-1);
+       }
+
+       if ( (charset_t) -1 == ( ch_to = add_charset(to_charset)) ) {
+               fprintf( stderr, "Setting codepage %s as destination codepage failed", to_charset);
+               exit (-1);
+       }
+
+       if ( (charset_t) -1 == ( ch_mac = add_charset(mac_charset)) ) {
+               fprintf( stderr, "Setting codepage %s as mac codepage failed", mac_charset);
+               exit (-1);
+       }
+
+       cnid_init();
+       init(path);
+
+       return (0);
+}
diff --git a/config/AppleVolumes.default b/config/AppleVolumes.default
deleted file mode 100644 (file)
index fd146a1..0000000
+++ /dev/null
@@ -1,79 +0,0 @@
-# This file looks empty when viewed with "vi".  In fact, there is one
-# '~', so users with no AppleVolumes file in their home directory get
-# their home directory by default.
-# 
-# volume format:
-# :DEFAULT: [all of the default options except volume name]
-# path [name] [casefold:x] [codepage:y] [options:z,l,j] \
-#   [allow:a,@b,c,d] [deny:a,@b,c,d] [dbpath:path] [password:p] \
-#   [rwlist:a,@b,c,d] [rolist:a,@b,c,d] [limitsize:value in bytes]
-#
-#
-# name:      volume name. it can't include the ':' character and is limited
-#            to 27 characters in length.
-#
-# variable substitutions:
-# you can use variables for both <path> and <name> now. here are the
-# rules:
-#     1) if you specify an unknown variable, it will not get converted. 
-#     2) if you specify a known variable, but that variable doesn't have
-#        a value, it will get ignored.
-#
-# the variables:
-# $c   -> client's ip or appletalk address
-# $f   -> full name (whatever's in the gecos field)
-# $g   -> group
-# $h   -> hostname 
-# $s   -> server name (can be the hostname)
-# $u   -> username (if guest, it's whatever user guest is running as)
-# $v   -> volume name (either ADEID_NAME or basename of path)
-# $z   -> zone (may not exist)
-# $$   -> $
-#
-# casefold options [syntax: casefold:option]:
-# tolower    -> lowercases names in both directions
-# toupper    -> uppercases names in both directions
-# xlatelower -> client sees lowercase, server sees uppercase
-# xlateupper -> client sees uppercase, server sees lowercase
-#
-# allow/deny/rwlist/rolist format [syntax: allow:user1,@group]:
-# user1,@group,user2  -> allows/denies access from listed users/groups
-#                        rwlist/rolist control whether or not the
-#                       volume is ro for those users.
-#
-# miscellaneous options [syntax: options:option1,option2]:
-# prodos              -> make compatible with appleII clients.
-# crlf                -> enable crlf translation for TEXT files.
-# noadouble           -> don't create .AppleDouble unless a resource
-#                        fork needs to be created.
-# ro                  -> mount the volume as read-only.
-# utf8                -> use precomposed utf8 filenames
-# mswindows           -> enforce filename restrictions imposed by MS
-#                        Windows. this will also invoke a default
-#                       codepage (iso8859-1) if one isn't already 
-#                       specified.
-# nohex                      -> don't do :hex translations for anything
-#                       except dot files. specify usedots as well if
-#                       you want that turned off. note: this option
-#                       makes the / character illegal.
-# usedots             -> don't do :hex translation for dot files. note: when 
-#                        this option gets set, certain file names
-#                       become illegal. these are .Parent and
-#                       anything that starts with .Apple. also, dot
-#                       files created on the unix side are marked
-#                       invisible. 
-# limitsize           -> limit disk size reporting to 2GB. this is
-#                        here for older macintoshes using newer
-#                        appleshare clients. yucko.
-# nofileid            -> don't advertise createfileid, resolveid, deleteid 
-#                        calls
-# upriv               -> use unix privilege.
-#
-# codepage:filename   -> load filename from nls directory.
-# dbpath:path         -> store the database stuff in the following path.
-# password:password   -> set a volume password (8 characters max)
-#
-# The "~" below indicates that Home directories are visible by default.
-# If you do not wish to have people accessing their Home directories,
-# please put a pound sign in front of the tilde or delete it.
-~
diff --git a/config/AppleVolumes.default.tmpl b/config/AppleVolumes.default.tmpl
new file mode 100644 (file)
index 0000000..6c07304
--- /dev/null
@@ -0,0 +1,103 @@
+# This file looks empty when viewed with "vi".  In fact, there is one
+# '~', so users with no AppleVolumes file in their home directory get
+# their home directory by default.
+# 
+# volume format:
+# :DEFAULT: [all of the default options except volume name]
+# path [name] [casefold:x] [options:z,l,j] \
+#   [allow:a,@b,c,d] [deny:a,@b,c,d] [dbpath:path] [password:p] \
+#   [rwlist:a,@b,c,d] [rolist:a,@b,c,d] [limitsize:value in bytes]\
+#   [preexec:cmd] [root_preexec:cmd] [postexec:cmd]  [root_postexec:cmd] 
+#
+#
+# name:      volume name. it can't include the ':' character and is limited
+#            to 27 characters in length.
+#
+# variable substitutions:
+# you can use variables for both <path> and <name> now. here are the
+# rules:
+#     1) if you specify an unknown variable, it will not get converted. 
+#     2) if you specify a known variable, but that variable doesn't have
+#        a value, it will get ignored.
+#
+# the variables:
+# $b   -> basename of path
+# $c   -> client's ip or appletalk address
+# $d   -> volume pathname on server    
+# $f   -> full name (whatever's in the gecos field)
+# $g   -> group
+# $h   -> hostname 
+# $i   -> client ip without tcp port or appletalk network   
+# $s   -> server name (can be the hostname)
+# $u   -> username (if guest, it's whatever user guest is running as)
+# $v   -> volume name (either ADEID_NAME or basename of path)
+# $z   -> zone (may not exist)
+# $$   -> $
+#
+# casefold options [syntax: casefold:option]:
+# tolower    -> lowercases names in both directions
+# toupper    -> uppercases names in both directions
+# xlatelower -> client sees lowercase, server sees uppercase
+# xlateupper -> client sees uppercase, server sees lowercase
+#
+# allow/deny/rwlist/rolist format [syntax: allow:user1,@group]:
+# user1,@group,user2  -> allows/denies access from listed users/groups
+#                        rwlist/rolist control whether or not the
+#                       volume is ro for those users.
+# preexec             -> command to be run when the volume is mounted,
+#                        ignore for user defined volumes
+# root_preexec        -> command to be run as root when the volume is mounted,
+#                        ignore for user defined volumes
+# postexec             -> command to be run when the volume is closed,
+#                        ignore for user defined volumes
+# root_postexec        -> command to be run as root when the volume is closed,
+#                        ignore for user defined volumes
+#
+# codepage options [syntax: options:charsetname]
+# volcharset           -> specifies the charset to be used as the volume codepage
+#                         e.g. "UTF8", "UTF8-MAC", "ISO-8859-15"
+# maccharset           -> specifies the charset to be used as the mac client codepage
+#                         e.g. "MAC_ROMAN", "MAC_CYRILLIC"
+#
+# miscellaneous options [syntax: options:option1,option2]:
+# prodos              -> make compatible with appleII clients.
+# crlf                -> enable crlf translation for TEXT files.
+# noadouble           -> don't create .AppleDouble unless a resource
+#                        fork needs to be created.
+# ro                  -> mount the volume as read-only.
+# mswindows           -> enforce filename restrictions imposed by MS
+#                        Windows. this will also invoke a default
+#                       codepage (iso8859-1) if one isn't already 
+#                       specified.
+# nohex                      -> don't do :hex translations for anything
+#                       except dot files. specify usedots as well if
+#                       you want that turned off. note: this option
+#                       makes the / character illegal.
+# usedots             -> don't do :hex translation for dot files. note: when 
+#                        this option gets set, certain file names
+#                       become illegal. these are .Parent and
+#                       anything that starts with .Apple. also, dot
+#                       files created on the unix side are marked
+#                       invisible. 
+# limitsize           -> limit disk size reporting to 2GB. this is
+#                        here for older macintoshes using newer
+#                        appleshare clients. yucko.
+# nofileid            -> don't advertise createfileid, resolveid, deleteid 
+#                        calls
+# root_preexec_close  -> a non-zero return code from root_preexec close the 
+#                        volume being mounted.
+# preexec_close       -> a non-zero return code from preexec close the 
+#                        volume being mounted.
+# nostat              -> don't stat volume path when enumerating volumes list
+# upriv               -> use unix privilege.  
+#
+#
+# dbpath:path         -> store the database stuff in the following path.
+# password:password   -> set a volume password (8 characters max)
+# cnidscheme:scheme   -> set the cnid scheme for the volume, default is [:DEFAULT_CNID_SCHEME:]
+#                        available schemes: [:COMPILED_BACKENDS:]
+#
+# The "~" below indicates that Home directories are visible by default.
+# If you do not wish to have people accessing their Home directories,
+# please put a pound sign in front of the tilde or delete it.
+~
index 23685e3e670aabc6246cacf689daee3227100041..48bc4d9db2d08e2042de36e171703b924c8e8859 100644 (file)
@@ -9,10 +9,12 @@
 #
 
 # default translation -- note that CR <-> LF translation is done on all
-# files of type TEXT.  The first line turns off translation for files of
-# unknown type, the second turns this translation on.
-.         "BINA"  "UNIX"      Unix Binary                    Unix                      application/octet-stream
-# .         "TEXT"  "ttxt"      ASCII Text                     SimpleText                text/plain
+# files of type TEXT (if crlf is set in volume's options).  
+# The first line turns off translation for files of unknown type, 
+# the third turns this translation on.
+#.         "????"  "????"      Unix Binary                    Unix                      application/octet-stream
+#.         "BINA"  "UNIX"      Unix Binary                    Unix                      application/octet-stream
+#.         "TEXT"  "ttxt"      ASCII Text                     SimpleText                text/plain
 
 .1st      "TEXT"  "ttxt"      Text Readme                    SimpleText                application/text
 .669      "6669"  "SNPL"      669 MOD Music                  PlayerPro
@@ -93,7 +95,7 @@
 .hp       "TEXT"  "CWIE"      C Include File                 CodeWarrior
 .hpgl     "HPGL"  "GKON"      HP GL/2                        GraphicConverter
 .hpp      "TEXT"  "CWIE"      C Include File                 CodeWarrior
-.hqx      "TEXT"  "SITx"      BinHex                         StuffIt Expanderª         application/mac-binhex40
+.hqx      "TEXT"  "SITx"      BinHex                         StuffIt Expander          application/mac-binhex40
 .htm      "TEXT"  "MOSS"      HyperText                      Netscape Communicator     text/html
 .html     "TEXT"  "MOSS"      HyperText                      Netscape Communicator     text/html
 .i3       "TEXT"  "R*ch"      Modula 3 Interface             BBEdit
index 8f898a04ee0301bbefa3f981aebbd185a0a85be5..2b62afbca5a7c5f216443d4e7053eb89a6955396 100644 (file)
@@ -2,9 +2,9 @@
 
 SUFFIXES = .tmpl .
 
-GENFILES = afpd.conf
-TMPLFILES = $(foreach file,$(GENFILES),$(file).tmpl)
-CONFFILES = AppleVolumes.default AppleVolumes.system \
+GENFILES = afpd.conf AppleVolumes.default
+TMPLFILES = afpd.conf.tmpl AppleVolumes.default.tmpl
+CONFFILES = AppleVolumes.system \
        atalkd.conf netatalk.conf papd.conf
 PAMFILES = netatalk.pamd
 OVERWRITE_CONFIG = @OVERWRITE_CONFIG@
@@ -14,7 +14,6 @@ EXTRA_DIST = $(CONFFILES) $(TMPLFILES) $(PAMFILES)
 CLEANFILES = $(GENFILES)
 
 pkgconfdir = @PKGCONFDIR@
-nlsdir = @NLSDIR@
 
 #
 # rule to parse template files
@@ -22,8 +21,9 @@ nlsdir = @NLSDIR@
 
 .tmpl:
        sed -e s@:UAMS_PATH:@${UAMS_PATH}@ \
-           -e s@:NLS_PATH:@${nlsdir}@ \
            -e s@:ETCDIR:@${pkgconfdir}@ \
+           -e s@:COMPILED_BACKENDS:@"$(compiled_backends)"@ \
+           -e s@:DEFAULT_CNID_SCHEME:@$(DEFAULT_CNID_SCHEME)@ \
            <$< >$@
 
 #
index 47d4b03a5e501faab629fe78526cd2cb202064c4..08e32ac56ef7720c48a4714d54529731e0c11884 100644 (file)
@@ -97,9 +97,9 @@
 #                         :ETCDIR:/AppleVolumes.default
 #                         (same as -u on command line)
 #     -[no]uservol        [Don't] Read the user's volume file
+#     -closevol           After an AppleVolumes change, disconnect immediatly
+#                         removed volumes.
 #
-#     -nlspath <path>     Prepend this path to each code page filename
-#                         in volume options (default: :NLS_PATH:).
 #
 #   Miscellaneous:
 #     -authprintdir <path> Specifies the path to be used (per server) to 
 #     -k5service <service>
 #     -k5realm <realm>
 #               These are required if the server supports Kerberos 5 authentication
+#
+#   Codepage Options:
+#      -unixcodepage <CODEPAGE>     Specifies the servers unix codepage, e.g. "ISO-8859-15" or "UTF8".
+#                                  This is used to convert strings to/from the systems locale, e.g.
+#                                   for authenthication. Defaults to LOCALE if your system supports it, 
+#                                   otherwise ASCII will be used.
+#
+#      -maccodepage <CODEPAGE>      Specifies the mac clients codepage, e.g. "MAC_ROMAN".
+#                                  This is used to convert strings to the systems locale, e.g. 
+#                                   for authenthication and SIGUSR2 messaging. This will also be
+#                                   the default for volumes maccharset.
+#
+#   CNID related options:
+#      -cnidserver ipaddress:port   Specifies the IP address and port of a cnid_metad server.
+#
+
  
 #              
 # Some examples:
index 4d3bef9c9972a2e23a7d508826e8c3adafe6d512..681b32094e6ffd67dd8e6aeddb50a9ab0ded805d 100644 (file)
@@ -8,6 +8,10 @@ AFPD_MAX_CLIENTS=20
 #ATALK_ZONE=@zone
 ATALK_NAME=`echo ${HOSTNAME}|cut -d. -f1`
 
+# specify the Mac and unix charsets to be used
+ATALK_MAC_CHARSET='MAC_ROMAN'
+ATALK_UNIX_CHARSET='LOCALE'
+
 # specify this if you don't want guest, clrtxt, and dhx
 # available options: uams_guest.so, uams_clrtxt.so, uams_dhx.so, 
 #                   uams_randnum.so
@@ -19,9 +23,14 @@ AFPD_GUEST=nobody
 # Set which daemons to run (papd is dependent upon atalkd):
 ATALKD_RUN=yes
 PAPD_RUN=yes
+CNID_METAD_RUN=yes
 AFPD_RUN=yes
 TIMELORD_RUN=no
 A2BOOT_RUN=no
 
 # Control whether the daemons are started in the background
 ATALK_BGROUND=no
+
+# export the charsets, read form ENV by apps
+export ATALK_MAC_CHARSET
+export ATALK_UNIX_CHARSET
index 6c1f3623f18fba1ae31b1252ca5e28652432e63d..cf5ab6ac189e13213eb4bf8647840b1d80a55b90 100644 (file)
@@ -16,6 +16,7 @@ AFPD_GUEST=nobody
 
 # Set which daemons to run:
 PAPD_RUN=no
+CNID_METAD_RUN=yes
 AFPD_RUN=yes
 
 # Control whether the daemons are started in the background
index 92bfcbe209750289fec60ca753c9099984322f67..ef5085d817384dbb4af3c7fdfc998fc61b3f6005 100644 (file)
@@ -1,4 +1,4 @@
-dnl $Id: configure.in,v 1.202 2004-01-14 16:10:29 bfernhomberg Exp $
+dnl $Id: configure.in,v 1.203 2005-04-28 20:49:17 bfernhomberg Exp $
 dnl configure.in for netatalk
 
 AC_INIT(etc/afpd/main.c)
@@ -10,13 +10,9 @@ AC_CANONICAL_SYSTEM
 AM_INIT_AUTOMAKE(netatalk, ${NETATALK_VERSION})
 AM_CONFIG_HEADER(config.h)
 
-dnl
 dnl Checks for programs.
-dnl
-
 AC_PROG_AWK
 AC_PROG_CC
-AC_PROG_GCC_TRADITIONAL
 AC_PROG_INSTALL
 AC_PROG_LN_S
 AC_PROG_MAKE_SET
@@ -25,43 +21,84 @@ AC_PROG_LIBTOOL
 AC_PROG_PERL
 AC_PROG_GREP
 AC_PROG_PS
-AC_PROG_DVIPS
-AC_PROG_TROFF2PS
-
-dnl
-dnl Checks for presence of some functions.
-dnl
 
+dnl *********************************************************************
+dnl FIXME! FIXME! These should be selectable properly, and should produce
+dnl the proper flags and defines...
+dnl *********************************************************************
+
+############################################
+# we need dlopen/dlclose/dlsym/dlerror for PAM, the password database plugins and the plugin loading code
+#AC_SEARCH_LIBS(dlopen, [dl])
+# dlopen/dlclose/dlsym/dlerror will be checked again later and defines will be set then
+
+dnl Checks for libraries.
+dnl Replace `main' with a function in -labs:
+dnl AC_CHECK_LIB(abs, main)
+dnl Replace `main' with a function in -laudit:
+dnl AC_CHECK_LIB(audit, main)
+dnl Replace `main' with a function in -lauth:
+dnl AC_CHECK_LIB(auth, main)
+dnl Replace `main' with a function in -lcmd:
+dnl AC_CHECK_LIB(cmd, main)
+dnl Replace `main' with a function in -lcrypt:
+dnl AC_CHECK_LIB(crypt, main)
+dnl Replace `main' with a function in -ld:
+dnl AC_CHECK_LIB(d, main)
+dnl Replace `main' with a function in -ldl:
+# AC_CHECK_LIB(dl, dlopen)
+dnl Replace `main' with a function in -lkauth:
+dnl AC_CHECK_LIB(kauth, main)
+dnl Replace `main' with a function in -lkrb:
+dnl AC_CHECK_LIB(krb, main)
+dnl Replace `main' with a function in -llwp:
+dnl AC_CHECK_LIB(lwp, main)
+dnl Replace `main' with a function in -ln:
+dnl AC_CHECK_LIB(n, main)
+dnl Replace `main' with a function in -lnsl:
+# AC_CHECK_LIB(nsl, main)
+dnl Replace `main' with a function in -lprot:
+dnl AC_CHECK_LIB(prot, main)
+dnl Replace `main' with a function in -lrx:
+dnl AC_CHECK_LIB(rx, main)
+dnl Replace `main' with a function in -lrxkad:
+dnl AC_CHECK_LIB(rxkad, main)
+dnl Replace `main' with a function in -lsocket:
+AC_CHECK_LIB(socket, socket)
+dnl Replace `main' with a function in -lsys:
+dnl AC_CHECK_LIB(sys, main)
+dnl Replace `main' with a function in -lubik:
+dnl AC_CHECK_LIB(ubik, main)
+
+
+#
+# Check presence of some functions
+#
+# Check for XPG4 access() function
+# Be sure to test before adding AFS libs in LIBS path as AFS lib
+# has such a function that works only on AFS filesystems.
+AC_CHECK_FUNCS(access)
+# 
 AC_CHECK_FUNCS(pread pwrite)
 
-dnl
 dnl Checks for header files.
-dnl
-
+AC_HEADER_DIRENT
 AC_HEADER_STDC
 AC_HEADER_SYS_WAIT
-AC_HEADER_TIME
-AC_CHECK_HEADERS(fcntl.h limits.h stdint.h strings.h sys/fcntl.h sys/time.h sys/mnttab.h sys/statvfs.h sys/stat.h sys/vfs.h mntent.h unistd.h termios.h sys/termios.h netdb.h sgtty.h sys/mount.h statfs.h sys/types.h dlfcn.h errno.h sys/errno.h)
-AC_CHECK_HEADERS(fcntl.h limits.h stdint.h strings.h sys/fcntl.h sys/file.h sys/ioctl.h sys/time.h sys/mnttab.h sys/statvfs.h sys/stat.h sys/vfs.h mntent.h syslog.h unistd.h termios.h sys/termios.h netdb.h sgtty.h ufs/quota.h mount.h  statfs.h sys/types.h dlfcn.h errno.h sys/errno.h crypt.h)
-
+AC_CHECK_HEADERS(fcntl.h limits.h stdint.h strings.h time.h sys/param.h sys/fcntl.h sys/file.h sys/ioctl.h sys/time.h sys/mnttab.h sys/statvfs.h sys/stat.h sys/vfs.h mntent.h syslog.h unistd.h termios.h sys/termios.h netdb.h sgtty.h ufs/quota.h mount.h statfs.h sys/types.h dlfcn.h errno.h sys/errno.h sys/uio.h)
 AC_CHECK_HEADER(sys/cdefs.h,,
        AC_MSG_RESULT([enabling generic cdefs.h from tree])
        CFLAGS="-I\$(top_srcdir)/sys/generic $CFLAGS"
 )
-
-AC_CHECK_HEADERS([sys/param.h])
-AC_CHECK_HEADERS([sys/mount.h], [], [],
-[
-#if HAVE_SYS_PARAM_H
+AC_CHECK_HEADERS([sys/mount.h], , , 
+[#ifdef HAVE_SYS_PARAM_H
 #include <sys/param.h>
 #endif
 ])
 
+AC_CHECK_HEADERS(langinfo.h locale.h sys/filio.h)
 
-dnl
 dnl Checks for typedefs, structures, and compiler characteristics.
-dnl
-
 AC_C_CONST
 AC_TYPE_UID_T
 AC_C_INLINE
@@ -69,109 +106,234 @@ AC_TYPE_MODE_T
 AC_TYPE_OFF_T
 AC_TYPE_PID_T
 AC_TYPE_SIZE_T
-AC_CHECK_MEMBERS(struct tm.tm_gmtoff,,, [#include <time.h>])
+AC_STRUCT_ST_RDEV
+AC_HEADER_TIME
+AC_STRUCT_TM
+
+dnl --------------------------------------------------------------------------
+dnl check if dlsym needs to add an underscore, uses libtool macros 
+dnl --------------------------------------------------------------------------
+AC_LTDL_DLLIB
+AC_CHECK_FUNCS(dlopen dlsym dlclose)
+AC_LTDL_DLSYM_USCORE
+if test x"$libltdl_cv_need_uscore" = xyes; then
+    AC_DEFINE(DLSYM_PREPEND_UNDERSCORE, 1, [BSD compatibility macro])
+fi
 
-dnl
-dnl Checks for library functions.
-dnl
 
+dnl Checks for library functions.
+AC_TYPE_GETGROUPS
+AC_PROG_GCC_TRADITIONAL
 AC_FUNC_MEMCMP
-AC_CHECK_FUNCS(strcasestr strchr memcpy)
+AC_HEADER_MAJOR
+AC_FUNC_MMAP
+AC_TYPE_SIGNAL
+AC_FUNC_UTIME_NULL
+AC_FUNC_WAIT3
+AC_CHECK_FUNCS(getcwd gethostname gettimeofday getusershell mkdir rmdir select socket strdup strcasestr strstr strtoul strchr memcpy)
+AC_CHECK_FUNCS(backtrace_symbols)
+AC_CHECK_FUNCS(setlocale nl_langinfo)
+AC_CHECK_FUNCS(waitpid getcwd strdup strndup strnlen strtoul strerror chown fchown chmod fchmod chroot link mknod mknod64)
+AC_CHECK_FUNCS(strlcpy strlcat)
+AC_CHECK_FUNCS(setlinebuf)
+AC_CHECK_MEMBERS(struct tm.tm_gmtoff,,, [#include <time.h>])
+AC_CACHE_SAVE
+
+dnl Checks for (v)snprintf
 NETATALK_SNPRINTF_CHECK
 
+dnl --------------------------------------------------------------------------
+dnl 64bit platform check
+dnl --------------------------------------------------------------------------
+
+AC_MSG_CHECKING([whether to check for 64bit libraries])
+dnl Determine libdir name
+case $host in
+*-*-linux*)
+  # Test if the compiler is 64bit
+  echo 'int i;' > conftest.$ac_ext
+  atalk_cv_cc_64bit_output=no
+  if AC_TRY_EVAL(ac_compile); then
+    case `/usr/bin/file conftest.$ac_objext` in
+    *"ELF 64"*)
+      atalk_cv_cc_64bit_output=yes
+      ;;
+    esac
+  fi
+  rm -rf conftest*
+  ;;
+esac
+
 dnl
-dnl Configuration options.
+dnl FIXME: Do we need something like this for Solaris 64bit?
 dnl
 
-NETATALK_ADMINGRP_CHECK
+case $host_cpu:$atalk_cv_cc_64bit_output in
+powerpc64:yes | s390x:yes | sparc64:yes | x86_64:yes)
+  atalk_libname="lib64"
+  AC_MSG_RESULT([yes])
+  ;;
+*:*)
+  atalk_libname="lib"
+  AC_MSG_RESULT([no])
+  ;;
+esac
+
+dnl --------------------------------------------------------------------------
+dnl specific configuration comes in here:
+dnl --------------------------------------------------------------------------
+
+
+netatalk_cv_admin_group=yes
+AC_MSG_CHECKING([for administrative group support])
+AC_ARG_ENABLE(admin-group,
+       [  --disable-admin-group   disable admin group],[
+        if test x"$enableval" = x"no"; then
+               AC_DEFINE(ADMIN_GRP, 0, [Define if the admin group should be enabled])
+               netatalk_cv_admin_group=no
+               AC_MSG_RESULT([no])
+       else
+               AC_DEFINE(ADMIN_GRP, 1, [Define if the admin group should be enabled])
+               AC_MSG_RESULT([yes])
+        fi],[
+               AC_DEFINE(ADMIN_GRP, 1, [Define if the admin group should be enabled])
+               AC_MSG_RESULT([yes])
+       ]
+)
+
 NETATALK_AFS_CHECK
+
 NETATALK_CONFIG_DIRS
 
-AC_MSG_CHECKING([for logfile path])
+AC_MSG_CHECKING([whether to use logfile])
 AC_ARG_WITH(logfile,
-       [  --with-logfile=PATH     path for file used by logger [/var/log/netatalk.log]
-                          use --without-logfile to disable logger], [
-        if test "x$withval" = "xno"; then
+       [  --with-logfile=PATH     path for file used by logger],[
+        if test x"$withval" = x"no"; then
                AC_DEFINE(DISABLE_LOGGER, 1, [Define if the logger should not be used])
-               AC_MSG_RESULT([syslog])
+               AC_MSG_RESULT([no, syslog])
        elif test "$withval" != "yes"; then
                AC_DEFINE_UNQUOTED(LOGFILEPATH, "$withval", [Path to the log file])
                AC_MSG_RESULT([$withval])
        else
-                AC_DEFINE_UNQUOTED(LOGFILEPATH, "/var/log/netatalk.log", [Path to the log file])
-                AC_MSG_RESULT([/var/log/netatalk.log]) 
-       fi], [
                AC_DEFINE_UNQUOTED(LOGFILEPATH, "/var/log/netatalk.log", [Path to the log file])
-               AC_MSG_RESULT([/var/log/netatalk.log])
+               AC_MSG_RESULT([/var/log/netatalk.log]) 
+       fi],[
+               AC_DEFINE(DISABLE_LOGGER, 1, [Define if the logger should not be used])
+               AC_MSG_RESULT([no, syslog])
        ]
 )
 
+
+netatalk_cv_with_cracklib=no
 AC_ARG_WITH(cracklib,
-       [  --with-cracklib=DICT    enable/set location of cracklib dictionary],
+       [  --with-cracklib=DICT    enable/set location of cracklib dictionary],[
        if test "x$withval" != "xno" ; then
                cracklib="$withval"
-               AC_CHECK_LIB(crack, main,
+               AC_CHECK_LIB(crack, main, [
                        AC_DEFINE(USE_CRACKLIB, 1, [Define if cracklib should be used])
                        LIBS="$LIBS -lcrack"
-                       AC_MSG_RESULT([enabling cracklib support])
                        if test "$cracklib" = "yes"; then
-                               cracklib="/usr/lib/cracklib_dict"
+                               cracklib="/usr/$atalk_libname/cracklib_dict"
                        fi
                        AC_DEFINE_UNQUOTED(_PATH_CRACKLIB, "$cracklib",
                                [path to cracklib dictionary])
-                       AC_MSG_RESULT([setting cracklib dictionary to $cracklib]),
+                       AC_MSG_RESULT([setting cracklib dictionary to $cracklib])
+                       netatalk_cv_with_cracklib=yes
+                       ],[
                        AC_MSG_ERROR([cracklib not found!])
+                       ]
                )
        fi
+       ]
 )
+AC_MSG_CHECKING([for cracklib support])
+AC_MSG_RESULT([$netatalk_cv_with_cracklib])
 
+netatalk_cv_ddp_enabled=yes
 AC_MSG_CHECKING([whether to enable DDP])
 AC_ARG_ENABLE(ddp,
-       [  --disable-ddp           disable DDP], [
-       if test "x$enableval" = "xno"; then 
+       [  --disable-ddp           disable DDP],[
+       if test "$enableval" = "no"; then 
                AC_DEFINE(NO_DDP, 1, [Define if DDP should be disabled])
                AC_MSG_RESULT([no])
+               netatalk_cv_ddp_enabled=no
        else
                AC_MSG_RESULT([yes])
        fi
-       ], [
+       ],[
                AC_MSG_RESULT([yes])
        ]
 )
 
-AC_MSG_CHECKING([whether to enable debugging code])
+AC_MSG_CHECKING([whether to enable debug code])
+AC_ARG_ENABLE(debug1,
+       [  --enable-debug1         enable debug code],[
+       if test "$enableval" != "no"; then
+               if test "$enableval" = "yes"; then
+                       AC_DEFINE(DEBUG1, 1, [Define if debugging information should be included])
+               else
+                       AC_DEFINE_UNQUOTED(DEBUG1, $enableval, [Define if debugging information should be included])
+               fi 
+               AC_MSG_RESULT([yes])
+       else
+               AC_MSG_RESULT([no])
+       fi
+       ],[
+               AC_MSG_RESULT([no])
+       ]
+)
+
+AC_MSG_CHECKING([whether to enable verbose debug code])
 AC_ARG_ENABLE(debug,
-       [  --enable-debug          enable debug code], [
-       if test "x$enableval" != "xno"; then
-               if test "x$enableval" = "xyes"; then
-                       AC_DEFINE(DEBUG, 1, [Define if debugging information should be included])
+       [  --enable-debug          enable verbose debug code],[
+       if test "$enableval" != "no"; then
+               if test "$enableval" = "yes"; then
+                       AC_DEFINE(DEBUG, 1, [Define if verbose debugging information should be included])
                else
-                       AC_DEFINE_UNQUOTED(DEBUG, $enableval, [Define if debugging information should be included])
+                       AC_DEFINE_UNQUOTED(DEBUG, $enableval, [Define if verbose debugging information should be included])
                fi 
                AC_MSG_RESULT([yes])
        else
                AC_MSG_RESULT([no])
        fi
-       ], [
+       ],[
                AC_MSG_RESULT([no])
        ]
 )
 
 afp3=no
+afp3set=no
+AC_MSG_CHECKING([whether AFP 3.x calls should be enabled])
 AC_ARG_ENABLE(afp3,
-       [  --enable-afp3           enable AFP 3.x calls],
-       if test "$enableval" = "yes"; then
+       [  --disable-afp3          disable AFP 3.x calls],
+       [
+           if test x"$enableval" != x"no"; then
+               afp3set=yes
                afp3=yes
-               AC_DEFINE(AFP3x, 1, [Define to enable AFP 3.x support])
-               AC_MSG_RESULT([enabling AFP 3.x calls])
-       fi
+               AC_MSG_RESULT([yes])
+           else
+               AC_MSG_RESULT([no])
+           fi
+       ],[
+           AC_MSG_RESULT([yes])
+           afp3=yes
+       ]
 )
 
-if test "$afp3" = "yes"; then
-       AM_ICONV
-        AC_SYS_LARGEFILE
+if test x"$afp3" = x"yes"; then
+        AC_SYS_LARGEFILE([
+               AC_DEFINE(AFP3x, 1, [Define to enable AFP 3.x support])
+       ],[
+               if test x"$afp3set" = x"yes"; then
+                       AC_MSG_ERROR([AFP 3.x support requires Large File Support.])
+               else
+                       AC_MSG_WARN([AFP 3.x support requires Large File Support. AFP3.x support disabled])
+                       afp3=no
+               fi
+       ])
 fi
 
+AC_CHECK_ICONV
 
 dnl ----------- A NOTE ABOUT DROPKLUDGE
 dnl The trouble with this fix is that if you know what the file is called, it
@@ -180,84 +342,54 @@ dnl since the students don't have telnet access to the Mac servers.  There is
 dnl currently no one working on further development/fixes of DROPKLUDGE.
 dnl -----------
 
+netatalk_cv_dropkludge=no
 AC_MSG_CHECKING([whether to enable experimental dropbox support])
 AC_ARG_ENABLE(dropkludge,
-       [  --enable-dropkludge     enable the experimental dropbox fix (INSECURE!) ], [
-       if test "x$enableval" = "xyes"; then 
+       [  --enable-dropkludge     enable the experimental dropbox fix (INSECURE!) ],[
+       if test "$enableval" = "yes"; then 
                AC_DEFINE(DROPKLUDGE, 1, [Define if you want to use the experimental dropkludge support])
                AC_MSG_RESULT([yes])
+               netatalk_cv_dropkludge=yes
        else
                AC_MSG_RESULT([no])
        fi
-       ], [AC_MSG_RESULT([no])]
+       ],[
+               AC_MSG_RESULT([no])
+       ]
 )
 
+netatalk_cv_force_uidgid=no
 AC_MSG_CHECKING([whether to enable forcing of uid/gid per volume])
 AC_ARG_ENABLE(force-uidgid,
-       [  --enable-force-uidgid   allow forcing of uid/gid per volume (BROKEN) ], [
-       if test "x$enableval" = "xyes"; then
+       [  --enable-force-uidgid   allow forcing of uid/gid per volume (BROKEN) ],[
+       if test "$enableval" = "yes"; then
                AC_DEFINE(FORCE_UIDGID, 1, [Define if you want forcing of uid/gid per volume])
+               AC_MSG_RESULT([enabling forcing of uid/gid per volume])
                AC_MSG_RESULT([yes])
+               netatalk_cv_force_uidgid=yes
        else
                AC_MSG_RESULT([no])
        fi
-       ], [AC_MSG_RESULT([no])]
-)
-
-NETATALK_ARG_DID
-
-dnl Determine whether or not to use filename mangling
-AC_MSG_CHECKING([whether 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])
-                       else
-                               AC_DEFINE(FILE_MANGLING, 1, [Define if file name mangling should be used])
-                               AC_MSG_RESULT([yes])
-                       fi
-               else
-                       AC_MSG_RESULT([no])
-               fi
-       ], [
-               if test "x$did_scheme" = "xcnid"; then
-                       AC_DEFINE(FILE_MANGLING, 1, [Define if file name mangling should be used])
-                       AC_MSG_RESULT([yes])
-               else
-                       AC_MSG_RESULT([no])
-               fi
+       ],[
+               AC_MSG_RESULT([no])
        ]
 )
 
-if test "$did_scheme" = "cnid"; then
-    USE_CDB="yes"
-else
-    USE_CDB="no"
-fi
-
-dnl Determine whether or not to use CDB or transactional DB store
-AC_MSG_CHECKING([whether 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])
-           else
-               USE_CDB="no"
-               AC_MSG_RESULT([no])
-           fi
-       else
-           USE_CDB="yes"
-           AC_MSG_RESULT([yes])
-       fi
-       , AC_MSG_RESULT([yes])
-)
-
-if test "$USE_CDB" = "yes"; then
-    AC_DEFINE(CNID_DB_CDB, 1, [Define if CNID should be used with Concurrent Data Store])
+dnl Check for CNID database backends
+bdb_required=no
+AC_NETATALK_CNID([bdb_required=yes],[bdb_required=no])
+
+dnl Check for Berkeley DB library
+if test "x$bdb_required" = "xyes"; then
+       AC_PATH_BDB(, [
+               AC_MSG_RESULT([])
+               AC_MSG_RESULT([Make sure you have the required Berkeley DB libraries AND headers installed.])
+               AC_MSG_RESULT([You can download the latest version from http://www.sleepycat.com.])
+               AC_MSG_RESULT([If you have installed BDB in a non standard location use the])
+               AC_MSG_RESULT([--with-bdb=/path/to/bdb configure option and make sure])
+               AC_MSG_RESULT([your linker is configured to check for libraries there.])
+               AC_MSG_ERROR([Berkeley DB library required but not found!])
+       ])
 fi
 
 dnl Check for quota support
@@ -266,51 +398,105 @@ AC_CHECK_QUOTA
 dnl Check for optional server location protocol support (used by MacOS X)
 NETATALK_SRVLOC
 
-dnl Check for gssapi
-NETATALK_GSSAPI_CHECK
-
 dnl Check for PAM libs
+netatalk_cv_use_pam=no
 AC_PATH_PAM([
        use_pam_so=yes
        compile_pam=yes
+       netatalk_cv_use_pam=yes
        AC_DEFINE(USE_PAM, 1, [Define to enable PAM support])
 ])
 
-AC_MSG_CHECKING([whether shadow support should be enabled])
+netatalk_cv_use_shadowpw=no
 AC_ARG_WITH(shadow,
-       [  --with-shadow           enable shadow password support],
-       [shadowpw="$withval"],
-       [shadowpw=no]
+       [  --with-shadow           enable shadow password support [[auto]]],
+       [netatalk_cv_use_shadowpw="$withval"],
+       [netatalk_cv_use_shadowpw=auto]
 )
-if test "x$shadowpw" = "xyes"; then
+
+if test "x$netatalk_cv_use_shadowpw" != "xno"; then
+    AC_CHECK_HEADER([shadow.h])
+    if test x"$ac_cv_header_shadow_h" = x"yes"; then
+       netatalk_cv_use_shadowpw=yes
        AC_DEFINE(SHADOWPW, 1, [Define if shadow passwords should be used])
+    else 
+      if test "x$shadowpw" = "xyes"; then
+        AC_MSG_ERROR([shadow support not available])
+      else
+               netatalk_cv_use_shadowpw=no
+      fi
+    fi 
 fi
-AC_MSG_RESULT([$shadowpw])
 
+AC_MSG_CHECKING([whether shadow support should be enabled])
+if test "x$netatalk_cv_use_shadowpw" = "xyes"; then
+       AC_MSG_RESULT([yes])
+else
+       AC_MSG_RESULT([no])
+fi
+       
+       
+       
+netatalk_cv_use_shellcheck=yes
+AC_MSG_CHECKING([whether checking for a valid shell should be enabled])
 AC_ARG_ENABLE(shell-check,
-       [  --disable-shell-check   disable checking for a valid shell],
+       [  --disable-shell-check   disable checking for a valid shell],[
        if test "$enableval" = "no"; then 
                AC_DEFINE(DISABLE_SHELLCHECK, 1, [Define if shell check should be disabled])
-               AC_MSG_RESULT([disabling valid shell check])
+               AC_MSG_RESULT([no])
+               netatalk_cv_use_shellcheck=no
+       else
+               AC_MSG_RESULT([yes])
        fi
+       ],[
+               AC_MSG_RESULT([yes])
+       ]
 )
 
 NETATALK_TCP_WRAPPERS
 
+AC_MSG_CHECKING([whether system (fcntl) locking should be disabled])
+AC_ARG_ENABLE(locking,
+        [  --disable-locking       disable system locking],[
+               if test "$enableval" = "no"; then
+                       AC_DEFINE(DISABLE_LOCKING, 1, [Define if system (fcntl) locking should be disabled])
+                       AC_MSG_RESULT([yes])
+               else
+                       AC_MSG_RESULT([no])
+               fi
+               
+       ],[
+               AC_MSG_RESULT([no])
+       ]
+
+)
+
+
 AC_ARG_ENABLE(redhat,
-       [  --enable-redhat         use redhat-style sysv configuration ],
+       [  --enable-redhat         use redhat-style sysv configuration ],[
        if test "$enableval" = "yes"; then
                sysv_style=redhat
        fi
        AC_MSG_RESULT([enabling redhat-style sysv support])
+       ]
 )
 
 AC_ARG_ENABLE(suse,
-       [  --enable-suse           use suse-style sysv configuration ],
+       [  --enable-suse           use suse-style sysv configuration ],[
        if test "$enableval" = "yes"; then
                sysv_style=suse
        fi
        AC_MSG_RESULT([enabling suse-style sysv support])
+       ]
+)
+
+AC_ARG_ENABLE(gentoo,
+       [  --enable-gentoo         use gentoo-style sysv configuration ],[
+       if test "$enableval" = "yes"; then
+               sysv_style=gentoo
+       fi
+       AC_MSG_RESULT([enabling gentoo-style sysv support])
+       ]
 )
 
 AC_ARG_ENABLE(cobalt,
@@ -329,6 +515,25 @@ AC_ARG_ENABLE(netbsd,
        AC_MSG_RESULT([enabling NetBSD-style rc.d support])
 )
 
+AC_ARG_ENABLE(debian,
+       [  --enable-debian         use debian-style sysv configuration ],[
+       if test "$enableval" = "yes"; then
+               sysv_style=debian
+       fi
+       AC_MSG_RESULT([enabling debian-style sysv support])
+       ]
+)
+
+dnl ----- timelord compilation (disabled by default)
+AC_MSG_CHECKING([whether timelord should be compiled])
+compile_timelord=no
+AC_ARG_ENABLE(timelord,
+       [  --enable-timelord       enable compilation of timelord server],
+       [compile_timelord="$enableval"],
+       [compile_timelord="no"]
+)
+AC_MSG_RESULT([$compile_timelord])
+
 dnl ----- a2boot compilation (disabled by default)
 AC_MSG_CHECKING([whether a2boot should be compiled])
 compile_a2boot=no
@@ -340,28 +545,47 @@ AC_ARG_ENABLE(a2boot,
 AC_MSG_RESULT([$compile_a2boot])
 
 AC_ARG_WITH(uams-path,
-       [  --with-uams-path=PATH   path to UAMs [[PKGCONF/uams]]],
-       uams_path="$withval",
-       uams_path="${PKGCONFDIR}/uams"
+       [  --with-uams-path=PATH   path to UAMs [[PKGCONF/uams]]],[
+               uams_path="$withval"
+       ],[
+               uams_path="${PKGCONFDIR}/uams"
+       ]
 )
 
+NETATALK_AC_CUPS
+
+dnl check if we can use attribute unused (gcc only) from ethereal
+AC_MSG_CHECKING(to see if we can add '__attribute__((unused))' to CFLAGS)
+if test x$GCC != x ; then
+  CFLAGS="-D_U_=\"__attribute__((unused))\" $CFLAGS"
+  AC_MSG_RESULT(yes)
+else
+  CFLAGS="-D_U_=\"\" $CFLAGS"
+  AC_MSG_RESULT(no)
+fi
+
 dnl --------------------------------------------------------------------------
 dnl FHS stuff has to be done last because it overrides other defaults
 dnl --------------------------------------------------------------------------
 
+AC_MSG_CHECKING([whether to use Filesystem Hierarchy Standard (FHS) compatibility])
 AC_ARG_ENABLE(fhs,
-       [  --enable-fhs            use Filesystem Hierarchy Standard (FHS) compatibility],
+       [  --enable-fhs            use Filesystem Hierarchy Standard (FHS) compatibility],[
        if test "$enableval" = "yes"; then
                uams_path="${libdir}/netatalk"
                sysconfdir="/etc"
                PKGCONFDIR=${sysconfdir}/netatalk
                SERVERTEXT="${PKGCONFDIR}/msg"
-               NLSDIR="${PKGCONFDIR}/nls"
                use_pam_so=yes
                mandir="/usr/share/man"
                AC_DEFINE(FHS_COMPATIBILITY, 1, [Define if you want compatibily with the FHS])
+               AC_MSG_RESULT([yes])
+       else
+               AC_MSG_RESULT([no])
        fi
-       AC_MSG_RESULT([enabling Filesystem Hierarchy Standard (FHS) compatibility])
+       ],[
+               AC_MSG_RESULT([no])
+       ]
 )
 
 dnl --------------------------------------------------------------------------
@@ -369,8 +593,8 @@ dnl post-FHS substitutions, etc
 dnl --------------------------------------------------------------------------
 
 dnl ***** UAMS_PATH
-AC_DEFINE_UNQUOTED(UAMS_PATH, "${uams_path}",
-       [path to UAMs [default=PKGCONF/uams]])
+dnl AC_DEFINE_UNQUOTED(UAMS_PATH, "${uams_path}",
+dnl    [path to UAMs [default=PKGCONF/uams]])
 UAMS_PATH="${uams_path}"
 AC_SUBST(UAMS_PATH)
 
@@ -417,6 +641,7 @@ dnl --------------------- operating system specific flags (port from sys/*)
 dnl ----- AIX specific -----
 if test x"$this_os" = "xaix"; then
        AC_MSG_RESULT([ * AIX specific configuration])
+       AC_DEFINE(NO_STRUCT_TM_GMTOFF, 1, [Define if the gmtoff member of struct tm is not available])
 
        dnl This is probably a lie; AIX 4.3 supports a 64-bit long
        dnl compilation environment.  It's enough to get things defined
@@ -428,6 +653,7 @@ dnl ----- FreeBSD specific -----
 if test x"$this_os" = "xfreebsd"; then 
        AC_MSG_RESULT([ * FreeBSD specific configuration])
        AC_DEFINE(BSD4_4, 1, [BSD compatiblity macro])
+       AC_DEFINE(FREEBSD, 1, [Define if OS is FreeBSD])
        AC_DEFINE(SENDFILE_FLAVOR_BSD, 1, [Define if the sendfile() function uses BSD semantics])
 fi
 
@@ -436,26 +662,31 @@ if test x"$this_os" = "xhpux11"; then
        AC_MSG_RESULT([ * HP-UX 11 specific configuration])
 
        AC_DEFINE(_ISOC9X_SOURCE, 1, [Compatibility macro])
+       AC_DEFINE(NO_STRUCT_TM_GMTOFF, 1, [Define if the gmtoff member of struct tm is not available])
+fi
+
+dnl ----- IRIX specific -----
+if test x"$this_os" = "xirix"; then
+       AC_MSG_RESULT([ * IRIX specific configuration])
+
+       AC_DEFINE(NO_STRUCT_TM_GMTOFF, 1, [Define if the gmtoff member of struct tm is not available])
 fi
 
 dnl ----- Linux specific -----
-ac_have_atalk_addr=no
 if test x"$this_os" = "xlinux"; then 
        AC_MSG_RESULT([ * Linux specific configuration])
-
+       
        dnl ----- kernel 2.6 changed struct at_addr to atalk_addr
        AC_MSG_CHECKING([for struct atalk_addr])
-       AC_COMPILE_IFELSE([
+dnl    AC_COMPILE_IFELSE([
+       AC_TRY_COMPILE([
 #include <sys/socket.h>
 #include <asm/types.h>
 #include <linux/atalk.h>
 
-int main() {
-       struct atalk_addr foo;
-
-       return 0;
-}
-       ], [
+       struct atalk_addr foo;
+],
+[ ], [
                ac_have_atalk_addr=yes
                AC_MSG_RESULT([yes])
        ], [
@@ -466,24 +697,74 @@ if test "x$ac_have_atalk_addr" = "xyes"; then
        AC_DEFINE(HAVE_ATALK_ADDR, 1, [set if struct at_addr is called atalk_addr])
 fi
 
+       dnl ----- check if we need the quotactl wrapper
+#      AC_CHECK_HEADERS(sys/quota.h linux/quota.h)
+#      AC_CHECK_FUNC(quotactl,,
+#              AC_DEFINE(NEED_QUOTACTL_WRAPPER, 1, [Define if the quotactl wrapper is needed])
+#              AC_MSG_RESULT([enabling quotactl wrapper])
+#      )
+
+        # For quotas on Linux XFS filesystems
+        AC_CHECK_HEADERS(linux/xqm.h linux/xfs_fs.h)
+        AC_CHECK_HEADERS(xfs/libxfs.h xfs/xqm.h xfs/xfs_fs.h)
+        # For linux > 2.5.56
+        AC_CHECK_HEADERS(linux/dqblk_xfs.h)
+
+
        dnl ----- as far as I can tell, dbtob always does the wrong thing
        dnl ----- on every single version of linux I've ever played with.
        dnl ----- see etc/afpd/quota.c
        AC_DEFINE(HAVE_BROKEN_DBTOB, 1, [Define if dbtob is broken])
 
-       dnl --- added by Yoshinobu Ishizaki (2001.03.13) ---
-       dnl ----- check if version is newer than 2.2.x
-       changequote(<<,>>)
-       majorvers="`uname -r | sed 's/\([0-9]\)..*/\1/'`"
-       minorvers="`uname -r | sed 's/[0-9]\.\([0-9]\)\..*/\1/'`"
-       if [ $majorvers -ge 2 ]; then
-               if [ $minorvers -ge 2 ]; then
-                       changequote([,])
-                       AC_MSG_RESULT([ * found Linux 2.2.x or higher])
-                       AC_DEFINE(SENDFILE_FLAVOR_LINUX, 1, [Define if the sendfile() function uses Linux semantics])
-               else
-                       AC_MSG_RESULT([ * found Linux 2.0.x ]) 
-               fi
+       netatalk_cv_linux_sendfile=no
+dnl    disable this for now, code doesn't use sendfile anyway
+dnl        AC_ARG_ENABLE(sendfile,
+dnl        [  --enable-sendfile       use sendfile syscall default (no) ],[
+dnl            if test "$enableval" = "yes"; then
+dnl                    netatalk_cv_linux_sendfile=yes
+dnl            fi
+dnl            AC_MSG_RESULT([enabling sendfile syscall])
+dnl        ]
+dnl       )
+
+       if test x"$netatalk_cv_linux_sendfile" = "xyes"; then 
+           AC_CACHE_CHECK([for linux sendfile support],netatalk_cv_HAVE_SENDFILE,[
+           AC_TRY_LINK([#include <sys/sendfile.h>],
+[\
+int tofd, fromfd;
+off_t offset;
+size_t total;
+ssize_t nwritten = sendfile(tofd, fromfd, &offset, total);
+],
+netatalk_cv_HAVE_SENDFILE=yes,netatalk_cv_HAVE_SENDFILE=no)])
+
+# Try and cope with broken Linux sendfile....
+           AC_CACHE_CHECK([for broken linux sendfile support],netatalk_cv_HAVE_BROKEN_LINUX_SENDFILE,[
+           AC_TRY_LINK([\
+#if defined(_FILE_OFFSET_BITS) && (_FILE_OFFSET_BITS == 64)
+#undef _FILE_OFFSET_BITS
+#endif
+#include <sys/sendfile.h>],
+[\
+int tofd, fromfd;
+off_t offset;
+size_t total;
+ssize_t nwritten = sendfile(tofd, fromfd, &offset, total);
+],
+netatalk_cv_HAVE_BROKEN_LINUX_SENDFILE=yes,netatalk_cv_HAVE_BROKEN_LINUX_SENDFILE=no,netatalk_cv_HAVE_BROKEN_SENDFILE=cross)])
+
+           if test x"$netatalk_cv_HAVE_SENDFILE" = x"yes"; then
+               AC_DEFINE(HAVE_SENDFILE,1,[Whether sendfile() is available])
+               AC_DEFINE(SENDFILE_FLAVOR_LINUX,1,[Whether linux sendfile() API is available])
+               AC_DEFINE(WITH_SENDFILE,1,[Whether sendfile() should be used])
+           elif test x"$netatalk_cv_HAVE_BROKEN_LINUX_SENDFILE" = x"yes"; then
+               AC_DEFINE(SENDFILE_FLAVOR_LINUX,1,[Whether linux sendfile() API is available])
+               AC_DEFINE(LINUX_BROKEN_SENDFILE_API,1,[Whether (linux) sendfile() is broken])
+               AC_DEFINE(WITH_SENDFILE,1,[Whether sendfile should be used])
+           else
+               netatalk_cv_linux_sendfile=no
+               AC_MSG_RESULT(no);
+           fi
        fi
 
        dnl ----- Linux/alpha specific -----
@@ -492,15 +773,18 @@ fi
                AC_DEFINE(HAVE_GCC_MEMCPY_BUG, 1, [Define if memcpy is buggy])
        fi
        need_dash_r=no
+
+
 fi
 
 dnl ----- Mac OSX specific -----
 if test x"$this_os" = "xmacosx"; then 
        AC_MSG_RESULT([ * Mac OSX specific configuration])
        AC_DEFINE(BSD4_4, 1, [BSD compatiblity macro])
-       AC_DEFINE(HAVE_BROKEN_CPP, 1, [Define if cpp is broken])
        AC_DEFINE(HAVE_2ARG_DBTOB, 1, [Define if dbtob takes two arguments])
        dnl AC_DEFINE(NO_DLFCN_H)
+       AC_DEFINE(NO_DDP, 1, [Define if DDP should be disabled])
+       AC_DEFINE(NO_QUOTA_SUPPORT, 1, [Define if Quota support should be disabled])
        AC_DEFINE(MACOSX_SERVER, 1, [Define if compiling for MacOS X Server])
 fi
 
@@ -508,21 +792,19 @@ dnl ----- NetBSD specific -----
 if test x"$this_os" = "xnetbsd"; then 
        AC_MSG_RESULT([ * NetBSD specific configuration])
        AC_DEFINE(BSD4_4, 1, [BSD compatiblity macro])
-       if echo __ELF__ | $CC -E - | grep __ELF__ > /dev/null; then
-               # NetBSD ELF machines don't have to have DLSYM_PREPEND_UNDERSCORE.
-               # If this test is true, it's not an ELF box.
-               # This REALLY should be a configure test.
-               AC_DEFINE(DLSYM_PREPEND_UNDERSCORE, 1, [BSD compatibility macro])
-       fi
-       CFLAGS="-I\$(top_srcdir)/sys/netbsd $CFLAGS"
+       AC_DEFINE(NETBSD, 1, [Define if OS is FreeBSD])
+       CFLAGS="-I\$(top_srcdir)/sys/netbsd -I/usr/include/kerberosIV $CFLAGS"
        need_dash_r=yes 
+
+       dnl ----- NetBSD does not have crypt.h, uses unistd.h -----
+       AC_DEFINE(UAM_DHX, 1, [Define if the DHX UAM modules should be compiled])
 fi
 
 dnl ----- OpenBSD specific -----
 if test x"$this_os" = "xopenbsd"; then 
        AC_MSG_RESULT([ * OpenBSD specific configuration])
-       AC_DEFINE(BSD4_4, 1, [BSD compatiblity macro])
-       AC_DEFINE(DLSYM_PREPEND_UNDERSCORE, 1, [BSD compatibility macro])
+       dnl ----- OpenBSD does not have crypt.h, uses unistd.h -----
+       AC_DEFINE(UAM_DHX, 1, [Define if the DHX UAM modules should be compiled])
 fi
 
 dnl ----- Solaris specific -----
@@ -530,12 +812,91 @@ if test x"$this_os" = "xsolaris"; then
        AC_MSG_RESULT([ * Solaris specific configuration])
        AC_DEFINE(__svr4__, 1, [Solaris compatibility macro])
        AC_DEFINE(_ISOC9X_SOURCE, 1, [Compatibility macro])
+       AC_DEFINE(NO_STRUCT_TM_GMTOFF, 1, [Define if the gmtoff member of struct tm is not available])
        AC_DEFINE(SOLARIS, 1, [Solaris compatibility macro])
        CFLAGS="-I\$(top_srcdir)/sys/generic $CFLAGS"
        need_dash_r=yes
+       sysv_style=solaris
 
-       AC_MSG_RESULT([enabling Solaris kernel module build])
-       solaris_module=yes
+       solaris_module=no
+       AC_MSG_CHECKING([if we can build Solaris kernel module])
+       if test -x /usr/ccs/bin/ld; then
+               solaris_module=yes
+       fi
+       AC_MSG_RESULT([$solaris_module])
+
+       COMPILE_64BIT_KMODULE=no
+       KCFLAGS=""
+       KLDFLAGS=""
+       COMPILE_KERNEL_GCC=no
+
+       if test "$solaris_module" = "yes"; then
+          dnl Solaris kernel module stuff
+           AC_MSG_CHECKING([if we have to build a 64bit kernel module])
+
+          # check for isainfo, if not found it has to be a 32 bit kernel (<=2.6)       
+          if test -x /usr/bin/isainfo; then
+               # check for 64 bit platform
+               if isainfo -kv | grep '^64-bit'; then
+                       COMPILE_64BIT_KMODULE=yes
+               fi
+          fi
+
+          AC_MSG_RESULT([$COMPILE_64BIT_KMODULE])
+
+          if test "${GCC}" = yes; then
+               COMPILE_KERNEL_GCC=yes
+               if test "$COMPILE_64BIT_KMODULE" = yes; then
+               
+                        AC_MSG_CHECKING([if we can build a 64bit kernel module])
+                       
+                        case `$CC --version 2>/dev/null` in
+                       [[12]].* | 3.0.*)
+                               COMPILE_64BIT_KMODULE=no
+                               COMPILE_KERNEL_GCC=no   
+                               solaris_module=no;;
+                       *)
+                               # use for 64 bit
+                               KCFLAGS="-m64"
+                               #KLDFLAGS="-melf64_sparc"
+                               KLDFLAGS="-64";;
+                       esac    
+                       
+                       AC_MSG_RESULT([$COMPILE_64BIT_KMODULE])
+                       
+               else
+                       KCFLAGS=""
+                       KLDFLAGS=""
+               fi
+               KCFLAGS="$KCFLAGS -D_KERNEL -Wall -Wstrict-prototypes"
+           else
+               if test "$COMPILE_64BIT_KMODULE" = yes; then
+                # use Sun CC (for a 64-bit kernel, uncomment " -xarch=v9 -xregs=no%appl ")
+                       KCFLAGS="-xarch=v9 -xregs=no%appl"
+                       KLDFLAGS="-64"
+               else
+                       KCFLAGS=""
+                       KLDFLAGS=""
+               fi
+               KCFLAGS="-D_KERNEL $KCFLAGS -mno-app-regs -munaligned-doubles -fpcc-struct-return"
+          fi
+
+           AC_CACHE_CHECK([for timeout_id_t],netatalk_cv_HAVE_TIMEOUT_ID_T,[
+           AC_TRY_LINK([\
+#include <sys/stream.h>
+#include <sys/ddi.h>],
+[\
+timeout_id_t dummy;
+],
+netatalk_cv_HAVE_TIMEOUT_ID_T=yes,netatalk_cv_HAVE_TIMEOUT_ID_T=no,netatalk_cv_HAVE_TIMEOUT_ID_T=cross)])
+
+          AC_DEFINE(HAVE_TIMEOUT_ID_T, test x"$netatalk_cv_HAVE_TIMEOUT_ID" = x"yes", [define for timeout_id_t])
+       fi
+
+       AC_SUBST(COMPILE_KERNEL_GCC)
+       AC_SUBST(COMPILE_64BIT_KMODULE)
+       AC_SUBST(KCFLAGS)
+       AC_SUBST(KLDFLAGS)
 fi
 
 dnl ----- Tru64 specific -----
@@ -545,27 +906,83 @@ if test x"$this_os" = "xtru64"; then
        AC_DEFINE(HAVE_64BIT_LONGS, 1, [Define if the data type long has 64 bit])
        dnl AC_DEFINE(USE_MOUNT_H)
        AC_DEFINE(USE_OLD_RQUOTA, 1, [Define to use old rquota])
+       dnl AC_DEFINE(USE_UFS_QUOTA_H)
        AC_DEFINE(TRU64, 1, [Define on Tru64 platforms])
+       AC_DEFINE(_OSF_SOURCE, 1, [Define if the *passwd UAMs should be used])
+       AC_DEFINE(_XOPEN_SOURCE_EXTENDED, 1, [Define for Berkeley DB 4])
        AC_CHECK_LIB(security,set_auth_parameters)
        CFLAGS="-I\$(top_srcdir)/sys/tru64 $CFLAGS"
        need_dash_r=no
        sysv_style=tru64
 fi
 
-dnl -- look for OpenSSL and other crypt libraries
-AC_PATH_GCRYPT
+dnl -- look for openssl
 AC_PATH_SSL
 
+dnl -- check for crypt
+AC_CRYPT
+
+dnl --------------------- check for building PGP UAM module
+
+AC_MSG_CHECKING([whether the PGP UAM should be build])
+AC_ARG_ENABLE(pgp-uam,
+       [  --enable-pgp-uam        enable build of PGP UAM module],[
+       if test "$enableval" = "yes"; then 
+               if test "$compile_ssl" = "yes"; then 
+                       AC_DEFINE(UAM_PGP, 1, [Define if the PGP UAM module should be compiled])
+                       compile_pgp=yes
+                       AC_MSG_RESULT([yes])
+               else
+                       AC_MSG_RESULT([no])
+               fi
+       fi
+       ],[
+               AC_MSG_RESULT([no])
+       ]
+)
+
 dnl --------------------- check for building Kerberos v4 UAM module
 
+AC_MSG_CHECKING([whether the Kerberos IV UAM should be build])
 AC_ARG_ENABLE(krb4-uam,
-       [  --enable-krb4-uam       enable build of Kerberos v4 UAM module],
+       [  --enable-krb4-uam       enable build of Kerberos v4 UAM module],[
        if test "$enableval" = "yes"; then
                AC_DEFINE(UAM_KRB4, 1, [Define if the Kerberos 4 UAM module should be compiled])
                compile_kerberos=yes
-               AC_MSG_RESULT([enabling build with Kerberos v4 UAM module])
+               AC_MSG_RESULT([yes])
+       else
+               AC_MSG_RESULT([no])
        fi
+       ],[
+               AC_MSG_RESULT([no])
+       ]
+)
+
+dnl --------------------- check for building Kerberos V UAM module
+
+netatalk_cv_build_krb5_uam=no
+AC_ARG_ENABLE(krbV-uam,
+       [  --enable-krbV-uam       enable build of Kerberos V UAM module],
+       [
+               if test x"$enableval" = x"yes"; then
+                       NETATALK_GSSAPI_CHECK([
+                               netatalk_cv_build_krb5_uam=yes
+                       ],[
+                               AC_MSG_ERROR([need GSSAPI to build Kerberos V UAM])
+                       ])
+               fi
+       ]
+       
 )
+
+AC_MSG_CHECKING([whether Kerberos V UAM should be build])
+if test x"$netatalk_cv_build_krb5_uam" = x"yes"; then
+       AC_MSG_RESULT([yes])
+else
+       AC_MSG_RESULT([no])
+fi
+AM_CONDITIONAL(USE_GSSAPI, test x"$netatalk_cv_build_krb5_uam" = x"yes")
+
 dnl --------------------- overwrite the config files . . . or not.
 
 AC_MSG_CHECKING([whether configuration files should be overwritten])
@@ -583,18 +1000,24 @@ AC_SUBST(CFLAGS)
 AC_SUBST(OVERWRITE_CONFIG)
 
 AM_CONDITIONAL(SOLARIS_MODULE, test x$solaris_module = xyes)
+AM_CONDITIONAL(COMPILE_TIMELORD, test x$compile_timelord = xyes)
 AM_CONDITIONAL(COMPILE_A2BOOT, test x$compile_a2boot = xyes)
 AM_CONDITIONAL(USE_DHX, test x$compile_ssl = xyes)
 AM_CONDITIONAL(USE_KERBEROS, test x$compile_kerberos = xyes)
 AM_CONDITIONAL(USE_PAM_SO, test x$use_pam_so = xyes)
-AM_CONDITIONAL(USE_PAM, test x$compile_pam = xyes)
+AM_CONDITIONAL(USE_PAM, test x$netatalk_cv_install_pam = xyes)
 AM_CONDITIONAL(BUILD_PAM, test x$compile_pam = xyes)
+AM_CONDITIONAL(USE_PGP, test x$compile_pgp = xyes)
 AM_CONDITIONAL(USE_COBALT, test x$sysv_style = xcobalt)
 AM_CONDITIONAL(USE_NETBSD, test x$sysv_style = xnetbsd)
 AM_CONDITIONAL(USE_REDHAT, test x$sysv_style = xredhat)
 AM_CONDITIONAL(USE_SUSE, test x$sysv_style = xsuse)
 AM_CONDITIONAL(USE_SHADOWPW, test x$shadowpw = xyes)
 AM_CONDITIONAL(USE_TRU64, test x$sysv_style = xtru64)
+AM_CONDITIONAL(USE_SOLARIS, test x$sysv_style = xsolaris)
+AM_CONDITIONAL(USE_GENTOO, test x$sysv_style = xgentoo)
+AM_CONDITIONAL(USE_DEBIAN, test x$sysv_style = xdebian)
+AM_CONDITIONAL(USE_UNDEF, test x$sysv_style = x)
 
 dnl --------------------- generate files
 
@@ -606,11 +1029,13 @@ AC_OUTPUT([Makefile
        bin/afppasswd/Makefile
        bin/cnid/Makefile
        bin/cnid/cnid_maint
+       bin/cnid/cnid2_create
        bin/getzones/Makefile
        bin/megatron/Makefile
        bin/nbp/Makefile
        bin/pap/Makefile
        bin/psorder/Makefile
+       bin/uniconv/Makefile
        config/Makefile
        contrib/Makefile
        contrib/macusers/Makefile
@@ -623,9 +1048,8 @@ AC_OUTPUT([Makefile
        contrib/shell_utils/apple_cp
        contrib/shell_utils/apple_mv
        contrib/shell_utils/apple_rm
+       contrib/shell_utils/asip-status.pl
        contrib/shell_utils/cleanappledouble.pl
-       contrib/shell_utils/lp2pap.sh
-       contrib/shell_utils/netatalkshorternamelinks.pl
        contrib/timelord/Makefile
        contrib/a2boot/Makefile
        distrib/Makefile
@@ -636,13 +1060,12 @@ AC_OUTPUT([Makefile
        doc/Makefile
        etc/Makefile
        etc/afpd/Makefile
-       etc/afpd/nls/Makefile
        etc/atalkd/Makefile
+       etc/cnid_dbd/Makefile
        etc/uams/Makefile
        etc/uams/uams_krb4/Makefile
        etc/papd/Makefile
        etc/psf/Makefile
-       etc/psf/etc2ps.sh
        include/Makefile
        include/atalk/Makefile
        libatalk/Makefile
@@ -650,11 +1073,21 @@ AC_OUTPUT([Makefile
        libatalk/asp/Makefile
        libatalk/atp/Makefile
        libatalk/cnid/Makefile
+       libatalk/cnid/db3/Makefile
+       libatalk/cnid/cdb/Makefile
+       libatalk/cnid/last/Makefile
+       libatalk/cnid/mtab/Makefile
+       libatalk/cnid/dbd/Makefile
+       libatalk/cnid/hash/Makefile
+       libatalk/cnid/tdb/Makefile
        libatalk/compat/Makefile
        libatalk/dsi/Makefile
        libatalk/nbp/Makefile
        libatalk/netddp/Makefile
        libatalk/util/Makefile
+       libatalk/tdb/Makefile
+       libatalk/unicode/Makefile
+       libatalk/unicode/charsets/Makefile
        macros/Makefile
        man/Makefile
        man/man1/Makefile
@@ -669,10 +1102,12 @@ AC_OUTPUT([Makefile
        sys/netbsd/Makefile
        sys/netbsd/netatalk/Makefile
        sys/solaris/Makefile
-       sys/solaris/Makefile.kernel
        sys/sunos/Makefile
        sys/ultrix/Makefile
        ],
        [chmod a+x distrib/config/netatalk-config contrib/shell_utils/apple_*]
 )
 
+AC_NETATALK_LIBS_SUMMARY
+AC_NETATALK_CONFIG_SUMMARY
+
index fa7b4912ac8d155a47ff58eda3294c2257ad48d6..633257c3df66f778a1cfc7ea6a554ace9a27ab45 100644 (file)
@@ -1,6 +1,17 @@
 # Makefile.am for contrib/
-# $Id: Makefile.am,v 1.9 2003-06-08 15:57:40 srittau Exp $
 
-SUBDIRS = macusers nu printing shell_utils timelord a2boot
+if COMPILE_TIMELORD
+TIMELORD = timelord
+else
+TIMELORD =
+endif
+
+if COMPILE_A2BOOT
+A2BOOT = a2boot
+else
+A2BOOT =
+endif
+
+SUBDIRS = macusers nu printing shell_utils ${TIMELORD} ${A2BOOT}
 
 EXTRA_DIST = ICDumpSuffixMap
index d8c1cd2cbd5053bd18a15ead7455cffec3db8c17..02d583cad26de3182267fb9bc6819d4389d0fe50 100644 (file)
@@ -1,18 +1,16 @@
 # Makefile.am for contrib/a2boot/
 
-if COMPILE_A2BOOT
 sbin_PROGRAMS = a2boot
-EXTRA_DIST = COPYRIGHT VERSION
-else
-sbin_PROGRAMS =
-EXTRA_DIST =
-endif
 
 a2boot_SOURCES = a2boot.c
 a2boot_LDADD = $(top_builddir)/libatalk/libatalk.la
 
-INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/sys \
-        @SLP_CFLAGS@ \
+LIBS = @LIBS@
+
+EXTRA_DIST = COPYRIGHT VERSION
+
+CFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/sys \
+        @CFLAGS@ @SLP_CFLAGS@ \
         -D_PATH_A_GS_BLOCKS=\"$(PKGCONFDIR)/a2boot/ProDOS16\ Boot\ Blocks\" \
         -D_PATH_A_2E_BLOCKS=\"$(PKGCONFDIR)/a2boot/Apple\ :2f:2fe\ Boot\ Blocks\" \
         -D_PATH_P16_IMAGE=\"$(PKGCONFDIR)/a2boot/ProDOS16\ Image\"
diff --git a/contrib/patches/README b/contrib/patches/README
new file mode 100644 (file)
index 0000000..731933b
--- /dev/null
@@ -0,0 +1,2 @@
+This directory contains patches that are under consideration or being
+tested.
diff --git a/contrib/patches/patch.afp_vfs b/contrib/patches/patch.afp_vfs
new file mode 100644 (file)
index 0000000..f2c08ee
--- /dev/null
@@ -0,0 +1,1678 @@
+First try for a netatalk vfs layer
+
+current schemes
+adouble=v1,v2 classic adouble format
+adouble=osx  ._<filename> OSX resource fork.
+adouble=ads  NT like alternate data stream. 
+
+Note for ads:
+* cf. patch.vfs for samba ADS vfs layer and patch.samba.xx for samba tree patch.
+
+* It's using Afp_AfpInfo name (MS SFM name) but it's not yet compatible with SFM.
+  from cdrecord source code Afp_AfpInfo is the raw HFS data, we are storing an appledouble file.
+
+* Server side copy and Macintosh copy only deal with resource fork, other NT ADS are lost.
+  unfixable for Macintosh copy but doable for server side.
+
+* It's ok for rename, delete, chown and chmod.
+
+* Copy from a NT box should work.
+
+* Last but not least : only on a new volume!
+
+TODO
+indirection for metadata, aka stored in EA, a different file, whatever.
+
+diff -Nur -X .cvsignore -x CVS ../src.dev2/etc/afpd/Makefile.am ./etc/afpd/Makefile.am
+--- ../src.dev2/etc/afpd/Makefile.am   Mon Feb  9 22:45:51 2004
++++ ./etc/afpd/Makefile.am     Fri Jun 18 19:15:47 2004
+@@ -8,14 +8,14 @@
+        file.c enumerate.c desktop.c filedir.c fork.c appl.c gettok.c \
+        mangle.c status.c afp_options.c afp_asp.c afp_dsi.c messages.c  \
+        afp_config.c nfsquota.c quota.c uam.c afs.c uid.c afp_util.c \
+-         catsearch.c afprun.c
++         catsearch.c afprun.c vfs_adouble.c
+ afpd_LDADD =  $(top_builddir)/libatalk/cnid/libcnid.la $(top_builddir)/libatalk/libatalk.la
+ afpd_LDFLAGS = -export-dynamic
+ noinst_HEADERS = auth.h afp_config.h desktop.h directory.h file.h \
+        filedir.h fork.h globals.h icon.h mangle.h misc.h status.h switch.h \
+-       uam_auth.h uid.h unix.h volume.h
++       uam_auth.h uid.h unix.h volume.h afp_vfs.h
+ LIBS = @LIBS@ @PAM_LIBS@ @QUOTA_LIBS@ @SLP_LIBS@
+diff -Nur -X .cvsignore -x CVS ../src.dev2/etc/afpd/afp_vfs.h ./etc/afpd/afp_vfs.h
+--- ../src.dev2/etc/afpd/afp_vfs.h     Thu Jan  1 00:00:00 1970
++++ ./etc/afpd/afp_vfs.h       Wed Jun 23 03:56:15 2004
+@@ -0,0 +1,49 @@
++/*
++   Copyright (c) 2004 Didier Gautheron
++ 
++   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.
++
++   vfs layer for afp
++*/
++
++#ifndef _AFP_VFS_H
++#define _AFP_VFS_H
++
++#include <atalk/adouble.h>
++struct vol;
++
++struct vfs_ops {
++    /* low level adouble fn */
++    char *(*ad_path)(const char *, int);
++
++    /* */
++    int (*validupath)(const struct vol *, const char *);
++    int (*rf_chown)(const struct vol *, const char *path, uid_t owner, gid_t group);
++    int (*rf_renamedir)(const struct vol *, const char *oldpath, const char *newpath);
++    int (*rf_deletecurdir)(const struct vol *);
++    int (*rf_setfilmode)(const struct vol *, const char * name, mode_t mode, struct stat *st);
++    int (*rf_setdirmode)(const struct vol *, const char * name, mode_t mode, struct stat *st);
++    int (*rf_setdirunixmode)(const struct vol *, const char * name, mode_t mode, struct stat *st);
++
++    int (*rf_setdirowner)(const struct vol *, const char *path, uid_t owner, gid_t group);
++
++    int (*rf_deletefile)(const struct vol *, const char * );
++    int (*rf_renamefile)(const struct vol *, const char *oldpath, const char *newpath);
++
++};
++
++void initvol_vfs(struct vol *vol);
++
++#endif
+diff -Nur -X .cvsignore -x CVS ../src.dev2/etc/afpd/directory.c ./etc/afpd/directory.c
+--- ../src.dev2/etc/afpd/directory.c   Mon Jul 12 08:46:03 2004
++++ ./etc/afpd/directory.c     Sat Jun 19 14:07:14 2004
+@@ -610,7 +610,7 @@
+    system rmdir with afp error code.
+    ENOENT is not an error.
+  */
+-static int netatalk_rmdir(const char *name)
++int netatalk_rmdir(const char *name)
+ {
+     if (rmdir(name) < 0) {
+         switch ( errno ) {
+@@ -2075,15 +2075,11 @@
+         }
+     }
+-    if (vol->v_adouble == AD_VERSION2_OSX) {
+-        /* We simply move the corresponding ad file as well */
+-        char   tempbuf[258]="._";
+-        rename(vol->ad_path(src,0),strcat(tempbuf,dst));
+-    }
++    vol->vfs->rf_renamedir(vol, src, dst);
+     len = strlen( newname );
+     /* rename() succeeded so we need to update our tree even if we can't open
+-     * .Parent
++     * metadata
+     */
+     
+     ad_init(&ad, vol->v_adouble);
+@@ -2132,12 +2128,9 @@
+     return( AFP_OK );
+ }
+-#define DOT_APPLEDOUBLE_LEN 13
+ /* delete an empty directory */
+-int deletecurdir( vol, path, pathlen )
++int deletecurdir( vol)
+ const struct vol      *vol;
+-char *path;
+-int pathlen;
+ {
+     struct dirent *de;
+     struct stat st;
+@@ -2162,42 +2155,9 @@
+             return  AFPERR_OLOCK;
+         }
+     }
+-
+-    if (vol->v_adouble == AD_VERSION2_OSX) {
+-       
+-        if ((err = netatalk_unlink(vol->ad_path(".",0) )) ) {
+-            return err;
+-        }
+-    }
+-    else {
+-        /* delete stray .AppleDouble files. this happens to get .Parent files
+-           as well. */
+-        if ((dp = opendir(".AppleDouble"))) {
+-            strcpy(path, ".AppleDouble/");
+-            while ((de = readdir(dp))) {
+-                /* skip this and previous directory */
+-                if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
+-                    continue;
+-
+-                /* bail if the file exists in the current directory.
+-                 * note: this will not fail with dangling symlinks */
+-                if (stat(de->d_name, &st) == 0) {
+-                    closedir(dp);
+-                    return AFPERR_DIRNEMPT;
+-                }
+-
+-                strcpy(path + DOT_APPLEDOUBLE_LEN, de->d_name);
+-                if ((err = netatalk_unlink(path))) {
+-                    closedir(dp);
+-                    return err;
+-                }
+-            }
+-            closedir(dp);
+-        }
+-
+-        if ( (err = netatalk_rmdir( ".AppleDouble" ))  ) {
+-            return err;
+-        }
++    err = vol->vfs->rf_deletecurdir(vol);
++    if (err) {
++        return err;
+     }
+     /* now get rid of dangling symlinks */
+diff -Nur -X .cvsignore -x CVS ../src.dev2/etc/afpd/directory.h ./etc/afpd/directory.h
+--- ../src.dev2/etc/afpd/directory.h   Mon May 10 18:40:32 2004
++++ ./etc/afpd/directory.h     Sat Jun 19 03:23:18 2004
+@@ -196,7 +196,7 @@
+ extern struct dir       *dirinsert __P((struct vol *, struct dir *));
+ extern int              movecwd __P((const struct vol *, struct dir *));
+-extern int              deletecurdir __P((const struct vol *, char *, int));
++extern int              deletecurdir __P((const struct vol *));
+ extern struct path      *cname __P((const struct vol *, struct dir *,
+                              char **));
+ extern mode_t           mtoumode __P((struct maccess *));
+@@ -215,6 +215,7 @@
+ extern int  check_access __P((char *name , int mode));
+ extern int file_access   __P((struct path *path, int mode));
++extern int netatalk_rmdir __P((const char *name));
+ extern int netatalk_unlink __P((const char *name));
+ /* from enumerate.c */
+diff -Nur -X .cvsignore -x CVS ../src.dev2/etc/afpd/enumerate.c ./etc/afpd/enumerate.c
+--- ../src.dev2/etc/afpd/enumerate.c   Mon Jul 12 08:46:03 2004
++++ ./etc/afpd/enumerate.c     Thu Jun 24 04:26:35 2004
+@@ -166,7 +166,7 @@
+     if (!strcmp(name, "..") || !strcmp(name, "."))
+         return NULL;
+-    if (!vol->validupath(vol, name))
++    if (!vol->vfs->validupath(vol, name))
+         return NULL;
+     /* check for vetoed filenames */
+diff -Nur -X .cvsignore -x CVS ../src.dev2/etc/afpd/file.c ./etc/afpd/file.c
+--- ../src.dev2/etc/afpd/file.c        Tue Jun 15 22:53:54 2004
++++ ./etc/afpd/file.c  Mon Jun 21 00:21:24 2004
+@@ -901,7 +901,7 @@
+     /* second try with adouble open 
+     */
+-    if (ad_open( upath, vol_noadouble(vol) | ADFLAGS_HF,
++    if ( ad_open( upath, vol_noadouble(vol) | ADFLAGS_HF,
+                  O_RDWR|O_CREAT, 0666, adp) < 0) {
+         /* for some things, we don't need an adouble header */
+         if (f_bitmap & ~(1<<FILPBIT_MDATE)) {
+@@ -1020,7 +1020,6 @@
+ char  *src, *dst, *newname;
+ struct adouble    *adp;
+ {
+-    char      adsrc[ MAXPATHLEN + 1];
+     int               rc;
+ #ifdef DEBUG
+@@ -1055,38 +1054,10 @@
+         }
+     }
+-    strcpy( adsrc, vol->ad_path( src, 0 ));
+-
+-    if (unix_rename( adsrc, vol->ad_path( dst, 0 )) < 0 ) {
+-        struct stat st;
++    if (vol->vfs->rf_renamefile(vol, src, dst) < 0 ) {
+         int err;
+         
+         err = errno;        
+-      if (errno == ENOENT) {
+-          struct adouble    ad;
+-
+-            if (stat(adsrc, &st)) /* source has no ressource fork, */
+-                return AFP_OK;
+-            
+-            /* We are here  because :
+-             * -there's no dest folder. 
+-             * -there's no .AppleDouble in the dest folder.
+-             * if we use the struct adouble passed in parameter it will not
+-             * 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.
+-             */
+-            ad_init(&ad, vol->v_adouble); 
+-            if (!ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, &ad)) {
+-              ad_close(&ad, ADFLAGS_HF);
+-              if (!unix_rename( adsrc, vol->ad_path( dst, 0 )) ) 
+-                   err = 0;
+-                else 
+-                   err = errno;
+-            }
+-            else { /* it's something else, bail out */
+-              err = errno;
+-          }
+-      }
+       /* try to undo the data fork rename,
+        * we know we are on the same device 
+       */
+@@ -1436,6 +1407,7 @@
+     if (ret_err) {
+         deletefile(d_vol, dst, 0);
+     }
++    /* ADS here */
+     /* set dest modification date to src date */
+     if (!stat(src, &st)) {
+@@ -1562,14 +1534,12 @@
+     if (adp && ad_tmplock( &ad, ADEID_DFORK, ADLOCK_WR, 0, 0, 0 ) < 0) {
+         err = AFPERR_BUSY;
+     }
+-    else if (!(err = netatalk_unlink( vol->ad_path( file, ADFLAGS_HF)) ) &&
+-             !(err = netatalk_unlink( file )) ) {
++    else if (!(err = vol->vfs->rf_deletefile(vol, file)) && !(err = netatalk_unlink( file )) ) {
+         cnid_t id;
+         if (checkAttrib && (id = cnid_get(vol->v_cdb, curdir->d_did, file, strlen(file)))) 
+         {
+             cnid_delete(vol->v_cdb, id);
+         }
+-
+     }
+     if (adp)
+         ad_close( &ad, adflags );  /* ad_close removes locks if any */
+diff -Nur -X .cvsignore -x CVS ../src.dev2/etc/afpd/filedir.c ./etc/afpd/filedir.c
+--- ../src.dev2/etc/afpd/filedir.c     Mon May 10 18:40:32 2004
++++ ./etc/afpd/filedir.c       Sat Jun 19 15:09:08 2004
+@@ -73,7 +73,7 @@
+         return AFPERR_NOOBJ ;
+     }
+-    adpath = vol->ad_path( upath, ADFLAGS_HF );
++    adpath = vol->vfs->ad_path( upath, ADFLAGS_HF );
+     /* FIXME dirsearch doesn't move cwd to did ! */
+     if (( dir = dirlookup( vol, did )) == NULL ) {
+         LOG(log_error, logtype_afpd, "matchfile2dirperms: Unable to get directory info.");
+@@ -313,7 +313,7 @@
+     if ((vol->v_flags & AFPVOL_NOHEX) && strchr(name, '/'))
+         return AFPERR_PARAM;
+-    if (!vol->validupath(vol, name))
++    if (!vol->vfs->validupath(vol, name))
+         return AFPERR_EXIST;
+     /* check for vetoed filenames */
+@@ -582,7 +582,7 @@
+           rc = AFPERR_ACCESS;
+       }
+       else {
+-            rc = deletecurdir( vol, obj->oldtmp, AFPOBJ_TMPSIZ);
++            rc = deletecurdir( vol);
+         }
+     } else if (of_findname(s_path)) {
+         rc = AFPERR_BUSY;
+@@ -764,7 +764,7 @@
+                 int  admode = ad_mode("", 0777);
+                 setfilmode(upath, admode, NULL);
+-                setfilmode(vol->ad_path( upath, ADFLAGS_HF ), ad_hf_mode(admode), NULL);
++                vol->vfs->rf_setfilmode(vol, upath, admode, NULL);
+             }
+         setvoltime(obj, vol );
+     }
+diff -Nur -X .cvsignore -x CVS ../src.dev2/etc/afpd/unix.c ./etc/afpd/unix.c
+--- ../src.dev2/etc/afpd/unix.c        Tue Jun 15 22:53:55 2004
++++ ./etc/afpd/unix.c  Wed Jun 23 04:04:01 2004
+@@ -260,8 +260,8 @@
+    rwx-wx-wx or rwx-wx-- 
+    rwx----wx (is not asked by a Mac with OS >= 8.0 ?)
+ */
+-static int stickydirmode(name, mode, dropbox)
+-char * name;
++int stickydirmode(name, mode, dropbox)
++const char * name;
+ const mode_t mode;
+ const int dropbox;
+ {
+@@ -405,12 +405,12 @@
+     if (setfilmode( path->u_name, mode, &path->st) < 0)
+         return -1;
+     /* we need to set write perm if read set for resource fork */
+-    return setfilmode(vol->ad_path( path->u_name, ADFLAGS_HF ), ad_hf_mode(mode), &path->st);
++    return vol->vfs->rf_setfilmode(vol, path->u_name, mode, &path->st);
+ }
+ /* --------------------- */
+ int setfilmode(name, mode, st)
+-char * name;
++const char * name;
+ mode_t mode;
+ struct stat *st;
+ {
+@@ -436,29 +436,18 @@
+ const char       *name;
+ const mode_t     mode;
+ {
+-char *adouble = vol->ad_path( name, ADFLAGS_DIR );
+     int dropbox = (vol->v_flags & AFPVOL_DROPBOX);
+     if (dir_rx_set(mode)) {
+-      /* extending right? dir first then .AppleDouble */
++      /* extending right? dir first then .AppleDouble in rf_setdirmode */
+       if ( stickydirmode(name, DIRBITS | mode, dropbox) < 0 )
+               return -1;
+-      if (vol->v_adouble != AD_VERSION2_OSX) {
+-            if (stickydirmode(ad_dir(adouble), DIRBITS | mode, dropbox) < 0 && !vol_noadouble(vol)) {
+-                return  -1 ;
+-            }
+-        }
+     }
+-    if (setfilmode(adouble, ad_hf_mode(mode), NULL) < 0 && !vol_noadouble(vol)) {
++    if (vol->vfs->rf_setdirunixmode(vol, name, mode, NULL) < 0 && !vol_noadouble(vol)) {
+         return  -1 ;
+     }
+     if (!dir_rx_set(mode)) {
+-      if (vol->v_adouble != AD_VERSION2_OSX) {
+-            if (stickydirmode(ad_dir(adouble), DIRBITS | mode, dropbox) < 0 && !vol_noadouble(vol)) {
+-                return  -1 ;
+-            }
+-        }
+       if ( stickydirmode(name, DIRBITS | mode, dropbox) < 0 )
+             return -1;
+     }
+@@ -471,26 +460,17 @@
+ const char       *name;
+ const mode_t mode;
+ {
+-    char              buf[ MAXPATHLEN + 1];
+     struct stat               st;
+-    char              *m;
+     struct dirent     *dirp;
+     DIR                       *dir;
+     int                 osx = vol->v_adouble == AD_VERSION2_OSX;
+     int                 hf_mode = ad_hf_mode(mode);
+     int                 dropbox = (vol->v_flags & AFPVOL_DROPBOX);
+-    char                *adouble = vol->ad_path( name, ADFLAGS_DIR );
+-    char                *adouble_p = ad_dir(adouble);
+     
+     if (dir_rx_set(mode)) {
+-      /* extending right? dir first then .AppleDouble */
++      /* extending right? dir first */
+       if ( stickydirmode(name, DIRBITS | mode, dropbox) < 0 )
+               return -1;
+-      if (!osx) {
+-            if (stickydirmode(adouble_p, DIRBITS | mode, dropbox) < 0 && !vol_noadouble(vol)) {
+-                return  -1 ;
+-            }
+-        }
+     }
+     
+     if (( dir = opendir( name )) == NULL ) {
+@@ -516,61 +496,13 @@
+                 return -1;
+            }
+         }
+-#if 0
+-        /* Don't change subdir perm */
+-        else if (S_ISDIR(st.st_mode)) {
+-                if (stickydirmode(dirp->d_name, DIRBITS | mode, dropbox) < 0)
+-                    return (-1);
+-            } else if (stickydirmode(dirp->d_name, mode, dropbox) < 0)
+-                return (-1);
+-        }
+-#endif
+     }
+     closedir( dir );
+     
+-    if (osx) {
+-        goto setdirmode_noadouble;
+-    }
+-    
+-    /* change perm of .AppleDouble's files
+-    */
+-    if (( dir = opendir( adouble_p )) == NULL ) {
+-        if (vol_noadouble(vol))
+-            goto setdirmode_noadouble;
+-        LOG(log_error, logtype_afpd, "setdirmode: opendir %s: %s", fullpathname(".AppleDouble"),strerror(errno) );
+-        return( -1 );
+-    }
+-    strcpy( buf, adouble_p);
+-    strcat( buf, "/" );
+-    m = strchr( buf, '\0' );
+-    for ( dirp = readdir( dir ); dirp != NULL; dirp = readdir( dir )) {
+-        if ( strcmp( dirp->d_name, "." ) == 0 ||
+-                strcmp( dirp->d_name, ".." ) == 0 ) {
+-            continue;
+-        }
+-        *m = '\0';
+-        strcat( buf, dirp->d_name );
+-
+-        if ( stat( buf, &st ) < 0 ) {
+-            LOG(log_error, logtype_afpd, "setdirmode: stat %s: %s", buf, strerror(errno) );
+-            continue;
+-        }
+-        if (!S_ISDIR(st.st_mode)) {
+-           if (setfilmode(buf, hf_mode , &st) < 0) {
+-               /* FIXME what do we do then? */
+-           }
+-        }
+-    } /* end for */
+-    closedir( dir );
+-
+-    if (!dir_rx_set(mode)) {
+-        /* XXX: need to preserve special modes */
+-        if (stickydirmode(adouble_p, DIRBITS | mode, dropbox) < 0 ) {
+-                return  -1 ;
+-        }
++    if (vol->vfs->rf_setdirmode(vol, name, mode, NULL) < 0 && !vol_noadouble(vol)) {
++        return  -1 ;
+     }
+-setdirmode_noadouble:
+     if (!dir_rx_set(mode)) {
+       if ( stickydirmode(name, DIRBITS | mode, dropbox) < 0 )
+               return -1;
+@@ -578,6 +510,7 @@
+     return( 0 );
+ }
++/* ----------------------------- */
+ int setdeskowner( uid, gid )
+ const uid_t   uid;
+ const gid_t   gid;
+@@ -648,8 +581,6 @@
+ const gid_t   gid;
+ struct path* path;
+ {
+-    struct stat st;
+-    char  *ad_p;
+     if (!path->st_valid) {
+         of_stat(path);
+@@ -665,22 +596,15 @@
+       return -1;
+     }
+-    ad_p = vol->ad_path( path->u_name, ADFLAGS_HF );
+-
+-    if ( stat( ad_p, &st ) < 0 ) {
+-      /* ignore */
+-        return 0;
+-    }
+-    if ( chown( ad_p, uid, gid ) < 0 &&
+-            errno != EPERM ) {
+-        LOG(log_debug, logtype_afpd, "setfilowner: chown %d/%d %s: %s",
+-            uid, gid, ad_p, strerror(errno) );
++    if (vol->vfs->rf_chown(vol, path->u_name, uid, gid ) < 0 && errno != EPERM) {
++        LOG(log_debug, logtype_afpd, "setfilowner: rf_chown %d/%d %s: %s",
++            uid, gid, path->u_name, strerror(errno) );
+         return -1;
+     }
++
+     return 0;
+ }
+-
+ /* --------------------------------- 
+  * uid/gid == 0 need to be handled as special cases. they really mean
+  * that user/group should inherit from other, but that doesn't fit
+@@ -692,15 +616,10 @@
+ const uid_t   uid;
+ const gid_t   gid;
+ {
+-    char              buf[ MAXPATHLEN + 1];
+     struct stat               st;
+-    char              *m;
+     struct dirent     *dirp;
+     DIR                       *dir;
+     int                 osx = vol->v_adouble == AD_VERSION2_OSX;
+-    int                 noadouble = vol_noadouble(vol);
+-    char                *adouble; 
+-    char                *adouble_p;
+     if (( dir = opendir( name )) == NULL ) {
+         return( -1 );
+@@ -723,56 +642,15 @@
+         }
+     }
+     closedir( dir );
+-    
+-    if (osx) {
+-       goto setdirowner_noadouble;
+-    }
+-    adouble = vol->ad_path( name, ADFLAGS_DIR );
+-    adouble_p = ad_dir(adouble);
+-    if (( dir = opendir( adouble_p )) == NULL ) {
+-        if (noadouble)
+-            goto setdirowner_noadouble;
+-        return( -1 );
+-    }
+-    strcpy( buf, adouble_p );
+-    strcat( buf, "/" );
+-    m = strchr( buf, '\0' );
+-    for ( dirp = readdir( dir ); dirp != NULL; dirp = readdir( dir )) {
+-        if ( strcmp( dirp->d_name, "." ) == 0 ||
+-                strcmp( dirp->d_name, ".." ) == 0 ) {
+-            continue;
+-        }
+-        *m = '\0';
+-        strcat( buf, dirp->d_name );
+-        if ( chown( buf, uid, gid ) < 0 && errno != EPERM ) {
+-            LOG(log_debug, logtype_afpd, "setdirowner: chown %d/%d %s: %s",
+-                uid, gid, fullpathname(buf), strerror(errno) );
+-            /* return ( -1 ); Sometimes this is okay */
+-        }
+-    }
+-    closedir( dir );
+-
+-    /*
+-     * We cheat: we know that chown doesn't do anything.
+-     */
+-    if ( stat( ".AppleDouble", &st ) < 0 ) {
+-        LOG(log_error, logtype_afpd, "setdirowner: stat %s: %s", fullpathname(".AppleDouble"), strerror(errno) );
+-        return( -1 );
+-    }
+-    if ( gid && gid != st.st_gid && chown( ".AppleDouble", uid, gid ) < 0 &&
+-            errno != EPERM ) {
+-        LOG(log_debug, logtype_afpd, "setdirowner: chown %d/%d %s: %s",
+-            uid, gid,fullpathname(".AppleDouble"), strerror(errno) );
+-        /* return ( -1 ); Sometimes this is okay */
++    if (vol->vfs->rf_setdirowner(vol, name, uid, gid) < 0) {
++        return -1;
+     }
+-
+-setdirowner_noadouble:
++    
+     if ( stat( ".", &st ) < 0 ) {
+         return( -1 );
+     }
+-    if ( gid && gid != st.st_gid && chown( ".", uid, gid ) < 0 &&
+-            errno != EPERM ) {
++    if ( gid && gid != st.st_gid && chown( ".", uid, gid ) < 0 && errno != EPERM ) {
+         LOG(log_debug, logtype_afpd, "setdirowner: chown %d/%d %s: %s",
+             uid, gid, fullpathname("."), strerror(errno) );
+     }
+diff -Nur -X .cvsignore -x CVS ../src.dev2/etc/afpd/unix.h ./etc/afpd/unix.h
+--- ../src.dev2/etc/afpd/unix.h        Mon May 10 18:40:33 2004
++++ ./etc/afpd/unix.h  Wed Jun 23 03:43:28 2004
+@@ -221,11 +221,12 @@
+ extern int setdirmode       __P((const struct vol *, const char *, const mode_t));
+ extern int setdeskowner     __P((const uid_t, const gid_t));
+ extern int setdirowner      __P((const struct vol *, const char *, const uid_t, const gid_t));
+-extern int setfilmode       __P((char *, mode_t , struct stat *));
++extern int setfilmode       __P((const char *, mode_t , struct stat *));
+ extern int setfilunixmode   __P((const struct vol *, struct path*, const mode_t));
+ extern int setfilowner      __P((const struct vol *, const uid_t, const gid_t, struct path*));
+ extern int unix_rename      __P((const char *oldpath, const char *newpath));
+ extern int dir_rx_set       __P((mode_t mode));
++extern int stickydirmode    __P((const char * name, const mode_t mode, const int dropbox));
+ extern void accessmode      __P((char *, struct maccess *, struct dir *, struct stat *));
+ extern char *fullpathname   __P((const char *));
+diff -Nur -X .cvsignore -x CVS ../src.dev2/etc/afpd/vfs_adouble.c ./etc/afpd/vfs_adouble.c
+--- ../src.dev2/etc/afpd/vfs_adouble.c Thu Jan  1 00:00:00 1970
++++ ./etc/afpd/vfs_adouble.c   Wed Jun 30 19:31:49 2004
+@@ -0,0 +1,749 @@
++/*
++    Copyright (c) 2004 Didier Gautheron
++ 
++   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 /* HAVE_CONFIG_H */
++
++#ifdef STDC_HEADERS
++#include <string.h>
++#endif
++
++#include <stdio.h>
++    
++#include <atalk/adouble.h>
++#include <atalk/logger.h>
++#include <atalk/util.h>
++
++#include "directory.h"
++#include "volume.h"
++#include "unix.h"
++
++struct perm {
++    uid_t uid;
++    gid_t gid;
++};
++
++typedef int (*rf_loop)(struct dirent *, char *, void *, int );
++
++/* ----------------------------- */
++static int 
++for_each_adouble(const char *from, const char *name, rf_loop fn, void *data, int flag)
++{
++    char            buf[ MAXPATHLEN + 1];
++    char            *m;
++    DIR             *dp;
++    struct dirent   *de;
++    int             ret;
++    
++
++    if (NULL == ( dp = opendir( name)) ) {
++        if (!flag) {
++            LOG(log_error, logtype_afpd, "%s: opendir %s: %s", from, fullpathname(name),strerror(errno) );
++            return -1;
++        }
++        return 0;
++    }
++    strlcpy( buf, name, sizeof(buf));
++    strlcat( buf, "/", sizeof(buf) );
++    m = strchr( buf, '\0' );
++    ret = 0;
++    while ((de = readdir(dp))) {
++        if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) {
++                continue;
++        }
++        
++        strlcat(buf, de->d_name, sizeof(buf));
++        if (fn && (ret = fn(de, buf, data, flag))) {
++           closedir(dp);
++           return ret;
++        }
++        *m = 0;
++    }
++    closedir(dp);
++    return ret;
++}
++
++/* ------------------------------ */
++static int ads_chown_loop(struct dirent *de, char *name, void *data, int flag)
++{
++    struct perm   *owner  = data;
++    
++    if (chown( name , owner->uid, owner->gid ) < 0) {
++        return -1;
++    }
++    return 0;
++}
++
++static int RF_chown_ads(const struct vol *vol, const char *path, uid_t uid, gid_t gid)
++
++{
++    struct        stat st;
++    char          *ad_p;
++    struct perm   owner;
++    
++    owner.uid = uid;
++    owner.gid = gid;
++
++
++    ad_p = ad_dir(vol->vfs->ad_path(path, ADFLAGS_HF ));
++
++    if ( stat( ad_p, &st ) < 0 ) {
++      /* ignore */
++        return 0;
++    }
++    
++    if (chown( ad_p, uid, gid ) < 0) {
++      return -1;
++    }
++    return for_each_adouble("chown_ads", ad_p, ads_chown_loop, &owner, 1);
++}
++
++/* --------------------------------- */
++static int deletecurdir_ads1_loop(struct dirent *de, char *name, void *data, int flag)
++{
++    return netatalk_unlink(name);
++}
++
++static int ads_delete_rf(char *name) 
++{
++    int err;
++
++    if ((err = for_each_adouble("deletecurdir", name, deletecurdir_ads1_loop, NULL, 1))) 
++        return err;
++    return netatalk_rmdir(name);
++}
++
++static int deletecurdir_ads_loop(struct dirent *de, char *name, void *data, int flag)
++{
++    struct stat st;
++    
++    /* bail if the file exists in the current directory.
++     * note: this will not fail with dangling symlinks */
++    
++    if (stat(de->d_name, &st) == 0) {
++        return AFPERR_DIRNEMPT;
++    }
++    return ads_delete_rf(name);
++}
++
++static int RF_deletecurdir_ads(const struct vol *vol)
++{
++    int err;
++    
++    /* delete stray .AppleDouble files. this happens to get .Parent files as well. */
++    if ((err = for_each_adouble("deletecurdir", ".AppleDouble", deletecurdir_ads_loop, NULL, 1))) 
++        return err;
++    return netatalk_rmdir( ".AppleDouble" );
++}
++
++/* ------------------- */
++struct set_mode {
++    mode_t mode;
++    struct stat *st;
++};
++
++static int ads_setfilmode_loop(struct dirent *de, char *name, void *data, int flag)
++{
++    struct set_mode *param = data;
++
++    return setfilmode(name, param->mode, param->st);
++}
++
++static int ads_setfilmode(const char * name, mode_t mode, struct stat *st)
++{
++    mode_t dir_mode = mode;
++    mode_t file_mode = ad_hf_mode(mode);
++    struct set_mode param;
++
++    if ((dir_mode & (S_IRUSR | S_IWUSR )))
++        dir_mode |= S_IXUSR;
++    if ((dir_mode & (S_IRGRP | S_IWGRP )))
++        dir_mode |= S_IXGRP;
++    if ((dir_mode & (S_IROTH | S_IWOTH )))
++        dir_mode |= S_IXOTH;  
++    
++      /* change folder */
++      dir_mode |= DIRBITS;
++    if (dir_rx_set(dir_mode)) {
++        if (chmod( name,  dir_mode ) < 0)
++            return -1;
++    }
++    param.st = st;
++    param.mode = file_mode;
++    if (for_each_adouble("setfilmode_ads", name, ads_setfilmode_loop, &param, 0) < 0)
++        return -1;
++
++    if (!dir_rx_set(dir_mode)) {
++        if (chmod( name,  dir_mode ) < 0)
++            return -1;
++    }
++
++    return 0;
++}
++
++static int RF_setfilmode_ads(const struct vol *vol, const char * name, mode_t mode, struct stat *st)
++{
++    return ads_setfilmode(ad_dir(vol->vfs->ad_path( name, ADFLAGS_HF )), mode, st);
++}
++
++/* ------------------- */
++static int RF_setdirunixmode_ads(const struct vol *vol, const char * name, mode_t mode, struct stat *st)
++{
++    char *adouble = vol->vfs->ad_path( name, ADFLAGS_DIR );
++    char   ad_p[ MAXPATHLEN + 1];
++    int dropbox = (vol->v_flags & AFPVOL_DROPBOX);
++
++    strlcpy(ad_p,ad_dir(adouble), MAXPATHLEN + 1);
++
++    if (dir_rx_set(mode)) {
++
++        /* .AppleDouble */
++        if (stickydirmode(ad_dir(ad_p), DIRBITS | mode, dropbox) < 0 && !vol_noadouble(vol)) 
++            return -1;
++
++        /* .AppleDouble/.Parent */
++        if (stickydirmode(ad_p, DIRBITS | mode, dropbox) < 0 && !vol_noadouble(vol)) 
++            return -1;
++    }
++
++    if (ads_setfilmode(ad_dir(vol->vfs->ad_path( name, ADFLAGS_DIR)), mode, st) < 0)
++        return -1;
++
++    if (!dir_rx_set(mode)) {
++        if (stickydirmode(ad_p, DIRBITS | mode, dropbox) < 0 && !vol_noadouble(vol)) 
++            return  -1 ;
++        if (stickydirmode(ad_dir(ad_p), DIRBITS | mode, dropbox) < 0 && !vol_noadouble(vol)) 
++            return -1;
++    }
++    return 0;
++}
++
++/* ------------------- */
++struct dir_mode {
++    mode_t mode;
++    int    dropbox;
++};
++
++static int setdirmode_ads_loop(struct dirent *de, char *name, void *data, int flag)
++{
++
++    struct dir_mode *param = data;
++    int    ret = 0; /* 0 ignore error, -1 */
++
++    if (dir_rx_set(param->mode)) {
++        if (stickydirmode(name, DIRBITS | param->mode, param->dropbox) < 0) {
++            if (flag) {
++                return 0;
++            }
++            return ret;
++        }
++    }
++    if (ads_setfilmode(name, param->mode, NULL) < 0)
++        return ret;
++
++    if (!dir_rx_set(param->mode)) {
++        if (stickydirmode(name, DIRBITS | param->mode, param->dropbox) < 0) {
++            if (flag) {
++                return 0;
++            }
++            return ret;
++        }
++    }
++    return 0;
++}
++
++static int RF_setdirmode_ads(const struct vol *vol, const char * name, mode_t mode, struct stat *st)
++{
++    char *adouble = vol->vfs->ad_path( name, ADFLAGS_DIR );
++    char   ad_p[ MAXPATHLEN + 1];
++    struct dir_mode param;
++
++    param.mode = mode;
++    param.dropbox = (vol->v_flags & AFPVOL_DROPBOX);
++
++    strlcpy(ad_p,ad_dir(adouble), sizeof(ad_p));
++
++    if (dir_rx_set(mode)) {
++        /* .AppleDouble */
++        if (stickydirmode(ad_dir(ad_p), DIRBITS | mode, param.dropbox) < 0 && !vol_noadouble(vol)) 
++            return -1;
++    }
++
++    if (for_each_adouble("setdirmode_ads", ad_dir(ad_p), setdirmode_ads_loop, &param, vol_noadouble(vol)))
++        return -1;
++
++    if (!dir_rx_set(mode)) {
++        if (stickydirmode(ad_dir(ad_p), DIRBITS | mode, param.dropbox) < 0 && !vol_noadouble(vol)) 
++            return -1;
++    }
++    return 0;
++}
++
++/* ------------------- */
++static int setdirowner_ads1_loop(struct dirent *de, char *name, void *data, int flag)
++{
++    struct perm   *owner  = data;
++
++    if ( chown( name, owner->uid, owner->gid ) < 0 && errno != EPERM ) {
++         LOG(log_debug, logtype_afpd, "setdirowner: chown %d/%d %s: %s",
++                owner->uid, owner->gid, fullpathname(name), strerror(errno) );
++         /* return ( -1 ); Sometimes this is okay */
++    }
++    return 0;
++}
++
++static int setdirowner_ads_loop(struct dirent *de, char *name, void *data, int flag)
++{
++    struct perm   *owner  = data;
++
++    if (for_each_adouble("setdirowner", name, setdirowner_ads1_loop, data, flag) < 0)
++        return -1;
++
++    if ( chown( name, owner->uid, owner->gid ) < 0 && errno != EPERM ) {
++         LOG(log_debug, logtype_afpd, "setdirowner: chown %d/%d %s: %s",
++                owner->uid, owner->gid, fullpathname(name), strerror(errno) );
++         /* return ( -1 ); Sometimes this is okay */
++    }
++    return 0;
++}
++
++static int RF_setdirowner_ads(const struct vol *vol, const char *name, uid_t uid, gid_t gid)
++{
++    int           noadouble = vol_noadouble(vol);
++    char          adouble_p[ MAXPATHLEN + 1];
++    struct stat   st;
++    struct perm   owner;
++    
++    owner.uid = uid;
++    owner.gid = gid;
++
++    strlcpy(adouble_p, ad_dir(vol->vfs->ad_path( name, ADFLAGS_DIR )), sizeof(adouble_p));
++
++    if (for_each_adouble("setdirowner", ad_dir(adouble_p), setdirowner_ads_loop, &owner, noadouble)) 
++        return -1;
++
++    /*
++     * We cheat: we know that chown doesn't do anything.
++     */
++    if ( stat( ".AppleDouble", &st ) < 0) {
++        if (errno == ENOENT && noadouble)
++            return 0;
++        LOG(log_error, logtype_afpd, "setdirowner: stat %s: %s", fullpathname(".AppleDouble"), strerror(errno) );
++        return -1;
++    }
++    if ( gid && gid != st.st_gid && chown( ".AppleDouble", uid, gid ) < 0 && errno != EPERM ) {
++        LOG(log_debug, logtype_afpd, "setdirowner: chown %d/%d %s: %s",
++            uid, gid,fullpathname(".AppleDouble"), strerror(errno) );
++        /* return ( -1 ); Sometimes this is okay */
++    }
++    return 0;
++}
++
++/* ------------------- */
++static int RF_deletefile_ads(const struct vol *vol, const char *file )
++{
++    char *ad_p = ad_dir(vol->vfs->ad_path(file, ADFLAGS_HF ));
++
++    return ads_delete_rf(ad_p);
++}
++
++/* --------------------------- */
++int RF_renamefile_ads(const struct vol *vol, const char *src, const char *dst)
++{
++    char  adsrc[ MAXPATHLEN + 1];
++    int   err = 0;
++
++    strcpy( adsrc, ad_dir(vol->vfs->ad_path( src, 0 )));
++    if (unix_rename( adsrc, ad_dir(vol->vfs->ad_path( dst, 0 ))) < 0) {
++        struct stat st;
++
++        err = errno;
++        if (errno == ENOENT) {
++              struct adouble    ad;
++
++            if (stat(adsrc, &st)) /* source has no ressource fork, */
++                return AFP_OK;
++            
++            /* We are here  because :
++             * -there's no dest folder. 
++             * -there's no .AppleDouble in the dest folder.
++             * if we use the struct adouble passed in parameter it will not
++             * 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.
++             */
++            ad_init(&ad, vol->v_adouble); 
++            if (!ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, &ad)) {
++              ad_close(&ad, ADFLAGS_HF);
++
++              /* We must delete it */
++              RF_deletefile_ads(vol, dst );
++              if (!unix_rename( adsrc, ad_dir(vol->vfs->ad_path( dst, 0 ))) ) 
++                   err = 0;
++                else 
++                   err = errno;
++            }
++            else { /* it's something else, bail out */
++                  err = errno;
++              }
++          }
++      }
++      if (err) {
++              errno = err;
++              return -1;
++      }
++      return 0;
++}
++
++/* ===================================================
++ classic adouble format 
++*/
++
++static int validupath_adouble(const struct vol *vol, const char *name) 
++{
++    return (vol->v_flags & AFPVOL_USEDOTS) ? strncasecmp(name,".Apple", 6) && strcasecmp(name, ".Parent")
++                                           : name[0] != '.';
++}
++
++/* ----------------- */
++static int RF_chown_adouble(const struct vol *vol, const char *path, uid_t uid, gid_t gid)
++
++{
++    struct stat st;
++    char        *ad_p;
++
++    ad_p = vol->vfs->ad_path(path, ADFLAGS_HF );
++
++    if ( stat( ad_p, &st ) < 0 )
++        return 0; /* ignore */
++
++    return chown( ad_p, uid, gid );
++}
++
++/* ----------------- */
++int RF_renamedir_adouble(const struct vol *vol, const char *oldpath, const char *newpath)
++{
++    return 0;
++}
++
++/* ----------------- */
++static int deletecurdir_adouble_loop(struct dirent *de, char *name, void *data, int flag)
++{
++    struct stat st;
++    int         err;
++    
++    /* bail if the file exists in the current directory.
++     * note: this will not fail with dangling symlinks */
++    
++    if (stat(de->d_name, &st) == 0)
++        return AFPERR_DIRNEMPT;
++
++    if ((err = netatalk_unlink(name)))
++        return err;
++
++    return 0;
++}
++
++static int RF_deletecurdir_adouble(const struct vol *vol)
++{
++    int err;
++
++    /* delete stray .AppleDouble files. this happens to get .Parent files
++       as well. */
++    if ((err = for_each_adouble("deletecurdir", ".AppleDouble", deletecurdir_adouble_loop, NULL, 1))) 
++        return err;
++    return netatalk_rmdir( ".AppleDouble" );
++}
++
++/* ----------------- */
++static int adouble_setfilmode(const char * name, mode_t mode, struct stat *st)
++{
++    return setfilmode(name, ad_hf_mode(mode), st);
++}
++
++static int RF_setfilmode_adouble(const struct vol *vol, const char * name, mode_t mode, struct stat *st)
++{
++    return adouble_setfilmode(vol->vfs->ad_path( name, ADFLAGS_HF ), mode, st);
++}
++
++/* ----------------- */
++static int RF_setdirunixmode_adouble(const struct vol *vol, const char * name, mode_t mode, struct stat *st)
++{
++    char *adouble = vol->vfs->ad_path( name, ADFLAGS_DIR );
++    int  dropbox = (vol->v_flags & AFPVOL_DROPBOX);
++
++    if (dir_rx_set(mode)) {
++        if (stickydirmode(ad_dir(adouble), DIRBITS | mode, dropbox) < 0 && !vol_noadouble(vol)) 
++            return -1;
++    }
++
++    if (adouble_setfilmode(vol->vfs->ad_path( name, ADFLAGS_DIR ), mode, st) < 0) 
++        return -1;
++
++    if (!dir_rx_set(mode)) {
++        if (stickydirmode(ad_dir(adouble), DIRBITS | mode, dropbox) < 0 && !vol_noadouble(vol)) 
++            return  -1 ;
++    }
++    return 0;
++}
++
++/* ----------------- */
++static int setdirmode_adouble_loop(struct dirent *de, char *name, void *data, int flag)
++{
++    int         hf_mode = *(int *)data;
++    struct stat st;
++
++    if ( stat( name, &st ) < 0 ) {
++        if (flag)
++            return 0;
++        LOG(log_error, logtype_afpd, "setdirmode: stat %s: %s", name, strerror(errno) );
++    }
++    else if (!S_ISDIR(st.st_mode)) {
++        if (setfilmode(name, hf_mode , &st) < 0) {
++               /* FIXME what do we do then? */
++        }
++    }
++    return 0;
++}
++
++static int RF_setdirmode_adouble(const struct vol *vol, const char * name, mode_t mode, struct stat *st1)
++{
++    int   dropbox = (vol->v_flags & AFPVOL_DROPBOX);
++    int   hf_mode = ad_hf_mode(mode);
++    char  *adouble = vol->vfs->ad_path( name, ADFLAGS_DIR );
++    char  *adouble_p = ad_dir(adouble);
++
++    if (dir_rx_set(mode)) {
++        if (stickydirmode(ad_dir(adouble), DIRBITS | mode, dropbox) < 0 && !vol_noadouble(vol)) 
++            return -1;
++    }
++
++    if (for_each_adouble("setdirmode", adouble_p, setdirmode_adouble_loop, &hf_mode, vol_noadouble(vol)))
++        return -1;
++
++    if (!dir_rx_set(mode)) {
++        if (stickydirmode(ad_dir(adouble), DIRBITS | mode, dropbox) < 0 && !vol_noadouble(vol)) 
++            return  -1 ;
++    }
++    return 0;
++}
++
++/* ----------------- */
++static int setdirowner_adouble_loop(struct dirent *de, char *name, void *data, int flag)
++{
++    struct perm   *owner  = data;
++
++    if ( chown( name, owner->uid, owner->gid ) < 0 && errno != EPERM ) {
++         LOG(log_debug, logtype_afpd, "setdirowner: chown %d/%d %s: %s",
++                owner->uid, owner->gid, fullpathname(name), strerror(errno) );
++         /* return ( -1 ); Sometimes this is okay */
++    }
++    return 0;
++}
++
++static int RF_setdirowner_adouble(const struct vol *vol, const char *name, uid_t uid, gid_t gid)
++
++{
++    int           noadouble = vol_noadouble(vol);
++    char          *adouble_p;
++    struct stat   st;
++    struct perm   owner;
++    
++    owner.uid = uid;
++    owner.gid = gid;
++
++    adouble_p = ad_dir(vol->vfs->ad_path( name, ADFLAGS_DIR ));
++
++    if (for_each_adouble("setdirowner", adouble_p, setdirowner_adouble_loop, &owner, noadouble)) 
++        return -1;
++
++    /*
++     * We cheat: we know that chown doesn't do anything.
++     */
++    if ( stat( ".AppleDouble", &st ) < 0) {
++        if (errno == ENOENT && noadouble)
++            return 0;
++        LOG(log_error, logtype_afpd, "setdirowner: stat %s: %s", fullpathname(".AppleDouble"), strerror(errno) );
++        return -1;
++    }
++    if ( gid && gid != st.st_gid && chown( ".AppleDouble", uid, gid ) < 0 && errno != EPERM ) {
++        LOG(log_debug, logtype_afpd, "setdirowner: chown %d/%d %s: %s",
++            uid, gid,fullpathname(".AppleDouble"), strerror(errno) );
++        /* return ( -1 ); Sometimes this is okay */
++    }
++    return 0;
++}
++
++/* ----------------- */
++static int RF_deletefile_adouble(const struct vol *vol, const char *file )
++{
++      return netatalk_unlink(vol->vfs->ad_path( file, ADFLAGS_HF));
++}
++
++/* ----------------- */
++int RF_renamefile_adouble(const struct vol *vol, const char *src, const char *dst)
++{
++    char  adsrc[ MAXPATHLEN + 1];
++    int   err = 0;
++
++    strcpy( adsrc, vol->vfs->ad_path( src, 0 ));
++    if (unix_rename( adsrc, vol->vfs->ad_path( dst, 0 )) < 0) {
++        struct stat st;
++
++        err = errno;
++        if (errno == ENOENT) {
++              struct adouble    ad;
++
++            if (stat(adsrc, &st)) /* source has no ressource fork, */
++                return AFP_OK;
++            
++            /* We are here  because :
++             * -there's no dest folder. 
++             * -there's no .AppleDouble in the dest folder.
++             * if we use the struct adouble passed in parameter it will not
++             * 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.
++             */
++            ad_init(&ad, vol->v_adouble); 
++            if (!ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, &ad)) {
++              ad_close(&ad, ADFLAGS_HF);
++              if (!unix_rename( adsrc, vol->vfs->ad_path( dst, 0 )) ) 
++                   err = 0;
++                else 
++                   err = errno;
++            }
++            else { /* it's something else, bail out */
++                  err = errno;
++              }
++          }
++      }
++      if (err) {
++              errno = err;
++              return -1;
++      }
++      return 0;
++}
++
++struct vfs_ops netatalk_adouble = {
++    /* ad_path:           */ ad_path,
++    /* validupath:        */ validupath_adouble,
++    /* rf_chown:          */ RF_chown_adouble,
++    /* rf_renamedir:      */ RF_renamedir_adouble,
++    /* rf_deletecurdir:   */ RF_deletecurdir_adouble,
++    /* rf_setfilmode:     */ RF_setfilmode_adouble,
++    /* rf_setdirmode:     */ RF_setdirmode_adouble,
++    /* rf_setdirunixmode: */ RF_setdirunixmode_adouble,
++    /* rf_setdirowner:    */ RF_setdirowner_adouble,
++    /* rf_deletefile:     */ RF_deletefile_adouble,
++    /* rf_renamefile:     */ RF_renamefile_adouble,
++};
++
++/* =======================================
++ osx adouble format 
++ */
++static int validupath_osx(const struct vol *vol, const char *name) 
++{
++    return strncasecmp(name,".Apple", 6) && strncasecmp(name,"._", 2);
++}
++
++/* ---------------- */
++int RF_renamedir_osx(const struct vol *vol, const char *oldpath, const char *newpath)
++{
++    /* We simply move the corresponding ad file as well */
++    char   tempbuf[258]="._";
++    return rename(vol->vfs->ad_path(oldpath,0),strcat(tempbuf,newpath));
++}
++
++/* ---------------- */
++int RF_deletecurdir_osx(const struct vol *vol)
++{
++    return netatalk_unlink( vol->vfs->ad_path(".",0) );
++}
++
++/* ---------------- */
++static int RF_setdirunixmode_osx(const struct vol *vol, const char * name, mode_t mode, struct stat *st)
++{
++    return adouble_setfilmode(vol->vfs->ad_path( name, ADFLAGS_DIR ), mode, st);
++}
++
++/* ---------------- */
++static int RF_setdirmode_osx(const struct vol *vol, const char * name, mode_t mode, struct stat *st)
++{
++    return 0;
++}
++
++/* ---------------- */
++static int RF_setdirowner_osx(const struct vol *vol, const char *path, uid_t uid, gid_t gid)
++{
++      return 0;
++}
++
++/* ---------------- */
++int RF_renamefile_osx(const struct vol *vol, const char *src, const char *dst)
++{
++    char  adsrc[ MAXPATHLEN + 1];
++
++    strcpy( adsrc, vol->vfs->ad_path( src, 0 ));
++    return unix_rename( adsrc, vol->vfs->ad_path( dst, 0 ));
++}
++
++struct vfs_ops netatalk_adouble_osx = {
++    /* ad_path:          */ ad_path_osx,
++    /* validupath:       */ validupath_osx,
++    /* rf_chown:         */ RF_chown_adouble,
++    /* rf_renamedir:     */ RF_renamedir_osx,
++    /* rf_deletecurdir:  */ RF_deletecurdir_osx,
++    /* rf_setfilmode:    */ RF_setfilmode_adouble,
++    /* rf_setdirmode:    */ RF_setdirmode_osx,
++    /* rf_setdirunixmode:*/ RF_setdirunixmode_osx,
++    /* rf_setdirowner:   */ RF_setdirowner_osx,
++    /* rf_deletefile:    */ RF_deletefile_adouble,
++    /* rf_renamefile:    */ RF_renamefile_osx,
++};
++
++/* =======================================
++   samba ads format 
++ */
++struct vfs_ops netatalk_adouble_ads = {
++    /* ad_path:          */ ad_path_ads,
++    /* validupath:       */ validupath_adouble,
++    /* rf_chown:         */ RF_chown_ads,
++    /* rf_renamedir:     */ RF_renamedir_adouble,
++    /* rf_deletecurdir:  */ RF_deletecurdir_ads,
++    /* rf_setfilmode:    */ RF_setfilmode_ads,
++    /* rf_setdirmode:    */ RF_setdirmode_ads,
++    /* rf_setdirunixmode:*/ RF_setdirunixmode_ads,
++    /* rf_setdirowner:   */ RF_setdirowner_ads,
++    /* rf_deletefile:    */ RF_deletefile_ads,
++    /* rf_renamefile:    */ RF_renamefile_ads,
++};
++
++/* ---------------- */
++void initvol_vfs(struct vol *vol)
++{
++    if (vol->v_adouble == AD_VERSION2_OSX) {
++        vol->vfs = &netatalk_adouble_osx;
++    }
++    else if (vol->v_adouble == AD_VERSION1_ADS) {
++        vol->vfs = &netatalk_adouble_ads;
++    }
++    else {
++        vol->vfs = &netatalk_adouble;
++    }
++}
++
+diff -Nur -X .cvsignore -x CVS ../src.dev2/etc/afpd/volume.c ./etc/afpd/volume.c
+--- ../src.dev2/etc/afpd/volume.c      Mon Jul 12 08:46:03 2004
++++ ./etc/afpd/volume.c        Mon Jul 12 00:29:11 2004
+@@ -427,6 +427,8 @@
+             options[VOLOPT_ADOUBLE].i_value = AD_VERSION2;
+         else if (strcasecmp(val + 1, "osx") == 0)
+             options[VOLOPT_ADOUBLE].i_value = AD_VERSION2_OSX;
++        else if (strcasecmp(val + 1, "ads") == 0)
++            options[VOLOPT_ADOUBLE].i_value = AD_VERSION1_ADS;
+ #endif
+     } else if (optionok(tmp, "options:", val)) {
+         char *p;
+@@ -523,34 +525,6 @@
+     }
+ }
+-/* ----------------- 
+- * FIXME should be define elsewhere
+-*/
+-static int validupath_adouble(const struct vol *vol, const char *name) 
+-{
+-    return (vol->v_flags & AFPVOL_USEDOTS) ? strncasecmp(name,".Apple", 6) && strcasecmp(name, ".Parent")
+-                                           : name[0] != '.';
+-}                                           
+-
+-/* ----------------- */
+-static int validupath_osx(const struct vol *vol, const char *name) 
+-{
+-    return strncasecmp(name,".Apple", 6) && strncasecmp(name,"._", 2);
+-}             
+-
+-/* ---------------- */
+-static void initvoladouble(struct vol *vol)
+-{
+-    if (vol->v_adouble == AD_VERSION2_OSX) {
+-        vol->validupath  = validupath_osx;
+-        vol->ad_path     = ad_path_osx;
+-    }
+-    else {
+-        vol->validupath  = validupath_adouble;
+-        vol->ad_path     = ad_path;
+-    }
+-}
+-
+ /* ------------------------------- */
+ static int creatvol(AFPObj *obj, struct passwd *pwd, 
+                     char *path, char *name, 
+@@ -653,7 +627,8 @@
+           volume->v_adouble = options[VOLOPT_ADOUBLE].i_value;
+       else 
+           volume->v_adouble = AD_VERSION;
+-      initvoladouble(volume);
++
++      initvol_vfs(volume);
+ #ifdef FORCE_UIDGID
+         if (options[VOLOPT_FORCEUID].c_value) {
+             volume->v_forceuid = strdup(options[VOLOPT_FORCEUID].c_value);
+@@ -2231,6 +2206,9 @@
+             break;
+         case AD_VERSION2_OSX:
+             strlcat(buf, "ADOUBLE_VER:osx\n", sizeof(buf));
++            break;
++        case AD_VERSION1_ADS:
++            strlcat(buf, "ADOUBLE_VER:ads\n", sizeof(buf));
+             break;
+     }
+diff -Nur -X .cvsignore -x CVS ../src.dev2/etc/afpd/volume.h ./etc/afpd/volume.h
+--- ../src.dev2/etc/afpd/volume.h      Mon Jul 12 08:46:03 2004
++++ ./etc/afpd/volume.h        Fri Jun 25 22:01:56 2004
+@@ -14,6 +14,7 @@
+ #include "atalk/unicode.h"
+ #include "globals.h"
++#include "afp_vfs.h"
+ #define AFPVOL_NAMELEN   27
+@@ -75,6 +76,7 @@
+     int                 v_preexec_close;
+     
+     /* adouble indirection */
++    struct vfs_ops      *vfs;
+     int                 (*validupath)(const struct vol *, const char *);
+     char                *(*ad_path)(const char *, int);
+ };
+diff -Nur -X .cvsignore -x CVS ../src.dev2/include/atalk/adouble.h ./include/atalk/adouble.h
+--- ../src.dev2/include/atalk/adouble.h        Tue Jun 15 01:08:28 2004
++++ ./include/atalk/adouble.h  Sun Jun 20 22:33:26 2004
+@@ -82,6 +82,7 @@
+ #define AD_VERSION1   0x00010000
+ #define AD_VERSION2   0x00020000
+ #define AD_VERSION2_OSX       0x00020001
++#define AD_VERSION1_ADS       0x00010002
+ #define AD_VERSION    AD_VERSION2
+ /*
+@@ -252,6 +253,7 @@
+                                         the header parameter size is too small.
+                                      */
+     char                *(*ad_path)(const char *, int);
++    int                 (*ad_mkrf)(char *);
+                            
+ #ifdef USE_MMAPPED_HEADERS
+     char                *ad_data;
+@@ -364,6 +366,7 @@
+ extern char *ad_dir       __P((const char *));
+ extern char *ad_path      __P((const char *, int));
+ extern char *ad_path_osx  __P((const char *, int));
++extern char *ad_path_ads  __P((const char *, int));
+ extern int ad_mode        __P((const char *, int));
+ extern int ad_mkdir       __P((const char *, int));
+diff -Nur -X .cvsignore -x CVS ../src.dev2/libatalk/adouble/ad_open.c ./libatalk/adouble/ad_open.c
+--- ../src.dev2/libatalk/adouble/ad_open.c     Mon Jul 12 02:01:45 2004
++++ ./libatalk/adouble/ad_open.c       Mon Jul 12 02:12:25 2004
+@@ -697,6 +697,25 @@
+     return( pathbuf );
+ }
++/* -------------------- */
++static int ad_mkrf(char *path)
++{
++    char *slash;
++    /*
++     * Probably .AppleDouble doesn't exist, try to mkdir it.
++     */
++     if (NULL == ( slash = strrchr( path, '/' )) ) {
++         return -1;
++     }
++     *slash = '\0';
++     errno = 0;
++     if ( ad_mkdir( path, 0777 ) < 0 ) {
++          return -1;
++     }
++     *slash = '/';
++     return 0;
++}
++
+ /* ---------------------------------------
+  * Put the resource fork where it needs to be:
+  * ._name
+@@ -729,8 +748,97 @@
+     strlcat( pathbuf, slash, MAXPATHLEN +1);
+     return pathbuf;
+ }
++/* -------------------- */
++static int ad_mkrf_osx(char *path)
++{
++    return 0;
++}
+-/*
++/* ---------------------------------------
++ * Put the .AppleDouble where it needs to be:
++ *
++ *        /   a/.AppleDouble/b/Afp_AfpInfo
++ *    a/b     
++ *        \   b/.AppleDouble/.Parent/Afp_AfpInfo
++ *
++ */
++char *
++ad_path_ads( path, adflags )
++    const char        *path;
++    int               adflags;
++{
++    static char       pathbuf[ MAXPATHLEN + 1];
++    char      c, *slash, buf[MAXPATHLEN + 1];
++    size_t      l;
++
++    l = strlcpy(buf, path, MAXPATHLEN +1);
++    if ( adflags & ADFLAGS_DIR ) {
++      strcpy( pathbuf, buf);
++      if ( *buf != '\0' && l < MAXPATHLEN) {
++          pathbuf[l++] = '/';
++          pathbuf[l] = 0;
++      }
++      slash = ".Parent";
++    } else {
++      if (NULL != ( slash = strrchr( buf, '/' )) ) {
++          c = *++slash;
++          *slash = '\0';
++          strcpy( pathbuf, buf);
++          *slash = c;
++      } else {
++          pathbuf[ 0 ] = '\0';
++          slash = buf;
++      }
++    }
++    strlcat( pathbuf, ".AppleDouble/", MAXPATHLEN +1);
++    strlcat( pathbuf, slash, MAXPATHLEN +1);
++
++    strlcat( pathbuf, "/Afp_AfpInfo", MAXPATHLEN +1);
++
++#if 0
++    if ((adflags & ADFLAGS_HF)) {
++        strlcat( pathbuf, "Afp_AfpInfo", MAXPATHLEN +1);
++    else {
++        strlcat( pathbuf, "Afp_Resource", MAXPATHLEN +1);
++    }
++#endif      
++    return( pathbuf );
++}
++
++/* -------------------- */
++static int ad_mkrf_ads(char *path)
++{
++    char *slash;
++    /*
++     * Probably .AppleDouble doesn't exist, try to mkdir it.
++     */
++     if (NULL == ( slash = strrchr( path, '/' )) ) {
++         return -1;
++     }
++     *slash = 0;
++     errno = 0;
++     if ( ad_mkdir( path, 0777 ) < 0 ) {
++         if ( errno == ENOENT ) {
++             char *slash1;
++             
++             if (NULL == ( slash1 = strrchr( path, '/' )) ) 
++                 return -1;
++             errno = 0;
++             *slash1 = 0;
++             if ( ad_mkdir( path, 0777 ) < 0 ) 
++                  return -1;
++             *slash1 = '/';
++             if ( ad_mkdir( path, 0777 ) < 0 )
++                 return -1;
++         }
++         else
++            return -1;
++     }     
++     *slash = '/';
++     return 0;
++}
++
++/* -------------------------
+  * Support inherited protection modes for AppleDouble files.  The supplied
+  * mode is ANDed with the parent directory's mask value in lieu of "umask",
+  * and that value is returned.
+@@ -914,10 +1022,16 @@
+     memset( ad, 0, sizeof( struct adouble ) );
+     ad->ad_flags = flags;
+     if (flags == AD_VERSION2_OSX) {
+-        ad->ad_path     = ad_path_osx;
++        ad->ad_path = ad_path_osx;
++        ad->ad_mkrf = ad_mkrf_osx;
++    }
++    else if (flags == AD_VERSION1_ADS) {
++        ad->ad_path = ad_path_ads;
++        ad->ad_mkrf = ad_mkrf_ads;
+     }
+     else {
+-        ad->ad_path     = ad_path;
++        ad->ad_path = ad_path;
++        ad->ad_mkrf = ad_mkrf;
+     }
+ }
+@@ -931,7 +1045,7 @@
+     struct adouble    *ad;
+ {
+     struct stat         st;
+-    char              *slash, *ad_p;
++    char              *ad_p;
+     int                       hoflags, admode;
+     int                 st_invalid;
+     int                 open_df = 0;
+@@ -1031,19 +1145,9 @@
+           st_invalid = ad_mode_st(ad_p, &admode, &st);
+           admode = ad_hf_mode(admode); 
+           if ( errno == ENOENT && !(adflags & ADFLAGS_NOADOUBLE) && ad->ad_flags != AD_VERSION2_OSX) {
+-              /*
+-               * Probably .AppleDouble doesn't exist, try to
+-               * mkdir it.
+-               */
+-              if (NULL == ( slash = strrchr( ad_p, '/' )) ) {
+-                  return ad_error(ad, adflags);
+-              }
+-              *slash = '\0';
+-              errno = 0;
+-              if ( ad_mkdir( ad_p, 0777 ) < 0 ) {
++              if (ad->ad_mkrf( ad_p) < 0) {
+                   return ad_error(ad, adflags);
+-              }
+-              *slash = '/';
++              }
+               admode = mode;
+               st_invalid = ad_mode_st(ad_p, &admode, &st);
+               admode = ad_hf_mode(admode); 
diff --git a/contrib/patches/patch.mangled_trash_with_ip b/contrib/patches/patch.mangled_trash_with_ip
new file mode 100644 (file)
index 0000000..38976fc
--- /dev/null
@@ -0,0 +1,252 @@
+Workaround for Network Trash and system without byte locking (broken nfs/afs)
+mangle OS9 "Network Trash Folder/Trash Can #2" name to
+"Network Trash Folder/Trash Can #2.<client ip>.<tcp port>"
+So multiple clients can share the same volume and have a working trash.
+
+Index: etc/afpd/directory.c
+===================================================================
+RCS file: /cvsroot/netatalk/netatalk/etc/afpd/directory.c,v
+retrieving revision 1.71.2.4.2.12
+diff -u -r1.71.2.4.2.12 directory.c
+--- etc/afpd/directory.c       11 Mar 2004 16:16:40 -0000      1.71.2.4.2.12
++++ etc/afpd/directory.c       21 Apr 2004 12:42:03 -0000
+@@ -554,6 +554,7 @@
+  * attempt to extend the current dir. tree to include path
+  * as a side-effect, movecwd to that point and return the new dir
+  */
++
+ static struct dir *
+             extenddir( vol, dir, path )
+ struct vol    *vol;
+@@ -563,7 +564,25 @@
+     char *save_m_name;
+     if ( path->u_name == NULL) {
+-        path->u_name = mtoupath(vol, path->m_name, dir->d_did, (path->m_type==3) );
++#ifdef DISABLE_LOCKING
++        int l = strlen(TRASH_PREFIX);
++        /* XXX replace mac name with unix name */
++      if (vol->v_trash_id && vol->v_trash_id  == dir->d_did && vol->v_ip &&
++             !strncmp(TRASH_PREFIX , path->m_name, l ) )
++      {
++          static char temp[MAXPATHLEN + 1];
++          char *u;
++
++          strcpy(temp, path->m_name);
++          u = temp +l;
++          strcat(temp, ".");
++          strcat(temp, vol->v_ip);
++          path->u_name = temp;
++      
++      }
++        else 
++#endif
++            path->u_name = mtoupath(vol, path->m_name, dir->d_did, (path->m_type==3) );
+     }
+     path->dir = NULL;
+Index: etc/afpd/enumerate.c
+===================================================================
+RCS file: /cvsroot/netatalk/netatalk/etc/afpd/enumerate.c,v
+retrieving revision 1.39.2.2.2.4
+diff -u -r1.39.2.2.2.4 enumerate.c
+--- etc/afpd/enumerate.c       11 Mar 2004 02:01:59 -0000      1.39.2.2.2.4
++++ etc/afpd/enumerate.c       21 Apr 2004 12:42:04 -0000
+@@ -54,9 +54,39 @@
+     if (id == 0) {
+         return NULL;
+     }
++    
++#ifdef DISABLE_LOCKING
++    if (!path->m_name) {
++        int l = strlen(TRASH_PREFIX);
++        /* XXX */
++      if (vol->v_trash_id && vol->v_trash_id  == dir->d_did && vol->v_ip &&
++             !strncmp(TRASH_PREFIX , upath, l ) )
++      {
++          static char temp[MAXPATHLEN + 1];
++          char *u;
++
++          strcpy(temp, upath);
++          u = temp +l;
++          
++          while (*u >= '0' && *u <= '9') {
++              u++;
++          }
++          if (*u == '.') {
++              *u = '\0';
++          }
++          path->m_name = temp; 
++      }
++          
++        else if(!(path->m_name = utompath(vol, upath, id , utf8_encoding()))) {
++           return NULL;
++        }
++    }
++#else 
+     if (!path->m_name && !(path->m_name = utompath(vol, upath, id , utf8_encoding()))) {
+-        return NULL;
++       return NULL;
+     }
++#endif
++    
+     name  = path->m_name;    
+     if ((cdir = dirnew(name, upath)) == NULL) {
+         LOG(log_error, logtype_afpd, "adddir: malloc: %s", strerror(errno) );
+@@ -185,6 +215,32 @@
+     return name;
+ }
++#ifdef DISABLE_LOCKING
++/* ----------------------------- */
++int check_trash(const struct vol *vol, char *name)
++{
++int l = strlen(TRASH_PREFIX);
++char *u;
++
++    if (strncmp(TRASH_PREFIX , name, l)) 
++        return 0;
++    /* */
++    u = name +l;
++    while (*u >= '0' && *u <= '9') {
++        u++;
++    }
++
++    if (u == name +l)
++        return 0;
++
++    if (*u == '.' && !strcmp(vol->v_ip, u +1)) {
++        return 0;
++    }
++    /* hide this one */
++    return 1;
++}
++#endif
++
+ /* ----------------------------- */
+ int 
+ for_each_dirent(const struct vol *vol, char *name, dir_loop fn, void *data)
+@@ -193,15 +249,28 @@
+     struct dirent     *de;
+     char            *m_name;
+     int             ret;
++#ifdef DISABLE_LOCKING
++    int             mangle_trash = 0;
++#endif
+     
+     if (NULL == ( dp = opendir( name)) ) {
+         return -1;
+     }
++
++#ifdef DISABLE_LOCKING
++    if (vol->v_trash_id && vol->v_trash_id == curdir->d_did && !strcmp(name, ".")) {
++        mangle_trash = 1;
++    }
++#endif    
+     ret = 0;
+     for ( de = readdir( dp ); de != NULL; de = readdir( dp )) {
+         if (!(m_name = check_dirent(vol, de->d_name)))
+             continue;
++#ifdef DISABLE_LOCKING
++        if (mangle_trash && check_trash(vol, de->d_name))
++            continue;
++#endif
+         ret++;
+         if (fn && fn(de,m_name, data) < 0) {
+            closedir(dp);
+Index: etc/afpd/volume.c
+===================================================================
+RCS file: /cvsroot/netatalk/netatalk/etc/afpd/volume.c,v
+retrieving revision 1.51.2.7.2.28
+diff -u -r1.51.2.7.2.28 volume.c
+--- etc/afpd/volume.c  6 Apr 2004 23:29:37 -0000       1.51.2.7.2.28
++++ etc/afpd/volume.c  21 Apr 2004 12:42:05 -0000
+@@ -73,7 +73,11 @@
+ static struct vol *Volumes = NULL;
+ static u_int16_t      lastvid = 0;
+-static char           *Trash = "\02\024Network Trash Folder";
++
++/* type, len, name */
++static char           *Trash2 = "\02\024Network Trash Folder";
++/* type, hint (4 bytes), len (2bytes), name */
++static char           *Trash3 = "\03\0\0\0\0\0\024Network Trash Folder";
+ static struct extmap  *Extmap = NULL, *Defextmap = NULL;
+ static int              Extmap_cnt;
+@@ -1038,6 +1042,10 @@
+     free(vol->v_forceuid);
+     free(vol->v_forcegid);
+ #endif /* FORCE_UIDGID */
++
++#ifdef DISABLE_LOCKING
++    free(vol->v_ip);
++#endif    
+ }
+ /* ------------------------------- */
+@@ -1730,9 +1738,31 @@
+               goto openvol_err;
+           }
+       }
+-      else {
+-            p = Trash;
+-            cname( volume, volume->v_dir, &p );
++#ifndef DISABLE_LOCKING       
++      else 
++#endif        
++        {
++            struct path *s_path;
++
++            /* use the right name format */
++            p = (afp_version>= 30)?Trash3:Trash2;
++            s_path = cname( volume, volume->v_dir, &p );
++#ifdef DISABLE_LOCKING
++            if (s_path && *s_path->m_name == '\0' ) {
++                /* XXXX should do the same with ASP, could use volxlate but there's ':' in $p */
++                if (obj->proto == AFPPROTO_DSI) {
++                    DSI *dsi = obj->handle;
++                
++                    /* cname moved into dest folder */
++                    volume->v_trash_id = curdir->d_did;
++                    volume->v_ip = malloc(MAXPATHLEN +1);
++                    if (volume->v_ip) {
++                        sprintf(volume->v_ip, "%s.%u", inet_ntoa(dsi->client.sin_addr),
++                              ntohs(dsi->client.sin_port));
++                    }
++                }
++            }
++#endif
+         }
+         return( AFP_OK );
+     }
+Index: etc/afpd/volume.h
+===================================================================
+RCS file: /cvsroot/netatalk/netatalk/etc/afpd/volume.h,v
+retrieving revision 1.19.2.5.2.6
+diff -u -r1.19.2.5.2.6 volume.h
+--- etc/afpd/volume.h  11 Mar 2004 02:02:04 -0000      1.19.2.5.2.6
++++ etc/afpd/volume.h  21 Apr 2004 12:42:05 -0000
+@@ -81,6 +81,12 @@
+     /* adouble indirection */
+     int                 (*validupath)(const struct vol *, const char *);
+     char                *(*ad_path)(const char *, int);
++
++#ifdef DISABLE_LOCKING
++    /* for OS 9 trash when there's no working byte locking (afs, nfs) */
++    cnid_t            v_trash_id;
++    char              *v_ip;
++#endif    
+ };
+ #ifdef NO_LARGE_VOL_SUPPORT
+@@ -167,6 +173,8 @@
+ #define VOLPBIT_BSIZE   11        /* block size */
++#define TRASH_PREFIX "Trash Can #"
++
+ #define vol_noadouble(vol) (((vol)->v_flags & AFPVOL_NOADOUBLE) ? \
+                           ADFLAGS_NOADOUBLE : 0)
+ #ifdef AFP3x
diff --git a/contrib/patches/patch.samba.3.0.5pre2-SVN b/contrib/patches/patch.samba.3.0.5pre2-SVN
new file mode 100644 (file)
index 0000000..8b17608
--- /dev/null
@@ -0,0 +1,453 @@
+Index: source/smbd/nttrans.c
+===================================================================
+--- source/smbd/nttrans.c      (revision 1473)
++++ source/smbd/nttrans.c      (working copy)
+@@ -661,11 +661,16 @@
+                        * Check to see if this is a mac fork of some kind.
+                        */
+-                      if( strchr_m(fname, ':')) {
+-                              END_PROFILE(SMBntcreateX);
+-                              return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND);
+-                      }
+-
++                        if( !strchr_m(fname, ':')) {
++                                /* it's not an alternate stream */
++                                END_PROFILE(SMBntcreateX);
++                                return(ERROR_DOS(ERRDOS,ERRbadfid));
++                        }
++                        else if (-1 == SMB_VFS_LISTADS(conn, NULL, NULL, 0)) {
++                                /* fs have no support for alternate streams */
++                                END_PROFILE(SMBntcreateX);
++                                return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND);
++                        }
+                       /*
+                         we need to handle the case when we get a
+                         relative open relative to a file and the
+@@ -673,26 +678,29 @@
+                         (hint from demyn plantenberg)
+                       */
+-                      END_PROFILE(SMBntcreateX);
+-                      return(ERROR_DOS(ERRDOS,ERRbadfid));
++                      /*
++                       * Copy in the base name.
++                       */
++                      pstrcpy( fname, dir_fsp->fsp_name );
++                      dir_name_len = strlen(fname);
+               }
++              else { /* it's a dir */
++                      /*
++                       * Copy in the base directory name.
++                       */
+-              /*
+-               * Copy in the base directory name.
+-               */
++                      pstrcpy( fname, dir_fsp->fsp_name );
++                      dir_name_len = strlen(fname);
+-              pstrcpy( fname, dir_fsp->fsp_name );
+-              dir_name_len = strlen(fname);
++                      /*
++                       * Ensure it ends in a '\'.
++                       */
+-              /*
+-               * Ensure it ends in a '\'.
+-               */
+-
+-              if(fname[dir_name_len-1] != '\\' && fname[dir_name_len-1] != '/') {
+-                      pstrcat(fname, "/");
+-                      dir_name_len++;
+-              }
+-
++                      if(fname[dir_name_len-1] != '\\' && fname[dir_name_len-1] != '/') {
++                              pstrcat(fname, "/");
++                              dir_name_len++;
++                      }
++                }
+               srvstr_get_path(inbuf, rel_fname, smb_buf(inbuf), sizeof(rel_fname), 0, STR_TERMINATE, &status,False);
+               if (!NT_STATUS_IS_OK(status)) {
+                       END_PROFILE(SMBntcreateX);
+@@ -709,7 +717,6 @@
+               /* 
+                * Check to see if this is a mac fork of some kind.
+                */
+-
+               if( strchr_m(fname, ':')) {
+                       
+ #ifdef HAVE_SYS_QUOTAS
+@@ -725,8 +732,11 @@
+                                */
+                       } else {
+ #endif
+-                              END_PROFILE(SMBntcreateX);
+-                              return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND);
++                              if (-1 == SMB_VFS_LISTADS(conn, NULL, NULL, 0)) {  
++                                      END_PROFILE(SMBntcreateX);
++                                      return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND);
++                              }
++
+ #ifdef HAVE_SYS_QUOTAS
+                       }
+ #endif
+@@ -1235,12 +1245,10 @@
+                       }
+                       /*
+-                       * Check to see if this is a mac fork of some kind.
++                       * Check to see if this is a mac fork of some kind. FIXME
+                        */
+-
+-                      if( strchr_m(fname, ':'))
++                      if( strchr_m(fname, ':') && -1 == SMB_VFS_LISTADS(conn, NULL, NULL, 0))
+                               return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND);
+-
+                       return ERROR_DOS(ERRDOS,ERRbadfid);
+               }
+@@ -1278,7 +1286,7 @@
+                * Check to see if this is a mac fork of some kind.
+                */
+-              if( strchr_m(fname, ':'))
++              if( strchr_m(fname, ':') && -1 == SMB_VFS_LISTADS(conn, NULL, NULL, 0))
+                       return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND);
+       }
+Index: source/smbd/vfs.c
+===================================================================
+--- source/smbd/vfs.c  (revision 1473)
++++ source/smbd/vfs.c  (working copy)
+@@ -142,7 +142,10 @@
+               vfswrap_fremovexattr,
+               vfswrap_setxattr,
+               vfswrap_lsetxattr,
+-              vfswrap_fsetxattr
++              vfswrap_fsetxattr,
++
++              /* alternate streams operations. */
++              vfswrap_listads
+       }
+ };
+Index: source/smbd/vfs-wrap.c
+===================================================================
+--- source/smbd/vfs-wrap.c     (revision 1473)
++++ source/smbd/vfs-wrap.c     (working copy)
+@@ -1029,3 +1029,14 @@
+ {
+       return sys_fsetxattr(fd, name, value, size, flags);
+ }
++
++/****************************************************************
++ Alternate stream operations.
++*****************************************************************/
++
++ssize_t vfswrap_listads(struct vfs_handle_struct *handle, struct connection_struct *conn,const char *path, char *list, size_t size)
++{
++        errno = ENOSYS;
++        return -1;
++}
++
+Index: source/smbd/trans2.c
+===================================================================
+--- source/smbd/trans2.c       (revision 1473)
++++ source/smbd/trans2.c       (working copy)
+@@ -406,6 +406,159 @@
+ }
+ /****************************************************************************
++ ****************************************************************************
++ Return a linked list of the alternate streams Plus the total size
++****************************************************************************/
++struct ads_list {
++      struct ads_list *next, *prev;
++      struct ads_struct ads;
++};
++
++static struct ads_list *get_ads_list(TALLOC_CTX *mem_ctx, connection_struct *conn, files_struct *fsp, const char *fname, size_t *pads_total_len)
++{
++      /* Get a list of all ads with size, lax namesize is 64k. */
++      size_t ads_namelist_size = 4096;
++      char *ads_namelist;
++      char *p;
++      ssize_t sizeret;
++      int i;
++      struct ads_list *ads_list_head = NULL;
++
++      *pads_total_len = 0;
++
++      DEBUG(10,("get_ads_list\n" ));
++      
++      for (i = 0, ads_namelist = talloc(mem_ctx, ads_namelist_size); i < 6;
++                      ads_namelist = talloc_realloc(mem_ctx, ads_namelist, ads_namelist_size), i++) {
++
++              sizeret = SMB_VFS_LISTADS(conn, fname, ads_namelist, ads_namelist_size);
++              if (sizeret == -1 && errno == ERANGE) {
++                      ads_namelist_size *= 2;
++              } else {
++                      break;
++              }
++      }
++
++      if (sizeret == -1)
++              return NULL;
++
++      DEBUG(10,("get_ads_list: ads_namelist size = %d\n", sizeret ));
++
++      if (sizeret) { 
++              for (p = ads_namelist; p - ads_namelist < sizeret; p += strlen(p) +1) {
++                      struct ads_list *listp, *tmp;
++                      SMB_STRUCT_STAT sbuf;
++                      char *t;
++                      
++                      listp = talloc(mem_ctx, sizeof(struct ads_list));
++                      if (!listp)
++                              return NULL;
++
++                      listp->ads.name = talloc_strdup(mem_ctx, p);
++                      if (!listp->ads.name)
++                              return NULL;
++                      
++                      listp->ads.size = 0;
++                      listp->ads.allocation_size = 0;
++
++                      t = talloc_asprintf(mem_ctx, "%s%s", fname, p);
++                      if (!t)
++                              return NULL;
++                      if (!SMB_VFS_STAT(conn, t ,&sbuf)) {
++                              listp->ads.size = get_file_size(sbuf);
++                              listp->ads.allocation_size = get_allocation_size(NULL,&sbuf);
++                      }
++                      /* FIXME get ride of this */
++                      {
++                      fstring dos_ads_name;
++                              
++                              push_ascii_fstring(dos_ads_name, listp->ads.name);
++                              *pads_total_len += strlen(dos_ads_name) + 1 + 24;
++                              DEBUG(10,("get_ads_list: total_len = %u, %s, size = %llu\n",
++                                              *pads_total_len, dos_ads_name, listp->ads.size ));
++                      }
++                      DLIST_ADD_END(ads_list_head, listp, tmp);
++              }
++      }
++
++      DEBUG(10,("get_ads_list: total_len = %u\n", *pads_total_len));
++      return ads_list_head;
++}
++
++/****************************************************************************
++ Fill a qfilepathinfo buffer with alternate streams. 
++ Returns the length of the buffer that was filled.
++****************************************************************************/
++
++static unsigned int fill_ads_buffer(char *pdata, unsigned int total_data_size,
++      connection_struct *conn, files_struct *fsp, const char *fname)
++{
++      unsigned int ret_data_size = 0;
++      char *p = pdata;
++      size_t total_ads_len;
++      TALLOC_CTX *mem_ctx;
++      struct ads_list *ads_list;
++
++      SMB_ASSERT(total_data_size >= 24);
++
++      mem_ctx = talloc_init("fill_ads_buffer");
++      if (!mem_ctx) {
++              return 0;
++      }
++
++      ads_list = get_ads_list(mem_ctx, conn, fsp, fname, &total_ads_len);
++      if (!ads_list) {
++              talloc_destroy(mem_ctx);
++              return 0;
++      }
++
++      if (total_ads_len > total_data_size) {
++              talloc_destroy(mem_ctx);
++              return 0;
++      }
++
++      for (p = pdata; ads_list; ads_list = ads_list->next) {
++#if 0
++              size_t dos_namelen;
++              fstring dos_ads_name;
++
++              push_ascii_fstring(dos_ads_name, ads_list->ads.name);
++              dos_namelen = strlen(dos_ads_name);
++              if (dos_namelen > 255 || dos_namelen == 0) {
++                      break;
++              }
++              if (dos_namelen + 24 > total_data_size) {
++                      break;
++              }
++#endif
++              /* We know we have room. */
++              size_t byte_len = dos_PutUniCode(p +24, ads_list->ads.name, -1, False);
++              size_t off = SMB_ROUNDUP(24 +byte_len, 8); 
++              
++              SIVAL(p,0,0); /* from ethereal next entry offset */
++              SIVAL(p,4, byte_len); /* Byte length of unicode string :filename:$DATA */
++              SOFF_T(p,8, ads_list->ads.size);
++              SOFF_T(p,16, ads_list->ads.allocation_size);
++              if (ads_list->next) {
++                  SIVAL(p,0, off);
++              }
++              else {
++                  /* don't pad the last one */
++                  off = 24 +byte_len;
++              }
++
++              total_data_size -= off;
++              p += off;
++      }
++
++      ret_data_size = PTR_DIFF(p, pdata);
++      DEBUG(10,("fill_ads_buffer: data_size = %u, total_ads_len = %u\n",
++                      ret_data_size, total_ads_len ));
++      talloc_destroy(mem_ctx);
++      return ret_data_size;
++}
++
++/****************************************************************************
+   Send the required number of replies back.
+   We assume all fields other than the data fields are
+   set correctly for the type of call.
+@@ -2653,7 +2806,7 @@
+                       data_size = 4;
+                       break;
+-#if 0
++#if 1
+               /*
+                * NT4 server just returns "invalid query" to this - if we try to answer
+                * it then NTws gets a BSOD! (tridge).
+@@ -2663,16 +2816,24 @@
+ #endif
+               case SMB_FILE_STREAM_INFORMATION:
+                       DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_STREAM_INFORMATION\n"));
+-                      if (mode & aDIR) {
+-                              data_size = 0;
+-                      } else {
+-                              size_t byte_len = dos_PutUniCode(pdata+24,"::$DATA", 0xE, False);
+-                              SIVAL(pdata,0,0); /* ??? */
+-                              SIVAL(pdata,4,byte_len); /* Byte length of unicode string ::$DATA */
+-                              SOFF_T(pdata,8,file_size);
+-                              SIVAL(pdata,16,allocation_size);
+-                              SIVAL(pdata,20,0); /* ??? */
+-                              data_size = 24 + byte_len;
++                      {
++                              size_t off;
++ 
++                              if (mode & aDIR) {
++                                      off = 0;
++                              } else {
++                                      size_t byte_len = dos_PutUniCode(pdata+24,"::$DATA", 0xE, False);
++                              
++                                      off = SMB_ROUNDUP(24 +byte_len, 8); /* FIXME or 8 ? */
++                                      SIVAL(pdata,0,0); /* from ethereal next entry offset */
++                                      SIVAL(pdata,4,byte_len); /* Byte length of unicode string ::$DATA */
++                                      SOFF_T(pdata,8,file_size);
++                                      SOFF_T(pdata,16,allocation_size);
++                              }
++                              if ((data_size = fill_ads_buffer(pdata +off, data_size, conn, fsp, fname))) {
++                                      SIVAL(pdata,0,off);
++                              }
++                              data_size += off;
+                       }
+                       break;
+Index: source/include/vfs_macros.h
+===================================================================
+--- source/include/vfs_macros.h        (revision 1473)
++++ source/include/vfs_macros.h        (working copy)
+@@ -119,6 +119,9 @@
+ #define SMB_VFS_LSETXATTR(conn,path,name,value,size,flags) ((conn)->vfs.ops.lsetxattr((conn)->vfs.handles.lsetxattr,(conn),(path),(name),(value),(size),(flags)))
+ #define SMB_VFS_FSETXATTR(fsp,fd,name,value,size,flags) ((fsp)->conn->vfs.ops.fsetxattr((fsp)->conn->vfs.handles.fsetxattr,(fsp),(fd),(name),(value),(size),(flags)))
++/* ADS operations. */
++#define SMB_VFS_LISTADS(conn,path,list,size) ((conn)->vfs.ops.listads((conn)->vfs.handles.listads,(conn),(path),(list),(size)))
++
+ /*******************************************************************
+  Don't access conn->vfs_opaque.ops directly!!!
+  Use this macros!
+@@ -217,6 +220,9 @@
+ #define SMB_VFS_OPAQUE_LSETXATTR(conn,path,name,value,size,flags) ((conn)->vfs_opaque.ops.lsetxattr((conn)->vfs_opaque.handles.lsetxattr,(conn),(path),(name),(value),(size),(flags)))
+ #define SMB_VFS_OPAQUE_FSETXATTR(fsp,fd,name,value,size,flags) ((fsp)->conn->vfs_opaque.ops.fsetxattr((fsp)->conn->vfs_opaque.handles.fsetxattr,(fsp),(fd),(name),(value),(size),(flags)))
++/* ADS operations. */
++#define SMB_VFS_OPAQUE_LISTADS(conn,path,list,size) ((conn)->vfs_opaque.ops.listads((conn)->vfs_opaque.handles.listads,(conn),(path),(list),(size)))
++
+ /*******************************************************************
+  Don't access handle->vfs_next.ops.* directly!!!
+  Use this macros!
+@@ -315,4 +321,7 @@
+ #define SMB_VFS_NEXT_LSETXATTR(handle,conn,path,name,value,size,flags) ((handle)->vfs_next.ops.lsetxattr((handle)->vfs_next.handles.lsetxattr,(conn),(path),(name),(value),(size),(flags)))
+ #define SMB_VFS_NEXT_FSETXATTR(handle,fsp,fd,name,value,size,flags) ((handle)->vfs_next.ops.fsetxattr((handle)->vfs_next.handles.fsetxattr,(fsp),(fd),(name),(value),(size),(flags)))
++/* ADS operations. */
++#define SMB_VFS_NEXT_LISTADS(handle,conn,path,list,size) ((handle)->vfs_next.ops.listads((handle)->vfs_next.handles.listads,(conn),(path),(list),(size)))
++
+ #endif /* _VFS_MACROS_H */
+Index: source/include/vfs.h
+===================================================================
+--- source/include/vfs.h       (revision 1473)
++++ source/include/vfs.h       (working copy)
+@@ -55,7 +55,8 @@
+ /* Changed to version 8 includes EA calls. JRA. */
+ /* Changed to version 9 to include the get_shadow_data call. --metze */
+ /* Changed to version 10 to include pread/pwrite calls. */
+-#define SMB_VFS_INTERFACE_VERSION 10
++/* Changed to version 11 to include alternate data streams. */
++#define SMB_VFS_INTERFACE_VERSION 11
+ /* to bug old modules witch are trying to compile with the old functions */
+@@ -185,6 +186,9 @@
+       SMB_VFS_OP_SETXATTR,
+       SMB_VFS_OP_LSETXATTR,
+       SMB_VFS_OP_FSETXATTR,
++      
++      /* alternate stream */
++      SMB_VFS_OP_LISTADS,
+       /* This should always be last enum value */
+       
+@@ -294,6 +298,9 @@
+               int (*lsetxattr)(struct vfs_handle_struct *handle, struct connection_struct *conn,const char *path, const char *name, const void *value, size_t size, int flags);
+               int (*fsetxattr)(struct vfs_handle_struct *handle, struct files_struct *fsp,int filedes, const char *name, const void *value, size_t size, int flags);
++              /* alternate stream operations. */
++              ssize_t (*listads)(struct vfs_handle_struct *handle, struct connection_struct *conn,const char *path, char *list, size_t size);
++
+       } ops;
+       struct vfs_handles_pointers {
+@@ -394,6 +401,8 @@
+               struct vfs_handle_struct *lsetxattr;
+               struct vfs_handle_struct *fsetxattr;
++              /* alternate stream operations. */
++              struct vfs_handle_struct *listads;
+       } handles;
+ };
+Index: source/include/smb.h
+===================================================================
+--- source/include/smb.h       (revision 1473)
++++ source/include/smb.h       (working copy)
+@@ -1703,6 +1703,12 @@
+       DATA_BLOB value;
+ };
++struct ads_struct {
++      SMB_BIG_UINT size;
++      SMB_BIG_UINT allocation_size;
++      char *name;
++};
++
+ /* EA names used internally in Samba. KEEP UP TO DATE with prohibited_ea_names in trans2.c !. */
+ #define SAMBA_POSIX_INHERITANCE_EA_NAME "user.SAMBA_PAI"
+ /* EA to use for DOS attributes */
diff --git a/contrib/patches/patch.samba.3.0a20 b/contrib/patches/patch.samba.3.0a20
new file mode 100644 (file)
index 0000000..6d84621
--- /dev/null
@@ -0,0 +1,407 @@
+diff -ur ../smb3.0a20.orig/source/include/smb.h ./source/include/smb.h
+--- ../smb3.0a20.orig/source/include/smb.h     Mon Jan  6 18:04:22 2003
++++ ./source/include/smb.h     Fri Jun  4 05:34:14 2004
+@@ -1652,4 +1652,10 @@
+ extern struct poptOption popt_common_debug[];
++struct ads_struct {
++      SMB_BIG_UINT size;
++      SMB_BIG_UINT allocation_size;
++      char *name;
++};
++
+ #endif /* _SMB_H */
+diff -ur ../smb3.0a20.orig/source/include/smb_macros.h ./source/include/smb_macros.h
+--- ../smb3.0a20.orig/source/include/smb_macros.h      Mon Jan  6 18:04:22 2003
++++ ./source/include/smb_macros.h      Fri Jun  4 18:24:20 2004
+@@ -291,4 +291,8 @@
+ #define vfs_chdir(conn,fname) ((conn)->vfs_ops.chdir((conn),fname))
++/*******************************************************************
++ A wrapper for vfs_listads().
++********************************************************************/
++#define vfs_listads(conn,path,list,size)  ((conn)->vfs_ops.listads((conn),(path),(list),(size))) 
+ #endif /* _SMB_MACROS_H */
+diff -ur ../smb3.0a20.orig/source/include/vfs.h ./source/include/vfs.h
+--- ../smb3.0a20.orig/source/include/vfs.h     Mon Jan  6 18:04:23 2003
++++ ./source/include/vfs.h     Fri Jun  4 16:30:14 2004
+@@ -45,7 +45,8 @@
+ /* Changed to version 3 for POSIX acl extensions. JRA. */
+ /* Changed to version 4 for cascaded VFS interface. Alexander Bokovoy. */
+ /* Changed to version 5 for sendfile addition. JRA. */
+-#define SMB_VFS_INTERFACE_VERSION 5
++/* Changed to version 11 to include alternate data streams. */
++#define SMB_VFS_INTERFACE_VERSION 11
+ /* Version of supported cascaded interface backward copmatibility.
+@@ -173,6 +174,9 @@
+       int (*sys_acl_free_text)(struct connection_struct *conn, char *text);
+       int (*sys_acl_free_acl)(struct connection_struct *conn, SMB_ACL_T posix_acl);
+       int (*sys_acl_free_qualifier)(struct connection_struct *conn, void *qualifier, SMB_ACL_TAG_T tagtype);
++
++      /* alternate stream operations. */
++      ssize_t (*listads)(/* struct vfs_handle_struct *handle, */ struct connection_struct *conn,const char *path, char *list, size_t size);
+ };
+ struct vfs_options {
+@@ -269,6 +273,9 @@
+       SMB_VFS_OP_SYS_ACL_FREE_ACL,
+       SMB_VFS_OP_SYS_ACL_FREE_QUALIFIER,
+       
++      /* alternate stream */
++      SMB_VFS_OP_LISTADS,
++
+       /* This should always be last enum value */
+       
+       SMB_VFS_OP_LAST
+diff -ur ../smb3.0a20.orig/source/smbd/nttrans.c ./source/smbd/nttrans.c
+--- ../smb3.0a20.orig/source/smbd/nttrans.c    Mon Jan  6 18:05:44 2003
++++ ./source/smbd/nttrans.c    Fri Jul  2 07:38:38 2004
+@@ -52,6 +52,8 @@
+       FILE_GENERIC_ALL
+ };
++#define SMB_VFS_LISTADS vfs_listads
++
+ /****************************************************************************
+  Send the required number of replies back.
+  We assume all fields other than the data fields are
+@@ -625,30 +627,40 @@
+                        * Check to see if this is a mac fork of some kind.
+                        */
+-                      if( strchr_m(fname, ':')) {
++                      if( !strchr_m(fname, ':')) {
++                              /* it's not an alternate stream */
++                              END_PROFILE(SMBntcreateX);
++                              return(ERROR_DOS(ERRDOS,ERRbadfid));
++                      }
++                      else if (-1 == SMB_VFS_LISTADS(conn, NULL, NULL, 0)) {
++                              /* fs have no support for alternate streams */
+                               END_PROFILE(SMBntcreateX);
+                               return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND);
+                       }
+-                      END_PROFILE(SMBntcreateX);
+-                      return(ERROR_DOS(ERRDOS,ERRbadfid));
+-              }
+-              /*
+-               * Copy in the base directory name.
+-               */
++                      /*
++                      * Copy in the base name.
++                      */
++                      pstrcpy( fname, dir_fsp->fsp_name );
++                      dir_name_len = strlen(fname);
++              }
++              else { /* it's a dir */
++                      /*
++                       * Copy in the base directory name.
++                       */
+-              pstrcpy( fname, dir_fsp->fsp_name );
+-              dir_name_len = strlen(fname);
++                      pstrcpy( fname, dir_fsp->fsp_name );
++                      dir_name_len = strlen(fname);
+-              /*
+-               * Ensure it ends in a '\'.
+-               */
+-
+-              if(fname[dir_name_len-1] != '\\' && fname[dir_name_len-1] != '/') {
+-                      pstrcat(fname, "\\");
+-                      dir_name_len++;
+-              }
++                      /*
++                       * Ensure it ends in a '\'.
++                       */
++                      if(fname[dir_name_len-1] != '\\' && fname[dir_name_len-1] != '/') {
++                              pstrcat(fname, "\\");
++                              dir_name_len++;
++                      }
++                }
+               srvstr_pull_buf(inbuf, &fname[dir_name_len], smb_buf(inbuf), sizeof(fname)-dir_name_len, STR_TERMINATE);
+       } else {
+               srvstr_pull_buf(inbuf, fname, smb_buf(inbuf), sizeof(fname), STR_TERMINATE);
+@@ -656,8 +668,7 @@
+               /* 
+                * Check to see if this is a mac fork of some kind.
+                */
+-
+-              if( strchr_m(fname, ':')) {
++              if( strchr_m(fname, ':') && -1 == SMB_VFS_LISTADS(conn, NULL, NULL, 0)) {
+                       END_PROFILE(SMBntcreateX);
+                       return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND);
+               }
+@@ -1138,12 +1149,10 @@
+                       srvstr_pull(inbuf, fname, params+53, sizeof(fname), total_parameter_count-53, STR_TERMINATE);
+                       /*
+-                       * Check to see if this is a mac fork of some kind.
++                       * Check to see if this is a mac fork of some kind. FIXME ADS
+                        */
+-
+-                      if( strchr_m(fname, ':'))
++                      if( strchr_m(fname, ':') && -1 == SMB_VFS_LISTADS(conn, NULL, NULL, 0))
+                               return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND);
+-
+                       return ERROR_DOS(ERRDOS,ERRbadfid);
+               }
+@@ -1172,7 +1181,7 @@
+                * Check to see if this is a mac fork of some kind.
+                */
+-              if( strchr_m(fname, ':'))
++              if( strchr_m(fname, ':')  && -1 == SMB_VFS_LISTADS(conn, NULL, NULL, 0))
+                       return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND);
+       }
+diff -ur ../smb3.0a20.orig/source/smbd/trans2.c ./source/smbd/trans2.c
+--- ../smb3.0a20.orig/source/smbd/trans2.c     Mon Jan  6 18:05:48 2003
++++ ./source/smbd/trans2.c     Thu Jul  1 03:06:42 2004
+@@ -50,6 +50,162 @@
+       return ret;
+ }
++#define SMB_VFS_STAT vfs_stat
++#define SMB_VFS_LISTADS vfs_listads
++
++/****************************************************************************
++ ****************************************************************************
++ Return a linked list of the alternate streams Plus the total size
++****************************************************************************/
++struct ads_list {
++      struct ads_list *next, *prev;
++      struct ads_struct ads;
++};
++
++static struct ads_list *get_ads_list(TALLOC_CTX *mem_ctx, connection_struct *conn, files_struct *fsp, const char *fname, size_t *pads_total_len)
++{
++      /* Get a list of all ads with size, lax namesize is 64k. */
++      size_t ads_namelist_size = 4096;
++      char *ads_namelist;
++      char *p;
++      ssize_t sizeret;
++      int i;
++      struct ads_list *ads_list_head = NULL;
++
++      *pads_total_len = 0;
++
++      DEBUG(10,("get_ads_list\n" ));
++      
++      for (i = 0, ads_namelist = talloc(mem_ctx, ads_namelist_size); i < 6;
++                      ads_namelist = talloc_realloc(mem_ctx, ads_namelist, ads_namelist_size), i++) {
++
++              sizeret = SMB_VFS_LISTADS(conn, fname, ads_namelist, ads_namelist_size);
++              if (sizeret == -1 && errno == ERANGE) {
++                      ads_namelist_size *= 2;
++              } else {
++                      break;
++              }
++      }
++
++      if (sizeret == -1)
++              return NULL;
++
++      DEBUG(10,("get_ads_list: ads_namelist size = %d\n", sizeret ));
++
++      if (sizeret) { 
++              for (p = ads_namelist; p - ads_namelist < sizeret; p += strlen(p) +1) {
++                      struct ads_list *listp, *tmp;
++                      SMB_STRUCT_STAT sbuf;
++                      char *t;
++                      
++                      listp = talloc(mem_ctx, sizeof(struct ads_list));
++                      if (!listp)
++                              return NULL;
++
++                      listp->ads.name = talloc_strdup(mem_ctx, p);
++                      if (!listp->ads.name)
++                              return NULL;
++                      
++                      listp->ads.size = 0;
++                      listp->ads.allocation_size = 0;
++
++                      t = talloc_asprintf(mem_ctx, "%s%s", fname, p);
++                      if (!t)
++                              return NULL;
++                      if (!SMB_VFS_STAT(conn, t ,&sbuf)) {
++                              listp->ads.size = get_file_size(sbuf);
++                              listp->ads.allocation_size = get_allocation_size(NULL,&sbuf);
++                      }
++                      /* FIXME get ride of this */
++                      {
++                      fstring dos_ads_name;
++                              
++                              push_ascii_fstring(dos_ads_name, listp->ads.name);
++                              *pads_total_len += strlen(dos_ads_name) + 1 + 24;
++                              DEBUG(10,("get_ads_list: total_len = %u, %s, size = %llu\n",
++                                              *pads_total_len, dos_ads_name, listp->ads.size ));
++                      }
++                      DLIST_ADD_END(ads_list_head, listp, tmp);
++              }
++      }
++
++      DEBUG(10,("get_ads_list: total_len = %u\n", *pads_total_len));
++      return ads_list_head;
++}
++
++/****************************************************************************
++ Fill a qfilepathinfo buffer with alternate streams. 
++ Returns the length of the buffer that was filled.
++****************************************************************************/
++
++static unsigned int fill_ads_buffer(char *pdata, unsigned int total_data_size,
++      connection_struct *conn, files_struct *fsp, const char *fname)
++{
++      unsigned int ret_data_size = 0;
++      char *p = pdata;
++      size_t total_ads_len;
++      TALLOC_CTX *mem_ctx;
++      struct ads_list *ads_list;
++
++      SMB_ASSERT(total_data_size >= 24);
++
++      mem_ctx = talloc_init(/*"fill_ads_buffer"*/);
++      if (!mem_ctx) {
++              return 0;
++      }
++
++      ads_list = get_ads_list(mem_ctx, conn, fsp, fname, &total_ads_len);
++      if (!ads_list) {
++              talloc_destroy(mem_ctx);
++              return 0;
++      }
++
++      if (total_ads_len > total_data_size) {
++              talloc_destroy(mem_ctx);
++              return 0;
++      }
++
++      for (p = pdata; ads_list; ads_list = ads_list->next) {
++#if 0
++              size_t dos_namelen;
++              fstring dos_ads_name;
++
++              push_ascii_fstring(dos_ads_name, ads_list->ads.name);
++              dos_namelen = strlen(dos_ads_name);
++              if (dos_namelen > 255 || dos_namelen == 0) {
++                      break;
++              }
++              if (dos_namelen + 24 > total_data_size) {
++                      break;
++              }
++#endif
++              /* We know we have room. */
++              size_t byte_len = dos_PutUniCode(p +24, ads_list->ads.name, -1, False);
++              size_t off = SMB_ROUNDUP(24 +byte_len, 8); 
++              
++              SIVAL(p,0,0); /* from ethereal next entry offset */
++              SIVAL(p,4, byte_len); /* Byte length of unicode string :filename:$DATA */
++              SOFF_T(p,8, ads_list->ads.size);
++              SOFF_T(p,16, ads_list->ads.allocation_size);
++              if (ads_list->next) {
++                  SIVAL(p,0, off);
++              }
++              else {
++                  /* don't pad the last one */
++                  off = 24 +byte_len;
++              }
++
++              total_data_size -= off;
++              p += off;
++      }
++
++      ret_data_size = PTR_DIFF(p, pdata);
++      DEBUG(10,("fill_ads_buffer: data_size = %u, total_ads_len = %u\n",
++                      ret_data_size, total_ads_len ));
++      talloc_destroy(mem_ctx);
++      return ret_data_size;
++}
++
+ /****************************************************************************
+   Send the required number of replies back.
+   We assume all fields other than the data fields are
+@@ -1934,7 +2090,7 @@
+                               break;
+                       }
+               
+-#if 0
++#if 1
+               /*
+                * NT4 server just returns "invalid query" to this - if we try to answer
+                * it then NTws gets a BSOD! (tridge).
+@@ -1943,16 +2099,24 @@
+               case SMB_QUERY_FILE_STREAM_INFO:
+ #endif
+               case SMB_FILE_STREAM_INFORMATION:
+-                      if (mode & aDIR) {
+-                              data_size = 0;
+-                      } else {
+-                              size_t byte_len = dos_PutUniCode(pdata+24,"::$DATA", 0xE, False);
+-                              SIVAL(pdata,0,0); /* ??? */
+-                              SIVAL(pdata,4,byte_len); /* Byte length of unicode string ::$DATA */
+-                              SOFF_T(pdata,8,file_size);
+-                              SIVAL(pdata,16,allocation_size);
+-                              SIVAL(pdata,20,0); /* ??? */
+-                              data_size = 24 + byte_len;
++                      {
++                              size_t off;
++
++                              if (mode & aDIR) {
++                                      off = 0;
++                              } else {
++                                      size_t byte_len = dos_PutUniCode(pdata+24,"::$DATA", 0xE, False);
++                              
++                                      off = SMB_ROUNDUP(24 +byte_len, 8); /* FIXME or 8 ? */
++                                      SIVAL(pdata,0,0); /* from ethereal next entry offset */
++                                      SIVAL(pdata,4,byte_len); /* Byte length of unicode string ::$DATA */
++                                      SOFF_T(pdata,8,file_size);
++                                      SOFF_T(pdata,16,allocation_size);
++                              }
++                              if ((data_size = fill_ads_buffer(pdata +off, data_size, conn, fsp, fname))) {
++                                      SIVAL(pdata,0,off);
++                              }
++                              data_size += off;
+                       }
+                       break;
+diff -ur ../smb3.0a20.orig/source/smbd/vfs-wrap.c ./source/smbd/vfs-wrap.c
+--- ../smb3.0a20.orig/source/smbd/vfs-wrap.c   Mon Jan  6 18:05:49 2003
++++ ./source/smbd/vfs-wrap.c   Fri Jun  4 16:33:16 2004
+@@ -739,3 +739,14 @@
+ {
+       return sys_acl_free_qualifier(qualifier, tagtype);
+ }
++
++/****************************************************************
++ Alternate stream operations.
++*****************************************************************/
++
++ssize_t vfswrap_listads(/* struct vfs_handle_struct *handle, */ struct connection_struct *conn,const char *path, char *list, size_t size)
++{
++        errno = ENOSYS;
++        return -1;
++}
++
+Only in ./source/smbd: vfs-wrap.c.orig
+diff -ur ../smb3.0a20.orig/source/smbd/vfs.c ./source/smbd/vfs.c
+--- ../smb3.0a20.orig/source/smbd/vfs.c        Mon Jan  6 18:05:48 2003
++++ ./source/smbd/vfs.c        Fri Jun  4 05:40:09 2004
+@@ -124,7 +124,10 @@
+       vfswrap_sys_acl_get_perm,
+       vfswrap_sys_acl_free_text,
+       vfswrap_sys_acl_free_acl,
+-      vfswrap_sys_acl_free_qualifier
++      vfswrap_sys_acl_free_qualifier,
++
++      /* alternate streams operations. */
++      vfswrap_listads
+ };
+ /****************************************************************************
diff --git a/contrib/patches/patch.vfs b/contrib/patches/patch.vfs
new file mode 100644 (file)
index 0000000..06295d0
--- /dev/null
@@ -0,0 +1,1115 @@
+diff -Nur vfs/Makefile vfs.new/Makefile
+--- vfs/Makefile       Thu Jan  1 00:00:00 1970
++++ vfs.new/Makefile   Mon Jul 12 10:48:56 2004
+@@ -0,0 +1,40 @@
++##########################################################################
++# Makefile for Samba VFS modules 
++###########################################################################
++
++CC=gcc -g
++LIBTOOL=/usr/bin/libtool
++# REPLACE with samba source 
++SMB=/u/redhat/paris/cvs/samba/smb3.0a20
++
++# REPLACE with samba build folder
++BUILD=/mnt/hdd/build/smb.1.3
++
++CFLAGS=-Wall -I $(BUILD)/include \
++-I$(SMB)/source -I$(SMB)/source/include -I$(SMB)/source/ubiqx -I$(SMB)/source/smbwrapper
++
++
++LDFLAGS=-shared
++
++VFS_OBJS=vfs_ads.so
++
++SHELL=/bin/sh
++
++default: $(VFS_OBJS)
++
++# Pattern rules
++
++%.so: %.lo
++      @echo Linking $<
++      @$(LIBTOOL) --mode=link $(CC) -o $@ $< $(LDFLAGS)
++
++%.lo: %.c
++      @echo Compiling $<
++      @$(LIBTOOL) --mode=compile $(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@
++
++# Misc targets
++
++clean:
++      rm -rf .libs */.libs
++      rm -f core *~ *% *.bak *.o */*.o *.lo $(VFS_OBJS)
++
+diff -Nur vfs/README vfs.new/README
+--- vfs/README Thu Jan  1 00:00:00 1970
++++ vfs.new/README     Tue Jul 13 02:28:21 2004
+@@ -0,0 +1,34 @@
++This a vfs for NT ADS 
++you must set SMB and BUILD variables in Makefile.
++
++old smb.conf
++[test_ads]
++   comment = test ADS Mac/PC directory
++   path=/home/test_ads/
++#  /.AppleD* is mandatory 
++   veto files = /.AppleD*/Network Trash Folder/Icon\r/
++   delete veto files = True
++# full path to vfs_ads.so 
++   vfs object = /usr/src/samba/vfs/vfs_ads.so
++   browseable = yes
++   writable = yes
++
++new one (current svn tree)
++copy vfs_ads.so as ads.so in <prefix>/lib/vfs/
++eg
++cp vfs_ads.so /opt/lib/vfs/ads.so
++
++smb.conf
++[test_ads]
++   comment = test ADS Mac/PC directory
++   path=/home/test_ads/
++ 
++#  /.AppleD* is mandatory 
++   veto files = /.AppleD*/Network Trash Folder/Icon\r/
++   delete veto files = True
++   vfs objects = ads
++   browseable = yes
++   writable = yes
++
++
++Didier
+diff -Nur vfs/vfs_ads.c vfs.new/vfs_ads.c
+--- vfs/vfs_ads.c      Thu Jan  1 00:00:00 1970
++++ vfs.new/vfs_ads.c  Wed Jul 14 16:37:15 2004
+@@ -0,0 +1,1029 @@
++/* 
++ * CAP VFS module for Samba 3.x Version 0.3
++ *
++ * Copyright (C) Tim Potter, 1999-2000
++ * Copyright (C) Alexander Bokovoy, 2002-2003
++ * Copyright (C) Stefan (metze) Metzmacher, 2003
++ * Copyright (C) TAKAHASHI Motonobu (monyo), 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.
++ *
++ * modified for alternate data stream
++ * Copyright (C) Didier Gautheron 2004
++ * 
++ * this module should compile with old 3.0 API and 2004-07 svn API
++ */
++
++
++#include "includes.h"
++
++#undef DBGC_CLASS
++#define DBGC_CLASS DBGC_VFS
++
++#define ADS_FOLDER    ".AppleDouble"
++#define ADOUBLEMODE   0777
++
++/* FIXME found a better test */
++#ifdef        SMB_VFS_OP
++#define ADS_NEW_MODULE
++
++/* for current svn tree */
++#define ADS_TALLOC_INIT(a) talloc_init(a)
++
++#define HANDLE_PARAMETER vfs_handle_struct *handle,
++#define HANDLE handle,
++
++/* ------------------- */
++#else
++
++#define ADS_TALLOC_INIT(a) talloc_init()
++
++#define HANDLE_PARAMETER 
++#define HANDLE
++
++/* VFS operations */
++static struct vfs_ops default_vfs_ops;   /* For passthrough operation */
++static struct smb_vfs_handle_struct *ads_handle; 
++
++#define SMB_VFS_NEXT_DISK_FREE(a,b,c,d,e,f,g)       default_vfs_ops.disk_free(b,c,d,e,f,g)
++#define SMB_VFS_NEXT_OPENDIR(a,b,c)                 default_vfs_ops.opendir(b,c)
++#define SMB_VFS_NEXT_READDIR(a,b,c)                 default_vfs_ops.readdir(b,c)
++#define SMB_VFS_NEXT_MKDIR(a,b,c,d)                 default_vfs_ops.mkdir(b,c,d)
++#define SMB_VFS_NEXT_RMDIR(a,b,c)                   default_vfs_ops.rmdir(b,c)
++#define SMB_VFS_NEXT_OPEN(a,b,c,d,e)                default_vfs_ops.open(b,c,d,e)
++#define SMB_VFS_NEXT_RENAME(a,b,c,d)                default_vfs_ops.rename(b,c,d)
++#define SMB_VFS_NEXT_STAT(a,b,c,d)                  default_vfs_ops.stat(b,c,d)
++#define SMB_VFS_NEXT_LSTAT(a,b,c,d)                 default_vfs_ops.lstat(b,c,d)
++#define SMB_VFS_NEXT_UNLINK(a,b,c)                  default_vfs_ops.unlink(b,c)
++#define SMB_VFS_NEXT_CHMOD(a,b,c,d)                 default_vfs_ops.chmod(b,c,d)
++#define SMB_VFS_NEXT_CHOWN(a,b,c,d,e)               default_vfs_ops.chown(b,c,d,e) 
++#define SMB_VFS_NEXT_CHDIR(a,b,c)                   default_vfs_ops.chdir(b,c)
++#define SMB_VFS_NEXT_UTIME(a,b,c,d)                 default_vfs_ops.utime(b,c,d)
++#define SMB_VFS_NEXT_SYMLINK(a,b,c,d)               default_vfs_ops.symlink(b,c,d)
++#define SMB_VFS_NEXT_READLINK(a,b,c,d,e)            default_vfs_ops.readlink(b,c,d,e)
++#define SMB_VFS_NEXT_LINK(a,b,c,d)                  default_vfs_ops.link(b,c,d)
++#define SMB_VFS_NEXT_MKNOD(a,b,c,d,e)               default_vfs_ops.mknod(b,c,d,e)
++#define SMB_VFS_NEXT_REALPATH(a,b,c,d)              default_vfs_ops.realpath(b,c,d)
++#define SMB_VFS_NEXT_SET_NT_ACL(a,b,c,d,e)          default_vfs_ops.set_nt_acl(b,c,d,e)
++#define SMB_VFS_NEXT_CHMOD_ACL(a,b,c,d)             default_vfs_ops.chmod_acl(b,c,d)
++#define SMB_VFS_NEXT_SYS_ACL_GET_FILE(a,b,c,d)      default_vfs_ops.sys_acl_get_file(b,c,d)
++#define SMB_VFS_NEXT_SYS_ACL_SET_FILE(a,b,c,d,e)    default_vfs_ops.sys_acl_set_file(b,c,d,e)
++#define SMB_VFS_NEXT_SYS_ACL_DELETE_DEF_FILE(a,b,c) default_vfs_ops.sys_acl_delete_def_file(b,c)
++/* ads functions */
++
++#endif
++
++/* ------------------------- 
++ * format
++ * .AppleDouble/filename/stream name
++ * 
++ * return the *LAST* '/' in path
++ */
++static int ads_get_path_ptr(char *path)
++{
++      int i   = 0;
++      int ptr = 0;
++      
++      for (i = 0; path[i]; i ++) {
++              if (path[i] == '/')
++                      ptr = i;
++      }
++      
++      return ptr;
++}
++
++/* ------------------------------
++ * return the *FIRST* ':' in path
++*/
++static int ads_get_stream_ptr(const char *path)
++{
++      int i   = 0;
++      int ptr = 0;
++      
++      for (i = 0; path[i]; i ++) {
++              if (path[i] == ':') {
++                      ptr = i;
++                      break;
++              }
++      }
++      return ptr;
++}
++
++/* ---------------- 
++ * fname is only a filename
++*/
++
++static char *ads_canonical_dir(TALLOC_CTX *ctx, const char *path, const char *fname, int isdir)
++{
++    if (isdir) {
++        return talloc_asprintf(ctx, "%s/%s/%s/.Parent", path, fname, ADS_FOLDER);
++    }
++    return talloc_asprintf(ctx, "%s/%s/%s", path, ADS_FOLDER, fname);
++    
++}
++
++/* ---------------- 
++ * return directory pathname for an alternate data stream
++ * fname is *NOT* an altername name (ie foo:bar)
++*/
++static char *ads_dir(TALLOC_CTX *ctx, const char *path, const char *fname, int isdir)
++{
++    int ptr0 = 0;
++    int ptr1 = 0;
++    char *temp;
++
++#if 0
++    if (fname[0] == '.') ptr0 ++;
++    if (fname[1] == '/') ptr0 ++;
++#endif    
++    temp = talloc_asprintf(ctx, "%s/%s", path, &fname[ptr0]);
++    ptr1 = ads_get_path_ptr(temp);
++    temp[ptr1] = '\0';
++    return ads_canonical_dir(ctx, temp, &temp[ptr1 + 1], isdir);
++}
++
++/* ----------------------------------
++ * build the pathname for stream, create folder if (mode & O_CREAT)
++ * return -1 on error
++ * 0 it's not a stream
++ * 1 it's a stream
++ *
++ * main_path : file fullpathname with :$DATA removed
++ * ads_path: unix pathname 
++ * if it's not an ADS then main_path == ads_path
++ *
++ */
++static int ads_build_paths(TALLOC_CTX *ctx, const char *path, const char *fname,
++                              char **ads_path, char **main_path, SMB_STRUCT_STAT **main_info, int flag)
++{
++        int ret = 0;
++      int ptr0 = 0;
++      int ptr1 = 0;
++      int ptr2 = 0;
++      int ptr3 = 0;
++      char *dname = 0;
++      char *name  = 0;
++      SMB_STRUCT_STAT ads_info;
++
++      if (!ctx || !path || !fname || !ads_path || !main_path || !main_info || !*main_info)
++              return -1;
++#if 1
++      DEBUG(3, ("ADS: PATH: %s[%s]\n", path, fname));
++#endif
++      if (strstr(path, ADS_FOLDER) || strstr(fname, ADS_FOLDER)) {
++              DEBUG(1, ("ADS: path %s[%s] already contains %s\n", path, fname, ADS_FOLDER));
++              return -1;
++      }
++
++#if 0
++      if (fname[0] == '.') ptr0 ++;
++      if (fname[1] == '/') ptr0 ++;
++#endif
++
++      *main_path = talloc_asprintf(ctx, "%s/%s", path, &fname[ptr0]);
++      *ads_path = NULL;
++
++      /* get pointer to last '/' */
++      ptr1 = ads_get_path_ptr(*main_path);
++      ptr2 = ads_get_stream_ptr(*main_path +ptr1 +1);
++      /* FIXME
++       * what about ::$DATA or :name:$DATA
++      */
++
++      if (ptr2) {
++          /* it's an alternate stream */
++          ptr2 += ptr1 +1;
++          (*main_path)[ptr2] = 0;
++          ptr3 = ads_get_stream_ptr(*main_path +ptr2 +1);
++          if (ptr3) {
++              ptr3 += ptr2 +1;
++              /* check it's $DATA */
++              if (!strcmp("$DATA", &(*main_path)[ptr3+1])) {
++                  (*main_path)[ptr3] = 0;
++              }
++          }
++
++          DEBUG(3, ("ADS: MAIN DATA %s\n", *main_path));
++
++          if (sys_lstat(*main_path, *main_info) < 0) {
++              /* if we can't get the main file give up */
++              return -1;
++          }
++          (*main_path)[ptr2] = ':';
++          dname = talloc_strdup(ctx, *main_path);
++          dname[ptr1] = '\0'; 
++          name = *main_path;
++          name[ptr2] = '\0';
++          if (S_ISDIR((*main_info)->st_mode)) {
++              *ads_path = talloc_asprintf(ctx, "%s/%s/%s/.Parent/%s", dname, &name[ptr1 + 1], ADS_FOLDER, &name[ptr2 + 1]);
++          }
++          else {
++              *ads_path = talloc_asprintf(ctx, "%s/%s/%s/%s", dname, ADS_FOLDER, &name[ptr1 + 1], &name[ptr2 + 1]);
++          }
++          /* XXX are we always the right user ?*/
++          if (sys_lstat(*ads_path, &ads_info) < 0) {
++              int st_ret;
++              /* */
++              if (errno == ENOENT && (flag & O_CREAT))  {
++                  char *ads_base = ads_canonical_dir(ctx, dname, &name[ptr1 + 1], S_ISDIR((*main_info)->st_mode));
++                  mode_t mode;
++                  
++                  st_ret = mkdir(ads_base, 0777);
++                  if (st_ret < 0) {
++                      if (errno == ENOENT) {
++                          char *ads_double;
++                          if (S_ISDIR((*main_info)->st_mode)) {
++                              ads_double = talloc_asprintf(ctx, "%s/%s/%s", dname, &name[ptr1 + 1], ADS_FOLDER);
++                          }
++                          else {
++                              ads_double = talloc_asprintf(ctx, "%s/%s", dname, ADS_FOLDER);
++                          }
++                          if (mkdir(ads_double, 0777) < 0)
++                              return -1;
++                          if ((st_ret = mkdir(ads_base, 0777)) < 0)
++                              return -1;
++                          
++                          /* we just created .AppleDouble/file/ update mode with dir search 
++                           * XXX what about acl?
++                          */
++                          mode = (*main_info)->st_mode;
++                          if ((mode & (S_IRUSR | S_IWUSR )))
++                              mode |= S_IXUSR;
++                          if ((mode & (S_IRGRP | S_IWGRP )))
++                              mode |= S_IXGRP;
++                          if ((mode & (S_IROTH | S_IWOTH ))) 
++                              mode |= S_IXOTH;
++                          chmod(ads_base, mode);
++                      }
++                      else 
++                          errno = ENOENT;
++                  }
++              }
++              else 
++                  return -1;
++          }
++          ret = 1;
++      }
++      else {
++          *ads_path = *main_path;
++          if (sys_lstat(*main_path, *main_info) < 0) {
++              *main_info = NULL;
++          }
++      }
++#if 1
++      DEBUG(3, ("ADS: DEBUG:[%s] [%s]\n", *main_path, *ads_path)); 
++#endif
++      return ret;
++}
++
++/* ------------------------ */
++static SMB_BIG_UINT ads_disk_free(HANDLE_PARAMETER connection_struct *conn, const char *path,
++      BOOL small_query, SMB_BIG_UINT *bsize,
++      SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
++{
++      return SMB_VFS_NEXT_DISK_FREE(handle, conn, path, small_query, bsize, dfree, dsize);
++}
++
++static DIR *ads_opendir(HANDLE_PARAMETER connection_struct *conn, const char *fname)
++{
++      return SMB_VFS_NEXT_OPENDIR(handle, conn, fname);
++}
++
++static struct dirent *ads_readdir(HANDLE_PARAMETER connection_struct *conn, DIR *dirp)
++{
++        struct dirent *result;
++      DEBUG(3,("ads: ads_readdir\n"));
++      result = SMB_VFS_NEXT_READDIR(handle, conn, dirp);
++      if (result) {
++        DEBUG(3,("ads: ads_readdir: %s\n", result->d_name));
++        }
++        return result;
++}
++
++/* ------------------------- */
++static int ads_mkdir(HANDLE_PARAMETER connection_struct *conn, const char *path, mode_t mode)
++{
++      return SMB_VFS_NEXT_MKDIR(handle, conn, path, mode);
++}
++
++/* ------------------------- */
++static int unlink_file(const char *path)
++{
++int ret = 0;
++         
++      become_root();
++        ret = unlink(path);
++        unbecome_root();
++        return ret;
++}
++
++/* ------------------------- */
++static int unlink_folder(const char *path)
++{
++int ret = 0;
++         
++      become_root();
++        ret = rmdir(path);
++        unbecome_root();
++        return ret;
++}
++
++/* ------------------------- 
++   remove all files in an AppleDouble folder
++*/
++static void rrmdir(TALLOC_CTX *ctx, char *path)
++{
++        int n;
++        char *dpath;
++        struct dirent **namelist;
++ 
++        if (!path) return;
++ 
++        n = scandir(path, &namelist, 0, alphasort);
++        if (n < 0) {
++                return;
++        } 
++        while (n --) {
++              if (strcmp(namelist[n]->d_name, ".") == 0 || strcmp(namelist[n]->d_name, "..") == 0) {
++                      free(namelist[n]);
++                        continue;
++                }
++                if ((dpath = talloc_asprintf(ctx, "%s/%s",path, namelist[n]->d_name))) {
++                      unlink_file(dpath);
++                }
++                free(namelist[n]);
++        }
++        free(namelist);
++        unlink_folder(path);
++}
++
++/* --------------------------- */
++static void rrm_adsdir(TALLOC_CTX *ctx, char *path)
++{
++        int n;
++        char *dpath;
++        struct dirent **namelist;
++ 
++        if (!path) return;
++ 
++        n = scandir(path, &namelist, 0, alphasort);
++        if (n < 0) {
++                return;
++        } 
++        while (n --) {
++              if (strcmp(namelist[n]->d_name, ".") == 0 || strcmp(namelist[n]->d_name, "..") == 0) {
++                      free(namelist[n]);
++                        continue;
++                }
++                if ((dpath = talloc_asprintf(ctx, "%s/%s",path, namelist[n]->d_name))) {
++                      rrmdir(ctx, dpath);
++                }
++                free(namelist[n]);
++        }
++        free(namelist);
++        unlink_folder(path);
++}
++
++/* ------------------------- 
++ * XXX 
++ * if in smb.conf there's :
++ * delete veto files = True
++ * veto files = /.AppleD* /
++*/
++static int ads_rmdir( HANDLE_PARAMETER connection_struct *conn, const char *path)
++{
++        BOOL add = False;
++        TALLOC_CTX *ctx = 0;
++        char *dpath;
++        int  ret = 0;
++ 
++        if (!conn || !conn->origpath || !path) goto exit_rmdir;
++
++      /* .AppleD* */
++        strstr(path, ADS_FOLDER) ? (add = False) : (add = True);
++ 
++        if (!(ctx = ADS_TALLOC_INIT("ads_rmdir")))
++                goto exit_rmdir;
++ 
++        if (!(dpath = talloc_asprintf(ctx, "%s/%s%s",conn->origpath, path, add ? "/"ADS_FOLDER : "")))
++              goto exit_rmdir;
++              
++      /* remove folder .AppleDouble */
++        rrm_adsdir(ctx, dpath);
++ 
++exit_rmdir:
++      ret = SMB_VFS_NEXT_RMDIR(handle, conn, path);
++        talloc_destroy(ctx);
++
++      return ret;
++}
++
++/* ------------------------- */
++static int ads_open(HANDLE_PARAMETER connection_struct *conn, const char *fname, int flags, mode_t mode)
++{
++      int ret = 0;
++      char *ads_path = 0;
++      char *main_path = 0;
++      TALLOC_CTX *ctx;
++      SMB_STRUCT_STAT st;
++      SMB_STRUCT_STAT *main_info = &st;
++      
++      DEBUG(3,("ads: ads_open for %s %x\n", fname, flags));
++      if (!(ctx = ADS_TALLOC_INIT("ads_open")))
++              return -1;
++      /* convert to */
++      if (ads_build_paths(ctx, conn->origpath, fname, &ads_path, &main_path, &main_info, flags) < 0) {
++          talloc_destroy(ctx);
++          return -1;
++      }
++
++      ret = SMB_VFS_NEXT_OPEN(handle, conn, ads_path, flags, mode);
++      talloc_destroy(ctx);
++      return ret;
++
++}
++
++static int isDir(SMB_STRUCT_STAT *st)
++{
++     if (st == NULL) {
++         return 0;
++     }
++     return S_ISDIR(st->st_mode);
++}
++
++/* ------------------------- */
++static int ads_rename(HANDLE_PARAMETER connection_struct *conn, const char *old, const char *new)
++{
++      int ret = 0;
++      TALLOC_CTX *ctx;
++      char *ads_path = 0;
++      char *main_path = 0;
++      SMB_STRUCT_STAT st;
++      SMB_STRUCT_STAT *main_info = &st;
++      
++      DEBUG(3,("ads: ads_rename %s --> %sx\n", old, new));
++      
++      if (!(ctx = ADS_TALLOC_INIT("ads_rename")))
++          return -1;
++
++      if (ads_build_paths(ctx, conn->origpath, old, &ads_path, &main_path, &main_info, 0) < 0) {
++          talloc_destroy(ctx);
++          return -1;
++      }
++
++      if (ads_path != main_path) {
++          /* you can't rename an ads ! */
++          talloc_destroy(ctx);
++          errno = EINVAL;
++          return -1;
++      }
++
++      ret = SMB_VFS_NEXT_RENAME(handle, conn, old, new);
++      if (!ret && !isDir(main_info)) {
++          int  ptr1;
++          int  ptr2;
++          
++          char *ads_old  = ads_dir(ctx, conn->origpath, old, 0);
++          char *ads_new  = ads_dir(ctx, conn->origpath, new, 0);
++
++          /* is dest folder .Adouble there ? */
++          ptr1 = ads_get_path_ptr(ads_new);
++          ptr2 = ads_get_path_ptr(ads_old);
++
++          ads_new[ptr1] = '\0';
++          ads_old[ptr2] = '\0';
++          if (strcmp(ads_new, ads_old)) {
++              mkdir(ads_new, 0777);
++          }
++
++          ads_new[ptr1] = '/';
++          ads_old[ptr2] = '/';
++          
++          SMB_VFS_NEXT_RENAME(handle, conn, ads_old, ads_new);
++      }
++
++      talloc_destroy(ctx);
++      return ret;
++}
++
++/* ------------------------- 
++ * For an ADS what do we need to return , ADS ? main DATA?
++*/
++static int ads_stat(HANDLE_PARAMETER connection_struct *conn, const char *fname, SMB_STRUCT_STAT *sbuf)
++{
++      int ret = 0;
++      char *ads_path = 0;
++      char *main_path = 0;
++      TALLOC_CTX *ctx;
++      SMB_STRUCT_STAT st;
++      SMB_STRUCT_STAT *main_info = &st;
++
++      DEBUG(3,("ads: ads_stat for %s\n", fname));
++
++      if (!(ctx = ADS_TALLOC_INIT("ads_stat")))
++          return -1;
++      /* which inode ?
++      */
++      if (ads_build_paths(ctx, conn->origpath, fname, &ads_path, &main_path, &main_info, 0) < 0) {
++          talloc_destroy(ctx);
++          return -1;
++      }
++
++      ret = SMB_VFS_NEXT_STAT(handle, conn, ads_path, sbuf);
++      talloc_destroy(ctx);
++      return ret;
++}
++
++/* ------------------------- */
++static int ads_lstat(HANDLE_PARAMETER connection_struct *conn, const char *path, SMB_STRUCT_STAT *sbuf)
++{
++      int ret = 0;
++      char *ads_path = 0;
++      char *main_path = 0;
++      TALLOC_CTX *ctx;
++      SMB_STRUCT_STAT st;
++      SMB_STRUCT_STAT *main_info = &st;
++      
++      if (!(ctx = ADS_TALLOC_INIT("ads_lstat")))
++              return -1;
++      /* which inode ?
++      */
++      if (ads_build_paths(ctx, conn->origpath, path, &ads_path, &main_path, &main_info, 0) < 0) {
++          talloc_destroy(ctx);
++          return -1;
++      }
++
++      return SMB_VFS_NEXT_LSTAT(handle, conn, ads_path, sbuf);
++      talloc_destroy(ctx);
++      return ret;
++}
++
++/* ------------------------- */
++static int ads_unlink(HANDLE_PARAMETER connection_struct *conn, const char *path)
++{
++      int ret = 0;
++
++      char *ads_path = 0;
++      char *main_path = 0;
++      TALLOC_CTX *ctx;
++      SMB_STRUCT_STAT st;
++      SMB_STRUCT_STAT *main_info = &st;
++      
++      DEBUG(3,("ads: ads_unlink %s\n", path));
++      if (!(ctx = ADS_TALLOC_INIT("ads_unlink")))
++              return -1;
++
++      if (ads_build_paths(ctx, conn->origpath, path, &ads_path, &main_path, &main_info, 0) < 0) {
++          talloc_destroy(ctx);
++          return -1;
++      }
++
++      ret = SMB_VFS_NEXT_UNLINK(handle, conn, ads_path);
++      /*
++         if data stream
++            for each stream
++                unlink
++      */
++      if (!ret && ads_path == main_path) {
++          char *ads_base  = ads_dir(ctx, conn->origpath, path, isDir(main_info));
++          struct dirent *dent = 0;
++          DIR *dir = opendir(ads_base);
++          
++          if (dir) {
++              char *dpath;
++              
++              while (NULL != (dent = readdir(dir))) {
++                  if (strcmp(dent->d_name, ".") == 0 || strcmp(dent->d_name, "..") == 0)
++                      continue;
++                  if (!(dpath = talloc_asprintf(ctx, "%s/%s", ads_base, dent->d_name)))
++                      continue;
++                  /* XXX need to be root ?  */
++                  SMB_VFS_NEXT_UNLINK(handle, conn, dpath);               
++              }
++              closedir(dir);
++              rmdir(ads_base);
++          }
++      }
++
++      talloc_destroy(ctx);
++      return ret;
++}
++
++/* ------------------------- */
++static int ads_chmod(HANDLE_PARAMETER connection_struct *conn, const char *path, mode_t mode)
++{
++      int ret = 0;
++      char *ads_path = 0;
++      char *main_path = 0;
++      TALLOC_CTX *ctx;
++      SMB_STRUCT_STAT st;
++      SMB_STRUCT_STAT *main_info = &st;
++
++      DEBUG(3,("ads: ads_chmod %s\n", path));
++      /* if stream 
++             error ?, change only the stream
++      */
++      if (!(ctx = ADS_TALLOC_INIT("ads_chmod")))
++              return -1;
++
++      if (ads_build_paths(ctx, conn->origpath, path, &ads_path, &main_path, &main_info, 0) < 0) {
++          talloc_destroy(ctx);
++          return -1;
++      }
++
++      ret = SMB_VFS_NEXT_CHMOD(handle, conn, ads_path, mode);
++      /*
++         if data stream
++            for each stream
++                chmod
++      */
++      if (!ret && ads_path == main_path) {
++          char *ads_base  = ads_dir(ctx, conn->origpath, path, isDir(main_info));
++          struct dirent *dent = 0;
++          DIR *dir = opendir(ads_base);
++          
++          if (dir) {
++              char *dpath;
++              
++              while (NULL != (dent = readdir(dir))) {
++                  if (strcmp(dent->d_name, ".") == 0 || strcmp(dent->d_name, "..") == 0)
++                      continue;
++                  if (!(dpath = talloc_asprintf(ctx, "%s/%s", ads_base, dent->d_name)))
++                      continue;
++                  /* XXX need to be root ? */
++                  SMB_VFS_NEXT_CHMOD(handle, conn, dpath, mode);
++              }
++              closedir(dir);
++              /* XXX need to change ads_base too*/
++          }
++      }
++
++      talloc_destroy(ctx);
++      return ret;
++}
++
++/* ------------------------- */
++static int ads_chown(HANDLE_PARAMETER connection_struct *conn, const char *path, uid_t uid, gid_t gid)
++{
++      int ret = 0;
++      char *ads_path = 0;
++      char *main_path = 0;
++      TALLOC_CTX *ctx;
++      SMB_STRUCT_STAT st;
++      SMB_STRUCT_STAT *main_info = &st;
++
++      DEBUG(3,("ads: ads_chown %s\n", path));
++      /* if stream 
++             error ?, change only the stream
++      */
++      if (!(ctx = ADS_TALLOC_INIT("ads_chown")))
++              return -1;
++
++      if (ads_build_paths(ctx, conn->origpath, path, &ads_path, &main_path, &main_info, 0) < 0) {
++          talloc_destroy(ctx);
++          return -1;
++      }
++
++      ret = SMB_VFS_NEXT_CHOWN(handle, conn, ads_path, uid, gid);
++      /* if data stream
++            for each stream
++                chmod
++      */
++      if (!ret && ads_path == main_path) {
++          char *ads_base  = ads_dir(ctx, conn->origpath, path, isDir(main_info));
++          struct dirent *dent = 0;
++          DIR *dir = opendir(ads_base);
++          
++          if (dir) {
++              char *dpath;
++              
++              while (NULL != (dent = readdir(dir))) {
++                  if (strcmp(dent->d_name, ".") == 0 || strcmp(dent->d_name, "..") == 0)
++                      continue;
++                  if (!(dpath = talloc_asprintf(ctx, "%s/%s", ads_base, dent->d_name)))
++                      continue;
++                  /* XXX need to be root ?, what do we do in case of error? */
++                  SMB_VFS_NEXT_CHOWN(handle, conn, dpath, uid, gid);
++              }
++              closedir(dir);
++              SMB_VFS_NEXT_CHOWN(handle, conn, ads_path, uid, gid);
++          }
++      }
++
++      talloc_destroy(ctx);
++      return ret;
++}
++
++/* ------------------------- */
++static int ads_chdir(HANDLE_PARAMETER connection_struct *conn, const char *path)
++{
++      DEBUG(3,("ads: ads_chdir for %s\n", path));
++      return SMB_VFS_NEXT_CHDIR(handle, conn, path);
++}
++
++static int ads_utime(HANDLE_PARAMETER connection_struct *conn, const char *path, struct utimbuf *times)
++{
++      return SMB_VFS_NEXT_UTIME(handle, conn, path, times);
++}
++
++
++static BOOL ads_symlink(HANDLE_PARAMETER connection_struct *conn, const char *oldpath, const char *newpath)
++{
++      return SMB_VFS_NEXT_SYMLINK(handle, conn, oldpath, newpath);
++}
++
++static BOOL ads_readlink(HANDLE_PARAMETER connection_struct *conn, const char *path, char *buf, size_t bufsiz)
++{
++      return SMB_VFS_NEXT_READLINK(handle, conn, path, buf, bufsiz);
++}
++
++static int ads_link( HANDLE_PARAMETER connection_struct *conn, const char *oldpath, const char *newpath)
++{
++      return SMB_VFS_NEXT_LINK(handle, conn, oldpath, newpath);
++}
++
++static int ads_mknod(HANDLE_PARAMETER connection_struct *conn, const char *path, mode_t mode, SMB_DEV_T dev)
++{
++      return SMB_VFS_NEXT_MKNOD(handle, conn, path, mode, dev);
++}
++
++static char *ads_realpath(HANDLE_PARAMETER connection_struct *conn, const char *path, char *resolved_path)
++{
++      return SMB_VFS_NEXT_REALPATH(handle, conn, path, resolved_path);
++}
++
++static BOOL ads_set_nt_acl(HANDLE_PARAMETER files_struct *fsp, const char *name, uint32 security_info_sent, struct security_descriptor_info *psd)
++{
++      return SMB_VFS_NEXT_SET_NT_ACL(handle, fsp, name, security_info_sent, psd);
++}
++
++static int ads_chmod_acl(HANDLE_PARAMETER connection_struct *conn, const char *name, mode_t mode)
++{
++      /* If the underlying VFS doesn't have ACL support... */
++#ifdef ADS_NEW_MODULE
++        if (!handle->vfs_next.ops.chmod_acl) {                                                                          
++#else
++      if (!default_vfs_ops.chmod_acl) {
++#endif
++              errno = ENOSYS;
++              return -1;
++      }
++      return SMB_VFS_NEXT_CHMOD_ACL(handle, conn, name, mode);
++}
++
++static SMB_ACL_T ads_sys_acl_get_file(HANDLE_PARAMETER connection_struct *conn, const char *path_p, SMB_ACL_TYPE_T type)
++{
++      return SMB_VFS_NEXT_SYS_ACL_GET_FILE(handle, conn, path_p, type);
++}
++
++static int ads_sys_acl_set_file(HANDLE_PARAMETER connection_struct *conn, const char *name, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl)
++{
++      return SMB_VFS_NEXT_SYS_ACL_SET_FILE(handle, conn, name, acltype, theacl);
++}
++
++static int ads_sys_acl_delete_def_file(HANDLE_PARAMETER connection_struct *conn, const char *path)
++{
++      return SMB_VFS_NEXT_SYS_ACL_DELETE_DEF_FILE(handle, conn, path);
++}
++
++#ifdef        ADS_NEW_MODULE 
++static ssize_t ads_getxattr(vfs_handle_struct *handle, struct connection_struct *conn,const char *path, const char *name, void *value, size_t size)
++{
++        return SMB_VFS_NEXT_GETXATTR(handle, conn, path, name, value, size);
++}
++
++static ssize_t ads_lgetxattr(vfs_handle_struct *handle, struct connection_struct *conn,const char *path, const char *name, void *value, size_t
++size)
++{
++        return SMB_VFS_NEXT_LGETXATTR(handle, conn, path, name, value, size);
++}
++
++static ssize_t ads_fgetxattr(vfs_handle_struct *handle, struct files_struct *fsp,int fd, const char *name, void *value, size_t size)
++{
++        return SMB_VFS_NEXT_FGETXATTR(handle, fsp, fd, name, value, size);
++}
++
++static ssize_t ads_listxattr(vfs_handle_struct *handle, connection_struct *conn,const char *path, char *list, size_t size)
++{
++        return SMB_VFS_NEXT_LISTXATTR(handle, conn, path, list, size);
++}
++
++static ssize_t ads_llistxattr(vfs_handle_struct *handle,struct connection_struct *conn,const char *path, char *list, size_t size)
++{
++        return SMB_VFS_NEXT_LLISTXATTR(handle, conn, path, list, size);
++}
++
++static int ads_removexattr(vfs_handle_struct *handle, struct connection_struct *conn,const char *path, const char *name)
++{
++        return SMB_VFS_NEXT_REMOVEXATTR(handle, conn, path, name);
++}
++
++static int ads_lremovexattr(vfs_handle_struct *handle, struct connection_struct *conn,const char *path, const char *name)
++{
++        return SMB_VFS_NEXT_LREMOVEXATTR(handle, conn, path, name);
++}
++
++static int ads_fremovexattr(vfs_handle_struct *handle, struct files_struct *fsp,int fd, const char *name)
++{
++        return SMB_VFS_NEXT_FREMOVEXATTR(handle, fsp, fd, name);
++}
++
++static int ads_setxattr(vfs_handle_struct *handle, struct connection_struct *conn,const char *path, const char *name, const void *value, size_t size, int flags)
++{
++        return SMB_VFS_NEXT_SETXATTR(handle, conn, path, name, value, size, flags);
++}
++
++static int ads_lsetxattr(vfs_handle_struct *handle, struct connection_struct *conn,const char *path, const char *name, const void *value, size_t size, int flags)
++{
++        return SMB_VFS_NEXT_LSETXATTR(handle, conn, path, name, value, size, flags);
++}
++
++static int ads_fsetxattr(vfs_handle_struct *handle, struct files_struct *fsp,int fd, const char *name, const void *value, size_t size, int flags)
++{
++        return SMB_VFS_NEXT_FSETXATTR(handle, fsp, fd, name, value, size, flags);
++}
++
++#endif
++
++/* ---------------------------------- 
++ * enumerate 
++*/
++static ssize_t ads_listads(HANDLE_PARAMETER struct connection_struct *conn,const char *path, char *list, size_t size)
++{
++      char *ads_path = 0;
++      char *main_path = 0;
++      TALLOC_CTX *ctx;
++      size_t     len, total = 0;
++      SMB_STRUCT_STAT st;
++      SMB_STRUCT_STAT *main_info = &st;
++      
++
++      if (!list || !path) {
++              /* aka we have ads functionnality */
++              return 0;
++      }
++
++      DEBUG(3,("ads: ads_listads %s\n", path));
++
++      if (!(ctx = ADS_TALLOC_INIT("ads_listads")))
++              return -1;
++
++      if (ads_build_paths(ctx, conn->origpath, path, &ads_path, &main_path, &main_info, 0) < 0) {
++          talloc_destroy(ctx);
++          return -1;
++      }
++
++      /*
++         if data stream
++            for each stream
++      */
++      if (ads_path == main_path) {
++          char *ads_base  = ads_dir(ctx, conn->origpath, path, isDir(main_info));
++          struct dirent *dent = 0;
++          DIR *dir = opendir(ads_base);
++          
++          /* XXX need to be root ? */
++          if (dir) {
++              
++              while (NULL != (dent = readdir(dir))) {
++                  if (strcmp(dent->d_name, ".") == 0 || strcmp(dent->d_name, "..") == 0)
++                      continue;
++                  len = strlen(dent->d_name) +8 ;
++                  total += len;
++                  if (total >= size) {
++                      talloc_destroy(ctx);
++                      errno = ERANGE;
++                      return -1;
++                  }
++                  snprintf (list, len, ":%s:$DATA", dent->d_name);
++                  list += len;
++              }
++              closedir(dir);
++          }
++      }
++
++      talloc_destroy(ctx);
++      return total;
++}
++
++/* ------------------------------------
++ * VFS operations structure */
++
++#ifndef SMB_VFS_OP
++#define SMB_VFS_OP(x) ((void *) x)  
++#endif
++
++static vfs_op_tuple ads_op_tuples[] = {
++
++      /* Disk operations */
++
++      {SMB_VFS_OP(ads_disk_free),                     SMB_VFS_OP_DISK_FREE,           SMB_VFS_LAYER_TRANSPARENT},
++      
++      /* Directory operations */
++
++      {SMB_VFS_OP(ads_opendir),                       SMB_VFS_OP_OPENDIR,             SMB_VFS_LAYER_TRANSPARENT},
++      {SMB_VFS_OP(ads_readdir),                       SMB_VFS_OP_READDIR,             SMB_VFS_LAYER_TRANSPARENT},
++      {SMB_VFS_OP(ads_mkdir),                         SMB_VFS_OP_MKDIR,               SMB_VFS_LAYER_TRANSPARENT},
++      {SMB_VFS_OP(ads_rmdir),                         SMB_VFS_OP_RMDIR,               SMB_VFS_LAYER_TRANSPARENT},
++
++      /* File operations */
++
++      {SMB_VFS_OP(ads_open),                          SMB_VFS_OP_OPEN,                SMB_VFS_LAYER_TRANSPARENT},
++      {SMB_VFS_OP(ads_rename),                        SMB_VFS_OP_RENAME,              SMB_VFS_LAYER_TRANSPARENT},
++      {SMB_VFS_OP(ads_stat),                          SMB_VFS_OP_STAT,                SMB_VFS_LAYER_TRANSPARENT},
++      {SMB_VFS_OP(ads_lstat),                         SMB_VFS_OP_LSTAT,               SMB_VFS_LAYER_TRANSPARENT},
++      {SMB_VFS_OP(ads_unlink),                        SMB_VFS_OP_UNLINK,              SMB_VFS_LAYER_TRANSPARENT},
++      {SMB_VFS_OP(ads_chmod),                         SMB_VFS_OP_CHMOD,               SMB_VFS_LAYER_TRANSPARENT},
++      {SMB_VFS_OP(ads_chown),                         SMB_VFS_OP_CHOWN,               SMB_VFS_LAYER_TRANSPARENT},
++      {SMB_VFS_OP(ads_chdir),                         SMB_VFS_OP_CHDIR,               SMB_VFS_LAYER_TRANSPARENT},
++      {SMB_VFS_OP(ads_utime),                         SMB_VFS_OP_UTIME,               SMB_VFS_LAYER_TRANSPARENT},
++      {SMB_VFS_OP(ads_symlink),                       SMB_VFS_OP_SYMLINK,             SMB_VFS_LAYER_TRANSPARENT},
++      {SMB_VFS_OP(ads_readlink),                      SMB_VFS_OP_READLINK,            SMB_VFS_LAYER_TRANSPARENT},
++      {SMB_VFS_OP(ads_link),                          SMB_VFS_OP_LINK,                SMB_VFS_LAYER_TRANSPARENT},
++      {SMB_VFS_OP(ads_mknod),                         SMB_VFS_OP_MKNOD,               SMB_VFS_LAYER_TRANSPARENT},
++      {SMB_VFS_OP(ads_realpath),                      SMB_VFS_OP_REALPATH,            SMB_VFS_LAYER_TRANSPARENT},
++
++      /* NT File ACL operations */
++
++      {SMB_VFS_OP(ads_set_nt_acl),                    SMB_VFS_OP_SET_NT_ACL,          SMB_VFS_LAYER_TRANSPARENT},
++
++      /* POSIX ACL operations */
++
++      {SMB_VFS_OP(ads_chmod_acl),                     SMB_VFS_OP_CHMOD_ACL,           SMB_VFS_LAYER_TRANSPARENT},
++
++      {SMB_VFS_OP(ads_sys_acl_get_file),              SMB_VFS_OP_SYS_ACL_GET_FILE,            SMB_VFS_LAYER_TRANSPARENT},
++      {SMB_VFS_OP(ads_sys_acl_set_file),              SMB_VFS_OP_SYS_ACL_SET_FILE,            SMB_VFS_LAYER_TRANSPARENT},
++      {SMB_VFS_OP(ads_sys_acl_delete_def_file),       SMB_VFS_OP_SYS_ACL_DELETE_DEF_FILE,     SMB_VFS_LAYER_TRANSPARENT},
++#ifdef        ADS_NEW_MODULE
++      /* EA operations. */
++      {SMB_VFS_OP(ads_getxattr),                      SMB_VFS_OP_GETXATTR,                    SMB_VFS_LAYER_TRANSPARENT},
++      {SMB_VFS_OP(ads_lgetxattr),                     SMB_VFS_OP_LGETXATTR,                   SMB_VFS_LAYER_TRANSPARENT},
++      {SMB_VFS_OP(ads_fgetxattr),                     SMB_VFS_OP_FGETXATTR,                   SMB_VFS_LAYER_TRANSPARENT},
++      {SMB_VFS_OP(ads_listxattr),                     SMB_VFS_OP_LISTXATTR,                   SMB_VFS_LAYER_TRANSPARENT},
++      {SMB_VFS_OP(ads_llistxattr),                    SMB_VFS_OP_LLISTXATTR,                  SMB_VFS_LAYER_TRANSPARENT},
++      {SMB_VFS_OP(ads_removexattr),                   SMB_VFS_OP_REMOVEXATTR,                 SMB_VFS_LAYER_TRANSPARENT},
++      {SMB_VFS_OP(ads_lremovexattr),                  SMB_VFS_OP_LREMOVEXATTR,                SMB_VFS_LAYER_TRANSPARENT},
++      {SMB_VFS_OP(ads_fremovexattr),                  SMB_VFS_OP_FREMOVEXATTR,                SMB_VFS_LAYER_TRANSPARENT},
++      {SMB_VFS_OP(ads_setxattr),                      SMB_VFS_OP_SETXATTR,                    SMB_VFS_LAYER_TRANSPARENT},
++      {SMB_VFS_OP(ads_lsetxattr),                     SMB_VFS_OP_LSETXATTR,                   SMB_VFS_LAYER_TRANSPARENT},
++      {SMB_VFS_OP(ads_fsetxattr),                     SMB_VFS_OP_FSETXATTR,                   SMB_VFS_LAYER_TRANSPARENT},
++#endif
++      /* ADS operations */
++      {SMB_VFS_OP(ads_listads),                       SMB_VFS_OP_LISTADS,                     SMB_VFS_LAYER_TRANSPARENT},
++
++      {NULL,                                          SMB_VFS_OP_NOOP,                        SMB_VFS_LAYER_NOOP}
++};
++
++#ifdef ADS_NEW_MODULE
++
++#if 0
++NTSTATUS vfs_ads_init(void)
++{
++        return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "ads", ads_op_tuples);
++}
++#endif
++
++NTSTATUS vfs_ads_init(void)
++{
++        DEBUG(3, ("ADS: vfs_ads_init\n"));
++        return NT_STATUS_OK;
++}
++         
++
++NTSTATUS init_module(void)
++{
++      DEBUG(3, ("ADS: init_module\n" ));
++        return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "ads", ads_op_tuples);
++}
++
++#else
++/* VFS initialisation function.  Return vfs_op_tuple array back to SAMBA. */
++vfs_op_tuple *vfs_init(int *vfs_version, struct vfs_ops *def_vfs_ops,struct smb_vfs_handle_struct *vfs_handle)
++{
++      *vfs_version = SMB_VFS_INTERFACE_VERSION;
++        memcpy(&default_vfs_ops, def_vfs_ops, sizeof(struct vfs_ops));
++                   
++        ads_handle = vfs_handle;
++        DEBUG(3, ("ADS: vfs module loaded\n"));
++        return ads_op_tuples;
++}
++                                             
++/* VFS finalization function. */
++void vfs_done(connection_struct *conn)
++{
++      DEBUG(3, ("ADS: vfs module unloaded\n"));
++}
++
++#endif
index 10ff466852d7092ca22c04f9acb7c56a440a73f9..e1776e224ae1cc04d50ec94fe6b286b8b2255160 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: timeout.c,v 1.4 2001-07-31 19:49:37 srittau Exp $
+ * $Id: timeout.c,v 1.5 2005-04-28 20:49:36 bfernhomberg Exp $
  */
 
 #ifdef HAVE_CONFIG_H
@@ -163,7 +163,8 @@ main (argc, argv)
 
        av = argv;
 
-       while ((i = getopt (argc, argv, "s:")) != -1) {
+       while ((i = getopt (argc, argv, "+s:")) != -1) {
+
                switch (i) {
                case 's':
                        if (isdigit (*optarg)) {
index 0a7b3665b69293fcaf1fc0bfe82687a8f7017d28..0d52d6241bcf6532d3737e3f9a66037bc3937592 100644 (file)
@@ -7,3 +7,4 @@ apple_rm
 cleanappledouble.pl
 netatalkshorternamelinks.pl
 lp2pap.sh
+asip-status.pl
index 6584ae14f1b1bfcf71f472b7294fe9a2548046e7..aef4e6c7339128401bd2e70fc8654c564132e774 100644 (file)
@@ -2,16 +2,24 @@
 
 pkgconfdir = @PKGCONFDIR@
 
-GENERATED_FILES = \
+GENERATED_FILES = lp2pap.sh
+TEMPLATE_FILES = lp2pap.sh.tmpl
+PERLSCRIPTS = \
        afpd-mtab.pl                    \
        apple_cp apple_mv apple_rm      \
        cleanappledouble.pl             \
-       lp2pap.sh                       \
-       netatalkshorternamelinks.pl
-TEMPLATE_FILES = $(foreach f,$(GENERATED_FILES),$(f).in)
+       asip-status.pl
+
+SUFFIXES = .tmpl .
+
+.tmpl:
+       sed -e s@:BINDIR:@${bindir}@ \
+               -e s@:SBINDIR:@${sbindir}@ \
+               -e s@:ETCDIR:@${pkgconfdir}@ \
+               <$< >$@
 
 CLEANFILES = $(GENERATED_FILES)
 
-bin_SCRIPTS = $(GENERATED_FILES)
+bin_SCRIPTS = $(PERLSCRIPTS) $(GENERATED_FILES)
 
-EXTRA_DIST = $(TEMPLATE_FILES)
+EXTRA_DIST = $(PERLSCRIPTS) $(TEMPLATE_FILES)
diff --git a/contrib/shell_utils/asip-status.pl.in b/contrib/shell_utils/asip-status.pl.in
new file mode 100755 (executable)
index 0000000..226ec9e
--- /dev/null
@@ -0,0 +1,521 @@
+#!@PERL@
+#
+# asip-status - send DSIGetStatus to an AppleShare IP file server (aka
+#               ASIP, aka AFP over TCP port 548).  A returned UAM of 
+#               "No User Authen" means that the server supports guest access.
+#
+# author: James W. Abendschan  <jwa@jammed.com>
+# license: GPL - http://www.gnu.org/copyleft/gpl.html
+# url: http://www.jammed.com/~jwa/hacks/security/asip/
+# date: 7 May 1997 (v1.0)
+# see also: 
+#   - http://developer.apple.com/techpubs/macos8/NetworkCommSvcs/AppleShare/
+#   - http://www2.opendoor.com/asip/   (excellent Mac sharing / security site)
+#
+# todo: log in as guest & get a list of shares
+#
+# $Id: asip-status.pl.in,v 1.2 2005-04-28 20:49:36 bfernhomberg Exp $
+#
+
+use strict;
+use IO::Socket;                        # sucks because Timeout doesn't
+
+my ($arg);
+my ($host);
+
+while ($arg = shift @ARGV)
+{
+       $main::show_icon = 1 if ($arg eq "-i");
+       $main::debug = 1 if ($arg eq "-d");
+       $main::hexdump = 1 if ($arg eq "-x");
+       $host = $arg if ($arg !~ /^-/);
+}
+
+if ($host eq "")
+{
+       print "usage: $0 hostname [-i show icon] [-d debug] [-x hex dump]\n";
+       exit(-1);
+}
+
+my ($packet) = build_packet();
+my ($code) = sendpacket($host, 548, $packet);
+exit $code;
+
+
+sub build_packet 
+{
+       my (@packet) = 
+               (
+               0x00,                   # 0- request, 1-reply
+               0x03,                   # 3- DSIGetStatus
+               0xde, 0xad, 0x00,       # request ID
+               0x00, 0x00, 0x00, 0x00, # data field
+               0x00, 0x00, 0x00, 0x00, # length of data stream header
+               0x00, 0x00, 0x00, 0x00  # reserved
+               );
+
+
+        my ($packet) = pack("C*", @packet);
+
+       return $packet;
+
+}
+
+sub sendpacket 
+{
+       my ($host, $port, $packet) = @_;
+       my ($b, $buf);
+
+       print "opening $host:$port\n" if ($main::debug);
+
+       my ($asip_sock) = IO::Socket::INET->new( 
+               PeerAddr => $host, 
+               PeerPort => $port, 
+               Proto => 'tcp', 
+               Type => SOCK_STREAM, 
+               Timeout => 10
+               ) || die "connect to $host failure: $!"; 
+       $asip_sock->autoflush(1);
+
+       print "sending packet\n" if ($main::debug);
+
+       my ($count) = syswrite($asip_sock, $packet, length($packet));
+
+       if ($count != length($packet))
+       {
+               print "only wrote $count of " . length($packet) . " bytes?\n";
+               exit(-1);
+       }
+
+       # reply can span multiple packets
+
+       print "sysread: " if ($main::debug);
+       while (sysread($asip_sock, $b, 256))
+       {
+               $buf .= $b;
+               print "." if ($main::debug);
+       }       
+
+       close ($asip_sock);
+
+       print " read " . length($buf) . " bytes\n" if ($main::debug);
+
+       if (length($buf) == 0)
+       {
+               print "empty reply packet?\n";
+               return -2;
+       }
+       else
+       {
+               print "AFP reply from $host:$port\n";
+               return (parse_packet($buf));
+       }       
+}
+
+
+sub parse_packet 
+{
+       my ($buf) = shift @_;
+       my (@packet);
+       my ($i);
+
+       hexdump($buf) if ($main::hexdump);
+
+       for ($i=0;$i<length($buf);$i++)
+       {
+               push(@packet, substr($buf, $i, 1));
+       }       
+
+       my ($flags) = unpack("C", @packet[0]);
+       my ($cmd) = unpack("C", @packet[1]);
+
+       my ($request_id) = unpack("n", @packet[2] . @packet[3]);
+       print "Flags: $flags  Cmd: $cmd  ID: $request_id\n";
+
+       print getasipsrv("flags", $flags) . ": " . getasipsrv("command", $cmd) . "\n";
+       print "Request ID: $request_id\n";
+
+       print "** Request ID didn't match what we sent!\n" if ($request_id != 0xdead);
+
+       # "Error Code / Enclosed Data Offset"
+       # I have never seen this be non-zero ..
+
+       my ($edo) = unpack("N2", @packet[4] . @packet[5] . @packet[6] . @packet[7]);
+       print "** Wow, a non-zero Error/Enclosed Data Offset: $edo\n" if ($edo);
+
+       # "Total Data Length"
+
+       my ($datalen) = unpack("N2", @packet[8] . @packet[9] . @packet[10] . @packet[11]);
+
+       print "Total data length: $datalen\n" if ($main::debug);
+
+       # "Reserved Field"
+
+       my ($reserved) = unpack("N2", @packet[12] . @packet[13] . @packet[14] . @packet[15]);
+
+       print "Reserved field: $reserved\n" if ($reserved);
+
+       if ($cmd != 3)
+       {
+               print "I can only parse packets of reply-type DSIGetStatus (3)\n";
+               print "This is reply-type " . getasipsrv("command", $cmd) . "\n";
+       }
+       if ($datalen == 0)
+       {
+               print "No data in packet?\n";
+       }       
+       if (($datalen > 0) && ($cmd == 3)) 
+       {
+               my (@AFPpacket) = @packet[($edo+16)..($edo+16+$datalen)];
+               return (parse_FPGetSrvrInfo(@AFPpacket));
+       }
+       else
+       {
+               print "I don't know how to parse this type of packet.\n";
+               return(2);
+       }       
+}
+
+
+
+sub parse_FPGetSrvrInfo() 
+{
+       my (@packet) = @_;
+       my ($i);
+
+       my ($machinetype_offset) = unpack("n", @packet[0] . @packet[1]);
+       print "Machine type offset in packet: $machinetype_offset\n" if ($main::debug);
+       my ($machinetype) = extract(1, $machinetype_offset, @packet);
+       print "Machine type: $machinetype\n";
+
+       my ($afpversioncount_offset) = unpack("n", @packet[2] . @packet[3]);
+       print "AFPversion count offset: $afpversioncount_offset\n" if ($main::debug);
+       my (@afpversions) = extract(0, $afpversioncount_offset, @packet);
+       print "AFP versions: " . join(",", @afpversions) . "\n";
+
+       my ($uamcount_offset) = unpack("n", @packet[4] . @packet[5]);
+       print "UAMcount offset: $uamcount_offset\n" if ($main::debug);
+       my (@uams) = extract(0, $uamcount_offset, @packet);
+       print "UAMs: " . join(",", @uams) . "\n";
+
+       my ($allow_guest) = 0;
+       $allow_guest = 1 if (grep(/No User Authen/, @uams));
+
+       # it would be cute to see the icon.
+
+       my ($icon_offset) = unpack("n", @packet[6] . @packet[7]);
+       print "Volume Icon & Mask offset: $icon_offset\n" if ($main::debug);
+
+       my ($flags) = unpack("n", @packet[8] . @packet[9]);
+       my (@flags) = parse_afp_flags($flags);
+
+       print "Flags: ";
+       print "$flags - " if ($main::debug);
+       print join(",", @flags) . "\n";
+
+       # server name starts at offset+10, length byte first.
+
+       my ($servername_len) = unpack("C1", @packet[10]);
+       my ($servername) = join("", @packet[11..(11+$servername_len-1)]);
+       print "Server name length: $servername_len\n" if ($main::debug);
+       print "Server name: $servername\n";
+
+       my ($offset) = 11 + $servername_len;
+
+       # quietly ++ the $offset to account for the padding that happens
+       # in the reply packet if the field names don't align on an even boundary
+
+       $offset++ if ($servername_len % 2 == 0);
+
+       print "New offset: $offset\n" if ($main::debug);
+
+       my ($signature_offset) = unpack("n2", @packet[$offset] . @packet[$offset+1]);
+       print "Signature offset: $signature_offset\n" if ($main::debug);
+       if ($signature_offset)
+       {
+                my ($signature) = join("",  @packet[$signature_offset..$signature_offset+15]);
+
+               print "Signature:\n";   
+               hexdump($signature);
+       }
+
+       my ($network_address_count_offset) = unpack("n2", @packet[$offset+2] . @packet[$offset+3]);
+       print "Network address count offset: $network_address_count_offset\n" if ($main::debug);
+
+       extract_network_address($network_address_count_offset, @packet);
+
+       $offset += 4;
+       if ($flags & (1<<8)) { # Supports directory services
+               my ($directory_service_offset) = unpack("n2", @packet[$offset] . @packet[$offset+1]);
+               print "Directory service offset: $directory_service_offset\n" if ($main::debug);
+               if ($directory_service_offset)
+               {
+                       my (@dirsvcs) = extract(0, $directory_service_offset, @packet);
+                       while (@dirsvcs)
+                       {
+                               printf "Directory Service: %s\n", shift @dirsvcs;
+                       }
+               }
+               $offset +=2;
+       }
+
+       if ($flags & (1<<9)) { # Supports UTF8 servername
+               my ($utf8_name_offset) = unpack("n2", @packet[$offset] . @packet[$offset+1]);
+               print "UTF8 name offset: $utf8_name_offset\n" if ($main::debug);
+               if ($utf8_name_offset)
+               {
+                       my ($utf8name) = extract(1, $utf8_name_offset+1, @packet);
+                       print "UTF8 Servername: $utf8name\n";
+               }
+       }
+
+       draw_icon($icon_offset, @packet) if ($main::show_icon);
+
+       return $allow_guest;
+}
+
+# getsrvbyname .. sorta ..
+
+sub getasipsrv 
+{
+       my ($what, $code) = @_;
+
+       if ($what eq "flags") 
+       {
+               return "Request" if ($code == 0);
+               return "Reply" if ($code == 1); 
+       }
+
+       if ($what eq "command") 
+       {
+               return "DSICloseSession" if ($code == 1);
+               return "DSICommand" if ($code == 2);
+               return "DSIGetStatus" if ($code == 3);
+               return "DSIOpenSession" if ($code == 4);
+               return "DSITickle" if ($code == 5);
+               return "DSIWrite" if ($code == 6);
+               return "DSIAttention" if ($code == 7);
+       }
+       return "[$what/$code] unknown";
+}
+
+
+# return "counted" data at @packet[$offset]
+# when called with a zero as the first argument, this will
+# look in the packet for the count.  Otherwise, it will
+# assume I know what I'm doing.  (hah, what a foolish function..)
+
+sub extract 
+{
+       my ($count, $offset, @packet) = @_;
+       my ($i, $j);
+       my (@items, $data);
+       my ($hack);
+
+       if ($count == 0)
+       {
+               ($count) = unpack("C", @packet[$offset]);
+               return if ($count == 0);
+               $offset++;
+       }
+       else
+       {
+               $hack = 1;
+       }       
+       #print ">> extracting $count items from offset $offset\n";
+       for ($i=0;$i<$count;$i++)
+       {
+               #print "Working on count $i\n";
+               my ($len) = unpack("C1", @packet[$offset]);
+               $data = join("",  @packet[$offset+1..$offset+$len]);
+               #print "$i. [$data] ($len)\n";
+               push (@items, $data);
+               $offset = $offset + $len + 1;
+               #print "new offset is $offset\n";
+       }
+       return $data if ($hack);
+       return @items;
+}
+
+sub draw_icon
+{
+       my ($offset, @packet) = @_;
+       my ($cols);
+       my ($i, $j);
+
+       # icons are 32x32 bitmaps; 128 byte icon + 128 byte mask
+       # to show the mask, change 128 to 256.  
+
+       for ($i=0;$i<128;$i++)
+       {
+               my ($c) = @packet[$i+$offset];
+               my ($bin) = unpack ("B*", $c);
+
+               for ($j=0;$j<8;$j++)
+               {
+                       if (substr($bin, $j, 1))
+                       {
+                               print "#";
+                       }
+                       else
+                       {
+                               print " ";
+                       }
+               }       
+               $cols++;
+               if ($cols == 4)
+               {
+                       $cols = 0;
+                       print "\n";
+               }
+
+       }
+       print "\n";
+}
+
+
+sub parse_afp_flags
+{
+       my ($flags) = shift @_;
+       my (@flags);
+
+       # $flags is a 16 bit little-endian number
+
+       push (@flags, "SupportsCopyFile") if ($flags & (1<<0));
+       push (@flags, "SupportsChgPwd") if ($flags & (1<<1));
+       push (@flags, "DontAllowSavePwd") if ($flags & (1<<2));
+       push (@flags, "SupportsServerMessages") if ($flags & (1<<3));
+       push (@flags, "SupportsServerSignature") if ($flags & (1<<4));
+       push (@flags, "SupportsTCP/IP") if ($flags & (1<<5));
+       push (@flags, "SupportsSrvrNotifications") if ($flags & (1<<6));
+       push (@flags, "SupportsReconnect") if ($flags & (1<<7));
+       push (@flags, "SupportsOpenDirectory") if ($flags & (1<<8));
+       push (@flags, "SupportsUTF8Servername") if ($flags & (1<<9));
+       push (@flags, "SupportsSuperClient") if ($flags & (1<<15));
+
+       return @flags;
+}
+
+
+sub hexdump
+{
+       my ($buf) = @_;
+       my ($p, $c, $pc, $str);
+       my ($i);
+
+       for ($i=0;$i<length($buf);$i++)
+       {
+               $p = substr($buf, $i, 1);
+               $c = ord ($p);
+               printf "%.2x ", $c;
+               $pc++;
+               if (($c > 31) && ($c < 127))
+               {
+                       $str .= $p;
+               }
+               else
+               {
+                       $str .= ".";
+               }       
+               if ($pc == 16)
+               {
+                       print " $str\n";
+                       undef $str;
+                       $pc = 0;
+               }       
+       }
+       print "   " x (16 - $pc);
+       print " $str \n";
+}
+
+
+sub extract_network_address
+{
+       my ($offset, @packet) = @_;
+       my ($count);
+       my ($i) = 0;
+       my ($data);
+
+       # get the number of addresses
+        ($count) = unpack("C", @packet[$offset]);
+        return if ($count == 0);
+        $offset++;
+
+        #print "\n>> extracting $count items from offset $offset\n";
+        for ($i=0;$i<$count;$i++)
+        {
+                #print "Working on count $i\n";
+                my ($len) = unpack("C1", @packet[$offset]);
+               #printf "len:  %u\n",$len;
+               my ($type) = unpack("C1", @packet[$offset+1]);
+               #printf "type: %u\n",$type;
+                $data = join("",  @packet[$offset+2..$offset+$len-1]);
+                #print "$i. [$data] ($len)\n";
+                $offset = $offset + $len ;
+                #print "new offset is $offset\n";
+
+
+               # 1st byte is 'tag'
+               # 1 - IP address; 4 bytes
+               # 2 - IP address (4) + port (2)
+               # 3 - DDP (2 bytes net, 1 byte node, 1 byte socket)
+               # 4 - DNS address
+               # 5 - IP address (4) + port (2), for SSH tunnel
+               # 6 - IPV6 address (16)
+               # 7 - IPV6 address (16) + port (2)
+
+               my (@nap) = unpack("C*", $data);
+
+               if ($type == 1)
+               {
+                       # quad
+                       my ($ip) = sprintf "%d.%d.%d.%d (TCP/IP address)",
+                               $nap[0], $nap[1], @nap[2], @nap[3];
+       
+                       print "Network address: $ip\n";
+               }
+               elsif ($type == 2)
+               {
+                       # quad+port
+                       my ($ipport) = sprintf "%d.%d.%d.%d:%d",
+                               @nap[0], @nap[1], @nap[2], @nap[3], (@nap[4]*256 + @nap[5]);
+                       print "Network address: $ipport (TCP/IP address and port)\n";
+               }
+               elsif ($type == 3)
+               {
+                       printf "Network address: %d.%d (ddp address)\n",
+                               (@nap[0] * 256) + @nap[1], @nap[2];
+               }
+               elsif ($type == 4)
+               {
+                       print "Network address: $data (DNS address)\n";
+               }
+               elsif ($type == 5)
+               {
+                       # according to the specs this should be an IP address
+                       # however, OSX Server uses the FQDN instead
+                       print "Network address: $data (SSH tunnel address)\n";
+               }
+               elsif ($type == 6 || $type == 7)
+               {
+                       print "Network address: ";
+                       my ($j) = 0;
+                       for ( $j = 0; $j<=13; $j = $j+2) {
+                               printf("%.2x%.2x:", @nap[$j], @nap[$j+1]);
+                       }
+                       printf("%.2x%.2x", @nap[14], @nap[15]);
+                       if ($type == 7 ) {
+                               printf(":%d", (@nap[16]*256) + @nap[17]);
+                               print " (IPv6 address + port)\n";
+                       }
+                       else {
+                               print " (IPv6 address)\n";
+                       }
+               }
+               else 
+               {
+                       printf "unsupported address type: %u\n", $type;
+               }
+
+        }
+}
diff --git a/contrib/shell_utils/lp2pap.sh.in b/contrib/shell_utils/lp2pap.sh.in
deleted file mode 100644 (file)
index ae3b6f3..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-#!/bin/sh
-# pap script for lp systems
-
-chdir "/etc/lp/printers/`basename $0`"
-
-if [ -r "$6" ]; then
-    @bindir@/pap -E "$6"
-    exit $?
-fi
-
-exit 2
diff --git a/contrib/shell_utils/lp2pap.sh.tmpl b/contrib/shell_utils/lp2pap.sh.tmpl
new file mode 100755 (executable)
index 0000000..fea0cf4
--- /dev/null
@@ -0,0 +1,11 @@
+#!/bin/sh
+# pap script for lp systems
+
+chdir "/etc/lp/printers/`basename $0`"
+
+if [ -r "$6" ]; then
+    :BINDIR:/pap -E "$6"
+    exit $?
+fi
+
+exit 2
diff --git a/contrib/shell_utils/netatalkshorternamelinks.pl.in b/contrib/shell_utils/netatalkshorternamelinks.pl.in
deleted file mode 100644 (file)
index 1c4f2b7..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-#!@PERL@
-#
-# $Id: netatalkshorternamelinks.pl.in,v 1.1 2002-01-17 05:59:25 srittau Exp $
-# 
-# (c) 2000 Christian Wolff, scarabaeus@scarabaeus.org
-# quick hack to create symbolic links for files with names over 31 chars long 
-# 
-
-$searchpath='/data/mp3/';
-$destpath='/data/mac_mp3/';
-
-# only if you dare!
-`rm -rf ${destpath}*`;
-foreach $f (`find $searchpath -name '*.mp3'`) {
-       chomp $f;
-       $f=~s/^$searchpath//;
-       if ($f=~/^(.*)\/(.*)$/) {
-               ($path,$file)=($1,$2);
-       } else {
-               ($path,$file)=('',$f);
-               }
-       $shortpath='';
-       for $splitpath (split /\//,$path) {
-               if (length $splitpath > 31) {
-                       # keep the last 2 chars of the directory name
-                       $splitpath=substr($splitpath,0,29).substr($splitpath,-2,2);
-                       }
-               $shortpath.="${splitpath}/";
-               mkdir $destpath.$shortpath,0755;
-       }
-       $shortfile=$file;
-       if (length $file > 31) {
-               # keep the extension of 4 chars
-               $shortfile=substr($file,0,27).substr($file,-4,4);
-       }
-       `ln -sf ${searchpath}${f} ${destpath}${shortpath}${shortfile}`;
-}
-
index c93841e10cc6a0bd16cfad626e27777ad5d1306a..b5926952688703a5541471670d3a78d3d49e005c 100644 (file)
@@ -2,9 +2,9 @@
 
 sbin_PROGRAMS = timelord
 
-INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/sys
-
 timelord_SOURCES = timelord.c
 timelord_LDADD = $(top_builddir)/libatalk/libatalk.la
 
+LIBS = @LIBS@
+
 EXTRA_DIST = COPYRIGHT README VERSION
index bbdff1c0f1f71fbedae0b2036127bca8f61fcc5a..60fdb8e5069c1fa36ff8b6da9e0cdc2bad5b0992 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: timelord.c,v 1.7 2002-01-04 04:45:47 sibaz Exp $
+ * $Id: timelord.c,v 1.8 2005-04-28 20:49:36 bfernhomberg Exp $
  *
  * Copyright (c) 1990,1992 Regents of The University of Michigan.
  * All Rights Reserved. See COPYRIGHT.
@@ -25,6 +25,7 @@
 #include <sys/time.h>
 #include <sys/file.h>
 #include <sys/uio.h>
+#include <stdlib.h>
 
 #include <unistd.h>
 
index 3705c1ccb44ece9bc9db204d5e6beacb577b4dfa..43e3fc4629ebe02e898539a276f7981c5f444db3 100644 (file)
@@ -1,2 +1 @@
 contrib/printing/add_netatalk_printer
-contrib/shell_utils/netatalkshorternamelinks.pl
index 2d744a58deb87c7dc3d6de865e09bd5a70650e39..31c23c267ec2aa4967e0d1487251c7e781580df4 100644 (file)
@@ -21,14 +21,35 @@ GENERATED_FILES = \
        rc.atalk.bsd            \
        rc.atalkd.netbsd        \
        rc.atalk.suse           \
+       rc.cnid_metad.netbsd    \
        rc.papd.netbsd          \
-       rc.timelord.netbsd
-TEMPLATES = $(foreach f,$(GENERATED_FILES),$(f).tmpl)
-
-CLEANFILES = $(GENERATED_FILES)
-EXTRA_DIST = $(TEMPLATES) rc.atalk.cobalt rc.atalk.sysv
-
-install-data-hook: $(GENERATED_FILES)
+       rc.timelord.netbsd      \
+       rc.atalk.sysv           \
+       rc.atalk.gentoo         \
+       rc.atalk.debian
+
+TEMPLATES = \
+       rc.afpd.netbsd.tmpl             \
+       rc.atalk.redhat.tmpl            \
+       rc.atalk.tru64.tmpl             \
+       rc.atalk.bsd.tmpl               \
+       rc.atalkd.netbsd.tmpl           \
+       rc.atalk.suse.tmpl              \
+       rc.cnid_metad.netbsd.tmpl       \
+       rc.papd.netbsd.tmpl             \
+       rc.timelord.netbsd.tmpl         \
+       rc.atalk.sysv.tmpl              \
+       rc.atalk.gentoo.tmpl            \
+       rc.atalk.debian.tmpl
+
+CLEANFILES = $(GENERATED_FILES) atalk afpd atalkd papd timelord
+EXTRA_DIST = $(TEMPLATES) rc.atalk.cobalt
+
+# overwrite automake uninstall
+# not beautiful, but this way we can call the OS specific init script
+# tools, like chkconfig, insserv or rc-update
+
+uninstall: uninstall-startup
 
 #
 # checking for "redhat" style sysv scripts:
@@ -43,6 +64,13 @@ atalk: rc.atalk.redhat
        cp -f rc.atalk.redhat atalk
        chmod a+x atalk
 
+install-data-hook:
+       -chkconfig --add atalk
+
+uninstall-startup:
+       -chkconfig --del atalk
+       rm -f /etc/rc.d/init.d/atalk
+
 endif
 
 #
@@ -58,9 +86,15 @@ atalk: rc.atalk.suse
        cp -f rc.atalk.suse atalk
        chmod a+x atalk
 
+install-data-hook:
+       -insserv atalk
+
+uninstall-startup:
+       -insserv -d atalk
+       rm -f /etc/init.d/atalk
+
 endif
 
-#
 #
 # checking for "cobalt" style sysv scripts:
 #
@@ -74,6 +108,12 @@ atalk: rc.atalk.cobalt
        cp -f rc.atalk.cobalt atalk
        chmod a+x atalk
 
+install-data-hook:
+
+uninstall-hook:
+
+uninstall-startup: uninstall-am
+
 endif
 
 #
@@ -89,6 +129,12 @@ atalk: rc.atalk.tru64
        cp -f rc.atalk.tru64 atalk
        chmod a+x atalk
 
+install-data-hook:
+
+uninstall-hook:
+
+uninstall-startup: uninstall-am
+
 endif
 
 #
@@ -98,7 +144,7 @@ endif
 if USE_NETBSD
 
 sysvdir = /etc/rc.d
-sysv_SCRIPTS = afp atalk pap timelord
+sysv_SCRIPTS = afpd atalkd papd timelord
 
 afpd: rc.afpd.netbsd
        cp -f $< $@
@@ -115,5 +161,94 @@ timelord: rc.timelord.netbsd
        cp -f $< $@
        chmod a+x $@
 
+install-data-hook:
+
+uninstall-hook:
+
+uninstall-startup: uninstall-am
+
+endif
+
+#
+# checking for Solaris init scripts
+#
+
+if USE_SOLARIS
+
+sysvdir = /etc/init.d
+sysv_SCRIPTS = atalk
+
+atalk: rc.atalk.sysv
+       cp -f rc.atalk.sysv $@
+       chmod a+x $@
+
+install-data-hook:
+       rm -f /etc/rc2.d/S90atalk
+       -ln -s ../init.d/atalk /etc/rc2.d/S90atalk
+       rm -f /etc/rc0.d/K04atalk
+       -ln -s ../init.d/atalk /etc/rc0.d/K04atalk
+
+uninstall-startup:
+       rm -f /etc/init.d/atalk /etc/rc2.d/S90atalk /etc/rc0.d/K04atalk
+
+endif
+
+#
+# checking for "Gentoo" style sysv scripts:
+#
+
+if USE_GENTOO
+
+sysvdir = /etc/init.d
+sysv_SCRIPTS = atalk
+
+atalk: rc.atalk.gentoo
+       cp -f rc.atalk.gentoo atalk
+       chmod a+x atalk
+
+install-data-hook:
+       -rc-update add atalk default
+
+uninstall-startup:
+       -rc-update del atalk default
+       rm -f /etc/init.d/atalk
+
+endif
+
+#
+# checking for "Debian" style sysv scripts:
+#
+
+if USE_DEBIAN
+
+sysvdir = /etc/init.d
+sysv_SCRIPTS = atalk
+
+atalk: rc.atalk.debian
+       cp -f rc.atalk.debian atalk
+       chmod a+x atalk
+
+install-data-hook:
+       update-rc.d atalk defaults 90 10
+
+uninstall-startup:
+       rm -f /etc/init.d/atalk
+       update-rc.d atalk remove
+
+endif
+
+
+#
+# defaults, no init scripts installed
+#
+
+if USE_UNDEF
+
+install-data-hook:
+
+uninstall-hook:
+
+uninstall-startup: uninstall-am
+
 endif
 
index fd81fad1f2ed8eded52a544b24aeeed596aabfb9..a24474d2541328299610f671b326f83ebb069655 100755 (executable)
@@ -29,6 +29,10 @@ if [ -x :SBINDIR:/papd ]; then
        :SBINDIR:/papd;         echo -n ' papd'
 fi
 
+if [ -x :SBINDIR:/cnid_metad ]; then
+       :SBINDIR:/cnid_metad;           echo -n ' cnid_metad'
+fi
+
 if [ -x :SBINDIR:/afpd ]; then
        :SBINDIR:/afpd;         echo -n ' afpd'
 fi
index 7ccbb5bedaefb5124c4865dcbef9368802c81ef5..8c92802aa068f394ad7c932ff4716df4d5a8aa17 100644 (file)
@@ -48,6 +48,7 @@ test -f /etc/atalk/netatalk.conf || exit 0
 RETVAL=1
 RETVAL_ATALKD=0
 RETVAL_PAPD=0
+RETVAL_CNID_METAD=0
 RETVAL_AFPD=0
 
 # startup code for everything
@@ -71,13 +72,18 @@ atalk_startup() {
        fi
     fi
 
+    if [ x"${CNID_METAD_RUN}" = x"yes" -a -x /usr/sbin/cnid_metad ] ; then
+           daemon /usr/sbin/cnid_metad
+           RETVAL_CNID_METAD=$?
+    fi
+
     if [ x"${AFPD_RUN}" = x"yes" -a -x /usr/sbin/afpd ] ; then
            daemon /usr/sbin/afpd ${AFPD_UAMLIST} -g ${AFPD_GUEST} \
                -c ${AFPD_MAX_CLIENTS} -n "${ATALK_NAME}${ATALK_ZONE}"
            RETVAL_AFPD=$?
     fi
 
-    if [ $RETVAL_ATALKD -eq 0 -a $RETVAL_PAPD -eq 0 -a $RETVAL_AFPD -eq 0 ]; then
+    if [ $RETVAL_ATALKD -eq 0 -a $RETVAL_PAPD -eq 0 -a $RETVAL_CNID_METAD -eq 0 -a $RETVAL_AFPD -eq 0 ]; then
         RETVAL=0
        touch /var/lock/subsys/atalk || RETVAL=1
     fi
@@ -127,7 +133,12 @@ case "$1" in
            RETVAL_AFPD=$?
        fi
 
-       if [ $RETVAL_ATALKD -eq 0 -a $RETVAL_PAPD -eq 0 -a $RETVAL_AFPD -eq 0 ] ; then
+       if [ x"${CNID_METAD_RUN}" = x"yes" -a -x /usr/sbin/cnid_metad ]; then
+           killproc cnid_metad
+           RETVAL_CNID_METAD=$?
+       fi
+
+       if [ $RETVAL_ATALKD -eq 0 -a $RETVAL_PAPD -eq 0 -a $RETVAL_CNID_METAD -eq 0 -a $RETVAL_AFPD -eq 0 ] ; then
            RETVAL=0
            rm -f /var/lock/subsys/atalk || RETVAL=1
        fi
diff --git a/distrib/initscripts/rc.atalk.debian.tmpl b/distrib/initscripts/rc.atalk.debian.tmpl
new file mode 100644 (file)
index 0000000..cbdbe88
--- /dev/null
@@ -0,0 +1,117 @@
+#!/bin/sh
+#
+# atalk         Netatalk 2.x initscript
+#
+# Author:       Thomas Kaiser <Thomas.Kaiser@phg-online.de>
+#
+# Version:      $Id: rc.atalk.debian.tmpl,v 1.2 2005-04-28 20:49:37 bfernhomberg Exp $
+
+set -e
+
+PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
+DESC="Netatalk"
+NAME=atalk
+SCRIPTNAME=/etc/init.d/$NAME
+
+# Guard to prevent execution if netatalk was removed.
+test -x :SBINDIR:/atalkd || exit 0
+
+# Read in netatalk configuration.
+if [ -f :ETCDIR:/netatalk.conf ]; then
+       . :ETCDIR:/netatalk.conf
+fi
+
+# Start Netatalk servers.
+atalk_startup() {
+       if [ x"$ATALKD_RUN" = x"yes" ]; then
+
+       # Try to load the AppleTalk kernel module
+       /sbin/modprobe appletalk || echo "[could not load appletalk module]"
+
+       # Start atalkd server.
+       :SBINDIR:/atalkd
+
+       # register workstation
+       :BINDIR:/nbprgstr -p 4 "$ATALK_NAME:Workstation$ATALK_ZONE"
+       :BINDIR:/nbprgstr -p 4 "$ATALK_NAME:netatalk$ATALK_ZONE"
+
+       echo -n " atalkd"
+       fi
+       
+       # prepare startup of file services
+       if [ x"${CNID_METAD_RUN}" = x"yes" -a -x :SBINDIR:/cnid_metad ] ; then
+               echo -n " cnid_metad"
+               :SBINDIR:/cnid_metad
+       fi
+       
+       if [ x"$AFPD_RUN" = x"yes" ]; then
+       :SBINDIR:/afpd $AFPD_UAMLIST -g $AFPD_GUEST -c $AFPD_MAX_CLIENTS \
+               -n "$ATALK_NAME$ATALK_ZONE"
+       echo -n " afpd"
+       fi
+
+       if [ x"$ATALKD_RUN" = x"yes" -a x"$PAPD_RUN" = x"yes" ]; then
+       :SBINDIR:/papd
+       echo -n " papd"
+       fi
+
+       if [ x"$TIMELORD_RUN" = x"yes" ]; then
+       :SBINDIR:/timelord
+       echo -n " timelord"
+       fi
+}
+
+case "$1" in
+       start)
+               if test x"${ATALK_BGROUND}" = x"yes"; then
+                       echo "Starting Netatalk services in the background."
+                       atalk_startup >/dev/null &
+               else
+                       echo -n "Starting Netatalk services (this will take a while): "
+                       atalk_startup
+                       echo "."
+               fi
+       ;;
+
+       stop)
+               echo -n "Stopping Netatalk Daemons:"
+               echo -n " afpd"
+               start-stop-daemon --stop --quiet --oknodo --exec :SBINDIR:/afpd
+
+               echo -n " cnid_metad"
+               start-stop-daemon --stop --quiet --oknodo --exec :SBINDIR:/cnid_metad
+       
+               echo -n " papd"
+               start-stop-daemon --stop --quiet --oknodo --exec :SBINDIR:/papd
+       
+               if test -x :SBINDIR:/timelord; then
+                    echo -n " timelord"
+                   start-stop-daemon --stop --quiet --oknodo --exec :SBINDIR:/timelord
+               fi
+
+               echo -n " atalkd"
+               start-stop-daemon --stop --quiet --oknodo --exec :SBINDIR:/atalkd
+       
+               echo "."
+       ;;
+       
+       restart)
+               $0 force-reload
+       ;;
+
+       force-reload)
+               echo -n "Restarting Netatalk Daemons (this will take a while)"
+               $0 stop
+               echo -n "."
+               sleep 2
+               echo -n "."
+               if $0 start; then
+                       echo "done."
+               fi
+       ;;
+  
+       *)
+               echo "Usage: $0 {start|stop|restart|force-reload}" >&2
+               exit 1
+       ;;
+esac
diff --git a/distrib/initscripts/rc.atalk.gentoo.tmpl b/distrib/initscripts/rc.atalk.gentoo.tmpl
new file mode 100644 (file)
index 0000000..47bba4a
--- /dev/null
@@ -0,0 +1,111 @@
+#!/sbin/runscript
+
+# AppleTalk daemons. Make sure not to start atalkd in the background:
+# its data structures must have time to stablize before running the
+# other processes.
+
+depend() {
+       need net
+       use logger dns
+}
+
+atalk_startup () {
+#      . :ETCDIR:/netatalk.conf
+
+       if [ "${ATALKD_RUN}" != "no" ]; then
+               ebegin "Starting atalkd"
+               start-stop-daemon --start --quiet --exec :SBINDIR:/atalkd
+               eend $?
+
+               for reg in \
+                       "${ATALK_NAME}:Workstation${ATALK_ZONE}" \
+                       "${ATALK_NAME}:netatalk${ATALK_ZONE}"
+               do
+                       ebegin "  Registering $reg"
+                       :BINDIR:/nbprgstr "$reg"
+                       eend $?
+               done
+
+               if [ "${PAPD_RUN}" = "yes" ]; then
+                       ebegin "  Starting papd"
+                       start-stop-daemon --start --quiet --exec :SBINDIR:/papd
+                       eend $?
+               fi
+
+       fi
+
+       if [ "${CNID_METAD_RUN}" = "yes" ] ; then
+               ebegin "Starting cnid_metad"
+               start-stop-daemon --start --quiet --exec :SBINDIR:/cnid_metad
+               eend $?
+       fi
+
+
+       if [ "${AFPD_RUN}" = "yes" ]; then
+               ebegin "Starting afpd"
+               start-stop-daemon --start --quiet --exec :SBINDIR:/afpd -- \
+                       ${AFPD_UAMLIST} -g ${AFPD_GUEST} -c ${AFPD_MAX_CLIENTS} \
+                       -n "${ATALK_NAME}${ATALK_ZONE}"
+               eend $?
+       fi
+
+       if [ "${TIMELORD_RUN}" = "yes" ]; then
+               ebegin "Starting timelord"
+               start-stop-daemon --start --quiet --exec :SBINDIR:/timelord
+               eend $?
+       fi
+}
+
+start () {
+       . :ETCDIR:/netatalk.conf
+
+        if [ x"${ATALK_BGROUND}" = x"yes" ]; then
+            echo "Starting netatalk in the background ... "
+            atalk_startup >& /dev/null &
+        else
+            atalk_startup
+        fi
+}
+
+stop () {
+       . :ETCDIR:/netatalk.conf
+
+       if [ "${AFPD_RUN}" = "yes" ]; then
+               ebegin "Stopping afpd"
+               start-stop-daemon --stop --quiet --exec :SBINDIR:/afpd
+               eend $?
+       fi
+
+       if [ "${TIMELORD_RUN}" = "yes" ]; then
+               ebegin "Stopping timelord"
+               start-stop-daemon --stop --quiet --exec :SBINDIR:/timelord
+               eend $?
+       fi
+
+       if [ "${ATALKD_RUN}" != "no" ]; then
+               if [ "${PAPD_RUN}" = "yes" ]; then
+                       ebegin "Stopping papd"
+                       start-stop-daemon --stop --quiet --exec :SBINDIR:/papd
+                       eend $?
+               fi
+
+               for reg in \
+                       "${ATALK_NAME}:Workstation${ATALK_ZONE}" \
+                       "${ATALK_NAME}:netatalk${ATALK_ZONE}"
+               do
+                       ebegin "Unregistering $reg"
+                       :BINDIR:/nbpunrgstr "$reg"
+                       eend $?
+               done
+
+               ebegin "Stopping atalkd"
+               start-stop-daemon --stop --quiet --exec :SBINDIR:/atalkd
+               eend $?
+       fi
+
+       if [ "${CNID_METAD_RUN}" = "yes" ] ; then
+               ebegin "Stopping cnid_metad"
+               start-stop-daemon --stop --quiet --exec :SBINDIR:/cnid_metad
+               eend $?
+       fi
+}
index 4a7b79bba55814a78f8803095534e5e9f0a89b70..330ca139fa20e5e7dbf53f18bbcb1a5595781963 100644 (file)
@@ -48,6 +48,7 @@ fi
 RETVAL=1
 RETVAL_ATALKD=0
 RETVAL_PAPD=0
+RETVAL_CNID_METAD=0
 RETVAL_AFPD=0
 
 # startup code for everything
@@ -100,6 +101,13 @@ atalk_startup() {
 
     fi
 
+    if [ x"${CNID_METAD_RUN}" = x"yes" -a -x ${ATALK_SBIN}/cnid_metad ] ; then
+           echo -n "  Starting cnid_metad:"
+           daemon ${ATALK_SBIN}/cnid_metad
+           RETVAL_CNID_METAD=$?
+           echo
+    fi
+
     if [ x"${AFPD_RUN}" = x"yes" -a -x ${ATALK_SBIN}/afpd ] ; then
            echo -n "  Starting afpd:"
            daemon ${ATALK_SBIN}/afpd ${AFPD_UAMLIST} -g ${AFPD_GUEST} \
@@ -108,7 +116,7 @@ atalk_startup() {
            echo
     fi
 
-    if [ $RETVAL_ATALKD -eq 0 -a $RETVAL_PAPD -eq 0 -a $RETVAL_AFPD -eq 0 ]; then
+    if [ $RETVAL_ATALKD -eq 0 -a $RETVAL_PAPD -eq 0 -a $RETVAL_CNID_METAD -eq 0 -a $RETVAL_AFPD -eq 0 ]; then
         RETVAL=0
        touch /var/lock/subsys/atalk || RETVAL=1
     fi
@@ -184,6 +192,13 @@ case "$1" in
            echo
        fi
 
+       if [ x"${CNID_METAD_RUN}" = x"yes" -a -x ${ATALK_SBIN}/cnid_metad ]; then
+           echo -n "  Stopping cnid_metad:"
+           killproc cnid_metad
+           RETVAL_CNID_METAD=$?
+           echo
+       fi
+
        if [ $RETVAL_ATALKD -eq 0 -a $RETVAL_PAPD -eq 0 -a $RETVAL_AFPD -eq 0 ] ; then
            RETVAL=0
            rm -f /var/lock/subsys/atalk || RETVAL=1
index 6718b01403b2ecc5d182870e93f730d2725f2551..7421d6393091a389c5a59fe26c57eff51d126720 100755 (executable)
@@ -7,7 +7,7 @@
 # 
 ### BEGIN INIT INFO
 # Provides:       netatalk
-# Required-Start: $network $named $remote_fs $netdaemons $syslog
+# Required-Start: $network $named $remote_fs $syslog
 # Required-Stop:
 # Default-Start:  3 5
 # Default-Stop:
@@ -56,6 +56,11 @@ atalk_startup() {
 
     fi
 
+    if [ x"${CNID_METAD_RUN}" = x"yes" -a -x :SBINDIR:/cnid_metad ] ; then
+           echo -n "  Starting cnid_metad:"
+           startproc :SBINDIR:/cnid_metad
+    fi
+
     if [ x"${AFPD_RUN}" = x"yes" -a -x :SBINDIR:/afpd ] ; then
            echo -n "  Starting afpd:"
            echo ${AFPD_UAMLIST} -g ${AFPD_GUEST} \
@@ -82,9 +87,12 @@ case "$1" in
        killproc -TERM :SBINDIR:/papd
         if test -x :SBINDIR:/timelord ; then
          killproc -TERM :SBINDIR:/timelord
-        fi
+        fi        
        killproc -TERM :SBINDIR:/atalkd
        killproc -TERM :SBINDIR:/afpd
+       if test -x :SBINDIR:/cnid_metad ; then
+         killproc -TERM :SBINDIR:/cnid_metad
+        fi
        echo -e "$return"
        ;;
     restart|reload)
@@ -97,7 +105,10 @@ case "$1" in
         if test -x :SBINDIR:/timelord ; then
          checkproc :SBINDIR:/timelord || return=$rc_failed
         fi
-        checkproc :SBINDIR:/atalkd && echo "OK" || echo "No process"
+        if test -x :SBINDIR:/cnid_metad ; then
+         checkproc :SBINDIR:/cnid_metad || return=$rc_failed
+        fi
+        checkproc :SBINDIR:/atalkd && echo "OK" || echo "No process"   
        ;;
     *)
        echo "Usage: $0 {start|stop|restart|status}"
diff --git a/distrib/initscripts/rc.atalk.sysv b/distrib/initscripts/rc.atalk.sysv
deleted file mode 100755 (executable)
index 3845f8e..0000000
+++ /dev/null
@@ -1,91 +0,0 @@
-#! /bin/sh
-#
-# Start/stop the AppleTalk daemons.
-#
-# AppleTalk daemons. Make sure not to start atalkd in the background:
-# its data structures must have time to stablize before running the
-# other processes.
-#
-
-#
-# kill the named process(es)
-#
-killproc() {
-       pid=`/usr/bin/ps -e |
-            /usr/bin/grep $1 |
-            /usr/bin/sed -e 's/^  *//' -e 's/ .*//'`
-       [ "$pid" != "" ] && kill $pid
-}
-
-case "$1" in
-
-#
-# Start the appletalk server processes.
-#
-
-'start')
-
-       echo 'starting appletalk daemons: \c'
-       if [ -x :SBINDIR:/atalkd ]; then
-               :SBINDIR:/atalkd;               echo ' atalkd\c'
-       fi
-
-       if [ -x :BINDIR:/nbprgstr ]; then
-               :BINDIR:/nbprgstr -p 4 `hostname|sed 's/\..*$//'`:Workstation
-               :BINDIR:/nbprgstr -p 4 `hostname|sed 's/\..*$//'`:netatalk
-                                               echo ' nbprgstr\c'
-       fi
-
-       if [ -x :SBINDIR:/papd ]; then
-               :SBINDIR:/papd;                 echo ' papd\c'
-       fi
-
-       if [ -x :SBINDIR:/afpd ]; then
-               :SBINDIR:/afpd;                 echo ' afpd\c'
-       fi
-
-       if [ -x :SBINDIR:/timelord ]; then
-               :SBINDIR:/timelord;             echo ' timelord\c'
-       fi
-
-       echo '.'
-
-       ;;
-
-#
-# Stop the appletalk server processes.
-#
-
-'stop')
-
-       echo 'stopping appletalk daemons:\c'
-
-       if [ -x :SBINDIR:/papd ]; then
-               killproc papd;                  echo ' papd\c'
-       fi
-
-       if [ -x :SBINDIR:/afpd ]; then
-               killproc afpd;                  echo ' afpd\c'
-       fi
-
-       if [ -x :SBINDIR:/timelord ]; then
-               killproc timelord;              echo ' timelord\c'
-       fi
-
-       # kill atalkd last, since without it the plumbing goes away.
-       if [ -x :SBINDIR:/atalkd ]; then
-               killproc atalkd;                echo ' atalkd\c'
-       fi
-
-       echo '.'
-       ;;
-
-#
-# Usage statement.
-#
-
-*)
-       echo "usage: $0 {start|stop}"
-       exit 1
-       ;;
-esac
diff --git a/distrib/initscripts/rc.atalk.sysv.tmpl b/distrib/initscripts/rc.atalk.sysv.tmpl
new file mode 100755 (executable)
index 0000000..a774cb0
--- /dev/null
@@ -0,0 +1,115 @@
+#! /bin/sh
+#
+# Start/stop the Netatalk daemons.
+#
+# AppleTalk daemons. Make sure not to start atalkd in the background:
+# its data structures must have time to stablize before running the
+# other processes.
+#
+
+#
+# kill the named process(es)
+#
+killproc() {
+       pid=`/usr/bin/ps -e |
+            /usr/bin/grep $1 |
+            /usr/bin/sed -e 's/^  *//' -e 's/ .*//'`
+       [ "$pid" != "" ] && kill $pid
+}
+
+# netatalk.conf expects hostname in $HOSTNAME by default
+HOSTNAME=`hostname`
+
+. :ETCDIR:/netatalk.conf
+
+
+#
+# Start the appletalk server processes.
+#
+
+atalk_startup() {
+       echo 'starting appletalk daemons: \c'
+       if [ x"${ATALKD_RUN}" != x"no" ]; then
+               if [ -x :SBINDIR:/atalkd ]; then
+                       :SBINDIR:/atalkd;               echo ' atalkd\c'
+               fi
+
+               if [ -x :BINDIR:/nbprgstr ]; then
+                       :BINDIR:/nbprgstr -p 4 "${ATALK_NAME}:Workstation${ATALK_ZONE}";
+                       :BINDIR:/nbprgstr -p 4 "${ATALK_NAME}:netatalk${ATALK_ZONE}";
+                                                       echo ' nbprgstr\c'
+               fi
+
+               if [ x"${PAPD_RUN}" = x"yes"  -a -x :SBINDIR:/papd ]; then
+                       :SBINDIR:/papd;                 echo ' papd\c'
+               fi
+
+               if [ x"${TIMELORD_RUN}" = x"yes"  -a -x :SBINDIR:/timelord ]; then
+                       :SBINDIR:/timelord;             echo ' timelord\c'
+               fi
+       fi
+
+       if [ x"${CNID_METAD_RUN}" = x"yes" -a -x :SBINDIR:/cnid_metad ]; then
+               :SBINDIR:/cnid_metad;                   echo ' cnid_metad\c'
+       fi
+
+       if [  x"${AFPD_RUN}" = x"yes" -a -x :SBINDIR:/afpd ]; then
+               :SBINDIR:/afpd  ${AFPD_UAMLIST} -g ${AFPD_GUEST} \
+               -c ${AFPD_MAX_CLIENTS} -n "${ATALK_NAME}${ATALK_ZONE}"; echo ' afpd\c'
+       fi
+
+       echo '.'
+}
+
+
+case "$1" in
+
+'start')
+        if [ x"${ATALK_BGROUND}" = x"yes" ]; then
+            echo "Starting netatalk in the background ... "
+            atalk_startup > /dev/null &
+        else
+            atalk_startup
+        fi
+        ;;
+
+#
+# Stop the appletalk server processes.
+#
+'stop')
+
+       echo 'stopping appletalk daemons:\c'
+
+       if [ -x :SBINDIR:/papd ]; then
+               killproc papd;                  echo ' papd\c'
+       fi
+
+       if [ -x :SBINDIR:/afpd ]; then
+               killproc afpd;                  echo ' afpd\c'
+       fi
+
+       if [ -x :SBINDIR:/cnid_metad ]; then
+               killproc cnid_met;              echo ' cnid_metad\c'
+       fi
+
+       if [ -x :SBINDIR:/timelord ]; then
+               killproc timelord;              echo ' timelord\c'
+       fi
+
+       # kill atalkd last, since without it the plumbing goes away.
+       if [ -x :SBINDIR:/atalkd ]; then
+               killproc atalkd;                echo ' atalkd\c'
+       fi
+
+       echo '.'
+       ;;
+
+#
+# Usage statement.
+#
+
+*)
+       echo "usage: $0 {start|stop}"
+       exit 1
+       ;;
+esac
index 703645de88b740c2076c1de1ebcf1b6b2b042e84..fa9bb25201cc9ae330b2874322ccd3738a7db485 100755 (executable)
@@ -14,6 +14,7 @@ ATALK_SBIN=:SBINDIR:
 ATALK_START_ATALKD=0
 ATALK_START_NBPRGSTR=0
 ATALK_START_PAPD=0
+ATALK_START_CNID_METAD=1
 ATALK_START_AFPD=1
 ATALK_START_TIMELORD=0
 
@@ -51,6 +52,10 @@ case "$1" in
                ${ATALK_SBIN}/papd;                     echo ' papd\c'
        fi
 
+       if [ ${ATALK_START_CNID_METAD} -eq 1 -a -x ${ATALK_SBIN}/cnid_metad ]; then
+               ${ATALK_SBIN}/cnid_metad;                       echo ' cnid_metad\c'
+       fi
+
        if [ ${ATALK_START_AFPD} -eq 1 -a -x ${ATALK_SBIN}/afpd ]; then
                ${ATALK_SBIN}/afpd;                     echo ' afpd\c'
        fi
@@ -79,6 +84,10 @@ case "$1" in
                killproc afpd;                  echo ' afpd\c'
        fi
 
+       if [ -x ${ATALK_SBIN}/cnid_metad ]; then
+               killproc cnid_metad;                    echo ' cnid_metad\c'
+       fi
+
        if [ -x ${ATALK_SBIN}/timelord ]; then
                killproc timelord;              echo ' timelord\c'
        fi
diff --git a/distrib/initscripts/rc.cnid_metad.netbsd.tmpl b/distrib/initscripts/rc.cnid_metad.netbsd.tmpl
new file mode 100644 (file)
index 0000000..1af4719
--- /dev/null
@@ -0,0 +1,19 @@
+#!/bin/sh
+#
+# PROVIDE: cnid_metad
+#
+# AppleTalk daemons. Make sure not to start atalkd in the background:
+# its data structures must have time to stablize before running the
+# other processes.
+#
+
+. /etc/rc.subr
+
+name="cnid_metad"
+rcvar=$name
+command=":SBINDIR:/cnid_metad"
+etcdir=":ETCDIR:"
+
+load_rc_config $name
+run_rc_command "$1"
+
index 09c8bbc3e4f5b72069aff030b2ba89b79857f38d..dc759a279e77177742eccac739f9acbf42ce3417 100644 (file)
@@ -6,7 +6,7 @@ dnl Test for netatalk, and define NETATALK_CFLAGS and NETATALK_LIBS
 dnl   to be used as follows:
 dnl AM_PATH_NETATALK(MINIMUM-VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]])
 dnl
-AC_DEFUN(AM_PATH_NETATALK,
+AC_DEFUN([AM_PATH_NETATALK],
 [dnl 
 dnl Get the cflags and libraries from the netatalk-config script
 dnl
diff --git a/doc/CONFIGURE b/doc/CONFIGURE
deleted file mode 100644 (file)
index 5e8d230..0000000
+++ /dev/null
@@ -1,278 +0,0 @@
-Configuring Netatalk
-====================
-
-These files should have been copied into the configuration directory
-(default: /usr/local/etc)  by the `make install' in step 4 of
-the INSTALL file.
-
-
-Netatalk supplies two different types of AFP servers and both can run at
-the same time. Classic AFP over AppleTalk requires afpd and atalkd. AFP
-over IP only requires afpd.
-
-
-
-1. /usr/local/etc/afpd.conf
-===========================
-
-Edit /usr/local/etc/afpd.conf as required. Some options:
-
-Format:
-- [options]            to specify options for the default server
-and/or
- "Server name" [options]       to specify an additional server
-
-The following options are available:
-
-Transport Protocols:
-     -[no]tcp  Make AFP-over-TCP [not] available
-     -[no]ddp  Make AFP over AppleTalk [not] available. if you have
-               -proxy specified, specify -uamlist "" to prevent ddp
-               connections from working. 
-     -transall      Make both available (default)
-
-Transport Options:
-     -ipaddr <w.x.y.z> 
-               Specifies the IP address the server should
-               respond to (default is the first IP address of the system).
-               This option also allows one machine to advertise TCP/IP for
-               another machine.
-     -server_quantum <number> 
-               Specifies the DSI server quantum. The minimum
-               value is 1MB. The max value is 0xFFFFFFFF. If you specify a
-               value that is out of range, you'll get the default value
-               (currently the minimum). 
-     -admingroup <groupname>
-                         Specifies the group of administrators who should all
-                         be seen as the superuser when they log in.  Default
-                         is disabled.
-     -ddpaddr x.y      Specifies the DDP address of the server. the default
-               is to auto-assign an address (0.0). this is only
-               useful if you're running on a multihomed host.
-     -port <number>    Specifies the TCP port the server should
-               respond to (default is 548)
-     -fqdn <name:port> Specify a fully-qualified domain name
-                       (+optional port). this gets discarded if the
-                       server can't resolve it. this is not honored
-                       by appleshare clients <= 3.8.3 (default: none)
-     -proxy            Run an AppleTalk proxy server for specified AFP/TCP
-               server (if address/port aren't given, then first IP
-               address of the system/548 will be used). if you don't
-               want the proxy server to act as a ddp server as well,
-               set -uamlist to an empty string.
-
-Authentication Methods:
-     -uampath <path>   Use this path to look for User Authentication
-               Modules. (default: /etc/atalk/uams)
-     -uamlist <a,b,c> Comma-separated list of UAMs. (default:
-               uams_guest.so,uams_clrtxt.so,uams_dhx.so)
-
-       Some Common UAMs
-       uams_guest.so: Allow guest logins
-
-       uams_clrtxt.so: (uams_pam.so or uams_passwd.so)
-               Allow logins with passwords transmitted in the clear.
-
-       uams_randnum.so:        Allow Random Number and Two-Way Random Number
-                       exchange for authentication.
-
-       uams_dhx.so: (uams_dhx_pam.so or uams_dhx_passwd.so)
-                       Allow Diffie-Hellman eXchange (DHX) for authentication.
-
-Password Options:
-     -[no]savepassword [Don't] Allow clients to save password locally
-     -passwdfile <path>        Use this path to store Randnum
-                       passwords. (default: ~/.passwd. the only other
-                       useful value is /etc/atalk/afppasswd.)
-     -passwdminlen <#> Minimum password length. may be ignored.
-     -[no]setpassword          [Don't] Allow clients to change their passwords.
-     -loginmaxfail <#>         Maximum number of failed logins. this may be
-                       ignored if the uam can't handle it.
-
-AppleVolumes files:
-     -defaultvol <path>        Specifies path to AppleVolumes.default file
-                       (default /etc/atalk/AppleVolumes.default, same
-                       as -f on command line)
-     -systemvol <path> Specifies path to AppleVolumes.system file
-                       (default /etc/atalk/AppleVolumes.system, same
-                       as -s on command line)
-     -[no]uservolfirst [Don't] read the user's ~/AppleVolumes or
-               ~/.AppleVolumes before reading
-               /etc/atalk/AppleVolumes.default (same as -u on
-                       command line)
-     -[no]uservol      [Don't] Read the user's volume file
-
-     -nlspath <path>   Prepend this path to each code page filename in volume
-               options (default: /etc/atalk/nls).
-
-Miscellaneous:
-     -guestname "user" Specifies the user name for the guest login
-                       (default "nobody", same as -g on command line)
-     -loginmesg "Message"      Client will display "Message" upon logging in
-                       (no default, same as -l "Message" on
-                       command-line)
-     -nodebug          Switch off debugging
-     -client_polling   Disable server notifications.  This forces the
-                       clients to poll every 10 seconds for directory updates.  Note, 
-                       currently this is the only way to get asynchronous updates.
-     -ticklevel <number>       Specify the tickle timeout interval (in seconds)
-     -timeout <number>         Specify the number of tickles to miss before tearing
-                       down a client connection
-     -icon                     Use the platform-specific icon.
-
-An example:
-"Lance" -transall -uamlist uams_dhx.so -nosavepassword -setpassword
-"Lance" is the server name, I enable both TCP and DDP, all logins via DHX
-(requires AppleShare Client 3.8.6), the users cannot save the password
-with keychains and it allows the users to set their passwords.
-
-With no afpd.conf the default is:
-
-- -transall -uamlist uams_guest.so,uams_clrtxt.so,uams_dhx.so
--nosavepassword 
-
-No server name, allow afp over tcp and afp over AppleTalk , allow
-guest access, logins in clear text and DHX, don't allow the user to
-save the password.
-
-Try   man afpd  and  man afpd.conf  for further details.
-
-
-2. /usr/local/etc/atalkd.conf
-=============================
-
-The AppleTalk protocol is configured in atalkd.conf. For detailed
-information please reference 
-
-http://www.neon.com/atalk_routing.html and
-http://www-commeng.cso.uiuc.edu/docs/appletalk/
-
-The whole point of setting up atalkd is to allow AppleTalk routing to
-the localhost as a file and print server. The atalkd.conf file sets up
-the AppleTalk routing by assigning AppleTalk zone (or zones)
-information to the networks it is attached to.
-
-Within AppleTalk there are three different types of routers: seed,
-nonseed and soft seed.
-
-Seed publishes the network and zone information to the network. In the
-case of a conflict, this router takes precedence. Nonseed acts as a
-forwarder in that all network and zone information for its network
-segment is pulled from an upstream router. A soft seed router is
-configured like a seed router, but will defer and use upstream seeded
-zone information if there is a conflict.
-
-Netatalk has the option to behave like a nonseed router or a soft seed
-router. Netatalk will defer to an upstream seed if there is a
-conflict. Any missing configurations will be filled from the network.
-
-Appletalk phases are of two types. The unused, unsupported, obsolete
-phase 1, or the new useful phase 2. 
-
-Phase 1 was Apple's original protocol for Appletalk over LocalTalk. It
-treated an entire network segment as one AppleTalk network capable of
-holding 254 nodes. Don't use this unless you are directly connected to a
-LocalTalk network (unlikely these days).
-
-Phase 2 is the new version. It allows a configurable network range
-between the numbers 1 and 65279, each network capable of hosting 253
-nodes for a total of 16,515,587 AppleTalk interfaces. That's a lot
-of iMacs. :-)
-
-Within an AppleTalk network addressing is a Network:Node:Socket
-triplet. The socket number is generally dropped because nothing uses the
-information. 
-
-Using ethernet and phase 2 the network number can be singular, '1' or
-a range, '1-20'. Node assignment is the responsibility of the clients so
-you don't have to worry about it. The range of 65280-65534 is called
-the startup range and is used by the Mac when it is on a network
-without any routers, you probably shouldn't publish a network within
-this range. If you're publishing to a LocalTalk network segment
-(Hello? Welcome to Y2K. :) your maximum network range is _one_
-network.
-
-Zones must be less then 32 characters long.
-
-Format of lines in this file:
-       interface [ -seed ] [ -router | -dontroute ] 
-       [ -phase { 1 | 2 } ] [ -addr net.node ]
-       [ -net first[-last] ] [ -zone ZoneName ] ...
-
-       interface: the interface that is publishing the appletalk server.  eth0
-
-       -seed - requires two interfaces. The router is acting as a
-       bridge between the two networks. A soft seed router.
-
-       -router - only requires one interface.
-       
-       -dontroute - don't publish routing information
-       
-       -addr this machines network.node address.
-
-Examples: 
-
-eth0
- - Appletalk network is off eth0, no routing information
-published, get it all off the network.
-
-eth0 -router -phase 2 -addr 100.10 -net 100-110 -zone "Upstairs"
-- Appletalk network is off eth0, this server is not a bridge, it
-publishes zone information for Networks 100-110. The servers appletalk
-node address is node 10 of network 100. This zone is called Upstairs.
-
-eth0 -phase 2
-eth1 -seed -phase 2 -addr 100.10 -net 100-110 -zone "Upstairs"
-- This allows routing between the appletalk networks on eth0 and eth1,
-for eth1 this server acts as a soft seed router of a phase 2 network
-segment of 100-110 where this machine is 100.10
-
-Try   man atalkd  and  man atalkd.conf  for further details.
-
-
-3. /usr/local/etc/netatalk.conf
-===============================
-
-Set the options as appropriate:
-
-AFPD_MAX_CLIENTS - Maximum number of concurrent clients.
-
-ATALK_ZONE - Name of the zone. Should match the zone in afpd.conf, or use @zone.
-
-ATALK_NAME - Name of the netatalk server.
-
-AFPD_UAMLIST - List of uams available to the clients. Should match
-list in afpd.conf "-U uam1, uam2" 
-
-AFPD_GUEST - If guest access is enabled, the id of the afpd process
-for the guest client.
-
-ATALKD_RUN, PAPD_RUN, AFPD_RUN - Run these daemons, 'yes/no'.
-
-
-4. /usr/local/etc/papd.conf    for the Printer Access Protocol (PAP) daemon.
-===========================
-
-See the config/papd.conf file for some examples.
-A configuration file that works under Solaris 8 is:
-MacLaserJet:\
-        :pr=|/usr/bin/lp -d fred:\
-        :op=nobody:\
-        :pd=/usr/local/etc/HPLJ46_1.PPD:
-
-where
-  MacLaserJet is some name you have chosen by which Macintoshes will
-     refer to the printer. This is the name that appears in the Chooser.
-  pr gives the printer name on the Unix system ('fred' in this example).
-     On some operating systems you can just specify something like :pr=fred:
-     while on others (including Solaris) it is necessary to pipe the print
-     command into lp or lpr as shown above.
-  op gives the operator name for LPD spooling
-  pd gives the pathname to the PostScript Printer Description (PPD) file.
-     PPD files are available from Adobe Inc,  via anonymous ftp
-     (ftp://ftp.adobe.com//pub/adobe/printerdrivers/mac/all/ppdfiles
-               or        //pub/adobe/printerdrivers/win/all/ppdfiles)
-     or http://download.sourceforge.net/lpr/hp-ppd-0.2.tar.gz
-     or from the printer's manufacturer.
-
-Try   man papd  and  man papd.conf  for further options.
index 7f6cc90b214147081da80c2bc870bd7517cbc3b0..9e308de722ca27b9399ce401b8adda49cd3908b8 100644 (file)
@@ -149,6 +149,6 @@ scalable, and mission-critical database support to software
 developers. BDB can downloaded from
 http://www.sleepycat.com/download.html
 Netatalk's CNID database uses the library and header files from BDB.
-Currently, Netatalk supports BDB 3.1.17, 3.2.9, 3.3.11, 4.0.14, and 4.1.25.
-The recommended version is 3.3.11 as that is the version on which most
+Currently, Netatalk supports BDB 4.1.25 and 4.2.52.
+The recommended version is 4.2.52 as that is the version on which most
 testing has been done.
diff --git a/doc/INSTALL b/doc/INSTALL
deleted file mode 100644 (file)
index 2114c6d..0000000
+++ /dev/null
@@ -1,183 +0,0 @@
-Basic Installation
-==================
-
-Netatalk is known to run on these operating systems:
-
-       OS      Versions        Hardware        Notes
-       --      --------        --------        -----
-       Solaris 2.5-8           Sparc
-       Linux   1.3.x,2.x       PC
-       FreeBSD 2.2-current     PC              after 12 Sept 96
-       NetBSD  1.3             PC
-       OpenBSD 2.2             PC
-       SunOS   4.1+            Sparc           kernel must have VDDRV
-                                               option installed
-       Ultrix  4.[1-4]         3100,5000
-       Tru64   4.0             Alpha           afpd only
-
-See README.platforms for more information.
-
-Quickly:
-$> ./configure [options]
-$> make
-$> make install
-
-
-----------------------------------------------------------------
-0. Get the source
-
-A. Download a binary. Several Linux distributions support netatalk
-with a package. There are also Deb's and RPM packages available on the
-the Netatalk Sourceforge
-site. (http://sourceforge.net/projects/netatalk/)
-
-B. Download the tarball. There are tar.gz and tar.bz2 files available
-for download and compiling.
-(http://sourceforge.net/projects/netatalk/)
-
-C. Anonymous CVS. Downloading of the CVS source can be done quickly
-and easily.
-
-1. make sure you have cvs installed. 
-$> which cvs 
-should produce a path to cvs.
-
-2. if you don't have one make a source directory. Mine is
-~lance/src/working/ cd to this directory.
-
-3. Authenticate yourself with your local cvs and the remote cvs: (all
-one line)
-
-cvs \
--d:pserver:anonymous@cvs.netatalk.sourceforge.net:/cvsroot/netatalk \
-login
-
-Just hit enter for the password for the anonymous user.
-
-4. Now that both machines know who you are, get the source: (all one
-line)
-
-cvs -z3 \
--d:pserver:anonymous@cvs.netatalk.sourceforge.net:/cvsroot/netatalk \
-co netatalk
-
-This tells cvs what compression, (-z3) what protocol, repository and
-where the source is (-d:protocol:host:path) what to do (co is an alias
-for checkout) and what (netatalk) module.
-
-This will create a netatalk directory and download a complete and
-fresh copy of the netatalk source
-
-
-----------------------------------------------------------------
-
-1. ./autogen.sh (Not necessary for a release tarball.)
-This shell script runs libtoolize, aclocal, autoheader, automake and
-autoconf. This sets up all the conditions for the next step. You may
-or may not have to do this. If you downloaded a release tarball, or if
-your download contains a ./configure file then this has already been
-run for you.
-
-----------------------------------------------------------------
-
-2. ./configure 
-This step reads the options to the ./configure program and checks your
-system against the requirements of those options. It generally fails
-if your system doesn't meet the requirements. You should read the
-DEVELOPER file because some of these options require external sources
-to function correctly. (PAM, OpenSSL, Berkeley DB, TCP Wrappers, etc).
-
-Netatalk options to the ./configure script: Use ./configure --help for
-a complete list.
-
---disable-admin-group: disable admin group (default on),
-
---disable-ddp: disable DDP support (AppleTalk),
-
---enable-debug: enable debugging messages in syslog,
-
---enable-dropkludge: enable the experimental dropbox fix
-       (INSECURE!),
-
---with-bdb=PATH: specify path to Berkeley DB installation,
-
---with-did=[scheme]: set DID scheme (cnid,last),
-       CNID is a new scheme using Berkeley DB files to store a
-       per-volume cnid database persistently.
-
-       The last DID scheme recreates version 37b behaviour where
-       directory id's are incrementally calculated versus the new
-       hash method. Unfortunately for machines that have a lot of
-       devices, and/or a lot of inodes the hash can fail with
-       multiple directories resolving to the same DID.
-
---with-message-dir=path: path to message files [default is DISABLED],
-
---enable-srvloc: Turn on Server Location Protocol support,
-
---with-pam: enable pluggable authentication modules support,
-       PAM provides a flexible mechanism for authenticating
-       users. PAM was invented by SUN Microsystems.
-
-       Linux-PAM is a suite of shared libraries that enable the local
-       system administrator to choose how applications authenticate users.
-       You can get the Linux PAM documentation and sources from
-       http://www.kernel.org/pub/linux/libs/pam/
-
---with-shadow: enable shadow password support,
-
---disable-shell-check: disable checking for a valid shell,
-
---with-flock-locks: enable flock locks support,
-
---with-tcp-wrappers: enable TCP wrappers support.
-       Wietse Venema's network logger, also known as TCPD or
-       LOG_TCP. These programs log the client host name of incoming
-       telnet, ftp, rsh, rlogin, finger etc. requests. Security
-       options are: access control per host, domain and/or service;
-       detection of host name spoofing or host address spoofing;
-       booby traps to implement an early-warning system.  TCP
-       Wrappers can be gotten at
-       ftp://ftp.porcupine.org/pub/security/
-
---with-ssl-dirs=[PATH]: specify path to OpenSSL installation. 
-       NOTE: This is dependent on the same directory layout as the
-       source distribution of Openssl. That is: ./include/ and
-       ./lib/ to be on the same level. Many .rpm formats do not
-       have their files laid out in this format.
-       The OpenSSL Project is a collaborative effort to develop a
-       robust, commercial-grade, full-featured, and Open Source
-       toolkit implementing the Secure Sockets Layer (SSL v2/v3)
-       and Transport Layer Security (TLS v1) protocols as well as a
-       full-strength general purpose cryptography library.
-       This is required to enable DHX login support, which
-       will encrypt all of the passwords being sent across the 
-       connection. (Some old mac clients don't support this, check
-       the FAQ for the section on AppleShare clients.)
-       Check to see if your unix has OpenSSL already, or
-       get everything at http://www.openssl.org/ 
-
---with-uams-path=path: path to UAMs [default=PKGCONF/uams]
-
---enable-fhs: use Filesystem Hierarchy Standard (FHS) compatibility
-
---with-ssl-dir=PATH: specify path to openssl installation (must contain
-       lib and include dirs) 
-
---enable-pgp-uam: enable build of PGP UAM module
-
---enable-krb4-uam: enable build of Kerberos v4 UAM module
-
---enable-overwrite: Overwrite configuration files in PKGCONFDIR
-
-----------------------------------------------------------------
-
-3. make
-
-Compile all of the programs.  
-Note: GNU make is required to build netatalk.
-
-----------------------------------------------------------------
-
-4. make install Install the programs, scripts and man pages in the
-places specified by the ./configure process.
diff --git a/doc/README.documentation b/doc/README.documentation
new file mode 100644 (file)
index 0000000..6dd72f1
--- /dev/null
@@ -0,0 +1,4 @@
+                       ATTENTION
+
+The Netatalk documentation is now maintained in Docbook XML format.
+It is kept in the separate CVS module 'netatalk-docs'.
index b0e8d235c0ed8322008a85d6275f03e981d42b42..a8539c3856f78fe942f0379fa27cf198e349d99d 100644 (file)
@@ -62,6 +62,8 @@ their embeded documents.  These can break in the same way as aliases.
 
 So how does netatalk approach the problem?
 
+!!! The following is outdated, please refer to the Manual instead !!!
+
 Netatalk has two different methods of allocating IDs: last and cnid.
 
 DID = last.
@@ -88,8 +90,8 @@ default. On top of that, Netatalk uses the Concurrent Datastore method to
 avoid the need for database locking and transactions.
 
 As stated above, CNID requires Berkeley DB.  Currently, Netatalk supports
-BDB 3.1.17, 3.2.9, 3.3.11, 4.0.14, and 4.1.25.  The recommended version is
-3.3.11 as that is the version on which most testing has been done.  
+BDB 4.1.25 and 4.2.52  The recommended version is 4.2.52 as that is the version
+on which most testing has been done.  
 
 CNID has seen many contributors over the years.  It was conceived by
 Adrian Sun <asun@zoology.washington.edu>.  His developer notes can be found
index 9d0d17934b17338dd1ff77f62ed628796b3fcc6a..10e823b6bd0eab47c1f3bd87959db65a09fd12bc 100644 (file)
@@ -127,7 +127,7 @@ C. SOLARIS
 
 1.  SELECT COMPILER.  This distribution is configured to build with
     gcc.  It should also work with cc. At the present time only cc
-    v5.0 and above can build the 64-bit kernel module.
+    v5.0 and gcc 3.1 and above can build the 64-bit kernel module.
 
 1a. SELECT KERNEL TYPE.  Edit sys/solaris/Makefile.kernel and set KCFLAGS
      to include sparcv9 support if you run a 64-bit kernel, or leave it
diff --git a/doc/README.veto b/doc/README.veto
deleted file mode 100644 (file)
index 7c08f00..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-Veto Options Patch for Netatalk
-===============================
-
-   The patch at the below address adds a function similar to Samba's
-"veto files" option to Netatalk. It is not derived from Samba is anyway
-so GPL'ing Netatalk wasn't a factor. :-)
-
-http://ariel.ucs.unimelb.edu.au/~epl/netatalk/veto/netatalk-veto.diff
-
-   For those people who do not use Samba, it allows the server to hide
-files which the user could otherwise access. Hopefully, if this patch
-works, clients will not be able to see any veto'ed files/directories.
-Nor will they be able to create, rename or move files/directories
-matching the veto'ed filespecs (on the Unix side).
-
-   For example, if you use Samba and Netatalk, you would commonly have
-the following line in Samba's configuration files. That line hides the
-files on the filesystem which Netatalk/Mac client creates, but the
-Mac-user never sees. By hiding it, users cannot fiddle with these
-directories and nor will they confuse themselves by files appear in
-Windows which doesn't appear under Macs.
-
-veto files = /.AppleDouble/.AppleDesktop/Network Trash Folder/TheVolumeSettingsFolder/
-
-   Likewise, Windows often create some "special" files which you may
-wish to hide from mac users. Hence, the following line might be useful.
-
-veto:recycled/desktop.ini/Folder.htt/Folder Settings/
-
-   The option as implemented is case sensitive, so YMMV.
-
-Limitations and other notes
-===========================
-- This patch may have a memory leak as a result of strdup()'ing v_veto,
-  but not freeing it anywhere. I'm not sure if this is a practical
-  problem, as presumably v_veto should be free()'ed when the user
-  disconnects. Upon which the fork()'ed ``afpd'' will die and its
-  memory resources reclaimed by the operating system.
-- This patch does not deal with wildcards at all. Once I've worked out
-  a good design and algorithm, I might add it. It currently fulfills
-  all my requirements. But if there is a demand for wildcard support,
-  I'd be happy to spend additional time on this problem. Until then, I
-  want to make sure that the rest of the code is correct.
-- In theory, (with the veto option of veto:foobar/) it would be able to
-  create a filename named ":66oobar" on the unix side which will then
-  appear to the mac client as "foobar". Due to other code in Netatalk
-  (not related to this patch), this won't actually work. However, there
-  is no fundamental reason why the mac client would not be able to
-  read files which seemingly matched the veto filespec (from the mac).
-
-How was the patch made
-======================
-I did things in the following steps.
-1) I added per-volume support for the "veto:string" option to
-   ``volume.{c,h}''.
-2) I determined that the veto option was functionally most similar to
-   the "validupath()" function. Therefore, after every "validupath()"
-   call, I added a "veto_file()".
-3) I placed the "veto_file()" function in the ``etc/afpd/filedir.c''
-   source file. It could also be in any of the other files, but I
-   figured that filedir.c was the best spot. The "veto_file()" function
-   takes the "veto_str" parameter directly from value "string" in point
-   1) above.
-4) Inside "veto_file()", uncomment the DEBUG code if you want.
-
-   If you want more information, contact me at <epl@unimelb.edu.au>.
index 83a4d085f852d83281eb9e9ffa77ba395e857264..7ed56ed6612fc957a815944cf3eaf610e0727de5 100644 (file)
@@ -1,3 +1,3 @@
 # Makefile.am for etc/
 
-SUBDIRS = afpd atalkd papd psf uams
+SUBDIRS = afpd cnid_dbd atalkd papd psf uams
index 88be22e6ca15ff1e5ba7ccf0516ef4326286c2f6..2e6e01b1528c84175f22fb3ad40729d82022d686 100644 (file)
@@ -1,34 +1,30 @@
 # Makefile.am for etc/afpd/
 
 pkgconfdir = @PKGCONFDIR@
-nlsdir = @NLSDIR@
-
-SUBDIRS = nls
 
 sbin_PROGRAMS = afpd
 
 afpd_SOURCES = unix.c ofork.c main.c switch.c auth.c volume.c directory.c \
         file.c enumerate.c desktop.c filedir.c fork.c appl.c gettok.c \
         mangle.c status.c afp_options.c afp_asp.c afp_dsi.c messages.c  \
-        afp_config.c nfsquota.c codepage.c quota.c uam.c afs.c uid.c  \
-        afp_util.c catsearch.c precompose.c
+        afp_config.c nfsquota.c quota.c uam.c afs.c uid.c afp_util.c \
+         catsearch.c afprun.c vfs_adouble.c
 
-afpd_LDADD = @WRAP_LIBS@ @PAM_LIBS@ @QUOTA_LIBS@ @SLP_LIBS@ \
-       $(top_builddir)/libatalk/libatalk.la
+afpd_LDADD =  $(top_builddir)/libatalk/cnid/libcnid.la $(top_builddir)/libatalk/libatalk.la
 afpd_LDFLAGS = -export-dynamic
 
-noinst_HEADERS = auth.h codepage.h afp_config.h desktop.h directory.h file.h \
+noinst_HEADERS = auth.h afp_config.h desktop.h directory.h file.h \
         filedir.h fork.h globals.h icon.h mangle.h misc.h status.h switch.h \
-        uam_auth.h uid.h unix.h volume.h
+        uam_auth.h uid.h unix.h volume.h afp_vfs.h
+
+LIBS = @LIBS@ @PAM_LIBS@ @QUOTA_LIBS@ @SLP_LIBS@ @WRAP_LIBS@ @LIBADD_DL@
 
-INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/sys \
-        @SLP_CFLAGS@ \
+CFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/sys \
+        @CFLAGS@ @SLP_CFLAGS@ \
         -D_PATH_AFPDDEFVOL=\"$(pkgconfdir)/AppleVolumes.default\" \
         -D_PATH_AFPDSYSVOL=\"$(pkgconfdir)/AppleVolumes.system\" \
         -D_PATH_AFPDPWFILE=\"$(pkgconfdir)/afppasswd\" \
         -D_PATH_AFPDCONF=\"$(pkgconfdir)/afpd.conf\" \
         -D_PATH_AFPDUAMPATH=\"$(UAMS_PATH)/\" \
-        -D_PATH_AFPDNLSPATH=\"$(nlsdir)/\" \
-        -DAFPD_MTAB_FILE=\"$(pkgconfdir)/afpd.mtab\" \
         -DAPPLCNAME \
         -DSERVERTEXT=\"$(SERVERTEXT)/\"
index 31aa8a753db1fadd6af549eb83fc4270f0074712..958e557b2eb981bca7c4f7bae3dab792f1524de9 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: afp_asp.c,v 1.21 2003-08-29 23:35:34 bfernhomberg Exp $
+ * $Id: afp_asp.c,v 1.22 2005-04-28 20:49:39 bfernhomberg Exp $
  *
  * Copyright (c) 1997 Adrian Sun (asun@zoology.washington.edu)
  * Copyright (c) 1990,1993 Regents of The University of Michigan.
@@ -53,6 +53,7 @@ static __inline__ void afp_asp_close(AFPObj *obj)
 {
     ASP asp = obj->handle;
 
+    close_all_vol();
     if (obj->options.authprintdir) afp_authprint_remove(obj);
 
     if (obj->logout)
@@ -61,7 +62,6 @@ static __inline__ void afp_asp_close(AFPObj *obj)
     LOG(log_info, logtype_afpd, "%.2fKB read, %.2fKB written",
         asp->read_count / 1024.0, asp->write_count / 1024.0);
     asp_close( asp );
-    close_vols();
 }
 
 /* removes the authprint trailing when appropriate */
@@ -123,6 +123,9 @@ static __inline__ void afp_authprint_remove(AFPObj *obj)
     }
 }
 
+/* ------------------------
+ * SIGTERM
+*/
 static void afp_asp_die(const int sig)
 {
     ASP asp = child->handle;
@@ -139,6 +142,9 @@ static void afp_asp_die(const int sig)
         exit(sig);
 }
 
+/* -----------------------------
+ * SIGUSR1
+ */
 static void afp_asp_timedown()
 {
     struct sigaction   sv;
@@ -154,43 +160,58 @@ static void afp_asp_timedown()
     it.it_value.tv_usec = 0;
     if ( setitimer( ITIMER_REAL, &it, 0 ) < 0 ) {
         LOG(log_error, logtype_afpd, "afp_timedown: setitimer: %s", strerror(errno) );
-        afp_asp_die(1);
+        afp_asp_die(EXITERR_SYS);
     }
 
     memset(&sv, 0, sizeof(sv));
     sv.sa_handler = afp_asp_die;
     sigemptyset( &sv.sa_mask );
+    sigaddset(&sv.sa_mask, SIGHUP);
+    sigaddset(&sv.sa_mask, SIGTERM);
     sv.sa_flags = SA_RESTART;
     if ( sigaction( SIGALRM, &sv, 0 ) < 0 ) {
         LOG(log_error, logtype_afpd, "afp_timedown: sigaction: %s", strerror(errno) );
-        afp_asp_die(1);
+        afp_asp_die(EXITERR_SYS);
     }
 
-    /* ignore SIGHUP */
+    /* ignore myself */
     sv.sa_handler = SIG_IGN;
     sigemptyset( &sv.sa_mask );
     sv.sa_flags = SA_RESTART;
-    if ( sigaction( SIGHUP, &sv, 0 ) < 0 ) {
-        LOG(log_error, logtype_afpd, "afp_timedown: sigaction SIGHUP: %s", strerror(errno) );
-        afp_asp_die(1);
+    if ( sigaction( SIGUSR1, &sv, 0 ) < 0 ) {
+        LOG(log_error, logtype_afpd, "afp_timedown: sigaction SIGUSR1: %s", strerror(errno) );
+        afp_asp_die(EXITERR_SYS);
     }
 }
 
+/* ---------------------------------
+ * SIGHUP reload configuration file
+*/
+extern volatile int reload_request;
+
+static void afp_asp_reload()
+{
+    reload_request = 1;
+}
+
 /* ---------------------- */
 #ifdef SERVERTEXT
-static void afp_asp_getmesg (int sig)
+static void afp_asp_getmesg (int sig _U_)
 {
-    readmessage();
+    readmessage(child);
     asp_attention(child->handle, AFPATTN_MESG | AFPATTN_TIME(5));
 }
 #endif /* SERVERTEXT */
 
-
+/* ---------------------- */
 void afp_over_asp(AFPObj *obj)
 {
     ASP asp;
     struct sigaction  action;
-    int                func, ccnt = 0, reply = 0;
+    int                func,  reply = 0;
+#ifdef DEBUG1
+    int ccnt = 0;
+#endif    
 
     obj->exit = afp_asp_die;
     obj->reply = (int (*)()) asp_cmdreply;
@@ -198,36 +219,66 @@ void afp_over_asp(AFPObj *obj)
     child = obj;
     asp = (ASP) obj->handle;
 
-    /* install signal handlers */
+    /* install signal handlers 
+     * With ASP tickle handler is done in the parent process
+    */
     memset(&action, 0, sizeof(action));
-    action.sa_handler = afp_asp_timedown;
+
+    /* install SIGHUP */
+    action.sa_handler = afp_asp_reload; 
     sigemptyset( &action.sa_mask );
+    sigaddset(&action.sa_mask, SIGTERM);
+    sigaddset(&action.sa_mask, SIGUSR1);
+#ifdef SERVERTEXT
+    sigaddset(&action.sa_mask, SIGUSR2);
+#endif    
     action.sa_flags = SA_RESTART;
     if ( sigaction( SIGHUP, &action, 0 ) < 0 ) {
         LOG(log_error, logtype_afpd, "afp_over_asp: sigaction: %s", strerror(errno) );
-        afp_asp_die(1);
+        afp_asp_die(EXITERR_SYS);
     }
 
+    /*  install SIGTERM */
     action.sa_handler = afp_asp_die;
     sigemptyset( &action.sa_mask );
+    sigaddset(&action.sa_mask, SIGHUP);
+    sigaddset(&action.sa_mask, SIGUSR1);
+#ifdef SERVERTEXT
+    sigaddset(&action.sa_mask, SIGUSR2);
+#endif    
     action.sa_flags = SA_RESTART;
     if ( sigaction( SIGTERM, &action, 0 ) < 0 ) {
         LOG(log_error, logtype_afpd, "afp_over_asp: sigaction: %s", strerror(errno) );
-        afp_asp_die(1);
+        afp_asp_die(EXITERR_SYS);
     }
 
 #ifdef SERVERTEXT
     /* Added for server message support */
     action.sa_handler = afp_asp_getmesg;
     sigemptyset( &action.sa_mask );
-    sigaddset(&action.sa_mask, SIGUSR2);
+    sigaddset(&action.sa_mask, SIGTERM);
+    sigaddset(&action.sa_mask, SIGUSR1);
+    sigaddset(&action.sa_mask, SIGHUP);
     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);
+        afp_asp_die(EXITERR_SYS);
     }
 #endif /* SERVERTEXT */
 
+    /*  SIGUSR1 - set down in 5 minutes  */
+    action.sa_handler = afp_asp_timedown; 
+    sigemptyset( &action.sa_mask );
+    sigaddset(&action.sa_mask, SIGHUP);
+    sigaddset(&action.sa_mask, SIGTERM);
+#ifdef SERVERTEXT
+    sigaddset(&action.sa_mask, SIGUSR2);
+#endif    
+    action.sa_flags = SA_RESTART;
+    if ( sigaction( SIGUSR1, &action, 0 ) < 0 ) {
+        LOG(log_error, logtype_afpd, "afp_over_asp: sigaction: %s", strerror(errno) );
+        afp_asp_die(EXITERR_SYS);
+    }
 
     LOG(log_info, logtype_afpd, "session from %u.%u:%u on %u.%u:%u",
         ntohs( asp->asp_sat.sat_addr.s_net ),
@@ -237,14 +288,20 @@ void afp_over_asp(AFPObj *obj)
         atp_sockaddr( asp->asp_atp )->sat_port );
 
     while ((reply = asp_getrequest(asp))) {
+        if (reload_request) {
+            reload_request = 0;
+            load_volumes(child);
+        }
         switch (reply) {
         case ASPFUNC_CLOSE :
             afp_asp_close(obj);
             LOG(log_info, logtype_afpd, "done" );
 
+#ifdef DEBUG1
             if ( obj->options.flags & OPTION_DEBUG ) {
                 printf( "done\n" );
             }
+#endif
             return;
             break;
 
@@ -259,10 +316,12 @@ void afp_over_asp(AFPObj *obj)
             }
 #endif /* AFS */
             func = (u_char) asp->commands[0];
+#ifdef DEBUG1
             if ( obj->options.flags & OPTION_DEBUG ) {
                 printf("command: %d (%s)\n", func, AfpNum2name(func));
                 bprint( asp->commands, asp->cmdlen );
             }
+#endif            
             if ( afp_switch[ func ] != NULL ) {
                 /*
                  * The function called from afp_switch is expected to
@@ -284,23 +343,26 @@ void afp_over_asp(AFPObj *obj)
                 asp->datalen = 0;
                 reply = AFPERR_NOOP;
             }
+#ifdef DEBUG1
             if ( obj->options.flags & OPTION_DEBUG ) {
                 printf( "reply: %d, %d\n", reply, ccnt++ );
                 bprint( asp->data, asp->datalen );
             }
-
+#endif
             if ( asp_cmdreply( asp, reply ) < 0 ) {
                 LOG(log_error, logtype_afpd, "asp_cmdreply: %s", strerror(errno) );
-                afp_asp_die(1);
+                afp_asp_die(EXITERR_CLNT);
             }
             break;
 
         case ASPFUNC_WRITE :
             func = (u_char) asp->commands[0];
+#ifdef DEBUG1
             if ( obj->options.flags & OPTION_DEBUG ) {
                 printf( "(write) command: %d\n", func );
                 bprint( asp->commands, asp->cmdlen );
             }
+#endif
             if ( afp_switch[ func ] != NULL ) {
                 asp->datalen = ASP_DATASIZ;
                 reply = (*afp_switch[ func ])(obj,
@@ -316,13 +378,15 @@ void afp_over_asp(AFPObj *obj)
                 asp->datalen = 0;
                 reply = AFPERR_NOOP;
             }
+#ifdef DEBUG1
             if ( obj->options.flags & OPTION_DEBUG ) {
                 printf( "(write) reply code: %d, %d\n", reply, ccnt++ );
                 bprint( asp->data, asp->datalen );
             }
+#endif
             if ( asp_wrtreply( asp, reply ) < 0 ) {
                 LOG(log_error, logtype_afpd, "asp_wrtreply: %s", strerror(errno) );
-                afp_asp_die(1);
+                afp_asp_die(EXITERR_CLNT);
             }
             break;
         default:
@@ -333,7 +397,7 @@ void afp_over_asp(AFPObj *obj)
             LOG(log_info, logtype_afpd, "main: asp_getrequest: %d", reply );
             break;
         }
-
+#ifdef DEBUG1
         if ( obj->options.flags & OPTION_DEBUG ) {
 #ifdef notdef
             pdesc( stdout );
@@ -341,6 +405,7 @@ void afp_over_asp(AFPObj *obj)
             of_pforkdesc( stdout );
             fflush( stdout );
         }
+#endif
     }
 }
 
index 74c089fa25f4617d02fe84ab87a617e33dde747c..fa6a99b56d78998566c57851ffc84226c10a6b64 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: afp_config.c,v 1.22 2003-02-09 20:34:38 jmarcus Exp $
+ * $Id: afp_config.c,v 1.23 2005-04-28 20:49:39 bfernhomberg Exp $
  *
  * Copyright (c) 1997 Adrian Sun (asun@zoology.washington.edu)
  * All Rights Reserved.  See COPYRIGHT.
@@ -34,6 +34,7 @@ char *strchr (), *strrchr ();
 #endif /* HAVE_UNISTD_H */
 #include <ctype.h>
 #include <atalk/logger.h>
+#include <atalk/util.h>
 
 #include <sys/socket.h>
 #include <netinet/in.h>
@@ -48,7 +49,6 @@ char *strchr (), *strrchr ();
 #include <atalk/server_child.h>
 #ifdef USE_SRVLOC
 #include <slp.h>
-static char srvloc_url[512];
 #endif /* USE_SRVLOC */
 
 #include "globals.h"
@@ -96,9 +96,62 @@ void configfree(AFPConfig *configs, const AFPConfig *config)
 }
 
 #ifdef USE_SRVLOC
-static void SRVLOC_callback(SLPHandle hslp, SLPError errcode, void *cookie) {
+static void SRVLOC_callback(SLPHandle hslp _U_, SLPError errcode, void *cookie) {
     *(SLPError*)cookie = errcode;
 }
+
+static char hex[17] = "0123456789abcdef";
+
+static char * srvloc_encode(const struct afp_options *options, const char *name)
+{
+       static char buf[512];
+       char *conv_name;
+       unsigned char *p;
+       unsigned int i = 0;
+#ifndef NO_DDP
+       char *Obj, *Type = "", *Zone = "";
+#endif
+
+       /* Convert name to maccharset */
+        if ((size_t)-1 ==(convert_string_allocate( options->unixcharset, options->maccharset,
+                        name, strlen(name), &conv_name)) )
+               return (char*)name;
+
+       /* Escape characters */
+       p = conv_name;
+       while (*p && i<(sizeof(buf)-4)) {
+           if (*p == '@')
+               break;
+           else if (isspace(*p)) {
+               buf[i++] = '%';
+               buf[i++] = '2';
+               buf[i++] = '0';
+               p++;
+           }   
+           else if ((!isascii(*p)) || *p <= 0x2f || *p == 0x3f ) {
+               buf[i++] = '%';
+               buf[i++] = hex[*p >> 4];
+               buf[i++] = hex[*p++ & 15];
+           }
+           else {
+               buf[i++] = *p++;
+           }
+       }
+       buf[i] = '\0';
+
+#ifndef NO_DDP
+       /* Add ZONE,  */
+        if (nbp_name(options->server, &Obj, &Type, &Zone )) {
+               LOG(log_error, logtype_afpd, "srvloc_encode: can't parse %s", options->server );
+       }
+       else {
+               snprintf( buf+i, sizeof(buf)-i-1 ,"&ZONE=%s", Zone);
+       }
+#endif
+       free (conv_name);
+
+       return buf;
+}
 #endif /* USE_SRVLOC */
 
 #ifdef USE_SRVLOC
@@ -107,9 +160,10 @@ static void dsi_cleanup(const AFPConfig *config)
     SLPError err;
     SLPError callbackerr;
     SLPHandle hslp;
+    DSI *dsi = (DSI *)config->obj.handle;
 
     /*  Do nothing if we didn't register.  */
-    if (srvloc_url[0] == '\0')
+    if (!dsi || dsi->srvloc_url[0] == '\0')
         return;
 
     err = SLPOpen("en", SLP_FALSE, &hslp);
@@ -119,20 +173,21 @@ static void dsi_cleanup(const AFPConfig *config)
     }
 
     err = SLPDereg(hslp,
-                   srvloc_url,
+                   dsi->srvloc_url,
                    SRVLOC_callback,
                    &callbackerr);
     if (err != SLP_OK) {
-        LOG(log_error, logtype_afpd, "dsi_cleanup: Error unregistering %s from SRVLOC", srvloc_url);
+        LOG(log_error, logtype_afpd, "dsi_cleanup: Error unregistering %s from SRVLOC", dsi->srvloc_url);
         goto srvloc_dereg_err;
     }
 
     if (callbackerr != SLP_OK) {
-        LOG(log_error, logtype_afpd, "dsi_cleanup: Error in callback while trying to unregister %s from SRVLOC (%d)", srvloc_url, callbackerr);
+        LOG(log_error, logtype_afpd, "dsi_cleanup: Error in callback while trying to unregister %s from SRVLOC (%d)", dsi->srvloc_url, callbackerr);
         goto srvloc_dereg_err;
     }
 
 srvloc_dereg_err:
+    dsi->srvloc_url[0] = '\0';
     SLPClose(hslp);
 }
 #endif /* USE_SRVLOC */
@@ -140,6 +195,8 @@ srvloc_dereg_err:
 #ifndef NO_DDP
 static void asp_cleanup(const AFPConfig *config)
 {
+    /* we need to stop tickle handler */
+    asp_stop_tickle();
     nbp_unrgstr(config->obj.Obj, config->obj.Type, config->obj.Zone,
                 &config->obj.options.ddpaddr);
 }
@@ -154,7 +211,7 @@ static int asp_start(AFPConfig *config, AFPConfig *configs,
     if (!(asp = asp_getsession(config->obj.handle, server_children,
                                config->obj.options.tickleval))) {
         LOG(log_error, logtype_afpd, "main: asp_getsession: %s", strerror(errno) );
-        exit( 1 );
+        exit( EXITERR_CLNT );
     }
 
     if (asp->child) {
@@ -175,7 +232,7 @@ static int dsi_start(AFPConfig *config, AFPConfig *configs,
     if (!(dsi = dsi_getsession(config->obj.handle, server_children,
                                config->obj.options.tickleval))) {
         LOG(log_error, logtype_afpd, "main: dsi_getsession: %s", strerror(errno) );
-        exit( 1 );
+        exit( EXITERR_CLNT );
     }
 
     /* we've forked. */
@@ -196,6 +253,7 @@ static AFPConfig *ASPConfigInit(const struct afp_options *options,
     ATP atp;
     ASP asp;
     char *Obj, *Type = "AFPServer", *Zone = "*";
+    char *convname = NULL;
 
     if ((config = (AFPConfig *) calloc(1, sizeof(AFPConfig))) == NULL)
         return NULL;
@@ -215,10 +273,20 @@ static AFPConfig *ASPConfigInit(const struct afp_options *options,
 
     /* register asp server */
     Obj = (char *) options->hostname;
-    if (nbp_name(options->server, &Obj, &Type, &Zone )) {
+    if (options->server && (size_t)-1 ==(convert_string_allocate( options->unixcharset, options->maccharset,
+                         options->server, strlen(options->server), &convname)) ) {
+        if ((convname = strdup(options->server)) == NULL ) {
+            LOG(log_error, logtype_afpd, "malloc: %s", strerror(errno) );
+            goto serv_free_return;
+        }
+    }
+
+    if (nbp_name(convname, &Obj, &Type, &Zone )) {
         LOG(log_error, logtype_afpd, "main: can't parse %s", options->server );
         goto serv_free_return;
     }
+    if (convname)
+        free (convname);
 
     /* dup Obj, Type and Zone as they get assigned to a single internal
      * buffer by nbp_name */
@@ -286,8 +354,7 @@ static AFPConfig *DSIConfigInit(const struct afp_options *options,
     SLPHandle hslp;
     struct servent *afpovertcp;
     int afp_port = 548;
-    const char *srvloc_hostname, *hostname;
-    struct hostent *h;
+    char *srvloc_hostname, *hostname;
 #endif /* USE_SRVLOC */
 
     if ((config = (AFPConfig *) calloc(1, sizeof(AFPConfig))) == NULL) {
@@ -315,7 +382,7 @@ static AFPConfig *DSIConfigInit(const struct afp_options *options,
     }
 
 #ifdef USE_SRVLOC
-    srvloc_url[0] = '\0';      /*  Mark that we haven't registered.  */
+    dsi->srvloc_url[0] = '\0'; /*  Mark that we haven't registered.  */
     if (!(options->flags & OPTION_NOSLP)) {
        err = SLPOpen("en", SLP_FALSE, &hslp);
        if (err != SLP_OK) {
@@ -333,44 +400,49 @@ static AFPConfig *DSIConfigInit(const struct afp_options *options,
        if (afpovertcp != NULL) {
            afp_port = afpovertcp->s_port;
        }
-       /* Try to use the FQDN to register with srvloc. */
-       h = gethostbyaddr((char*)&dsi->server.sin_addr, sizeof(dsi->server.sin_addr), AF_INET);
-       if (h) hostname = h->h_name;
-       else hostname = inet_ntoa(dsi->server.sin_addr);
-       srvloc_hostname = (options->server ? options->server : options->hostname);
-       if (strlen(srvloc_hostname) > (sizeof(srvloc_url) - strlen(hostname) - 21)) {
+       /* If specified use the FQDN to register with srvloc, otherwise use IP. */
+       p = NULL;
+       if (options->fqdn) {
+           hostname = options->fqdn;
+           p = strchr(hostname, ':');
+       }       
+       else 
+           hostname = inet_ntoa(dsi->server.sin_addr);
+       srvloc_hostname = srvloc_encode(options, (options->server ? options->server : options->hostname));
+
+       if (strlen(srvloc_hostname) > (sizeof(dsi->srvloc_url) - strlen(hostname) - 21)) {
            LOG(log_error, logtype_afpd, "DSIConfigInit: Hostname is too long for SRVLOC");
-           srvloc_url[0] = '\0';
+           dsi->srvloc_url[0] = '\0';
            goto srvloc_reg_err;
        }
-       if (dsi->server.sin_port == afp_port) {
-           sprintf(srvloc_url, "afp://%s/?NAME=%s", hostname, srvloc_hostname);
+       if ((p) || dsi->server.sin_port == afp_port) {
+           sprintf(dsi->srvloc_url, "afp://%s/?NAME=%s", hostname, srvloc_hostname);
        }
        else {
-           sprintf(srvloc_url, "afp://%s:%d/?NAME=%s", hostname, ntohs(dsi->server.sin_port), srvloc_hostname);
+           sprintf(dsi->srvloc_url, "afp://%s:%d/?NAME=%s", hostname, ntohs(dsi->server.sin_port), srvloc_hostname);
        }
 
        err = SLPReg(hslp,
-                    srvloc_url,
+                    dsi->srvloc_url,
                     SLP_LIFETIME_MAXIMUM,
-                    "",
+                    "afp",
                     "",
                     SLP_TRUE,
                     SRVLOC_callback,
                     &callbackerr);
        if (err != SLP_OK) {
-           LOG(log_error, logtype_afpd, "DSIConfigInit: Error registering %s with SRVLOC", srvloc_url);
-           srvloc_url[0] = '\0';
+           LOG(log_error, logtype_afpd, "DSIConfigInit: Error registering %s with SRVLOC", dsi->srvloc_url);
+           dsi->srvloc_url[0] = '\0';
            goto srvloc_reg_err;
        }
 
        if (callbackerr != SLP_OK) {
-           LOG(log_error, logtype_afpd, "DSIConfigInit: Error in callback trying to register %s with SRVLOC", srvloc_url);
-           srvloc_url[0] = '\0';
+           LOG(log_error, logtype_afpd, "DSIConfigInit: Error in callback trying to register %s with SRVLOC", dsi->srvloc_url);
+           dsi->srvloc_url[0] = '\0';
            goto srvloc_reg_err;
        }
 
-       LOG(log_info, logtype_afpd, "Sucessfully registered %s with SRVLOC", srvloc_url);
+       LOG(log_info, logtype_afpd, "Sucessfully registered %s with SRVLOC", dsi->srvloc_url);
 
 srvloc_reg_err:
        SLPClose(hslp);
@@ -396,7 +468,7 @@ srvloc_reg_err:
     config->server_start = dsi_start;
 #ifdef USE_SRVLOC
     config->server_cleanup = dsi_cleanup;
-#endif /* USE_SRVLOC */
+#endif 
     return config;
 }
 
@@ -463,8 +535,9 @@ AFPConfig *configinit(struct afp_options *cmdline)
     FILE *fp;
     char buf[LINESIZE + 1], *p, have_option = 0;
     struct afp_options options;
-    AFPConfig *config, *first = NULL;
+    AFPConfig *config=NULL, *first = NULL; 
 
+    status_reset();
     /* if config file doesn't exist, load defaults */
     if ((fp = fopen(cmdline->configfile, "r")) == NULL)
     {
index b8a28b9f697111535f19cc2f9b27291aa615f37f..cb54af027f8187af188bfc8188dda274d6d4c16f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: afp_config.h,v 1.3 2001-12-03 05:03:38 jmarcus Exp $
+ * $Id: afp_config.h,v 1.4 2005-04-28 20:49:39 bfernhomberg Exp $
  */
 
 #ifndef AFPD_CONFIG_H
@@ -17,7 +17,7 @@ typedef struct AFPConfig {
     AFPObj obj;
     int fd, statuslen;
     unsigned char *optcount;
-    char status[ATP_MAXDATA];
+    char status[1400];
     const void *defoptions, *signature;
     int (*server_start) __P((struct AFPConfig *, struct AFPConfig *,
                              server_child *));
index db620fe4b1ef2c2ffd079a84fa85ce174ece5d25..a12532237ccd127557d9416481f615707eb8e907 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: afp_dsi.c,v 1.31 2003-06-26 02:15:21 didg Exp $
+ * $Id: afp_dsi.c,v 1.32 2005-04-28 20:49:39 bfernhomberg Exp $
  *
  * Copyright (c) 1999 Adrian Sun (asun@zoology.washington.edu)
  * Copyright (c) 1990,1993 Regents of The University of Michigan.
@@ -60,6 +60,7 @@ static __inline__ void afp_dsi_close(AFPObj *obj)
 {
     DSI *dsi = obj->handle;
 
+    close_all_vol();
     if (obj->logout)
         (*obj->logout)();
 
@@ -70,12 +71,25 @@ static __inline__ void afp_dsi_close(AFPObj *obj)
         dsi->read_count/1024.0, dsi->write_count/1024.0);
 
     dsi_close(dsi);
-    close_vols();
 }
 
-/* a little bit of code duplication. */
+/* -------------------------------
+ * SIGTERM
+ * a little bit of code duplication. 
+ */
 static void afp_dsi_die(int sig)
 {
+static volatile int in_handler;
+    
+    if (in_handler) {
+       return;
+    }
+    /* it's not atomic but we don't care because it's an exit function
+     * ie if a signal is received here, between the test and the affectation,
+     * it will not return.
+    */
+    in_handler = 1;
+
     dsi_attention(child.obj->handle, AFPATTN_SHUTDOWN);
     afp_dsi_close(child.obj);
     if (sig) /* if no signal, assume dieing because logins are disabled &
@@ -115,9 +129,8 @@ static void afp_dsi_timedown()
 
     if ( setitimer( ITIMER_REAL, &it, 0 ) < 0 ) {
         LOG(log_error, logtype_afpd, "afp_timedown: setitimer: %s", strerror(errno) );
-        afp_dsi_die(1);
+        afp_dsi_die(EXITERR_SYS);
     }
-
     memset(&sv, 0, sizeof(sv));
     sv.sa_handler = afp_dsi_die;
     sigemptyset( &sv.sa_mask );
@@ -126,24 +139,36 @@ static void afp_dsi_timedown()
     sv.sa_flags = SA_RESTART;
     if ( sigaction( SIGALRM, &sv, 0 ) < 0 ) {
         LOG(log_error, logtype_afpd, "afp_timedown: sigaction: %s", strerror(errno) );
-        afp_dsi_die(1);
+        afp_dsi_die(EXITERR_SYS);
     }
 
-    /* ignore SIGHUP */
+    /* ignore myself */
     sv.sa_handler = SIG_IGN;
     sigemptyset( &sv.sa_mask );
     sv.sa_flags = SA_RESTART;
-    if ( sigaction( SIGHUP, &sv, 0 ) < 0 ) {
+    if ( sigaction( SIGUSR1, &sv, 0 ) < 0 ) {
         LOG(log_error, logtype_afpd, "afp_timedown: sigaction SIGHUP: %s", strerror(errno) );
-        afp_dsi_die(1);
+        afp_dsi_die(EXITERR_SYS);
     }
 
 }
 
+/* ---------------------------------
+ * SIGHUP reload configuration file
+ * FIXME here or we wait ?
+*/
+volatile int reload_request = 0;
+
+static void afp_dsi_reload()
+{
+    reload_request = 1;
+}
+
+/* ---------------------- */
 #ifdef SERVERTEXT
-static void afp_dsi_getmesg (int sig)
+static void afp_dsi_getmesg (int sig _U_)
 {
-    readmessage();
+    readmessage(child.obj);
     dsi_attention(child.obj->handle, AFPATTN_MESG | AFPATTN_TIME(5));
 }
 #endif /* SERVERTEXT */
@@ -160,32 +185,35 @@ static void alarm_handler()
         if (!(err = pollvoltime(child.obj)))
             err = dsi_tickle(child.obj->handle);
         if (err <= 0) 
-            afp_dsi_die(1);
+            afp_dsi_die(EXITERR_CLNT);
         
     } else { /* didn't receive a tickle. close connection */
         LOG(log_error, logtype_afpd, "afp_alarm: child timed out");
-        afp_dsi_die(1);
+        afp_dsi_die(EXITERR_CLNT);
     }
 }
 
 
-/*
- *  Signal handler for SIGUSR1 - set the debug flag and 
+#ifdef DEBUG1
+/*  ---------------------------------
+ *  old signal handler for SIGUSR1 - set the debug flag and 
  *  redirect stdout to <tmpdir>/afpd-debug-<pid>.
  */
 void afp_set_debug (int sig)
 {
     char       fname[MAXPATHLEN];
 
-    snprintf(fname, MAXPATHLEN-1, "%s/afpd-debug-%d", P_tmpdir, getpid());
+    snprintf(fname, MAXPATHLEN-1, "%safpd-debug-%d", P_tmpdir, getpid());
     freopen(fname, "w", stdout);
     child.obj->options.flags |= OPTION_DEBUG;
 
     return;
 }
+#endif
 
-
-/* afp over dsi. this never returns. */
+/* -------------------------------------------
+ afp over dsi. this never returns. 
+*/
 void afp_over_dsi(AFPObj *obj)
 {
     DSI *dsi = (DSI *) obj->handle;
@@ -196,52 +224,71 @@ void afp_over_dsi(AFPObj *obj)
     obj->exit = afp_dsi_die;
     obj->reply = (int (*)()) dsi_cmdreply;
     obj->attention = (int (*)(void *, AFPUserBytes)) dsi_attention;
+
     obj->sleep = afp_dsi_sleep;
     child.obj = obj;
     child.tickle = child.flags = 0;
 
-    /* install SIGTERM and SIGHUP */
     memset(&action, 0, sizeof(action));
-    action.sa_handler = afp_dsi_timedown;
+
+    /* install SIGHUP */
+    action.sa_handler = afp_dsi_reload;
     sigemptyset( &action.sa_mask );
     sigaddset(&action.sa_mask, SIGALRM);
     sigaddset(&action.sa_mask, SIGTERM);
+    sigaddset(&action.sa_mask, SIGUSR1);
+#ifdef SERVERTEXT
+    sigaddset(&action.sa_mask, SIGUSR2);
+#endif    
     action.sa_flags = SA_RESTART;
     if ( sigaction( SIGHUP, &action, 0 ) < 0 ) {
         LOG(log_error, logtype_afpd, "afp_over_dsi: sigaction: %s", strerror(errno) );
-        afp_dsi_die(1);
+        afp_dsi_die(EXITERR_SYS);
     }
 
+    /* install SIGTERM */
     action.sa_handler = afp_dsi_die;
     sigemptyset( &action.sa_mask );
     sigaddset(&action.sa_mask, SIGALRM);
     sigaddset(&action.sa_mask, SIGHUP);
+    sigaddset(&action.sa_mask, SIGUSR1);
+#ifdef SERVERTEXT
+    sigaddset(&action.sa_mask, SIGUSR2);
+#endif    
     action.sa_flags = SA_RESTART;
     if ( sigaction( SIGTERM, &action, 0 ) < 0 ) {
         LOG(log_error, logtype_afpd, "afp_over_dsi: sigaction: %s", strerror(errno) );
-        afp_dsi_die(1);
+        afp_dsi_die(EXITERR_SYS);
     }
 
 #ifdef SERVERTEXT
     /* Added for server message support */
     action.sa_handler = afp_dsi_getmesg;
     sigemptyset( &action.sa_mask );
-    sigaddset(&action.sa_mask, SIGUSR2);
+    sigaddset(&action.sa_mask, SIGALRM);
+    sigaddset(&action.sa_mask, SIGTERM);
+    sigaddset(&action.sa_mask, SIGUSR1);
+    sigaddset(&action.sa_mask, SIGHUP);
     action.sa_flags = SA_RESTART;
     if ( sigaction( SIGUSR2, &action, 0) < 0 ) {
         LOG(log_error, logtype_afpd, "afp_over_dsi: sigaction: %s", strerror(errno) );
-        afp_dsi_die(1);
+        afp_dsi_die(EXITERR_SYS);
     }
 #endif /* SERVERTEXT */
 
-    /*  SIGUSR1 - set "debug" flag on this process.  */
-    action.sa_handler = afp_set_debug;
+    /*  SIGUSR1 - set down in 5 minutes  */
+    action.sa_handler = afp_dsi_timedown;
     sigemptyset( &action.sa_mask );
-    sigaddset(&action.sa_mask, SIGUSR1);
+    sigaddset(&action.sa_mask, SIGALRM);
+    sigaddset(&action.sa_mask, SIGHUP);
+    sigaddset(&action.sa_mask, SIGTERM);
+#ifdef SERVERTEXT
+    sigaddset(&action.sa_mask, SIGUSR2);
+#endif    
     action.sa_flags = SA_RESTART;
     if ( sigaction( SIGUSR1, &action, 0) < 0 ) {
         LOG(log_error, logtype_afpd, "afp_over_dsi: sigaction: %s", strerror(errno) );
-        afp_dsi_die(1);
+        afp_dsi_die(EXITERR_SYS);
     }
 
     /* tickle handler */
@@ -249,33 +296,46 @@ void afp_over_dsi(AFPObj *obj)
     sigemptyset(&action.sa_mask);
     sigaddset(&action.sa_mask, SIGHUP);
     sigaddset(&action.sa_mask, SIGTERM);
+    sigaddset(&action.sa_mask, SIGUSR1);
+#ifdef SERVERTEXT
+    sigaddset(&action.sa_mask, SIGUSR2);
+#endif    
     action.sa_flags = SA_RESTART;
     if ((sigaction(SIGALRM, &action, NULL) < 0) ||
             (setitimer(ITIMER_REAL, &dsi->timer, NULL) < 0)) {
-        afp_dsi_die(1);
+        afp_dsi_die(EXITERR_SYS);
     }
 
+#ifdef DEBUG1
+    fault_setup((void (*)(void *))afp_dsi_die);
+#endif
+
     /* get stuck here until the end */
     while ((cmd = dsi_receive(dsi))) {
         child.tickle = 0;
         child.flags &= ~CHILD_SLEEPING;
         dsi_sleep(dsi, 0); /* wake up */
+        if (reload_request) {
+            reload_request = 0;
+            load_volumes(child.obj);
+        }
 
         if (cmd == DSIFUNC_TICKLE) {
-            /* so we don't get killed on the client side. */
+            /* timer is not every 30 seconds anymore, so we don't get killed on the client side. */
             if ((child.flags & CHILD_DIE))
                 dsi_tickle(dsi);
             continue;
         } else if (!(child.flags & CHILD_DIE)) { /* reset tickle timer */
             setitimer(ITIMER_REAL, &dsi->timer, NULL);
         }
-
         switch(cmd) {
         case DSIFUNC_CLOSE:
             afp_dsi_close(obj);
             LOG(log_info, logtype_afpd, "done");
+#ifdef DEBUG1
             if (obj->options.flags & OPTION_DEBUG )
                 printf("done\n");
+#endif                
             return;
             break;
 
@@ -290,10 +350,12 @@ void afp_over_dsi(AFPObj *obj)
 #endif /* AFS */
 
             function = (u_char) dsi->commands[0];
+#ifdef DEBUG1
             if (obj->options.flags & OPTION_DEBUG ) {
                 printf("command: %d (%s)\n", function, AfpNum2name(function));
                 bprint((char *) dsi->commands, dsi->cmdlen);
             }
+#endif            
 
             /* send off an afp command. in a couple cases, we take advantage
              * of the fact that we're a stream-based protocol. */
@@ -322,24 +384,26 @@ void afp_over_dsi(AFPObj *obj)
                 break;
             }
 
+#ifdef DEBUG1
             if (obj->options.flags & OPTION_DEBUG ) {
                 printf( "reply: %d, %d\n", err, dsi->clientID);
                 bprint((char *) dsi->data, dsi->datalen);
             }
-
+#endif
             if (!dsi_cmdreply(dsi, err)) {
                 LOG(log_error, logtype_afpd, "dsi_cmdreply(%d): %s", dsi->socket, strerror(errno) );
-                afp_dsi_die(1);
+                afp_dsi_die(EXITERR_CLNT);
             }
             break;
 
         case DSIFUNC_WRITE: /* FPWrite and FPAddIcon */
             function = (u_char) dsi->commands[0];
+#ifdef DEBUG1
             if ( obj->options.flags & OPTION_DEBUG ) {
                 printf("(write) command: %d, %d\n", function, dsi->cmdlen);
                 bprint((char *) dsi->commands, dsi->cmdlen);
             }
-
+#endif
             if ( afp_switch[ function ] != NULL ) {
                 dsi->datalen = DSI_DATASIZ;
                 child.flags |= CHILD_RUNNING;
@@ -357,14 +421,15 @@ void afp_over_dsi(AFPObj *obj)
                 err = AFPERR_NOOP;
             }
 
+#ifdef DEBUG1
             if (obj->options.flags & OPTION_DEBUG ) {
                 printf( "(write) reply code: %d, %d\n", err, dsi->clientID);
                 bprint((char *) dsi->data, dsi->datalen);
             }
-
+#endif
             if (!dsi_wrtreply(dsi, err)) {
                 LOG(log_error, logtype_afpd, "dsi_wrtreply: %s", strerror(errno) );
-                afp_dsi_die(1);
+                afp_dsi_die(EXITERR_CLNT);
             }
             break;
 
@@ -381,7 +446,7 @@ void afp_over_dsi(AFPObj *obj)
             dsi_writeflush(dsi);
             break;
         }
-
+#ifdef DEBUG1
         if ( obj->options.flags & OPTION_DEBUG ) {
 #ifdef notdef
             pdesc( stdout );
@@ -389,8 +454,9 @@ void afp_over_dsi(AFPObj *obj)
             of_pforkdesc( stdout );
             fflush( stdout );
         }
+#endif
     }
 
     /* error */
-    afp_dsi_die(1);
+    afp_dsi_die(EXITERR_CLNT);
 }
index 2bfbf217e67d1e3d406acac72b08b16874989d38..d6566dfdd0096f5943d63231db3fbb6046bd0f7d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: afp_options.c,v 1.34 2003-08-30 16:10:32 bfernhomberg Exp $
+ * $Id: afp_options.c,v 1.35 2005-04-28 20:49:39 bfernhomberg Exp $
  *
  * Copyright (c) 1997 Adrian Sun (asun@zoology.washington.edu)
  * Copyright (c) 1990,1993 Regents of The University of Michigan.
@@ -61,7 +61,11 @@ char *strchr (), *strrchr ();
 #define MIN(a, b)  ((a) < (b) ? (a) : (b))
 #endif /* MIN */
 
-#define OPTIONS "dn:f:s:uc:g:P:ptDS:TL:F:U:Ivm:"
+/* FIXME CNID */
+char             Cnid_srv[MAXHOSTNAMELEN + 1] = "localhost";
+int              Cnid_port = 4700;
+
+#define OPTIONS "dn:f:s:uc:g:P:ptDS:TL:F:U:hIvVm:"
 #define LENGTH 512
 
 /* return an option. this uses an internal array, so it's necessary
@@ -100,10 +104,21 @@ static char *getoption(char *buf, const char *option)
 void afp_options_free(struct afp_options *opt,
                       const struct afp_options *save)
 {
-    if (opt->defaultvol && (opt->defaultvol != save->defaultvol))
-        free(opt->defaultvol);
-    if (opt->systemvol && (opt->systemvol != save->systemvol))
-        free(opt->systemvol);
+    if (opt->defaultvol.name && (opt->defaultvol.name != save->defaultvol.name))
+        free(opt->defaultvol.name);
+    if (opt->defaultvol.full_name && (opt->defaultvol.full_name != save->defaultvol.full_name))
+        free(opt->defaultvol.full_name);
+
+    if (opt->systemvol.name && (opt->systemvol.name != save->systemvol.name))
+        free(opt->systemvol.name);
+    if (opt->systemvol.full_name && (opt->systemvol.full_name != save->systemvol.full_name))
+        free(opt->systemvol.full_name);
+
+    if (opt->uservol.name && (opt->uservol.name != save->uservol.name))
+        free(opt->uservol.name);
+    if (opt->uservol.full_name && (opt->uservol.full_name != save->uservol.full_name))
+        free(opt->uservol.full_name);
+
     if (opt->loginmesg && (opt->loginmesg != save->loginmesg))
         free(opt->loginmesg);
     if (opt->guest && (opt->guest != save->guest))
@@ -118,18 +133,20 @@ void afp_options_free(struct afp_options *opt,
         free(opt->uampath);
     if (opt->uamlist && (opt->uamlist != save->uamlist))
         free(opt->uamlist);
-    if (opt->nlspath && (opt->nlspath != save->nlspath))
-        free(opt->nlspath);
     if (opt->passwdfile && (opt->passwdfile != save->passwdfile))
         free(opt->passwdfile);
     if (opt->signature && (opt->signature != save->signature))
-        free(opt->signature);
+       free(opt->signature);
     if (opt->k5service && (opt->k5service != save->k5service))
-        free(opt->k5service);
+       free(opt->k5service);
     if (opt->k5realm && (opt->k5realm != save->k5realm))
-        free(opt->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 */
@@ -138,10 +155,9 @@ void afp_options_init(struct afp_options *options)
     memset(options, 0, sizeof(struct afp_options));
     options->connections = 20;
     options->pidfile = _PATH_AFPDLOCK;
-    options->defaultvol = _PATH_AFPDDEFVOL;
-    options->systemvol = _PATH_AFPDSYSVOL;
+    options->defaultvol.name = _PATH_AFPDDEFVOL;
+    options->systemvol.name = _PATH_AFPDSYSVOL;
     options->configfile = _PATH_AFPDCONF;
-    options->nlspath = _PATH_AFPDNLSPATH;
     options->uampath = _PATH_AFPDUAMPATH;
     options->uamlist = "uams_clrtxt.so,uams_dhx.so";
     options->guest = "nobody";
@@ -161,6 +177,10 @@ void afp_options_init(struct afp_options *options)
     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
@@ -201,6 +221,8 @@ int afp_options_parseline(char *buf, struct afp_options *options)
         options->flags &= ~OPTION_CUSTOMICON;
     if (strstr(buf, " -icon"))
         options->flags |= OPTION_CUSTOMICON;
+    if (strstr(buf, " -advertise_ssh"))
+        options->flags |= OPTION_ANNOUNCESSH;
 
     /* passwd bits */
     if (strstr(buf, " -nosavepassword"))
@@ -230,10 +252,21 @@ int afp_options_parseline(char *buf, struct afp_options *options)
 
     /* figure out options w/ values. currently, this will ignore the setting
      * if memory is lacking. */
+
+    if ((c = getoption(buf, "-hostname"))) {
+        int len = strlen (c);
+        if (len <= MAXHOSTNAMELEN) {
+            memcpy(options->hostname, c, len);
+            options->hostname[len] = 0;
+        }
+        else
+            LOG(log_info, logtype_afpd, "WARNING: hostname %s is too long (%d)",c,len);
+    }
+
     if ((c = getoption(buf, "-defaultvol")) && (opt = strdup(c)))
-        options->defaultvol = opt;
+        options->defaultvol.name = opt;
     if ((c = getoption(buf, "-systemvol")) && (opt = strdup(c)))
-        options->systemvol = opt;
+        options->systemvol.name = opt;
     if ((c = getoption(buf, "-loginmesg")) && (opt = strdup(c)))
         options->loginmesg = opt;
     if ((c = getoption(buf, "-guestname")) && (opt = strdup(c)))
@@ -272,15 +305,12 @@ int afp_options_parseline(char *buf, struct afp_options *options)
     /* -[no]setuplog <logtype> <loglevel> [<filename>]*/
     if ((c = getoption(buf, "-setuplog")))
     {
-      char *ptr, *logtype, *loglevel, *filename;
-#if 0
-      char *logsource;
-#endif
+      char *ptr, *logsource, *logtype, *loglevel, *filename;
 
       LOG(log_debug6, logtype_afpd, "setting up logtype, c is %s", c);
       ptr = c;
-
-#if 0
+      
+      /* 
       logsource = ptr = c;
       if (ptr)
       {
@@ -292,7 +322,7 @@ int afp_options_parseline(char *buf, struct afp_options *options)
             ptr++;
         }
       }
-#endif
+      */
 
       logtype = ptr; 
       if (ptr)
@@ -395,16 +425,17 @@ int afp_options_parseline(char *buf, struct afp_options *options)
 #endif /* ADMIN_GRP */
 
     if ((c = getoption(buf, "-k5service")) && (opt = strdup(c)))
-        options->k5service = opt;
+       options->k5service = opt;
     if ((c = getoption(buf, "-k5realm")) && (opt = strdup(c)))
-        options->k5realm = opt;
+       options->k5realm = opt;
     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);
+       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);
+       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;
@@ -412,16 +443,29 @@ int afp_options_parseline(char *buf, struct afp_options *options)
         options->uampath = opt;
     if ((c = getoption(buf, "-uamlist")) && (opt = strdup(c)))
         options->uamlist = opt;
-    if ((c = getoption(buf, "-nlspath")) && (opt = strdup(c)))
-        options->nlspath = opt;
 
     if ((c = getoption(buf, "-ipaddr"))) {
         struct in_addr inaddr;
         if (inet_aton(c, &inaddr) && (opt = strdup(c))) {
             if (!gethostbyaddr((const char *) &inaddr, sizeof(inaddr), AF_INET))
-                LOG(log_info, logtype_afpd, "WARNING: can't find %s\n", opt);
+                LOG(log_info, logtype_afpd, "WARNING: can't find %s", opt);
             options->ipaddr = opt;
         }
+        else {
+            LOG(log_error, logtype_afpd, "Error parsing -ipaddr, is %s in numbers-and-dots notation?", c);
+        }
+    }
+
+    /* FIXME CNID Cnid_srv is a server attribute */
+    if ((c = getoption(buf, "-cnidserver"))) {
+        char *p;
+       int len;        
+        p = strchr(c, ':');
+       if (p != NULL && (len = p - c) <= MAXHOSTNAMELEN) {
+           memcpy(Cnid_srv, c, len);
+           Cnid_srv[len] = 0;
+           Cnid_port = atoi(p +1);
+       }
     }
 
     if ((c = getoption(buf, "-port")))
@@ -442,11 +486,185 @@ int afp_options_parseline(char *buf, struct afp_options *options)
             if ((opt = strdup(c)))
                 options->fqdn = opt;
         }
+       else {
+            LOG(log_error, logtype_afpd, "error parsing -fqdn, gethostbyname failed for: %s", c);
+       }
+    }
+
+    if ((c = getoption(buf, "-unixcodepage"))) {
+       if ((charset_t)-1  == ( options->unixcharset = add_charset(c)) ) {
+            options->unixcharset = CH_UNIX;
+            LOG(log_warning, logtype_afpd, "setting Unix codepage to '%s' failed", c);
+       }
+       else {
+            if ((opt = strdup(c)))
+                options->unixcodepage = opt;
+       }
+    }
+       
+    if ((c = getoption(buf, "-maccodepage"))) {
+       if ((charset_t)-1 == ( options->maccharset = add_charset(c)) ) {
+            options->maccharset = CH_MAC;
+            LOG(log_warning, logtype_afpd, "setting Mac codepage to '%s' failed", c);
+       }
+       else {
+            if ((opt = strdup(c)))
+                options->maccodepage = opt;
+       }
+    }
+    
+    if ((c = strstr(buf, "-closevol"))) {
+        options->closevol= 1;
     }
 
     return 1;
 }
 
+/*
+ * Show version information about afpd.
+ * Used by "afp -v".
+ */
+void show_version( )
+{
+       printf( "afpd %s - Apple Filing Protocol (AFP) daemon of Netatalk\n\n", VERSION );
+
+       puts( "This program is free software; you can redistribute it and/or modify it under" );
+       puts( "the terms of the GNU General Public License as published by the Free Software" );
+       puts( "Foundation; either version 2 of the License, or (at your option) any later" );
+       puts( "version. Please see the file COPYING for further information and details.\n" );
+
+       puts( "afpd has been compiled with support for these features:\n" );
+
+       printf( "        AFP3.1 support:\t" );
+#ifdef AFP3x
+       puts( "Yes" );
+#else
+       puts( "No" );
+#endif
+
+       printf( "      Transport layers:\t" );
+#ifdef NO_DDP
+       puts( "TCP/IP" );
+#else
+       puts( "TCP/IP DDP" );
+#endif
+
+       printf( "         CNID backends:\t" );
+#ifdef CNID_BACKEND_CDB
+       printf( "cdb ");
+#endif
+#ifdef CNID_BACKEND_DB3
+       printf( "db3 " );
+#endif
+#ifdef CNID_BACKEND_DBD
+#ifdef CNID_BACKEND_DBD_TXN
+       printf( "dbd-txn " );
+#else
+       printf( "dbd " );
+#endif
+#endif
+#ifdef CNID_BACKEND_HASH
+       printf( "hash " );
+#endif
+#ifdef CNID_BACKEND_LAST
+       printf( "last " );
+#endif
+#ifdef CNID_BACKEND_MTAB
+       printf( "mtab " );
+#endif
+#ifdef CNID_BACKEND_TDB
+       printf( "tdb " );
+#endif
+       puts( "" );
+}
+
+/*
+ * Show extended version information about afpd and Netatalk.
+ * Used by "afp -V".
+ */
+void show_version_extended( )
+{
+       show_version( );
+
+       printf( "           SLP support:\t" );
+#ifdef USE_SRVLOC
+       puts( "Yes" );
+#else
+       puts( "No" );
+#endif
+
+       printf( "  TCP wrappers support:\t" );
+#ifdef TCPWRAP
+       puts( "Yes" );
+#else
+       puts( "No" );
+#endif
+
+       printf( "         Quota support:\t" );
+#ifndef NO_QUOTA_SUPPORT
+       puts( "Yes" );
+#else
+       puts( "No" );
+#endif
+
+       printf( "   Admin group support:\t" );
+#ifdef ADMIN_GRP
+       puts( "Yes" );
+#else
+       puts( "No" );
+#endif
+
+       printf( "    Valid shell checks:\t" );
+#ifndef DISABLE_SHELLCHECK
+       puts( "Yes" );
+#else
+       puts( "No" );
+#endif
+
+       printf( "      cracklib support:\t" );
+#ifdef USE_CRACKLIB
+       puts( "Yes" );
+#else
+       puts( "No" );
+#endif
+
+       printf( "        Dropbox kludge:\t" );
+#ifdef DROPKLUDGE
+       puts( "Yes" );
+#else
+       puts( "No" );
+#endif
+
+       printf( "  Force volume uid/gid:\t" );
+#ifdef FORCE_UIDGID
+       puts( "Yes" );
+#else
+       puts( "No" );
+#endif
+}
+
+/*
+ * Display compiled-in default paths
+ */
+void show_paths( void )
+{
+       printf( "             afpd.conf:\t%s\n", _PATH_AFPDCONF );
+       printf( "   AppleVolumes.system:\t%s\n", _PATH_AFPDSYSVOL );
+       printf( "  AppleVolumes.default:\t%s\n", _PATH_AFPDDEFVOL );
+       printf( "       UAM search path:\t%s\n", _PATH_AFPDUAMPATH );
+}
+
+/*
+ * Display usage information about adpd.
+ */
+void show_usage( char *name )
+{
+       fprintf( stderr, "Usage:\t%s [-dDIptTu] [-c maxconnections] [-f defaultvolumes] [-F config]\n", name );
+       fprintf( stderr, "\t     [-g guest] [-L message] [-m umask][-n nbpname] [-P pidfile]\n" );
+       fprintf( stderr, "\t     [-s systemvolumes] [-S port] [-U uams]\n" );
+       fprintf( stderr, "\t%s -h|-v|-V\n", name );
+}
+
 int afp_options_parse(int ac, char **av, struct afp_options *options)
 {
     extern char *optarg;
@@ -479,10 +697,10 @@ int afp_options_parse(int ac, char **av, struct afp_options *options)
             options->server = optarg;
             break;
         case 'f' :
-            options->defaultvol = optarg;
+            options->defaultvol.name = optarg;
             break;
         case 's' :
-            options->systemvol = optarg;
+            options->systemvol.name = optarg;
             break;
         case 'u' :
             options->flags |= OPTION_USERVOLFIRST;
@@ -524,8 +742,18 @@ int afp_options_parse(int ac, char **av, struct afp_options *options)
             options->uamlist = optarg;
             break;
         case 'v':      /* version */
-            printf( "afpd (version %s)\n", VERSION );
-            exit ( 1 );
+            show_version( ); puts( "" );
+           show_paths( ); puts( "" );
+            exit( 0 );
+            break;
+        case 'V':      /* extended version */
+            show_version_extended( ); puts( "" );
+           show_paths( ); puts( "" );
+            exit( 0 );
+            break;
+        case 'h':      /* usage */
+            show_usage( p );
+            exit( 0 );
             break;
         case 'I':
             options->flags |= OPTION_CUSTOMICON;
@@ -546,13 +774,8 @@ int afp_options_parse(int ac, char **av, struct afp_options *options)
         }
     }
     if ( err || optind != ac ) {
-        fprintf( stderr,
-                 "Usage:\t%s [ -dpDTIt ] [ -n nbpname ] [ -f defvols ] \
-                 [ -P pidfile ] [ -s sysvols ] \n", p );
-        fprintf( stderr,
-                 "\t[ -u ] [ -c maxconn ] [ -g guest ] \
-                 [ -S port ] [ -L loginmesg ] [ -F configfile ] [ -U uamlist ]\n" );
-        return 0;
+        show_usage( p );
+        exit( 2 );
     }
 
 #ifdef ultrix
index a80c83c799c6434fdbe5718f84c4715bd604217e..2e659cfafc29bc1f30dc4498d82b41dd08c81db3 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: afp_util.c,v 1.3 2003-03-12 15:07:01 didg Exp $
+ * $Id: afp_util.c,v 1.4 2005-04-28 20:49:40 bfernhomberg Exp $
  *
  * Copyright (c) 1999 Adrian Sun (asun@zoology.washington.edu)
  * Copyright (c) 1990,1993 Regents of The University of Michigan.
@@ -14,6 +14,7 @@
 #include "config.h"
 #endif /* HAVE_CONFIG_H */
 
+#ifdef DEBUG1
 #include <atalk/afp.h>
 
 const char *AfpNum2name(int num)
@@ -88,3 +89,4 @@ const char *AfpNum2name(int num)
        }                                                                                         
        return "not yet defined";                                                                 
 }
+#endif
diff --git a/etc/afpd/afp_vfs.h b/etc/afpd/afp_vfs.h
new file mode 100644 (file)
index 0000000..e9ec5c3
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+   Copyright (c) 2004 Didier Gautheron
+   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.
+
+   vfs layer for afp
+*/
+
+#ifndef _AFP_VFS_H
+#define _AFP_VFS_H
+
+#include <atalk/adouble.h>
+struct vol;
+
+struct vfs_ops {
+    /* low level adouble fn */
+    char *(*ad_path)(const char *, int);
+
+    /* */
+    int (*validupath)(const struct vol *, const char *);
+    int (*rf_chown)(const struct vol *, const char *path, uid_t owner, gid_t group);
+    int (*rf_renamedir)(const struct vol *, const char *oldpath, const char *newpath);
+    int (*rf_deletecurdir)(const struct vol *);
+    int (*rf_setfilmode)(const struct vol *, const char * name, mode_t mode, struct stat *st);
+    int (*rf_setdirmode)(const struct vol *, const char * name, mode_t mode, struct stat *st);
+    int (*rf_setdirunixmode)(const struct vol *, const char * name, mode_t mode, struct stat *st);
+
+    int (*rf_setdirowner)(const struct vol *, const char *path, uid_t owner, gid_t group);
+
+    int (*rf_deletefile)(const struct vol *, const char * );
+    int (*rf_renamefile)(const struct vol *, const char *oldpath, const char *newpath);
+
+};
+
+void initvol_vfs(struct vol *vol);
+
+#endif
diff --git a/etc/afpd/afprun.c b/etc/afpd/afprun.c
new file mode 100644 (file)
index 0000000..cd506a5
--- /dev/null
@@ -0,0 +1,266 @@
+/* 
+   Unix SMB/CIFS implementation.
+   run a command as a specified user
+   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.
+   
+   modified for netatalk dgautheron@magic.fr
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include <stdio.h>
+#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>
+
+/* FIXME */
+#ifdef linux
+#ifndef USE_SETRESUID
+#define USE_SETRESUID 1
+#endif
+#else
+#ifndef USE_SETEUID
+#define USE_SETEUID 1
+#endif
+#endif
+
+#include <atalk/logger.h>
+
+/**************************************************************************n
+ Find a suitable temporary directory. The result should be copied immediately
+  as it may be overwritten by a subsequent call.
+  ****************************************************************************/
+   
+static const char *tmpdir(void)
+{
+    char *p;
+
+    if ((p = getenv("TMPDIR")))
+        return p;
+    return "/tmp";
+}
+
+/****************************************************************************
+This is a utility function of afprun().
+****************************************************************************/
+
+static int setup_out_fd(void)
+{  
+       int fd;
+       char path[MAXPATHLEN +1];
+
+       snprintf(path, sizeof(path)-1, "%s/afp.XXXXXX", tmpdir());
+
+       /* now create the file */
+       fd = mkstemp(path);
+
+       if (fd == -1) {
+               LOG(log_error, logtype_afpd, "setup_out_fd: Failed to create file %s. (%s)",path, strerror(errno) );
+               return -1;
+       }
+
+       /* Ensure file only kept around by open fd. */
+       unlink(path);
+       return fd;
+}
+
+/****************************************************************************
+ Gain root privilege before doing something.
+ We want to end up with ruid==euid==0
+****************************************************************************/
+static void gain_root_privilege(void)
+{
+        seteuid(0);
+}
+/****************************************************************************
+ Ensure our real and effective groups are zero.
+ we want to end up with rgid==egid==0
+****************************************************************************/
+static void gain_root_group_privilege(void)
+{
+        setegid(0);
+}
+
+/****************************************************************************
+ Become the specified uid and gid - permanently !
+ there should be no way back if possible
+****************************************************************************/
+static void become_user_permanently(uid_t uid, gid_t gid)
+{
+    /*
+     * First - gain root privilege. We do this to ensure
+     * we can lose it again.
+     */
+    gain_root_privilege();
+    gain_root_group_privilege();
+#if USE_SETRESUID
+    setresgid(gid,gid,gid);
+    setgid(gid);
+    setresuid(uid,uid,uid);
+    setuid(uid);
+#endif
+#if USE_SETREUID
+    setregid(gid,gid);
+    setgid(gid);
+    setreuid(uid,uid);
+    setuid(uid);
+#endif
+#if USE_SETEUID
+    setegid(gid);
+    setgid(gid);
+    setuid(uid);
+    seteuid(uid);
+    setuid(uid);
+#endif
+#if USE_SETUIDX
+    setgidx(ID_REAL, gid);
+    setgidx(ID_EFFECTIVE, gid);
+    setgid(gid);
+    setuidx(ID_REAL, uid);
+    setuidx(ID_EFFECTIVE, uid);
+    setuid(uid);
+#endif
+}
+
+/****************************************************************************
+run a command being careful about uid/gid handling and putting the output in
+outfd (or discard it if outfd is NULL).
+****************************************************************************/
+
+int afprun(int root, char *cmd, int *outfd)
+{
+    pid_t pid;
+    uid_t uid = geteuid();
+    gid_t gid = getegid();
+       
+    /* point our stdout at the file we want output to go into */
+    if (outfd && ((*outfd = setup_out_fd()) == -1)) {
+        return -1;
+    }
+    LOG(log_debug, logtype_afpd, "running %s as user %d", cmd, root?0:uid);
+    /* in this method we will exec /bin/sh with the correct
+       arguments, after first setting stdout to point at the file */
+
+    if ((pid=fork()) < 0) {
+        LOG(log_error, logtype_afpd, "afprun: fork failed with error %s", strerror(errno) );
+       if (outfd) {
+           close(*outfd);
+           *outfd = -1;
+       }
+       return errno;
+    }
+
+    if (pid) {
+        /*
+        * Parent.
+        */
+       int status=0;
+       pid_t wpid;
+
+       /* the parent just waits for the child to exit */
+       while((wpid = waitpid(pid,&status,0)) < 0) {
+           if (errno == EINTR) {
+               errno = 0;
+               continue;
+           }
+           break;
+       }
+       if (wpid != pid) {
+           LOG(log_error, logtype_afpd, "waitpid(%d) : %s",(int)pid, strerror(errno) );
+           if (outfd) {
+               close(*outfd);
+               *outfd = -1;
+           }
+           return -1;
+       }
+       /* Reset the seek pointer. */
+       if (outfd) {
+           lseek(*outfd, 0, SEEK_SET);
+       }
+
+#if defined(WIFEXITED) && defined(WEXITSTATUS)
+        if (WIFEXITED(status)) {
+            return WEXITSTATUS(status);
+        }
+#endif
+        return status;
+    }
+    
+    /* we are in the child. we exec /bin/sh to do the work for us. we
+       don't directly exec the command we want because it may be a
+       pipeline or anything else the config file specifies */
+
+    /* point our stdout at the file we want output to go into */
+    if (outfd) {
+        close(1);
+       if (dup2(*outfd,1) != 1) {
+           LOG(log_error, logtype_afpd, "Failed to create stdout file descriptor");
+           close(*outfd);
+           exit(80);
+       }
+    }
+    
+    if (chdir("/") < 0) {
+        LOG(log_error, logtype_afpd, "afprun: can't change directory to \"/\" %s", strerror(errno) );
+        exit(83);
+    }
+
+    /* now completely lose our privileges. This is a fairly paranoid
+       way of doing it, but it does work on all systems that I know of */
+    if (root) {
+       become_user_permanently(0, 0);
+       uid = gid = 0;
+    }
+    else {
+       become_user_permanently(uid, gid);
+    }
+    if (getuid() != uid || geteuid() != uid || getgid() != gid || getegid() != gid) {
+        /* we failed to lose our privileges - do not execute the command */
+       exit(81); /* we can't print stuff at this stage, instead use exit codes for debugging */
+    }
+    
+    /* close all other file descriptors, leaving only 0, 1 and 2. 0 and
+       2 point to /dev/null from the startup code */
+    {
+       int fd;
+       for (fd=3;fd<256;fd++) close(fd);
+    }
+
+    execl("/bin/sh","sh","-c",cmd,NULL);  
+    /* not reached */
+    exit(82);
+    return 1;
+}
index 69618382fa5c43fd64f7593d44dc48f7b2b7f6d3..2c30865b0697de36681d2c329b5c94fe4c8c543d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: afs.c,v 1.16 2003-03-15 01:34:35 didg Exp $
+ * $Id: afs.c,v 1.17 2005-04-28 20:49:40 bfernhomberg Exp $
  * Copyright (c) 1990,1993 Regents of The University of Michigan.
  * All Rights Reserved.  See COPYRIGHT.
  */
 #ifdef HAVE_UNISTD_H
 #include <unistd.h>
 #endif /* HAVE_UNISTD_H */
+#include <sys/stat.h>
 
 #include "globals.h"
 #include "directory.h"
 #include "volume.h"
 #include "misc.h"
+#include "unix.h"
 
-afs_getvolspace( vol, bfree, btotal, bsize )
+int afs_getvolspace( vol, bfree, btotal, bsize )
 struct vol     *vol;
 VolSpace       *bfree, *btotal;
 u_int32_t   *bsize;
@@ -48,6 +50,9 @@ u_int32_t   *bsize;
 
     if ( vs->PartBlocksAvail > 0 ) {
         if ( vs->MaxQuota != 0 ) {
+#ifdef min
+#undef min
+#endif
 #define min(x,y)       (((x)<(y))?(x):(y))
             free = min( vs->MaxQuota - vs->BlocksInUse, vs->PartBlocksAvail );
         } else {
@@ -70,7 +75,7 @@ u_int32_t   *bsize;
     return( AFP_OK );
 }
 
-afp_getdiracl(obj, ibuf, ibuflen, rbuf, rbuflen )
+int afp_getdiracl(obj, ibuf, ibuflen, rbuf, rbuflen )
 AFPObj      *obj;
 char   *ibuf, *rbuf;
 int            ibuflen, *rbuflen;
@@ -127,7 +132,7 @@ int         ibuflen, *rbuflen;
     #undef accessmode
 #endif
 
-afsmode( path, ma, dir, st )
+void afsmode( path, ma, dir, st )
 char           *path;
 struct maccess *ma;
 struct dir      *dir;
@@ -151,7 +156,7 @@ struct stat     *st;
         return;
     }
 
-    accessmode( path, &ma, dir, st );
+    accessmode( path, ma, dir, st );
 
     return;
 }
@@ -160,7 +165,7 @@ extern struct dir   *curdir;
 /*
  * cmd | 0 | vid | did | pathtype | pathname | 0 | acl
  */
-afp_setdiracl(obj, ibuf, ibuflen, rbuf, rbuflen )
+int afp_setdiracl(obj, ibuf, ibuflen, rbuf, rbuflen )
 AFPObj      *obj;
 char   *ibuf, *rbuf;
 int            ibuflen, *rbuflen;
@@ -230,7 +235,7 @@ int         ibuflen, *rbuflen;
 extern C_Block         seskey;
 extern Key_schedule    seskeysched;
 
-afp_afschangepw(obj, ibuf, ibuflen, rbuf, rbuflen )
+int afp_afschangepw(obj, ibuf, ibuflen, rbuf, rbuflen )
 AFPObj      *obj;
 char   *ibuf, *rbuf;
 int            ibuflen, *rbuflen;
index 7eb6880dc724e0b51ec5dcafe1b77266fa61f65c..a595c21098b467cf0d83c64971e08b6fe04c1b90 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: appl.c,v 1.14 2003-06-09 15:09:19 srittau Exp $
+ * $Id: appl.c,v 1.15 2005-04-28 20:49:40 bfernhomberg Exp $
  *
  * Copyright (c) 1990,1993 Regents of The University of Michigan.
  * All Rights Reserved.  See COPYRIGHT.
 #include <stdlib.h>
 #include <string.h>
 #include <ctype.h>
-#ifdef HAVE_FCNTL_H
-#include <fcntl.h>
-#endif /* HAVE_FCNTL_H */
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif /* HAVE_UNISTD_H */
-#include <sys/types.h>
-#include <sys/stat.h>
+
 #include <sys/param.h>
 #include <atalk/logger.h>
 #include <errno.h>
 
-#include <netatalk/endian.h>
 #include <atalk/adouble.h>
 #include <atalk/afp.h>
 
@@ -35,7 +27,7 @@
 #include "file.h"
 #include "desktop.h"
 
-static struct savedt   sa = { { 0, 0, 0, 0 }, -1, 0 };
+static struct savedt   sa = { { 0, 0, 0, 0 }, -1, 0, 0};
 
 static __inline__ int pathcmp( p, plen, q, qlen )
 char   *p;
@@ -49,6 +41,8 @@ int   qlen;
 static int applopen( vol, creator, flags, mode )
 struct vol     *vol;
 u_char creator[ 4 ];
+int flags;
+int mode;
 {
     char       *dtf, *adt, *adts;
 
@@ -134,7 +128,8 @@ u_short     mplen;
  * but uses upaths instead of mac format paths.
  *
  * The new way: dir and path refer to an app, path is a mac format
- * pathname.  makemacpath() builds a cname.
+ * pathname.  makemacpath() builds a cname. (zero is a path separator
+ * and it's not \0 terminated).
  *
  * See afp_getappl() for the backward compatiblity code.
  */
@@ -149,10 +144,14 @@ char      *path;
 
     p = mpath + mpathlen;
     p -= strlen( path );
-    strncpy( p, path, strlen( path ));
+    memcpy( p, path, strlen( path )); 
 
     while ( dir->d_parent != NULL ) {
         p -= strlen( dir->d_m_name ) + 1;
+        if (p < mpath) {
+            /* FIXME: pathname too long */
+            return NULL;
+        }
         strcpy( p, dir->d_m_name );
         dir = dir->d_parent;
     }
@@ -161,9 +160,9 @@ char        *path;
 
 
 int afp_addappl(obj, ibuf, ibuflen, rbuf, rbuflen )
-AFPObj      *obj;
-char   *ibuf, *rbuf;
-int            ibuflen, *rbuflen;
+AFPObj  *obj;
+char   *ibuf, *rbuf _U_;
+int    ibuflen _U_, *rbuflen;
 {
     struct vol         *vol;
     struct dir         *dir;
@@ -218,6 +217,9 @@ int         ibuflen, *rbuflen;
     }
     mpath = obj->newtmp;
     mp = makemacpath( mpath, AFPOBJ_TMPSIZ, curdir, path->m_name );
+    if (!mp) {
+        return AFPERR_PARAM;
+    }
     mplen =  mpath + AFPOBJ_TMPSIZ - mp;
 
     /* write the new appl entry at start of temporary file */
@@ -248,9 +250,9 @@ int         ibuflen, *rbuflen;
 }
 
 int afp_rmvappl(obj, ibuf, ibuflen, rbuf, rbuflen )
-AFPObj      *obj;
-char   *ibuf, *rbuf;
-int            ibuflen, *rbuflen;
+AFPObj  *obj;
+char   *ibuf, *rbuf _U_;
+int    ibuflen _U_, *rbuflen;
 {
     struct vol         *vol;
     struct dir         *dir;
@@ -301,6 +303,10 @@ int                ibuflen, *rbuflen;
     }
     mpath = obj->newtmp;
     mp = makemacpath( mpath, AFPOBJ_TMPSIZ, curdir, path->m_name );
+    if (!mp) {
+        return AFPERR_PARAM ;
+    }
+
     mplen =  mpath + AFPOBJ_TMPSIZ - mp;
     cc = copyapplfile( sa.sdt_fd, tfd, mp, mplen );
     close( tfd );
@@ -318,9 +324,9 @@ int         ibuflen, *rbuflen;
 }
 
 int afp_getappl(obj, ibuf, ibuflen, rbuf, rbuflen )
-AFPObj      *obj;
+AFPObj  *obj;
 char   *ibuf, *rbuf;
-int            ibuflen, *rbuflen;
+int    ibuflen _U_, *rbuflen;
 {
     struct vol         *vol;
     char               *p, *q;
@@ -330,7 +336,7 @@ int         ibuflen, *rbuflen;
     u_char             appltag[ 4 ];
     char                *buf, *cbuf;
     struct path         *path;
-
+    
     ibuf += 2;
 
     memcpy( &vid, ibuf, sizeof( vid ));
index 4058741d4eaca4b5acffc9378575e5b96f737d4c..9349468ddd99349bf96b891e3ea2b69d395eb830 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: auth.c,v 1.47 2003-06-09 15:09:19 srittau Exp $
+ * $Id: auth.c,v 1.48 2005-04-28 20:49:40 bfernhomberg Exp $
  *
  * Copyright (c) 1990,1993 Regents of The University of Michigan.
  * All Rights Reserved.  See COPYRIGHT.
 #include <limits.h>
 #include <string.h>
 #include <ctype.h>
-
-#ifdef SHADOWPW
-#include <shadow.h>
-#endif /* SHADOWPW */
-
+#include <time.h>
 #include <pwd.h>
 #include <grp.h>
 #include <atalk/logger.h>
@@ -56,17 +52,18 @@ int afp_version = 11;
 static int afp_version_index;
 
 uid_t  uuid;
-#if defined( __svr4__ ) && !defined( NGROUPS )
-#define NGROUPS NGROUPS_MAX
-#endif /* __svr4__ NGROUPS */
+
 #if defined( sun ) && !defined( __svr4__ ) || defined( ultrix )
-int    groups[ NGROUPS ];
+
+int    *groups;
+#define GROUPS_SIZE sizeof(int)
+
 #else /* sun __svr4__ ultrix */
-#if defined( __svr4__ ) && !defined( NGROUPS )
-#define NGROUPS        NGROUPS_MAX
-#endif /* __svr4__ NGROUPS */
-gid_t  groups[ NGROUPS ];
+
+gid_t  *groups;
+#define GROUPS_SIZE sizeof(gid_t)
 #endif /* sun ultrix */
+
 int    ngroups;
 
 /*
@@ -84,9 +81,9 @@ static struct afp_versions    afp_versions[] = {
         };
 
 static struct uam_mod uam_modules = {NULL, NULL, &uam_modules, &uam_modules};
-static struct uam_obj uam_login = {"", "", 0, {{NULL}}, &uam_login,
+static struct uam_obj uam_login = {"", "", 0, {{NULL, NULL, NULL, NULL }}, &uam_login,
                                       &uam_login};
-static struct uam_obj uam_changepw = {"", "", 0, {{NULL}}, &uam_changepw,
+static struct uam_obj uam_changepw = {"", "", 0, {{NULL, NULL, NULL, NULL}}, &uam_changepw,
                                          &uam_changepw};
 
 static struct uam_obj *afp_uam = NULL;
@@ -157,7 +154,65 @@ static int send_reply(const AFPObj *obj, const int err)
     return AFP_OK;
 }
 
-static int login(AFPObj *obj, struct passwd *pwd, void (*logout)(void))
+static int afp_errpwdexpired(obj, ibuf, ibuflen, rbuf, rbuflen )
+AFPObj  *obj _U_;
+char   *ibuf _U_, *rbuf _U_;
+int    ibuflen _U_, *rbuflen;
+{
+    *rbuflen = 0;
+    return AFPERR_PWDEXPR;
+}
+
+
+static int set_auth_switch(int expired)
+{
+    int i;
+
+    if (expired) {
+       /* 
+        * BF: expired password handling
+        * to allow the user to change his/her password we have to allow login
+        * but every following call except for FPChangePassword will be thrown
+        * away with an AFPERR_PWDEXPR error. (thanks to Leland Wallace from Apple
+        * for clarifying this)
+         */
+
+       for (i=0; i<=0xff; i++) {
+           uam_afpserver_action(i, UAM_AFPSERVER_PREAUTH, afp_errpwdexpired, NULL); 
+       }
+        uam_afpserver_action(AFP_LOGOUT, UAM_AFPSERVER_PREAUTH, afp_logout, NULL); 
+       uam_afpserver_action(AFP_CHANGEPW, UAM_AFPSERVER_PREAUTH, afp_changepw, NULL);
+    }
+    else {
+        afp_switch = postauth_switch;
+        switch (afp_version) {
+        case 31:
+           uam_afpserver_action(AFP_ENUMERATE_EXT2, UAM_AFPSERVER_POSTAUTH, afp_enumerate_ext2, NULL); 
+        case 30:
+           uam_afpserver_action(AFP_ENUMERATE_EXT, UAM_AFPSERVER_POSTAUTH, afp_enumerate_ext, NULL); 
+           uam_afpserver_action(AFP_BYTELOCK_EXT,  UAM_AFPSERVER_POSTAUTH, afp_bytelock_ext, NULL); 
+            /* catsearch_ext uses the same packet as catsearch FIXME double check this, it wasn't true for enue
+               enumerate_ext */
+           uam_afpserver_action(AFP_CATSEARCH_EXT, UAM_AFPSERVER_POSTAUTH, afp_catsearch_ext, NULL); 
+           uam_afpserver_action(AFP_GETSESSTOKEN,  UAM_AFPSERVER_POSTAUTH, afp_getsession, NULL); 
+           uam_afpserver_action(AFP_READ_EXT,      UAM_AFPSERVER_POSTAUTH, afp_read_ext, NULL); 
+           uam_afpserver_action(AFP_WRITE_EXT,     UAM_AFPSERVER_POSTAUTH, afp_write_ext, NULL); 
+           uam_afpserver_action(AFP_DISCTOLDSESS,  UAM_AFPSERVER_POSTAUTH, afp_disconnect, NULL); 
+
+        case 22:
+            /*
+             * If first connection to a server is done in classic AFP2.2 version is used
+             * but OSX uses AFP3.x FPzzz command !
+            */
+           uam_afpserver_action(AFP_ZZZ,  UAM_AFPSERVER_POSTAUTH, afp_zzz, NULL); 
+           break;
+        }
+    }
+
+    return AFP_OK;
+}
+
+static int login(AFPObj *obj, struct passwd *pwd, void (*logout)(void), int expired)
 {
 #ifdef ADMIN_GRP
     int admin = 0;
@@ -175,6 +230,7 @@ static int login(AFPObj *obj, struct passwd *pwd, void (*logout)(void))
     LOG(log_info, logtype_afpd, "login %s (uid %d, gid %d) %s", pwd->pw_name,
         pwd->pw_uid, pwd->pw_gid , afp_versions[afp_version_index].av_name);
 
+#ifndef NO_DDP
     if (obj->proto == AFPPROTO_ASP) {
         ASP asp = obj->handle;
         int addr_net = ntohs( asp->asp_sat.sat_addr.s_net );
@@ -211,6 +267,7 @@ static int login(AFPObj *obj, struct passwd *pwd, void (*logout)(void))
             } /* if (addr_net && addr_node ) */
         } /* if (options->authprintdir) */
     } /* if (obj->proto == AFPPROTO_ASP) */
+#endif
 
     if (initgroups( pwd->pw_name, pwd->pw_gid ) < 0) {
 #ifdef RUN_AS_USER
@@ -224,10 +281,21 @@ static int login(AFPObj *obj, struct passwd *pwd, void (*logout)(void))
 
     /* Basically if the user is in the admin group, we stay root */
 
-    if (( ngroups = getgroups( NGROUPS, groups )) < 0 ) {
-        LOG(log_error, logtype_afpd, "login: getgroups: %s", strerror(errno) );
+    if (( ngroups = getgroups( 0, NULL )) < 0 ) {
+        LOG(log_error, logtype_afpd, "login: %s getgroups: %s", pwd->pw_name, strerror(errno) );
+        return AFPERR_BADUAM;
+    }
+    
+    if ( NULL == (groups = calloc(ngroups, GROUPS_SIZE)) ) {
+        LOG(log_error, logtype_afpd, "login: %s calloc: %d", ngroups);
+        return AFPERR_BADUAM;
+    }
+
+    if (( ngroups = getgroups( ngroups, groups )) < 0 ) {
+        LOG(log_error, logtype_afpd, "login: %s getgroups: %s", pwd->pw_name, strerror(errno) );
         return AFPERR_BADUAM;
     }
+
 #ifdef ADMIN_GRP
 #ifdef DEBUG
     LOG(log_info, logtype_afpd, "obj->options.admingid == %d", obj->options.admingid);
@@ -275,18 +343,15 @@ static int login(AFPObj *obj, struct passwd *pwd, void (*logout)(void))
             inet_ntoa( dsi->client.sin_addr ) );
 
         if (setegid( pwd->pw_gid ) < 0 || seteuid( pwd->pw_uid ) < 0) {
-            LOG(log_error, logtype_afpd, "login: %s", strerror(errno) );
+            LOG(log_error, logtype_afpd, "login: %s %s", pwd->pw_name, strerror(errno) );
             return AFPERR_BADUAM;
         }
     }
 #else /* TRU64 */
-#if 0
-        if (setregid(pwd->pw_gid, pwd->pw_gid ) < 0 || setreuid(pwd->pw_uid,pwd->pw_uid ) < 0) {
-#endif        
-        if (setegid( pwd->pw_gid ) < 0 || seteuid( pwd->pw_uid ) < 0) {
-            LOG(log_error, logtype_afpd, "login: %s", strerror(errno) );
-            return AFPERR_BADUAM;
-        }
+    if (setegid( pwd->pw_gid ) < 0 || seteuid( pwd->pw_uid ) < 0) {
+        LOG(log_error, logtype_afpd, "login: %s %s", pwd->pw_name, strerror(errno) );
+        return AFPERR_BADUAM;
+    }
 #endif /* TRU64 */
 
     /* There's probably a better way to do this, but for now, we just
@@ -298,39 +363,23 @@ static int login(AFPObj *obj, struct passwd *pwd, void (*logout)(void))
 #endif /* ADMIN_GRP */
         uuid = pwd->pw_uid;
 
-    afp_switch = postauth_switch;
-    switch (afp_version) {
-    case 31:
-       uam_afpserver_action(AFP_ENUMERATE_EXT2, UAM_AFPSERVER_POSTAUTH, afp_enumerate_ext2, NULL); 
-    case 30:
-       uam_afpserver_action(AFP_ENUMERATE_EXT, UAM_AFPSERVER_POSTAUTH, afp_enumerate_ext, NULL); 
-       uam_afpserver_action(AFP_BYTELOCK_EXT,  UAM_AFPSERVER_POSTAUTH, afp_bytelock_ext, NULL); 
-        /* catsearch_ext uses the same packet as catsearch FIXME double check this, it wasn't true for enue
-           enumerate_ext */
-       uam_afpserver_action(AFP_CATSEARCH_EXT, UAM_AFPSERVER_POSTAUTH, afp_catsearch_ext, NULL); 
-       uam_afpserver_action(AFP_GETSESSTOKEN,  UAM_AFPSERVER_POSTAUTH, afp_getsession, NULL); 
-       uam_afpserver_action(AFP_READ_EXT,      UAM_AFPSERVER_POSTAUTH, afp_read_ext, NULL); 
-       uam_afpserver_action(AFP_WRITE_EXT,     UAM_AFPSERVER_POSTAUTH, afp_write_ext, NULL); 
-       uam_afpserver_action(AFP_DISCTOLDSESS,  UAM_AFPSERVER_POSTAUTH, afp_disconnect, NULL); 
-       uam_afpserver_action(AFP_ZZZ,  UAM_AFPSERVER_POSTAUTH, afp_zzz, NULL); 
+    set_auth_switch(expired);
 
-       break;
-    }
     obj->logout = logout;
 
 #ifdef FORCE_UIDGID
     obj->force_uid = 1;
     save_uidgid ( &obj->uidgid );
-#endif                 
-
+#endif 
+       
     return( AFP_OK );
 }
 
 /* ---------------------- */
 int afp_zzz (obj, ibuf, ibuflen, rbuf, rbuflen ) /* Function 122 */
 AFPObj       *obj;
-char         *ibuf, *rbuf;
-unsigned int ibuflen, *rbuflen;
+char         *ibuf  _U_, *rbuf;
+unsigned int ibuflen  _U_, *rbuflen;
 {
     u_int32_t  retdata;
 
@@ -348,6 +397,41 @@ unsigned int ibuflen, *rbuflen;
     rbuf += sizeof(retdata);
     return AFP_OK;
 }
+
+/* ---------------------- */
+static int create_session_token(AFPObj *obj)
+{
+    pid_t pid;
+
+    /* use 8 bytes for token as OSX, don't know if it helps */
+    if ( sizeof(pid_t) > SESSIONTOKEN_LEN) {
+       LOG(log_error, logtype_afpd, "sizeof(pid_t) > %u", SESSIONTOKEN_LEN );
+       return AFPERR_MISC;
+    }
+
+    if ( NULL == (obj->sinfo.sessiontoken = malloc(SESSIONTOKEN_LEN)) )
+       return AFPERR_MISC;
+
+    memset(obj->sinfo.sessiontoken, 0, SESSIONTOKEN_LEN);
+    obj->sinfo.sessiontoken_len = SESSIONTOKEN_LEN;
+    pid = getpid();
+    memcpy(obj->sinfo.sessiontoken, &pid, sizeof(pid_t));
+
+    return 0;
+}
+
+static int create_session_key(AFPObj *obj)
+{
+    /* create session key */
+    if (obj->sinfo.sessionkey == NULL) {
+        if (NULL == (obj->sinfo.sessionkey = malloc(SESSIONKEY_LEN)) )
+            return AFPERR_MISC;   
+        uam_random_string(obj, obj->sinfo.sessionkey, SESSIONKEY_LEN);
+        obj->sinfo.sessionkey_len = SESSIONKEY_LEN;
+    }
+    return AFP_OK;
+}
+
    
 /* ---------------------- */
 int afp_getsession(obj, ibuf, ibuflen, rbuf, rbuflen )
@@ -358,25 +442,33 @@ unsigned int ibuflen, *rbuflen;
     u_int16_t           type;
     u_int32_t           idlen = 0;
     u_int32_t          boottime;
-
-    u_int16_t           tklen; /* FIXME: spec  u_int32_t? */
-    pid_t               token;
-    char               *p;
+    u_int32_t           tklen, tp;
+    char                *token; 
+    char                *p;
 
     *rbuflen = 0;
+    tklen = 0;
 
     ibuf += 2;
     ibuflen -= 2;
 
-    memcpy(&type, ibuf, sizeof(type));    
+    memcpy(&type, ibuf, sizeof(type));
     type = ntohs(type);
     ibuf += sizeof(type);
     ibuflen -= sizeof(type);
+
+    if ( obj->sinfo.sessiontoken == NULL ) {
+        if ( create_session_token( obj ) )
+            return AFPERR_MISC;
+    }
+
     /*
      * 
     */
     switch (type) {
     case 0: /* old version ?*/
+            tklen = obj->sinfo.sessiontoken_len;
+            token = obj->sinfo.sessiontoken;
         break;
     case 1: /* disconnect */
     case 2: /* reconnect update id */
@@ -389,6 +481,8 @@ unsigned int ibuflen, *rbuflen;
                 return AFPERR_PARAM;
             }
             /* memcpy (id, ibuf, idlen) */
+            tklen = obj->sinfo.sessiontoken_len;
+            token = obj->sinfo.sessiontoken;
         }
         break;
     case 3: /* Jaguar */
@@ -404,41 +498,57 @@ unsigned int ibuflen, *rbuflen;
            if (ibuflen < idlen || idlen > (90-10)) {
                return AFPERR_PARAM;
            }
-           server_ipc_write(IPC_GETSESSION, idlen+8, p ); 
+           server_ipc_write(IPC_GETSESSION, idlen+8, p );
+           tklen = obj->sinfo.sessiontoken_len;
+           token = obj->sinfo.sessiontoken;
        }
-       type = 0;
        break;
+     case 8: /* Panther Kerberos Token */
+            tklen = obj->sinfo.cryptedkey_len;
+            token = obj->sinfo.cryptedkey;
+        break;
+     default:
+            return AFPERR_NOOP;
+        break;
+
     }
-    *rbuflen = sizeof(type);
-    type = htons(type);
-    memcpy(rbuf, &type, sizeof(type));
-    rbuf += sizeof(type);
 
-    *rbuflen += sizeof(tklen);
-    tklen = htons(sizeof(pid_t));
-    memcpy(rbuf, &tklen, sizeof(tklen));
+    if (tklen == 0)
+        return AFPERR_MISC;
+
+    tp = htonl(tklen);
+    memcpy(rbuf, &tp, sizeof(tklen));
     rbuf += sizeof(tklen);
-    
-    *rbuflen += sizeof(pid_t);
-    token = getpid();
-    memcpy(rbuf, &token, sizeof(pid_t));
+    *rbuflen += sizeof(tklen);
+
+    memcpy(rbuf, token, tklen);
+    *rbuflen += tklen;
+
     return AFP_OK;
 }
 
 /* ---------------------- */
 int afp_disconnect(obj, ibuf, ibuflen, rbuf, rbuflen )
-AFPObj      *obj;
-char   *ibuf, *rbuf;
-int            ibuflen, *rbuflen;
+AFPObj  *obj  _U_;
+char   *ibuf, *rbuf  _U_;
+int    ibuflen  _U_, *rbuflen;
 {
     u_int16_t           type;
 
     u_int32_t           tklen;
     pid_t               token;
+    int                 i;
 
     *rbuflen = 0;
     ibuf += 2;
 
+#if 0
+    /* check for guest user */
+    if ( 0 == (strcasecmp(obj->username, obj->options.guest)) ) {
+        return AFPERR_MISC;
+    }
+#endif
+
     memcpy(&type, ibuf, sizeof(type));
     type = ntohs(type);
     ibuf += sizeof(type);
@@ -447,10 +557,24 @@ int               ibuflen, *rbuflen;
     tklen = ntohl(tklen);
     ibuf += sizeof(tklen);
 
-    if (tklen != sizeof(pid_t)) {
+    if ( sizeof(pid_t) > SESSIONTOKEN_LEN) {
+         LOG(log_error, logtype_afpd, "sizeof(pid_t) > %u", SESSIONTOKEN_LEN );
+         return AFPERR_MISC;
+    }
+    if (tklen != SESSIONTOKEN_LEN) {
         return AFPERR_MISC;
     }   
+    tklen = sizeof(pid_t);
     memcpy(&token, ibuf, tklen);
+
+    /* our stuff is pid + zero pad */
+    ibuf += tklen;
+    for (i = tklen; i < SESSIONTOKEN_LEN; i++, ibuf++) {
+         if (*ibuf != 0) {
+             return AFPERR_MISC;
+         }
+    }
+    
     /* killed old session, not easy */
     server_ipc_write(IPC_KILLTOKEN, tklen, &token);
     sleep(1);
@@ -535,11 +659,15 @@ int               ibuflen, *rbuflen;
     ibuf += len;
     ibuflen -= len;
 
+    if (AFP_OK != (i = create_session_key(obj)) )
+        return send_reply(obj, i);
+
     i = afp_uam->u.uam_login.login(obj, &pwd, ibuf, ibuflen, rbuf, rbuflen);
-    if (i || !pwd)
+
+    if (!pwd || ( i != AFP_OK && i != AFPERR_PWDEXPR))
         return send_reply(obj, i);
 
-    return send_reply(obj, login(obj, pwd, afp_uam->u.uam_login.logout));
+    return send_reply(obj, login(obj, pwd, afp_uam->u.uam_login.logout, ((i==AFPERR_PWDEXPR)?1:0)));
 }
 
 /* ---------------------- */
@@ -659,12 +787,17 @@ unsigned int      ibuflen, *rbuflen;
         ibuflen--;
     }
 
+    if (AFP_OK != (i = create_session_key(obj)) ) {
+        return send_reply(obj, i);
+    }
+
     /* FIXME user name are in UTF8 */    
     i = afp_uam->u.uam_login.login_ext(obj, username, &pwd, ibuf, ibuflen, rbuf, rbuflen);
-    if (i || !pwd)
+
+    if (!pwd || ( i != AFP_OK && i != AFPERR_PWDEXPR))
         return send_reply(obj, i);
 
-    return send_reply(obj, login(obj, pwd, afp_uam->u.uam_login.logout));
+    return send_reply(obj, login(obj, pwd, afp_uam->u.uam_login.logout, ((i==AFPERR_PWDEXPR)?1:0)));
 }
 
 /* ---------------------- */
@@ -681,22 +814,23 @@ int               ibuflen, *rbuflen;
         return send_reply(obj, AFPERR_NOTAUTH );
     }
 
-    ibuf += 2;
+    ibuf += 2; ibuflen -= 2;
     err = afp_uam->u.uam_login.logincont(obj, &pwd, ibuf, ibuflen,
                                          rbuf, rbuflen);
-    if (err || !pwd)
+    if (!pwd || ( err != AFP_OK && err != AFPERR_PWDEXPR))
         return send_reply(obj, err);
 
-    return send_reply(obj, login(obj, pwd, afp_uam->u.uam_login.logout));
+    return send_reply(obj, login(obj, pwd, afp_uam->u.uam_login.logout, ((err==AFPERR_PWDEXPR)?1:0)));
 }
 
 
 int afp_logout(obj, ibuf, ibuflen, rbuf, rbuflen)
 AFPObj     *obj;
-char       *ibuf, *rbuf;
-int        ibuflen, *rbuflen;
+char       *ibuf _U_, *rbuf  _U_;
+int        ibuflen  _U_, *rbuflen  _U_;
 {
     LOG(log_info, logtype_afpd, "logout %s", obj->username);
+    close_all_vol();
     obj->exit(0);
     return AFP_OK;
 }
@@ -722,6 +856,12 @@ int                ibuflen, *rbuflen;
     *rbuflen = 0;
     ibuf += 2;
 
+    /* check if password change is allowed, OS-X ignores the flag.
+     * we shouldn't trust the client on this anyway.
+     * not sure about the "right" error code, NOOP for now */ 
+    if (!(obj->options.passwdbits & PASSWD_SET))
+         return AFPERR_NOOP;
+
     /* make sure we can deal w/ this uam */
     len = (unsigned char) *ibuf++;
     if ((uam = auth_uamfind(UAM_SERVER_CHANGEPW, ibuf, len)) == NULL)
@@ -731,19 +871,30 @@ int               ibuflen, *rbuflen;
     if ((len + 1) & 1) /* pad byte */
         ibuf++;
 
-    len = (unsigned char) *ibuf++;
-    if ( len > sizeof(username) - 1) {
-        return AFPERR_PARAM;
+    if ( afp_version < 30) {
+        len = (unsigned char) *ibuf++;
+        if ( len > sizeof(username) - 1) {
+            return AFPERR_PARAM;
+        }
+        memcpy(username, ibuf, len);
+        username[ len ] = '\0';
+        ibuf += len;
+        if ((len + 1) & 1) /* pad byte */
+            ibuf++;
+    } else {
+       /* AFP > 3.0 doesn't pass the username, APF 3.1 specs page 124 */
+       if ( ibuf[0] != '\0' || ibuf[1] != '\0')
+           return AFPERR_PARAM;
+        ibuf += 2;
+       len = MIN(sizeof(username), strlen(obj->username));
+        memcpy(username, obj->username, len);
+       username[ len ] = '\0';
     }
-    memcpy(username, ibuf, len);
-    username[ len ] = '\0';
-    ibuf += len;
-    if ((len + 1) & 1) /* pad byte */
-        ibuf++;
+        
 
     LOG(log_info, logtype_afpd, "changing password for <%s>", username);
 
-    if (( pwd = uam_getname( username, sizeof(username))) == NULL )
+    if (( pwd = uam_getname( obj, username, sizeof(username))) == NULL )
         return AFPERR_PARAM;
 
     /* send it off to the uam. we really don't use ibuflen right now. */
@@ -753,15 +904,18 @@ int               ibuflen, *rbuflen;
     LOG(log_info, logtype_afpd, "password change %s.",
         (ret == AFPERR_AUTHCONT) ? "continued" :
         (ret ? "failed" : "succeeded"));
+    if ( ret == AFP_OK )
+       set_auth_switch(0);
+       
     return ret;
 }
 
 
 /* FPGetUserInfo */
 int afp_getuserinfo(obj, ibuf, ibuflen, rbuf, rbuflen )
-AFPObj      *obj;
+AFPObj  *obj _U_;
 char   *ibuf, *rbuf;
-int            ibuflen, *rbuflen;
+int    ibuflen _U_, *rbuflen;
 {
     u_int8_t  thisuser;
     u_int32_t id;
@@ -835,7 +989,7 @@ int auth_register(const int type, struct uam_obj *uam)
         return -1;
 
     if (!(start = UAM_LIST(type)))
-        return 0; /* silently fail */
+        return 1; /* we don't know what to do with it, caller must free it */
 
     uam_attach(start, uam);
     return 0;
@@ -852,7 +1006,7 @@ int auth_load(const char *path, const char *list)
     if (!path || !*path || !list || (len = strlen(path)) > sizeof(name) - 2)
         return -1;
 
-    strncpy(buf, list, sizeof(buf));
+    strlcpy(buf, list, sizeof(buf));
     if ((p = strtok(buf, ",")) == NULL)
         return -1;
 
@@ -863,7 +1017,7 @@ int auth_load(const char *path, const char *list)
     }
 
     while (p) {
-        strncpy(name + len, p, sizeof(name) - len);
+        strlcpy(name + len, p, sizeof(name) - len);
         LOG(log_debug, logtype_afpd, "uam: loading (%s)", name);
         /*
         if ((stat(name, &st) == 0) && (mod = uam_load(name, p))) {
index cb6bd5077f58f2e09e2673c847cbea1d2d8be202..803786b3870314efbe2613fb35e7839c5a9af72b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: auth.h,v 1.5 2003-03-12 15:07:02 didg Exp $
+ * $Id: auth.h,v 1.6 2005-04-28 20:49:40 bfernhomberg Exp $
  *
  * Copyright (c) 1990,1993 Regents of The University of Michigan.
  * All Rights Reserved.  See COPYRIGHT.
@@ -29,13 +29,10 @@ struct afp_versions {
 #define USERIBIT_ALL   (USERIBIT_USER | USERIBIT_GROUP)
 
 extern uid_t    uuid;
-#if defined( __svr4__ ) && !defined( NGROUPS )
-#define NGROUPS        NGROUPS_MAX
-#endif /*__svr4__ NGROUPS*/
 #if defined( sun ) && !defined( __svr4__ ) || defined( ultrix )
-extern int     groups[ NGROUPS ];
+extern int     *groups;
 #else /*sun __svr4__ ultrix*/
-extern gid_t   groups[ NGROUPS ];
+extern gid_t   *groups;
 #endif /*sun __svr4__ ultrix*/
 extern int     ngroups;
 
index 7d0385e7a8db3c43acc0467c4ed44d00966bf683..7fffaf7291da1c82b6e4d1982d2466555a36f928 100644 (file)
@@ -28,8 +28,6 @@
 #include <stdlib.h>
 #include <dirent.h>
 #include <errno.h>
-#include <syslog.h>
-#include <unistd.h>
 #include <ctype.h>
 #include <string.h>
 #include <time.h>
 #endif /* ! HAVE_MEMCPY */
 #endif
 
-#include <sys/types.h>
-#include <sys/stat.h>
 #include <sys/file.h>
 #include <netinet/in.h>
 
-#include <netatalk/endian.h>
 #include <atalk/afp.h>
 #include <atalk/adouble.h>
 #include <atalk/logger.h>
 struct finderinfo {
        u_int32_t f_type;
        u_int32_t creator;
-       u_int8_t attrs;    /* File attributes (8 bits)*/
-       u_int8_t label;    /* Label (8 bits)*/
+       u_int16_t attrs;    /* File attributes (high 8 bits)*/
+       u_int16_t label;    /* Label (low 8 bits )*/
        char reserved[22]; /* Unknown (at least for now...) */
 };
 
+typedef char packed_finder[ADEDLEN_FINDERI];
+
 /* Known attributes:
  * 0x04 - has a custom icon
  * 0x20 - name/icon is locked
@@ -97,10 +94,10 @@ struct scrit {
        time_t mdate;               /* Last modification date */
        time_t bdate;               /* Last backup date */
        u_int32_t pdid;             /* Parent DID */
-        u_int16_t offcnt;           /* Offspring count */
+    u_int16_t offcnt;           /* Offspring count */
        struct finderinfo finfo;    /* Finder info */
-       char lname[32];             /* Long name */
-       char utf8name[256];         /* UTF8 name */
+       char lname[64];             /* Long name */ 
+       char utf8name[512];         /* UTF8 name */
 };
 
 /*
@@ -112,8 +109,6 @@ struct scrit {
  *
  */
 struct dsitem {
-       char *m_name;    /* Mac name */
-       char *u_name;    /* unix name (== strrchr('/', path)) */
        struct dir *dir; /* Structure describing this directory */
        int pidx;        /* Parent's dsitem structure index. */
        int checked;     /* Have we checked this directory ? */
@@ -133,7 +128,7 @@ static int dsidx = 0;            /* First free item index... */
 static struct scrit c1, c2;          /* search criteria */
 
 /* Puts new item onto directory stack. */
-static int addstack(char *uname, char *mname, struct dir *dir, int pidx)
+static int addstack(char *uname, struct dir *dir, int pidx)
 {
        struct dsitem *ds;
        int           l;
@@ -148,18 +143,15 @@ static int addstack(char *uname, char *mname, struct dir *dir, int pidx)
 
        /* Put new element. Allocate and copy lname and path. */
        ds = dstack + dsidx++;
-       if (!(ds->m_name = strdup(mname)))
-               return -1;
        ds->dir = dir;
        ds->pidx = pidx;
        if (pidx >= 0) {
-               l = strlen(dstack[pidx].path);
-               if (!(ds->path = malloc(l + strlen(uname) + 2) ))
+           l = strlen(dstack[pidx].path);
+           if (!(ds->path = malloc(l + strlen(uname) + 2) ))
                        return -1;
                strcpy(ds->path, dstack[pidx].path);
                strcat(ds->path, "/");
                strcat(ds->path, uname);
-               ds->u_name = ds->path +l +1;
        }
 
        ds->checked = 0;
@@ -180,14 +172,12 @@ static int reducestack()
        while (dsidx > 0) {
                if (dstack[dsidx-1].checked) {
                        dsidx--;
-                       free(dstack[dsidx].m_name);
                        free(dstack[dsidx].path);
-                       /* Check if we need to free (or release) dir structures */
                } else
                        return dsidx - 1;
        } 
        return -1;
-} /* reducestack() */
+} 
 
 /* Clears directory stack. */
 static void clearstack() 
@@ -195,74 +185,64 @@ static void clearstack()
        save_cidx = -1;
        while (dsidx > 0) {
                dsidx--;
-               free(dstack[dsidx].m_name);
                free(dstack[dsidx].path);
-               /* Check if we need to free (or release) dir structures */
-       }
-} /* clearstack() */
-
-/* Fills in dir field of dstack[cidx]. Must fill parent dirs' fields if needed... */
-static int resolve_dir(struct vol *vol, int cidx)
-{
-       struct dir *dir, *cdir;
-       
-       if (dstack[cidx].dir != NULL)
-               return 1;
-
-       if (dstack[cidx].pidx < 0)
-               return 0;
-
-       if (dstack[dstack[cidx].pidx].dir == NULL && resolve_dir(vol, dstack[cidx].pidx) == 0)
-              return 0;
-
-       cdir = dstack[dstack[cidx].pidx].dir;
-       dir = cdir->d_child;
-       while (dir) {
-               if (strcmp(dir->d_m_name, dstack[cidx].m_name) == 0)
-                       break;
-               dir = (dir == cdir->d_child->d_prev) ? NULL : dir->d_next;
-       } /* while */
-
-       if (!dir) {
-               struct path path;
-
-               path.u_name = dstack[cidx].path;   
-               if (of_stat(&path)==-1) {
-                       syslog(LOG_DEBUG, "resolve_dir: stat %s: %s", dstack[cidx].path, strerror(errno));
-                       return 0;
-               }
-               path.m_name = dstack[cidx].m_name;
-               path.u_name = dstack[cidx].u_name;   
-               /* adddir works with a filename not absolute pathname */
-               if ((dir = adddir(vol, cdir, &path)) == NULL)
-                       return 0;
        }
-       dstack[cidx].dir = dir;
-
-       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, struct adouble *adp)
 {
        static struct adouble ad;
-       struct adouble *adp;
+       
        struct ofork *of;
-       int isdir = S_ISDIR(path->st.st_mode);
+       int isdir;
+       
+       if (adp)
+           return adp;
+           
+       isdir  = S_ISDIR(path->st.st_mode);
 
        if (!isdir && (of = of_findname(path))) {
                adp = of->of_ad;
        } else {
-               memset(&ad, 0, sizeof(ad));
+               ad_init(&ad, vol->v_adouble, vol->v_ad_options);
                adp = &ad;
        } 
 
-       if ( ad_open( path->u_name, ADFLAGS_HF | ((isdir)?ADFLAGS_DIR:0), O_RDONLY, 0, adp) < 0 ) {
-               return NULL;
-       } 
+    if ( ad_metadata( path->u_name, ((isdir)?ADFLAGS_DIR:0), adp) < 0 ) {
+        adp = NULL; /* FIXME without resource fork adl_lkup will be call again */
+    }
+    
        return adp;     
 }
 
+/* -------------------- */
+static struct finderinfo *unpack_buffer(struct finderinfo *finfo, char *buffer)
+{
+       memcpy(&finfo->f_type,  buffer +FINDERINFO_FRTYPEOFF, sizeof(finfo->f_type));
+       memcpy(&finfo->creator, buffer +FINDERINFO_FRCREATOFF, sizeof(finfo->creator));
+       memcpy(&finfo->attrs,   buffer +FINDERINFO_FRFLAGOFF, sizeof(finfo->attrs));
+       memcpy(&finfo->label,   buffer +FINDERINFO_FRFLAGOFF, sizeof(finfo->label));
+       finfo->attrs &= 0xff00; /* high 8 bits */
+       finfo->label &= 0xff;   /* low 8 bits */
+
+       return finfo;
+}
+
+/* -------------------- */
+static struct finderinfo *
+unpack_finderinfo(char *upath, struct adouble *adp, struct finderinfo *finfo)
+{
+       packed_finder  buf;
+       void           *ptr;
+       
+       ptr = get_finderinfo(upath, adp, &buf);
+       return unpack_buffer(finfo, ptr);
+}
+
+/* -------------------- */
 #define CATPBIT_PARTIAL 31
 /* Criteria checker. This function returns a 2-bit value. */
 /* bit 0 means if checked file meets given criteria. */
@@ -271,20 +251,47 @@ static struct adouble *adl_lkup(struct path *path)
  * fname - our fname (translated to UNIX)
  * cidx - index in directory stack
  */
-static int crit_check(struct vol *vol, struct path *path, int cidx) {
-       int r = 0;
-       u_int16_t attr;
+static int crit_check(struct vol *vol, struct path *path) {
+       int result = 0;
+       u_int16_t attr, flags = CONV_PRECOMPOSE;
        struct finderinfo *finfo = NULL, finderinfo;
        struct adouble *adp = NULL;
        time_t c_date, b_date;
+       u_int32_t ac_date, ab_date;
+       static char convbuf[512];
+       size_t len;
 
        if (S_ISDIR(path->st.st_mode)) {
-               r = 2;
                if (!c1.dbitmap)
-                       return r;
+                       return 0;
+       }
+       else {
+               if (!c1.fbitmap)
+                       return 0;
+
+               /* compute the Mac name 
+                * first try without id (it's slow to find it)
+                * An other option would be to call get_id in utompath but 
+                * we need to pass parent dir
+               */
+        if (!(path->m_name = utompath(vol, path->u_name, 0 , utf8_encoding()) )) {
+               /*retry with the right id */
+       
+               cnid_t id;
+               
+               adp = adl_lkup(vol, path, adp);
+               id = get_id(vol, adp, &path->st, path->d_dir->d_did, path->u_name, strlen(path->u_name));
+               if (!id) {
+                       /* FIXME */
+                       return 0;
+               }
+               /* save the id for getfilparm */
+               path->id = id;
+               if (!(path->m_name = utompath(vol, path->u_name, id , utf8_encoding()))) {
+                       return 0;
+               }
+        }
        }
-       else if (!c1.fbitmap)
-               return 0;
                
        /* Kind of optimization: 
         * -- first check things we've already have - filename
@@ -293,24 +300,30 @@ static int crit_check(struct vol *vol, struct path *path, int cidx) {
         */
 
        /* Check for filename */
-       if (c1.rbitmap & (1<<DIRPBIT_LNAME)) { 
-               if (c1.rbitmap & (1<<CATPBIT_PARTIAL)) {
-                       if (strcasestr(path->u_name, c1.lname) == NULL)
+       if ((c1.rbitmap & (1<<DIRPBIT_LNAME))) { 
+               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 & (1<<CATPBIT_PARTIAL))) {
+                       if (strcasestr_w( (ucs2_t*) convbuf, (ucs2_t*) c1.lname) == NULL)
                                goto crit_check_ret;
                } else
-                       if (strcasecmp(path->u_name, c1.lname) != 0)
+                       if (strcasecmp_w((ucs2_t*) convbuf, (ucs2_t*) c1.lname) != 0)
                                goto crit_check_ret;
-       } /* if (c1.rbitmap & ... */
+       } 
        
        if ((c1.rbitmap & (1<<FILPBIT_PDINFO))) { 
+               if ( (size_t)(-1) == (len = convert_charset( CH_UTF8_MAC, CH_UCS2, CH_UTF8, path->m_name, strlen(path->m_name), convbuf, 512, &flags))) {
+                       goto crit_check_ret;
+               }
+               convbuf[len] = 0; 
                if (c1.rbitmap & (1<<CATPBIT_PARTIAL)) {
-                       if (strcasestr(path->u_name, c1.utf8name) == NULL)
+                       if (strcasestr_w((ucs2_t *) convbuf, (ucs2_t*)c1.utf8name) == NULL)
                                goto crit_check_ret;
                } else
-                       if (strcasecmp(path->u_name, c1.utf8name) != 0)
+                       if (strcasecmp_w((ucs2_t *)convbuf, (ucs2_t*)c1.utf8name) != 0)
                                goto crit_check_ret;
-       } /* if (c1.rbitmap & ... */
-
+       } 
 
 
        /* FIXME */
@@ -321,47 +334,48 @@ static int crit_check(struct vol *vol, struct path *path, int cidx) {
        if ((unsigned)c2.bdate > 0x7fffffff)
                c2.bdate = 0x7fffffff;
 
-       /* Check for modification date FIXME: should we look at adouble structure ? */
-       if ((c1.rbitmap & (1<<DIRPBIT_MDATE))) 
+       /* Check for modification date */
+       if ((c1.rbitmap & (1<<DIRPBIT_MDATE))) {
                if (path->st.st_mtime < c1.mdate || path->st.st_mtime > c2.mdate)
                        goto crit_check_ret;
-
+       }
+       
        /* Check for creation date... */
-       if (c1.rbitmap & (1<<DIRPBIT_CDATE)) {
-               if (adp || (adp = adl_lkup(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;
-               } else c_date = path->st.st_mtime;
+       if ((c1.rbitmap & (1<<DIRPBIT_CDATE))) {
+               c_date = path->st.st_mtime;
+               adp = adl_lkup(vol, path, adp);
+               if (adp && ad_getdate(adp, AD_DATE_CREATE, &ac_date) >= 0)
+                   c_date = AD_DATE_TO_UNIX(ac_date);
+
                if (c_date < c1.cdate || c_date > c2.cdate)
                        goto crit_check_ret;
        }
 
        /* Check for backup date... */
-       if (c1.rbitmap & (1<<DIRPBIT_BDATE)) {
-               if (adp || (adp == adl_lkup(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;
-               } else b_date = path->st.st_mtime;
+       if ((c1.rbitmap & (1<<DIRPBIT_BDATE))) {
+               b_date = path->st.st_mtime;
+               adp = adl_lkup(vol, path, adp);
+               if (adp && ad_getdate(adp, AD_DATE_BACKUP, &ab_date) >= 0)
+                       b_date = AD_DATE_TO_UNIX(ab_date);
+
                if (b_date < c1.bdate || b_date > c2.bdate)
                        goto crit_check_ret;
        }
                                
        /* Check attributes */
        if ((c1.rbitmap & (1<<DIRPBIT_ATTR)) && c2.attr != 0) {
-               if (adp || (adp = adl_lkup(path))) {
+               if ((adp = adl_lkup(vol, path, adp))) {
                        ad_getattr(adp, &attr);
                        if ((attr & c2.attr) != c1.attr)
                                goto crit_check_ret;
-               } else goto crit_check_ret;
+               } else 
+                       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);
-               finfo = get_finderinfo(path->m_name, adp, &finderinfo);
+               adp = adl_lkup(vol, path, adp);
+           finfo = unpack_finderinfo(path->u_name, adp, &finderinfo);
                if (finfo->f_type != c1.finfo.f_type)
                        goto crit_check_ret;
        }
@@ -369,9 +383,8 @@ static int crit_check(struct vol *vol, struct path *path, int cidx) {
        /* Check creator ID */
        if ((c1.rbitmap & (1<<DIRPBIT_FINFO)) && c2.finfo.creator != 0) {
                if (!finfo) {
-                       if (!adp)
-                               adp = adl_lkup(path);
-                       finfo = get_finderinfo(path->m_name, adp, &finderinfo);
+               adp = adl_lkup(vol, path, adp);
+                       finfo = unpack_finderinfo(path->u_name, adp, &finderinfo);
                }
                if (finfo->creator != c1.finfo.creator)
                        goto crit_check_ret;
@@ -379,78 +392,36 @@ static int crit_check(struct vol *vol, struct path *path, int cidx) {
                
        /* Check finder info attributes */
        if ((c1.rbitmap & (1<<DIRPBIT_FINFO)) && c2.finfo.attrs != 0) {
-               u_int8_t attrs = 0;
-
-               if (adp || (adp = adl_lkup(path))) {
-                       finfo = (struct finderinfo*)ad_entry(adp, ADEID_FINDERI);
-                       attrs = finfo->attrs;
-               }
-               else if (*path->u_name == '.') {
-                       attrs = htons(FINDERINFO_INVISIBLE);
+               if (!finfo) {
+               adp = adl_lkup(vol, path, adp);
+                       finfo = unpack_finderinfo(path->u_name, adp, &finderinfo);
                }
 
-               if ((attrs & c2.finfo.attrs) != c1.finfo.attrs)
+               if ((finfo->attrs & c2.finfo.attrs) != c1.finfo.attrs)
                        goto crit_check_ret;
        }
        
        /* Check label */
        if ((c1.rbitmap & (1<<DIRPBIT_FINFO)) && c2.finfo.label != 0) {
-               if (adp || (adp = adl_lkup(path))) {
-                       finfo = (struct finderinfo*)ad_entry(adp, ADEID_FINDERI);
-                       if ((finfo->label & c2.finfo.label) != c1.finfo.label)
-                               goto crit_check_ret;
-               } else goto crit_check_ret;
+               if (!finfo) {
+               adp = adl_lkup(vol, path, adp);
+                       finfo = unpack_finderinfo(path->u_name, adp, &finderinfo);
+               }
+               if ((finfo->label & c2.finfo.label) != c1.finfo.label)
+                       goto crit_check_ret;
        }       
        /* FIXME: Attributes check ! */
        
        /* All criteria are met. */
-       r |= 1;
+       result |= 1;
 crit_check_ret:
        if (adp != NULL)
                ad_close(adp, ADFLAGS_HF);
-       return r;
+       return result;
 }  
 
-
-/* Adds an item to resultset. */
-static int rslt_add(struct vol *vol, char *fname, short cidx, int isdir, char **rbuf)
-{
-       char *p = *rbuf;
-       int l = fname != NULL ? strlen(fname) : 0;
-       u_int32_t did;
-       char p0;
-
-       p0 = p[0] = cidx != -1 ? l + 7 : l + 5;
-       if (p0 & 1) p[0]++;
-       p[1] = isdir ? 128 : 0;
-       p += 2;
-       if (cidx != -1) {
-               if (dstack[cidx].dir == NULL && resolve_dir(vol, cidx) == 0)
-                       return 0;
-               did = dstack[cidx].dir->d_did;
-               memcpy(p, &did, sizeof(did));
-               p += sizeof(did);
-       }
-
-       /* Fill offset of returned file name */
-       if (fname != NULL) {
-               *p++ = 0;
-               *p = (int)(p - *rbuf) - 1;
-               p++;
-               p[0] = l;
-               strcpy(p+1, fname);
-               p += l + 1;
-       }
-
-       if (p0 & 1)
-               *p++ = 0;
-
-       *rbuf = p;
-       /* *rbuf[0] = (int)(p-*rbuf); */
-       return 1;
-} /* rslt_add */
-
-static int rslt_add_ext ( struct vol *vol, struct path *path, char **buf, short cidx)
+/* ------------------------------ */
+static int rslt_add ( struct vol *vol, struct path *path, char **buf, int ext)
 {
 
        char            *p = *buf;
@@ -458,49 +429,49 @@ static int rslt_add_ext ( struct vol *vol, struct path *path, char **buf, short
        u_int16_t       resultsize;
        int             isdir = S_ISDIR(path->st.st_mode); 
 
-       if (dstack[cidx].dir == NULL && resolve_dir(vol, cidx) == 0)
-               return 0;
-
-       p += sizeof(resultsize); /* Skip resultsize */
+       /* Skip resultsize */
+       if (ext) {
+               p += sizeof(resultsize); 
+       }
+       else {
+               p++;
+       }
        *p++ = isdir ? FILDIRBIT_ISDIR : FILDIRBIT_ISFILE;    /* IsDir ? */
-       *p++ = 0;                  /* Pad */
+
+       if (ext) {
+               *p++ = 0;                  /* Pad */
+       }
        
-       if ( isdir )
-       {
-               struct dir* dir = NULL;
-
-               dir = dirsearch_byname(dstack[cidx].dir, path->u_name);
-               if (!dir) {
-                       if ((dir = adddir( vol, dstack[cidx].dir, path)) == NULL) {
-                               return 0;
-                       }
-               }
-               ret = getdirparams(vol, c1.dbitmap, path, dir, p , &tbuf ); 
+       if ( isdir ) {
+        ret = getdirparams(vol, c1.dbitmap, path, path->d_dir, p , &tbuf ); 
        }
-       else
-       {
-               ret = getfilparams ( vol, c1.fbitmap, path, dstack[cidx].dir, p, &tbuf);
+       else {
+           /* FIXME slow if we need the file ID, we already know it, done ? */
+               ret = getfilparams ( vol, c1.fbitmap, path, path->d_dir, p, &tbuf);
        }
 
        if ( ret != AFP_OK )
                return 0;
 
        /* Make sure entry length is even */
-       if (tbuf & 1) {
+       if ((tbuf & 1)) {
           *p++ = 0;
           tbuf++;
        }
 
-       resultsize = htons(tbuf);
-       memcpy ( *buf, &resultsize, sizeof(resultsize) );
-       
-       *buf += tbuf + 4;
+       if (ext) {
+               resultsize = htons(tbuf);
+               memcpy ( *buf, &resultsize, sizeof(resultsize) );
+               *buf += tbuf + 4;
+       }
+       else {
+               **buf = tbuf;
+               *buf += tbuf + 2;
+       }
 
        return 1;
-} /* rslr_add_ext */
+} 
        
-       
-
 #define VETO_STR \
         "./../.AppleDouble/.AppleDB/Network Trash Folder/TheVolumeSettingsFolder/TheFindByContentFolder/.AppleDesktop/.Parent/"
 
@@ -518,17 +489,17 @@ static int catsearch(struct vol *vol, struct dir *dir,
                     int rmatches, int *pos, char *rbuf, u_int32_t *nrecs, int *rsize, int ext)
 {
        int cidx, r;
-       char *fname = NULL;
        struct dirent *entry;
        int result = AFP_OK;
        int ccr;
-        struct path path;
+    struct path path;
        char *orig_dir = NULL;
        int orig_dir_len = 128;
        char *vpath = vol->v_path;
        char *rrbuf = rbuf;
-        time_t start_time;
-        int num_rounds = NUM_ROUNDS;
+    time_t start_time;
+    int num_rounds = NUM_ROUNDS;
+    int cached;
         
        if (*pos != 0 && *pos != cur_pos) 
                return AFPERR_CATCHNG;
@@ -536,7 +507,7 @@ static int catsearch(struct vol *vol, struct dir *dir,
        /* FIXME: Category "offspring count ! */
 
        /* So we are beginning... */
-        start_time = time(NULL);
+    start_time = time(NULL);
 
        /* We need to initialize all mandatory structures/variables and change working directory appropriate... */
        if (*pos == 0) {
@@ -546,7 +517,7 @@ static int catsearch(struct vol *vol, struct dir *dir,
                        dirpos = NULL;
                } 
                
-               if (addstack("","", dir, -1) == -1) {
+               if (addstack("", dir, -1) == -1) {
                        result = AFPERR_MISC;
                        goto catsearch_end;
                }
@@ -566,8 +537,11 @@ static int catsearch(struct vol *vol, struct dir *dir,
        } /* while() */
        
        while ((cidx = reducestack()) != -1) {
-               if (dirpos == NULL)
-                       dirpos = opendir(dstack[cidx].path);    
+               cached = 1;
+               if (dirpos == NULL) {
+                       dirpos = opendir(dstack[cidx].path);
+                       cached = (dstack[cidx].dir->d_child != NULL);
+               }
                if (dirpos == NULL) {
                        switch (errno) {
                        case EACCES:
@@ -585,13 +559,17 @@ static int catsearch(struct vol *vol, struct dir *dir,
                        } /* switch (errno) */
                        goto catsearch_end;
                }
+               /* FIXME error in chdir, what do we do? */
                chdir(dstack[cidx].path);
+               
+
                while ((entry=readdir(dirpos)) != NULL) {
                        (*pos)++;
 
-                       if (!(fname = path.m_name = check_dirent(vol, entry->d_name)))
+                       if (!check_dirent(vol, entry->d_name))
                           continue;
 
+                       memset(&path, 0, sizeof(path));
                        path.u_name = entry->d_name;
                        if (of_stat(&path) != 0) {
                                switch (errno) {
@@ -606,35 +584,40 @@ static int catsearch(struct vol *vol, struct dir *dir,
                                default:
                                        result = AFPERR_MISC;
                                        goto catsearch_end;
-                               } /* switch (errno) */
-                       } /* if (stat(entry->d_name, &path.st) != 0) */
-#if 0
-                       for (i = 0; fname[i] != 0; i++)
-                               fname[i] = tolower(fname[i]);
-#endif
-                       ccr = crit_check(vol, &path, cidx);
-                       /* bit 1 means that we have to descend into this directory. */
-                       if ((ccr & 2) && S_ISDIR(path.st.st_mode)) {
-                               if (addstack(entry->d_name, fname, NULL, cidx) == -1) {
+                               } 
+                       }
+                       if (S_ISDIR(path.st.st_mode)) {
+                               /* here we can short cut 
+                                  ie if in the same loop the parent dir wasn't in the cache
+                                  ALL dirsearch_byname will fail.
+                               */
+                               if (cached)
+                       path.d_dir = dirsearch_byname(dstack[cidx].dir, path.u_name);
+               else
+                       path.d_dir = NULL;
+               if (!path.d_dir) {
+                       /* path.m_name is set by adddir */
+                   if (NULL == (path.d_dir = adddir( vol, dstack[cidx].dir, &path) ) ) {
+                                               result = AFPERR_MISC;
+                                               goto catsearch_end;
+                                       }
+                }
+                path.m_name = path.d_dir->d_m_name; 
+                       
+                               if (addstack(path.u_name, path.d_dir, cidx) == -1) {
                                        result = AFPERR_MISC;
                                        goto catsearch_end;
                                } 
-                       }
+            }
+            else {
+               /* yes it sucks for directory d_dir is the directory, for file it's the parent directory*/
+               path.d_dir = dstack[cidx].dir;
+            }
+                       ccr = crit_check(vol, &path);
 
                        /* bit 0 means that criteria has been met */
-                       if (ccr & 1) {
-                               if ( ext ) { 
-                                       r = rslt_add_ext ( vol, &path, &rrbuf, cidx);
-                               }
-                               else
-                               {
-                                       r = rslt_add(vol,  
-                                                    (c1.fbitmap&(1<<FILPBIT_LNAME))|(c1.dbitmap&(1<<DIRPBIT_LNAME)) ? 
-                                                        fname : NULL,  
-                                                    (c1.fbitmap&(1<<FILPBIT_PDID))|(c1.dbitmap&(1<<DIRPBIT_PDID)) ? 
-                                                        cidx : -1, 
-                                                    S_ISDIR(path.st.st_mode), &rrbuf); 
-                               }
+                       if ((ccr & 1)) {
+                               r = rslt_add ( vol, &path, &rrbuf, ext);
                                
                                if (r == 0) {
                                        result = AFPERR_MISC;
@@ -648,11 +631,11 @@ static int catsearch(struct vol *vol, struct dir *dir,
                                if (rrbuf - rbuf >= 448)
                                        goto catsearch_pause;
                        }
-                        /* MacOS 9 doesn't like servers executing commands longer than few seconds */
+                       /* MacOS 9 doesn't like servers executing commands longer than few seconds */
                        if (--num_rounds <= 0) {
                            if (start_time != time(NULL)) {
-                               result=AFP_OK;
-                               goto catsearch_pause;
+                                       result=AFP_OK;
+                                       goto catsearch_pause;
                            }
                            num_rounds = NUM_ROUNDS;
                        }
@@ -679,7 +662,8 @@ catsearch_end: /* Exiting catsearch: error condition */
        return result;
 } /* catsearch() */
 
-int catsearch_afp(AFPObj *obj, char *ibuf, int ibuflen,
+/* -------------------------- */
+int catsearch_afp(AFPObj *obj _U_, char *ibuf, int ibuflen,
                   char *rbuf, int *rbuflen, int ext)
 {
     struct vol *vol;
@@ -691,6 +675,17 @@ int catsearch_afp(AFPObj *obj, char *ibuf, int ibuflen,
     int ret, rsize;
     u_int32_t nrecs = 0;
     unsigned char *spec1, *spec2, *bspec1, *bspec2;
+    size_t     len;
+    u_int16_t  namelen;
+    u_int16_t  flags;
+    char       tmppath[256];
+
+    *rbuflen = 0;
+
+    /* min header size */
+    if (ibuflen < 32) {
+        return AFPERR_PARAM;
+    }
 
     memset(&c1, 0, sizeof(c1));
     memset(&c2, 0, sizeof(c2));
@@ -699,7 +694,6 @@ int catsearch_afp(AFPObj *obj, char *ibuf, int ibuflen,
     memcpy(&vid, ibuf, sizeof(vid));
     ibuf += sizeof(vid);
 
-    *rbuflen = 0;
     if ((vol = getvolbyvid(vid)) == NULL) {
         return AFPERR_PARAM;
     }
@@ -735,6 +729,9 @@ int catsearch_afp(AFPObj *obj, char *ibuf, int ibuflen,
         spec_len = ntohs(spec_len);
     }
     else {
+        /* with catsearch only name and parent id are allowed */
+       c1.fbitmap &= (1<<FILPBIT_LNAME) | (1<<FILPBIT_PDID);
+       c1.dbitmap &= (1<<DIRPBIT_LNAME) | (1<<DIRPBIT_PDID);
         spec_len = *(unsigned char*)ibuf;
     }
 
@@ -796,73 +793,75 @@ int catsearch_afp(AFPObj *obj, char *ibuf, int ibuflen,
 
     /* Finder info */
     if (c1.rbitmap & (1 << FILPBIT_FINFO)) {
-           memcpy(&c1.finfo, spec1, sizeof(c1.finfo));
-           spec1 += sizeof(c1.finfo);
-           memcpy(&c2.finfo, spec2, sizeof(c2.finfo));
-           spec2 += sizeof(c2.finfo);
+       packed_finder buf;
+       
+           memcpy(buf, spec1, sizeof(buf));
+           unpack_buffer(&c1.finfo, buf);      
+           spec1 += sizeof(buf);
+
+           memcpy(buf, spec2, sizeof(buf));
+           unpack_buffer(&c2.finfo, buf);
+           spec2 += sizeof(buf);
     } /* Finder info */
 
     if ((c1.rbitmap & (1 << DIRPBIT_OFFCNT)) != 0) {
         /* Offspring count - only directories */
-       if (c1.fbitmap == 0) {
-           memcpy(&c1.offcnt, spec1, sizeof(c1.offcnt));
-           spec1 += sizeof(c1.offcnt);
-           c1.offcnt = ntohs(c1.offcnt);
-           memcpy(&c2.offcnt, spec2, sizeof(c2.offcnt));
-           spec2 += sizeof(c2.offcnt);
-           c2.offcnt = ntohs(c2.offcnt);
-       }
-       else if (c1.dbitmap == 0) {
-               /* ressource fork length */
-       }
-       else {
-           return AFPERR_BITMAP;  /* error */
-       }
+               if (c1.fbitmap == 0) {
+               memcpy(&c1.offcnt, spec1, sizeof(c1.offcnt));
+               spec1 += sizeof(c1.offcnt);
+               c1.offcnt = ntohs(c1.offcnt);
+               memcpy(&c2.offcnt, spec2, sizeof(c2.offcnt));
+               spec2 += sizeof(c2.offcnt);
+               c2.offcnt = ntohs(c2.offcnt);
+               }
+               else if (c1.dbitmap == 0) {
+                       /* ressource fork length */
+               }
+               else {
+               return AFPERR_BITMAP;  /* error */
+               }
     } /* Offspring count/ressource fork length */
 
     /* Long name */
     if (c1.rbitmap & (1 << FILPBIT_LNAME)) {
         /* 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);
+        if (len == (size_t)(-1))
+            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]);
+               /* 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;
 #endif
     }
         /* UTF8 Name */
     if (c1.rbitmap & (1 << FILPBIT_PDINFO)) {
-       char *          tmppath;
-       u_int16_t       namelen;
 
-       /* offset */
-       memcpy(&namelen, spec1, sizeof(namelen));
-       namelen = ntohs (namelen);
+               /* offset */
+               memcpy(&namelen, spec1, sizeof(namelen));
+               namelen = ntohs (namelen);
 
-       spec1 = bspec1+namelen+4; /* Skip Unicode Hint */
+               spec1 = bspec1+namelen+4; /* Skip Unicode Hint */
 
-       /* length */
-       memcpy(&namelen, spec1, sizeof(namelen));
-       namelen = ntohs (namelen);
-       if (namelen > 255)  /* Safeguard */
-               namelen = 255;
+               /* length */
+               memcpy(&namelen, spec1, sizeof(namelen));
+               namelen = ntohs (namelen);
+               if (namelen > 255)  /* Safeguard */
+                       namelen = 255;
 
-       memcpy (c1.utf8name, spec1+2, namelen);
-       c1.utf8name[(namelen+1)] =0;
+               memcpy (c1.utf8name, spec1+2, namelen);
+               c1.utf8name[(namelen+1)] =0;
 
-       /* convert charset */   
-       tmppath = mtoupath(vol, c1.utf8name, 1);
-        if (!tmppath)
+               /* convert charset */
+               flags = CONV_PRECOMPOSE;
+               len = convert_charset(CH_UTF8_MAC, CH_UCS2, CH_UTF8, c1.utf8name, namelen, c1.utf8name, 512, &flags);
+        if (len == (size_t)(-1))
             return AFPERR_PARAM;
-       memset (c1.utf8name, 0, 256);
-       memcpy (c1.utf8name, tmppath, MIN(strlen(tmppath), 255));
+               c1.utf8name[len]=0;
     }
     
     /* Call search */
@@ -887,6 +886,7 @@ int catsearch_afp(AFPObj *obj, char *ibuf, int ibuflen,
     return ret;
 } /* catsearch_afp */
 
+/* -------------------------- */
 int afp_catsearch (AFPObj *obj, char *ibuf, int ibuflen,
                   char *rbuf, int *rbuflen)
 {
diff --git a/etc/afpd/codepage.c b/etc/afpd/codepage.c
deleted file mode 100644 (file)
index cde0171..0000000
+++ /dev/null
@@ -1,292 +0,0 @@
-/*
- * $Id: codepage.c,v 1.8 2002-03-24 01:23:40 sibaz Exp $
- *
- * Copyright (c) 2000 Adrian Sun
- * All Rights Reserved. See COPYRIGHT.
- *
- * codepage support (based initially on some code from
- * julian@whistle.com)
- *
- * the strategy:
- * for single-byte maps, the codepage support devolves to a lookup
- * table for all possible 8-bit values. for double-byte maps, 
- * the first byte is used as a hash index followed by a linked list of
- * values.
- *
- * the badumap specifies illegal characters. these are 8-bit values
- * with an associated rule field. here are the rules:
- *   
- * illegal values: 0 is the only illegal value. no translation will
- * occur in those cases.  
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif /* HAVE_CONFIG_H */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#ifdef HAVE_FCNTL_H
-#include <fcntl.h>
-#endif /* HAVE_FCNTL_H */
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif /* HAVE_UNISTD_H */
-#include <atalk/logger.h>
-
-#include <netatalk/endian.h>
-
-#include "globals.h"
-#include "volume.h"
-#include "codepage.h"
-
-#define MAPSIZE 256
-
-/* deal with linked lists */
-#define CP_INIT(a) (a)->next = (a)->prev = (a)
-#define CP_ADD(a, b) do { \
-  (b)->next = (a)->next; \
-  (b)->prev = (a); \
-  (a)->next = (b); \
-} while (0)
-#define CP_REMOVE(a) do {  \
-  (a)->prev->next = (a)->next; \
-  (a)->next->prev = (a)->prev; \
-} while (0)
-
-/* search for stuff */
-#if 0
-static __inline__ unsigned char *codepage_find(struct codepage *page,
-        unsigned char *from)
-{
-}
-#endif
-
-static int add_code(struct codepage *page, unsigned char *from,
-                    unsigned char *to)
-{
-#if 0
-    union codepage_val *ptr;
-#endif /* 0 */
-
-    if (page->quantum < 1) /* no quantum given. don't do anything */
-        return 1;
-
-    if (page->quantum == 1) {
-        page->map[*from].value = *to;
-        return 0;
-    }
-
-#if 0
-    if (ptr = codepage_find(page->map, from)) {
-
-    } else {
-        unsigned char *space;
-        ptr = map[*from].hash;
-
-        space = (unsigned char *) malloc(sizeof(unsigned char)*quantum);
-        if (!ptr->from) {
-        } else {
-        }
-
-        map[*from].hash
-    }
-#endif /* 0 */
-    return 0;
-}
-
-static struct codepage *init_codepage(const int quantum)
-{
-    struct codepage *cp;
-
-    cp = (struct codepage *) malloc(sizeof(struct codepage));
-    if (!cp)
-        return NULL;
-
-    if ((cp->map = (union codepage_val *)
-                   calloc(MAPSIZE, sizeof(union codepage_val))) == NULL) {
-        free(cp);
-        return NULL;
-    }
-
-    cp->quantum = quantum;
-    return cp;
-}
-
-
-static void free_codepage(struct codepage *cp)
-{
-    int i;
-
-    if (!cp)
-        return;
-
-    if (cp->map) {
-        if (cp->quantum > 1) {
-            /* deal with any linked lists that may exist */
-            for (i = 0; i < MAPSIZE; i++) {
-                struct codepage_hash *ptr, *h;
-
-                h = &cp->map[i].hash; /* we don't free this one */
-                while ((ptr = h->prev) != h) {
-                    CP_REMOVE(ptr);
-                    free(ptr);
-                }
-            }
-        }
-        free(cp->map);
-    }
-    free(cp);
-}
-
-
-
-/* this is used by both codepages and generic mapping utilities. we
- * allocate enough space to map all 8-bit characters if necessary.
- * for double-byte mappings, we just use the table as a hash lookup.
- * if we don't match, we don't convert.
- */
-int codepage_init(struct vol *vol, const int rules,
-                  const int quantum)
-{
-    if ((rules & CODEPAGE_RULE_UTOM) && !vol->v_utompage) {
-        vol->v_utompage = init_codepage(quantum);
-        if (!vol->v_utompage)
-            goto err_utompage;
-    }
-
-    if ((rules & CODEPAGE_RULE_MTOU) && !vol->v_mtoupage) {
-        vol->v_mtoupage = init_codepage(quantum);
-        if (!vol->v_mtoupage) {
-            goto err_mtoupage;
-        }
-    }
-
-    if ((rules & CODEPAGE_RULE_BADU)  && !vol->v_badumap) {
-        vol->v_badumap = init_codepage(quantum);
-        if (!vol->v_badumap)
-            goto err_mtoupage;
-    }
-    return 0;
-
-err_mtoupage:
-    free_codepage(vol->v_mtoupage);
-    vol->v_mtoupage = NULL;
-
-err_utompage:
-    free_codepage(vol->v_utompage);
-    vol->v_utompage = NULL;
-    return -1;
-}
-
-void codepage_free(struct vol *vol)
-{
-    if (vol->v_utompage) {
-        free_codepage(vol->v_utompage);
-        vol->v_utompage = NULL;
-    }
-
-    if (vol->v_mtoupage) {
-        free_codepage(vol->v_mtoupage);
-        vol->v_mtoupage = NULL;
-    }
-
-    if (vol->v_badumap) {
-        free_codepage(vol->v_badumap);
-        vol->v_badumap = NULL;
-    }
-}
-
-
-int codepage_read(struct vol *vol, const char *path)
-{
-    unsigned char buf[CODEPAGE_FILE_HEADER_SIZE], *cur;
-    u_int16_t id;
-    int fd, i, quantum, rules;
-
-    if ((fd = open(path, O_RDONLY)) < 0) {
-        LOG(log_error, logtype_afpd, "%s: failed to open codepage", path);
-        return -1;
-    }
-
-    /* Read the codepage file header. */
-    if(read(fd, buf, sizeof(buf)) != sizeof(buf)) {
-        LOG(log_error, logtype_afpd, "%s: failed to read codepage header", path);
-        goto codepage_fail;
-    }
-
-    /* Check the file id */
-    cur = buf;
-    memcpy(&id, cur, sizeof(id));
-    cur += sizeof(id);
-    id = ntohs(id);
-    if (id != CODEPAGE_FILE_ID) {
-        LOG(log_error, logtype_afpd, "%s: not a codepage", path);
-        goto codepage_fail;
-    }
-
-    /* check the version number */
-    if (*cur++ != CODEPAGE_FILE_VERSION) {
-        LOG(log_error, logtype_afpd, "%s: codepage version not supported", path);
-        goto codepage_fail;
-    }
-
-    /* ignore namelen */
-    cur++;
-
-    /* find out the data quantum size. default to 1 if nothing's given. */
-    quantum = *cur ? *cur : 1;
-    cur++;
-
-    /* rules used in this file. */
-    rules = *cur++;
-
-    if (codepage_init(vol, rules, quantum) < 0) {
-        LOG(log_error, logtype_afpd, "%s: Unable to allocate memory", path);
-        goto codepage_fail;
-    }
-
-    /* offset to data */
-
-    /* skip to the start of the data */
-    memcpy(&id, cur , sizeof(id));
-    id = ntohs(id);
-    lseek(fd, id, SEEK_SET);
-
-    /* mtoupage is the the equivalent of samba's unix2dos. utompage is
-     * the equivalent of dos2unix. it's a little confusing due to a
-     * desire to match up with mtoupath and utompath. 
-     * NOTE: we allow codepages to specify 7-bit mappings if they want. 
-     */
-    i = 1 + 2*quantum;
-    while (read(fd, buf, i) == i) {
-        if (*buf & CODEPAGE_RULE_MTOU) {
-            if (add_code(vol->v_mtoupage, buf + 1, buf + 1 + quantum) < 0) {
-                LOG(log_error, logtype_afpd, "unable to allocate memory for mtoupage");
-                break;
-            }
-        }
-
-        if (*buf & CODEPAGE_RULE_UTOM) {
-            if (add_code(vol->v_utompage, buf + 1 + quantum, buf + 1) < 0) {
-                LOG(log_error, logtype_afpd, "unable to allocate memory for utompage");
-                break;
-            }
-        }
-
-        /* we only look at the first character here. if we need to
-         * do so, we can always use the quantum to expand the 
-         * available flags. */
-        if (*buf & CODEPAGE_RULE_BADU)
-            vol->v_badumap->map[*(buf + 1)].value = *(buf + 1 + quantum);
-    }
-    close(fd);
-    return 0;
-
-codepage_fail:
-    close(fd);
-    return -1;
-}
diff --git a/etc/afpd/codepage.h b/etc/afpd/codepage.h
deleted file mode 100644 (file)
index f7456a7..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * $Id: codepage.h,v 1.3 2001-12-03 05:03:38 jmarcus Exp $
- */
-
-#ifndef AFPD_CODEPAGE_H
-#define AFPD_CODEPAGE_H 1
-
-/*
- * header of a codepage --
- * file magic:                   2 bytes
- * file version:                 1 byte
- * size of name:                 1 byte
- * quantum:                      1 byte
- * rules:                        1 byte
- * offset to data:               2 bytes (network byte order)
- * size of data:                 2 bytes (network byte order)
- * name:                         strlen(name) bytes (padded)
- * 
- * data for a version 2 codepage --
- * mapping rule: 1 byte
- * mac/bad code:     <quantum> bytes
- * xlate/rule code:  <quantum> bytes
- * ...
- */
-
-#define CODEPAGE_FILE_ID 0xCFAF
-#define CODEPAGE_FILE_VERSION 0x02
-#define CODEPAGE_FILE_HEADER_SIZE 10
-
-/* m->u and u->m mappings */
-#define CODEPAGE_RULE_MTOU       (1 << 0)
-#define CODEPAGE_RULE_UTOM       (1 << 1)
-#define CODEPAGE_RULE_BADU       (1 << 2)
-
-/* rules for bad character assignment.
- *
- * bit assignments:
- * bit 0 set:  it's an illegal character
- *     unset:  it's okay
- *
- * bit 1 set:  bad anywhere
- *     unset:  only check at the beginning of each quantum. 
- *
- * bit 2 set:  all quanta are the same length
- *     unset:  quanta beginning with ascii characters are 1-byte long  
- *
- */
-#define CODEPAGE_BADCHAR_SET      (1 << 0) 
-#define CODEPAGE_BADCHAR_ANYWHERE (1 << 1)  
-#define CODEPAGE_BADCHAR_QUANTUM  (1 << 2) 
-
-#endif
index 2cd1ae896d8934bbafc9dee44721393e907b9af6..390909946f4d9be7eca8b1cbdc5229c40cc36836 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: desktop.c,v 1.30 2003-06-09 14:42:38 srittau Exp $
+ * $Id: desktop.c,v 1.31 2005-04-28 20:49:41 bfernhomberg Exp $
  *
  * See COPYRIGHT.
  *
 #include "config.h"
 #endif /* HAVE_CONFIG_H */
 
-#include <atalk/logger.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
 #include <errno.h>
-#include <sys/types.h>
-#include <sys/time.h>
+#include <dirent.h>
+
+#include <atalk/adouble.h>
 #include <sys/uio.h>
 #include <sys/param.h>
-#include <sys/stat.h>
 #include <sys/socket.h>
 #include <netatalk/at.h>
 #include <netatalk/endian.h>
 #include <atalk/atp.h>
 #include <atalk/asp.h>
 #include <atalk/afp.h>
-#include <atalk/adouble.h>
 #include <atalk/util.h>
-#include <dirent.h>
-#ifdef HAVE_FCNTL_H
-#include <fcntl.h>
-#endif /* HAVE_FCNTL_H */
-#include <stdio.h>
-#include <string.h>
-#include <ctype.h>
-#ifdef HAVE_FCNTL_H
-#include <unistd.h>
-#endif /* HAVE_FCNTL_H */
-
+#include <atalk/logger.h>
 #include "volume.h"
 #include "directory.h"
 #include "fork.h"
 #include "globals.h"
 #include "desktop.h"
-
-#ifdef FILE_MANGLING
 #include "mangle.h"
-#endif /* CNID_DB */
 
-#ifdef AFP3x
-#include <iconv.h>
-#endif
 
 int afp_opendt(obj, ibuf, ibuflen, rbuf, rbuflen )
-AFPObj      *obj;
+AFPObj  *obj _U_;
 char   *ibuf, *rbuf;
-int            ibuflen, *rbuflen;
+int    ibuflen _U_, *rbuflen;
 {
     struct vol *vol;
     u_int16_t  vid;
@@ -76,19 +62,26 @@ int         ibuflen, *rbuflen;
 }
 
 int afp_closedt(obj, ibuf, ibuflen, rbuf, rbuflen )
-AFPObj      *obj;
-char   *ibuf, *rbuf;
-int            ibuflen, *rbuflen;
+AFPObj  *obj _U_;
+char   *ibuf _U_, *rbuf _U_;
+int    ibuflen _U_, *rbuflen;
 {
     *rbuflen = 0;
     return( AFP_OK );
 }
 
-struct savedt  si = { { 0, 0, 0, 0 }, -1, 0 };
+struct savedt  si = { { 0, 0, 0, 0 }, -1, 0, 0 };
+
+static char *icon_dtfile(struct vol *vol, u_char creator[ 4 ])
+{
+    return dtfile( vol, creator, ".icon" );
+}
 
 static int iconopen( vol, creator, flags, mode )
 struct vol     *vol;
 u_char creator[ 4 ];
+int flags;
+int mode;
 {
     char       *dtf, *adt, *adts;
 
@@ -101,7 +94,7 @@ u_char       creator[ 4 ];
         si.sdt_fd = -1;
     }
 
-    dtf = dtfile( vol, creator, ".icon" );
+    dtf = icon_dtfile( vol, creator);
 
     if (( si.sdt_fd = open( dtf, flags, ad_mode( dtf, mode ))) < 0 ) {
         if ( errno == ENOENT && ( flags & O_CREAT )) {
@@ -119,7 +112,7 @@ u_char      creator[ 4 ];
             *adts = '/';
 
             if (( si.sdt_fd = open( dtf, flags, ad_mode( dtf, mode ))) < 0 ) {
-                LOG(log_error, logtype_afpd, "iconopen: open %s: %s", dtf, strerror(errno) );
+                LOG(log_error, logtype_afpd, "iconopen(%s): open: %s", dtf, strerror(errno) );
                 return -1;
             }
         } else {
@@ -134,12 +127,14 @@ u_char    creator[ 4 ];
 }
 
 int afp_addicon(obj, ibuf, ibuflen, rbuf, rbuflen)
-AFPObj      *obj;
+AFPObj  *obj;
 char   *ibuf, *rbuf;
-int            ibuflen, *rbuflen;
+int    ibuflen _U_, *rbuflen;
 {
     struct vol         *vol;
+#ifndef NO_DDP
     struct iovec       iov[ 2 ];
+#endif
     u_char             fcreator[ 4 ], imh[ 12 ], irh[ 12 ], *p;
     int                        itype, cc = AFP_OK, iovcnt = 0, buflen;
     u_int32_t           ftype, itag;
@@ -184,7 +179,7 @@ int         ibuflen, *rbuflen;
     if (lseek( si.sdt_fd, (off_t) 0L, SEEK_SET ) < 0) {
         close(si.sdt_fd);
         si.sdt_fd = -1;
-        LOG(log_error, logtype_afpd, "afp_addicon: lseek: %s", strerror(errno) );
+        LOG(log_error, logtype_afpd, "afp_addicon(%s): lseek: %s", icon_dtfile(vol, fcreator), strerror(errno) );
         cc = AFPERR_PARAM;
         goto addicon_err;
     }
@@ -219,7 +214,7 @@ int         ibuflen, *rbuflen;
         }
 
         if ( lseek( si.sdt_fd, (off_t) rsize, SEEK_CUR ) < 0 ) {
-            LOG(log_error, logtype_afpd, "afp_addicon: lseek: %s", strerror(errno) );
+            LOG(log_error, logtype_afpd, "afp_addicon(%s): lseek: %s", icon_dtfile(vol, fcreator),strerror(errno) );
             cc = AFPERR_PARAM;
         }
     }
@@ -229,7 +224,6 @@ int         ibuflen, *rbuflen;
      */
 addicon_err:
     if ( cc < 0 ) {
-        LOG(log_error, logtype_afpd, "afp_addicon: %s", strerror(errno) );
         if (obj->proto == AFPPROTO_DSI) {
             dsi_writeinit(obj->handle, rbuf, buflen);
             dsi_writeflush(obj->handle);
@@ -237,7 +231,6 @@ addicon_err:
         return cc;
     }
 
-
     switch (obj->proto) {
 #ifndef NO_DDP
     case AFPPROTO_ASP:
@@ -245,10 +238,12 @@ addicon_err:
         if ((asp_wrtcont(obj->handle, rbuf, &buflen) < 0) || buflen != bsize)
             return( AFPERR_PARAM );
 
+#ifdef DEBUG1
         if (obj->options.flags & OPTION_DEBUG) {
             printf("(write) len: %d\n", buflen);
             bprint(rbuf, buflen);
         }
+#endif
 
         /*
          * We're at the end of the file, add the headers, etc.  */
@@ -270,7 +265,7 @@ addicon_err:
         }
 
         if ( writev( si.sdt_fd, iov, iovcnt ) < 0 ) {
-            LOG(log_error, logtype_afpd, "afp_addicon: writev: %s", strerror(errno) );
+            LOG(log_error, logtype_afpd, "afp_addicon(%s): writev: %s", icon_dtfile(vol, fcreator), strerror(errno) );
             return( AFPERR_PARAM );
         }
         break;
@@ -283,25 +278,26 @@ addicon_err:
 
             /* add headers at end of file */
             if ((cc == 0) && (write(si.sdt_fd, imh, sizeof(imh)) < 0)) {
-                LOG(log_error, logtype_afpd, "afp_addicon: write: %s", strerror(errno));
+                LOG(log_error, logtype_afpd, "afp_addicon(%s): write: %s", icon_dtfile(vol, fcreator), strerror(errno));
                 dsi_writeflush(dsi);
                 return AFPERR_PARAM;
             }
 
             if ((cc = write(si.sdt_fd, rbuf, iovcnt)) < 0) {
-                LOG(log_error, logtype_afpd, "afp_addicon: write: %s", strerror(errno));
+                LOG(log_error, logtype_afpd, "afp_addicon(%s): write: %s", icon_dtfile(vol, fcreator), strerror(errno));
                 dsi_writeflush(dsi);
                 return AFPERR_PARAM;
             }
 
             while ((iovcnt = dsi_write(dsi, rbuf, buflen))) {
+#ifdef DEBUG1
                 if ( obj->options.flags & OPTION_DEBUG ) {
                     printf("(write) command cont'd: %d\n", iovcnt);
                     bprint(rbuf, iovcnt);
                 }
-
+#endif
                 if ((cc = write(si.sdt_fd, rbuf, iovcnt)) < 0) {
-                    LOG(log_error, logtype_afpd, "afp_addicon: write: %s", strerror(errno));
+                    LOG(log_error, logtype_afpd, "afp_addicon(%s): write: %s", icon_dtfile(vol, fcreator), strerror(errno));
                     dsi_writeflush(dsi);
                     return AFPERR_PARAM;
                 }
@@ -315,11 +311,11 @@ addicon_err:
     return( AFP_OK );
 }
 
-u_char utag[] = { 0, 0, 0, 0 };
-u_char ucreator[] = { 'U', 'N', 'I', 'X' };
-u_char utype[] = { 'T', 'E', 'X', 'T' };
-short  usize = 256;
-u_char uicon[] = {
+static const u_char    utag[] = { 0, 0, 0, 0 };
+static const u_char    ucreator[] = { 0, 0, 0, 0 };/* { 'U', 'N', 'I', 'X' };*/
+static const u_char    utype[] = { 0, 0, 0, 0 };/* { 'T', 'E', 'X', 'T' };*/
+static const short     usize = 256;
+static const u_char    uicon[] = {
     0x1F, 0xFF, 0xFC, 0x00, 0x10, 0x00, 0x06, 0x00,
     0x10, 0x00, 0x05, 0x00, 0x10, 0x00, 0x04, 0x80,
     0x10, 0x00, 0x04, 0x40, 0x10, 0x00, 0x04, 0x20,
@@ -355,9 +351,9 @@ u_char      uicon[] = {
 };
 
 int afp_geticoninfo(obj, ibuf, ibuflen, rbuf, rbuflen )
-AFPObj      *obj;
+AFPObj  *obj _U_;
 char   *ibuf, *rbuf;
-int            ibuflen, *rbuflen;
+int    ibuflen _U_, *rbuflen;
 {
     struct vol *vol;
     u_char     fcreator[ 4 ], ih[ 12 ];
@@ -415,7 +411,7 @@ int         ibuflen, *rbuflen;
         memcpy( &bsize, ih + 10, sizeof( bsize ));
         bsize = ntohs(bsize);
         if ( lseek( si.sdt_fd, (off_t) bsize, SEEK_CUR ) < 0 ) {
-            LOG(log_error, logtype_afpd, "afp_iconinfo: lseek: %s", strerror(errno) );
+            LOG(log_error, logtype_afpd, "afp_iconinfo(%s): lseek: %s", icon_dtfile(vol, fcreator), strerror(errno) );
             return( AFPERR_PARAM );
         }
         if ( si.sdt_index == iindex ) {
@@ -429,9 +425,9 @@ int         ibuflen, *rbuflen;
 
 
 int afp_geticon(obj, ibuf, ibuflen, rbuf, rbuflen )
-AFPObj      *obj;
+AFPObj  *obj;
 char   *ibuf, *rbuf;
-int            ibuflen, *rbuflen;
+int    ibuflen _U_, *rbuflen;
 {
     struct vol *vol;
     off_t       offset;
@@ -474,7 +470,7 @@ int         ibuflen, *rbuflen;
     if ( lseek( si.sdt_fd, (off_t) 0L, SEEK_SET ) < 0 ) {
         close(si.sdt_fd);
         si.sdt_fd = -1;
-        LOG(log_error, logtype_afpd, "afp_geticon: lseek: %s", strerror(errno));
+        LOG(log_error, logtype_afpd, "afp_geticon(%s): lseek: %s", icon_dtfile(vol, fcreator), strerror(errno));
         return( AFPERR_PARAM );
     }
 
@@ -490,14 +486,14 @@ int               ibuflen, *rbuflen;
         memcpy( &rsize, ih + 10, sizeof( rsize ));
         rsize = ntohs( rsize );
         if ( lseek( si.sdt_fd, (off_t) rsize, SEEK_CUR ) < 0 ) {
-            LOG(log_error, logtype_afpd, "afp_geticon: lseek: %s", strerror(errno) );
+            LOG(log_error, logtype_afpd, "afp_geticon(%s): lseek: %s", icon_dtfile(vol, fcreator), strerror(errno) );
             return( AFPERR_PARAM );
         }
         offset += rsize;
     }
 
     if ( rc < 0 ) {
-        LOG(log_error, logtype_afpd, "afp_geticon: read: %s", strerror(errno));
+        LOG(log_error, logtype_afpd, "afp_geticon(%s): read: %s", icon_dtfile(vol, fcreator), strerror(errno));
         return( AFPERR_PARAM );
     }
 
@@ -526,31 +522,30 @@ int               ibuflen, *rbuflen;
         /* do to the streaming nature, we have to exit if we encounter
          * a problem. much confusion results otherwise. */
         while (*rbuflen > 0) {
-#if defined(SENDFILE_FLAVOR_LINUX) || defined(SENDFILE_FLAVOR_BSD)
+#ifdef WITH_SENDFILE
             if (!obj->options.flags & OPTION_DEBUG) {
-#ifdef SENDFILE_FLAVOR_LINUX
-                if (sendfile(dsi->socket, si.sdt_fd, &offset, dsi->datasize) < 0)
-                    goto geticon_exit;
-#endif /* SENDFILE_FLAVOR_LINUX */
-
-#ifdef SENDFILE_FLAVOR_BSD
-                if (sendfile(si.sdt_fd, dsi->socket, offset, rc, NULL, NULL, 0) < 0)
-                    goto geticon_exit;
-#endif /* SENDFILE_FLAVOR_BSD */
-
+                if (sys_sendfile(dsi->socket, si.sdt_fd, &offset, dsi->datasize) < 0) {
+                    switch (errno) {
+                    case ENOSYS:
+                    case EINVAL:  /* there's no guarantee that all fs support sendfile */
+                        break;
+                    default:
+                        goto geticon_exit;
+                    }
+                }
                 goto geticon_done;
             }
-#endif /* SENDFILE_FLAVOR_LINUX || SENDFILE_FLAVOR_BSD */
-
+#endif
             buflen = read(si.sdt_fd, rbuf, *rbuflen);
             if (buflen < 0)
                 goto geticon_exit;
 
+#ifdef DEBUG1
             if (obj->options.flags & OPTION_DEBUG) {
                 printf( "(read) reply: %d, %d\n", buflen, dsi->clientID);
                 bprint(rbuf, buflen);
             }
-
+#endif
             /* dsi_read() also returns buffer size of next allocation */
             buflen = dsi_read(dsi, rbuf, buflen); /* send it off */
             if (buflen < 0)
@@ -564,9 +559,9 @@ geticon_done:
         return AFP_OK;
 
 geticon_exit:
-        LOG(log_info, logtype_afpd, "afp_geticon: %s", strerror(errno));
+        LOG(log_info, logtype_afpd, "afp_geticon(%s): %s", icon_dtfile(vol, fcreator), strerror(errno));
         dsi_readdone(dsi);
-        obj->exit(1);
+        obj->exit(EXITERR_SYS);
         return AFP_OK;
 
     } else {
@@ -574,12 +569,12 @@ geticon_exit:
             return( AFPERR_PARAM );
         }
         *rbuflen = rc;
-        return AFP_OK;
     }
+    return AFP_OK;
 }
 
-
-static char            hexdig[] = "0123456789abcdef";
+/* ---------------------- */
+static const char              hexdig[] = "0123456789abcdef";
 char *dtfile(const struct vol *vol, u_char creator[], char *ext )
 {
     static char        path[ MAXPATHLEN + 1];
@@ -616,437 +611,119 @@ char *dtfile(const struct vol *vol, u_char creator[], char *ext )
 
 /* ---------------------------
  * mpath is only a filename 
+ * did filename parent directory ID.
 */
-static char  upath[ MAXPATHLEN + 1];
-static char  mpath[ MAXPATHLEN + 1];
-#ifdef AFP3x
-static char  ucs2[ MAXPATHLEN + 1];
-#endif
-
-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 );
-}
-
-/* --------------- */
-#ifdef AFP3x
-extern unsigned int do_precomposition(unsigned int base, unsigned int comb);
-
-static char comp[MAXPATHLEN +1];
-
-static char *precompose(u_int16_t  *name, size_t inplen, size_t *outlen)
+char *mtoupath(const struct vol *vol, char *mpath, cnid_t did, int utf8)
 {
-size_t i;
-u_int16_t base, comb;
-u_int16_t *in, *out;
-u_int16_t result;
-
-    if (!inplen || (inplen & 1) || inplen > sizeof(comp)/sizeof(u_int16_t))
-        return NULL;
-    i = 0;
-    in  = name;
-    out = (u_int16_t *)comp;
-    *outlen = 0;
-    
-    base = *in;
-    while (1) {
-        i += 2;
-        in++;
-        if (i == inplen) {
-           *out = base;
-           *outlen += 2;
-           return comp;
-        }
-        comb = *in;
-        if (comb >= 0x300 && (result = do_precomposition(base, comb))) {
-           *out = result;
-           out++;
-           *outlen += 2;
-           i += 2;
-           in++;
-           if (i == inplen) 
-              return comp;
-           base = *in;
-        }
-        else {
-           *out = base;
-           out++;
-           *outlen += 2;
-           base = comb;
-        }
-    }
-}
-
-/* --------------- */
-extern unsigned int do_decomposition(unsigned int base);
-
-static char *decompose(u_int16_t  *name, size_t inplen, size_t *outlen)
-{
-size_t i;
-u_int16_t base;
-u_int16_t *in, *out;
-unsigned int result;
-
-    if (!inplen || (inplen & 1))
-        return NULL;
-    i = 0;
-    in  = name;
-    out = (u_int16_t *)comp;
-    *outlen = 0;
-    
-    while (i < inplen) {
-        if (*outlen >= sizeof(comp)/sizeof(u_int16_t) +2) {
-            return NULL;
-        }
-        base = *in;
-        if ((result = do_decomposition(base))) {
-           *out = result  >> 16;
-           out++;
-           *outlen += 2;
-           *out = result & 0xffff;
-           out++;
-           *outlen += 2;
-        }
-        else {
-           *out = base;
-           out++;
-           *outlen += 2;
-        }
-        i += 2;
-        in++;
-     }
-     return comp;
-}
-#endif
-
-/* --------------------------- */
-char *mtoupath(const struct vol *vol, char *mpath, int utf8)
-{
-    int                i = 0;
+    static char  upath[ MAXPATHLEN + 1];
     char       *m, *u;
-#ifdef AFP3x
-    char       *r;
     size_t       inplen;
     size_t       outlen;
-#endif
+    u_int16_t   flags = 0;
         
     if ( *mpath == '\0' ) {
         return( "." );
     }
 
-#ifdef FILE_MANGLING
-    m = demangle(vol, mpath);
+    /* 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 ((vol->v_flags & AFPVOL_EILSEQ)) {
+        flags |= CONV__EILSEQ;
+    }
+
+    m = demangle(vol, mpath, did);
     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 == '.') ||
-             (!utf8 && (unsigned char)*m == 0xf0) /* Apple logo */
-        ) {
-          /* 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) {
-        if ((size_t)(-1) == iconv(vol->v_mactoutf8, 0,0,0,0) )
-            return NULL;
-        /* assume precompose */
-        if ((size_t)(-1) == iconv(vol->v_mactoutf8, &u, &inplen, &r, &outlen))
-            return NULL;
-        u = ucs2;
-    }
-    else { 
-        if ((size_t)(-1) == iconv(vol->v_utf8toucs2, 0,0,0,0) )
-            return NULL;
-
-        if ((size_t)(-1) == iconv(vol->v_utf8toucs2, &u, &inplen, &r, &outlen))
-            return NULL;
-
-        u = precompose((u_int16_t *)ucs2, MAXPATHLEN -outlen, &inplen);
-
-        if ((size_t)(-1) == iconv(vol->v_ucs2toutf8, 0,0,0,0))
-            return NULL;
-            
-        outlen = MAXPATHLEN;
-        r = upath;
-        if ((size_t)(-1) == iconv(vol->v_ucs2toutf8, &u, &inplen, &r, &outlen))
-            return NULL;
-        u = upath;
+
+    if ((size_t)-1 == (outlen = convert_charset ( (utf8)?CH_UTF8_MAC:vol->v_maccharset, vol->v_volcharset, vol->v_maccharset, 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;
     }
-    u[MAXPATHLEN -outlen] = 0;
-#endif
+    upath[outlen] = 0;
+
 #ifdef DEBUG
     LOG(log_debug, logtype_afpd, "mtoupath: '%s':'%s'", mpath, upath);
 #endif /* DEBUG */
-    return( u );
+    return( upath );
 }
 
-/* --------------- */
-char *utompath(const struct vol *vol, char *upath, int utf8)
+/* --------------- 
+ * id filename ID
+*/
+char *utompath(const struct vol *vol, char *upath, cnid_t id, int utf8)
 {
-    int          h;
-    int          mangleflag = 0;
-    char       *m, *u;
-#ifdef AFP3x
-    char       *r;
-    size_t       inplen;
+    static char  mpath[ MAXPATHLEN + 1];
+    char        *m, *u;
+    u_int16_t    flags = CONV_IGNORE | CONV_UNESCAPEHEX;
     size_t       outlen;
-#endif
 
-    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++;
-    }
-    *m = '\0';
     m = mpath;
-#ifdef AFP3x    
-    if ((size_t)(-1) == iconv(vol->v_utf8toucs2, 0,0,0,0) )
-        return NULL;
-    inplen = strlen(mpath);
-    outlen = MAXPATHLEN;
-    r = ucs2;
-    if ((size_t)(-1) == iconv(vol->v_utf8toucs2, &m, &inplen, &r, &outlen))
-        return NULL;
-
-    if (utf8) {
-        if ( NULL == (m = decompose((u_int16_t *)ucs2, MAXPATHLEN -outlen, &inplen)))
-            return NULL;
-
-        if ((size_t)(-1) == iconv(vol->v_ucs2toutf8, 0,0,0,0))
-            return NULL;
-            
-        outlen = MAXPATHLEN;
-        r = mpath;
-        if ((size_t)(-1) == iconv(vol->v_ucs2toutf8, &m, &inplen, &r, &outlen))
-            return NULL;
+    outlen = strlen(upath);
+
+    if ((vol->v_casefold & AFPVOL_UTOMUPPER))
+        flags |= CONV_TOUPPER;
+    else if ((vol->v_casefold & AFPVOL_UTOMLOWER))
+        flags |= CONV_TOLOWER;
+
+    if ((vol->v_flags & AFPVOL_EILSEQ)) {
+        flags |= CONV__EILSEQ;
     }
-    else {
-        m = precompose((u_int16_t *)ucs2, MAXPATHLEN -outlen, &inplen);
-
-        if ((size_t)(-1) == iconv(vol->v_ucs2tomac, 0,0,0,0))
-            return NULL;
-            
-        outlen = MAXPATHLEN;
-        r = mpath;
-        if ((size_t)(-1) == iconv(vol->v_ucs2tomac, &m, &inplen, &r, &outlen)) {
-            switch (errno) {
-            case EILSEQ:
-                if (outlen != MAXPATHLEN) {
-                    mangleflag = 1;
-                }
-            default:
-                return NULL;
-            }
-        }
+
+    u = upath;
+
+    /* convert charsets */
+    if ((size_t)-1 == ( outlen = convert_charset ( vol->v_volcharset, (utf8)?CH_UTF8_MAC:vol->v_maccharset, 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[MAXPATHLEN -outlen] = 0;
-#endif
-#ifdef FILE_MANGLING
-    m = mangle(vol, mpath, upath, mangleflag);
-#else
-    if (mangleflag)
-        return NULL;
-    m = mpath;
-#endif /* FILE_MANGLING */
 
+    mpath[outlen] = 0; 
+    if (!(flags & CONV_REQMANGLE)) 
+        flags = 0;
+    else
+        flags = 1;
+
+    if (utf8)
+        flags |= 2;
+
+    m = mangle(vol, mpath, outlen, 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 = "???";
+    m = mangle(vol, u, strlen(u), upath, id, (utf8)?3:1);
     return(m);
 }
 
-/* ----------------------------- */
-int afp_addcomment(obj, ibuf, ibuflen, rbuf, rbuflen )
-AFPObj      *obj;
-char   *ibuf, *rbuf;
-int            ibuflen, *rbuflen;
+/* ------------------------- */
+static int ad_addcomment(struct vol *vol, struct path *path, char *ibuf)
 {
-    struct adouble     ad, *adp;
-    struct vol         *vol;
-    struct dir         *dir;
     struct ofork        *of;
-    struct path         *path;
     char                *name, *upath;
-    int                        clen;
-    u_int32_t           did;
-    u_int16_t          vid;
     int                 isadir;
-
-    *rbuflen = 0;
-    ibuf += 2;
-
-    memcpy( &vid, ibuf, sizeof( vid ));
-    ibuf += sizeof( vid );
-    if (NULL == ( vol = getvolbyvid( vid )) ) {
-        return( AFPERR_PARAM );
-    }
-
-    memcpy( &did, ibuf, sizeof( did ));
-    ibuf += sizeof( did );
-    if (NULL == ( dir = dirlookup( vol, did )) ) {
-       return afp_errno;
-    }
-
-    if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
-       return get_afp_errno(AFPERR_NOOBJ);
-    }
-
-    if ((u_long)ibuf & 1 ) {
-        ibuf++;
-    }
+    int                        clen;
+    struct adouble     ad, *adp;
 
     clen = (u_char)*ibuf++;
     clen = min( clen, 199 );
@@ -1055,10 +732,10 @@ int              ibuflen, *rbuflen;
     if (!vol_unix_priv(vol) && check_access(upath, OPENACC_WR ) < 0) {
         return AFPERR_ACCESS;
     }
-
+    
     isadir = path_isadir(path);
     if (isadir || !(of = of_findname(path))) {
-        memset(&ad, 0, sizeof(ad));
+        ad_init(&ad, vol->v_adouble, vol->v_ad_options);
         adp = &ad;
     } else
         adp = of->of_ad;
@@ -1069,39 +746,35 @@ int              ibuflen, *rbuflen;
         return( AFPERR_ACCESS );
     }
 
-    if ( (ad_getoflags( adp, ADFLAGS_HF ) & O_CREAT) ) {
-        if ( *path->m_name == '\0' ) {
-            name = curdir->d_m_name;
-        } else {
-            name = path->m_name;
+    if (ad_getentryoff(adp, ADEID_COMMENT)) {
+        if ( (ad_getoflags( adp, ADFLAGS_HF ) & O_CREAT) ) {
+            if ( *path->m_name == '\0' ) {
+                name = curdir->d_m_name;
+            } else {
+                name = path->m_name;
+            }
+            ad_setname(adp, name);
         }
-        ad_setentrylen( adp, ADEID_NAME, strlen( name ));
-        memcpy( ad_entry( adp, ADEID_NAME ), name,
-                ad_getentrylen( adp, ADEID_NAME ));
+        ad_setentrylen( adp, ADEID_COMMENT, clen );
+        memcpy( ad_entry( adp, ADEID_COMMENT ), ibuf, clen );
+        ad_flush( adp, ADFLAGS_HF );
     }
-
-    ad_setentrylen( adp, ADEID_COMMENT, clen );
-    memcpy( ad_entry( adp, ADEID_COMMENT ), ibuf, clen );
-    ad_flush( adp, ADFLAGS_HF );
     ad_close( adp, ADFLAGS_HF );
     return( AFP_OK );
 }
 
-int afp_getcomment(obj, ibuf, ibuflen, rbuf, rbuflen )
-AFPObj      *obj;
-char   *ibuf, *rbuf;
-int            ibuflen, *rbuflen;
+/* ----------------------------- */
+int afp_addcomment(obj, ibuf, ibuflen, rbuf, rbuflen )
+AFPObj  *obj _U_;
+char   *ibuf, *rbuf _U_;
+int    ibuflen _U_, *rbuflen;
 {
-    struct adouble     ad, *adp;
     struct vol         *vol;
     struct dir         *dir;
-    struct ofork        *of;
-    struct path         *s_path;
-    char               *upath;
-    u_int32_t          did;
+    struct path         *path;
+    u_int32_t           did;
     u_int16_t          vid;
-    int                 isadir;
-    
+
     *rbuflen = 0;
     ibuf += 2;
 
@@ -1117,27 +790,45 @@ int              ibuflen, *rbuflen;
        return afp_errno;
     }
 
-    if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
+    if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
        return get_afp_errno(AFPERR_NOOBJ);
     }
 
-    upath = s_path->u_name;
-    isadir = path_isadir(s_path);
-    if (isadir || !(of = of_findname(s_path))) {
-        memset(&ad, 0, sizeof(ad));
+    if ((u_long)ibuf & 1 ) {
+        ibuf++;
+    }
+
+    return ad_addcomment(vol, path, ibuf);
+}
+
+/* -------------------- */
+static int ad_getcomment(struct vol *vol, struct path *path, char *rbuf, int *rbuflen)
+{
+    struct adouble     ad, *adp;
+    struct ofork        *of;
+    char               *upath;
+    int                 isadir;
+
+
+    upath = path->u_name;
+    isadir = path_isadir(path);
+    if (isadir || !(of = of_findname(path))) {
+        ad_init(&ad, vol->v_adouble, vol->v_ad_options);
         adp = &ad;
     } else
         adp = of->of_ad;
-    if ( ad_open( upath,
-                  ( isadir) ? ADFLAGS_HF|ADFLAGS_DIR : ADFLAGS_HF,
-                  O_RDONLY, 0666, adp) < 0 ) {
+        
+    if ( ad_metadata( upath,( isadir) ? ADFLAGS_DIR : 0, adp) < 0 ) {
         return( AFPERR_NOITEM );
     }
 
+    if (!ad_getentryoff(adp, ADEID_COMMENT)) {
+        return AFPERR_NOITEM;
+    }
     /*
      * Make sure the AD file is not bogus.
      */
-    if ( ad_getentrylen( adp, ADEID_COMMENT ) < 0 ||
+    if ( ad_getentrylen( adp, ADEID_COMMENT ) <= 0 ||
             ad_getentrylen( adp, ADEID_COMMENT ) > 199 ) {
         ad_close( adp, ADFLAGS_HF );
         return( AFPERR_NOITEM );
@@ -1149,25 +840,21 @@ int              ibuflen, *rbuflen;
     *rbuflen = ad_getentrylen( adp, ADEID_COMMENT ) + 1;
     ad_close( adp, ADFLAGS_HF );
 
-    /* return AFPERR_NOITEM if len == 0 ? */
     return( AFP_OK );
 }
 
-int afp_rmvcomment(obj, ibuf, ibuflen, rbuf, rbuflen )
-AFPObj      *obj;
+/* -------------------- */
+int afp_getcomment(obj, ibuf, ibuflen, rbuf, rbuflen )
+AFPObj  *obj _U_;
 char   *ibuf, *rbuf;
-int            ibuflen, *rbuflen;
+int    ibuflen _U_, *rbuflen;
 {
-    struct adouble     ad, *adp;
     struct vol         *vol;
     struct dir         *dir;
-    struct ofork        *of;
     struct path         *s_path;
-    char               *upath;
     u_int32_t          did;
     u_int16_t          vid;
-    int                 isadir;
-
+    
     *rbuflen = 0;
     ibuf += 2;
 
@@ -1183,18 +870,29 @@ int              ibuflen, *rbuflen;
        return afp_errno;
     }
 
-    if (NULL == ( s_path = cname( vol, dir, &ibuf ))) {
+    if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
        return get_afp_errno(AFPERR_NOOBJ);
     }
 
-    upath = s_path->u_name;
+    return ad_getcomment(vol, s_path, rbuf, rbuflen);
+}
+
+/* ----------------------- */
+static int ad_rmvcomment(struct vol *vol, struct path *path)
+{
+    struct adouble     ad, *adp;
+    struct ofork        *of;
+    int                 isadir;
+    char               *upath;
+
+    upath = path->u_name;
     if (!vol_unix_priv(vol) && check_access(upath, OPENACC_WR ) < 0) {
         return AFPERR_ACCESS;
     }
 
-    isadir = path_isadir(s_path);
-    if (isadir || !(of = of_findname(s_path))) {
-        memset(&ad, 0, sizeof(ad));
+    isadir = path_isadir(path);
+    if (isadir || !(of = of_findname(path))) {
+        ad_init(&ad, vol->v_adouble, vol->v_ad_options);
         adp = &ad;
     } else
         adp = of->of_ad;
@@ -1212,8 +910,44 @@ int               ibuflen, *rbuflen;
         }
     }
 
-    ad_setentrylen( adp, ADEID_COMMENT, 0 );
-    ad_flush( adp, ADFLAGS_HF );
+    if (ad_getentryoff(adp, ADEID_COMMENT)) {
+        ad_setentrylen( adp, ADEID_COMMENT, 0 );
+        ad_flush( adp, ADFLAGS_HF );
+    }
     ad_close( adp, ADFLAGS_HF );
     return( AFP_OK );
 }
+
+/* ----------------------- */
+int afp_rmvcomment(obj, ibuf, ibuflen, rbuf, rbuflen )
+AFPObj  *obj _U_;
+char   *ibuf, *rbuf _U_;
+int    ibuflen _U_, *rbuflen;
+{
+    struct vol         *vol;
+    struct dir         *dir;
+    struct path         *s_path;
+    u_int32_t          did;
+    u_int16_t          vid;
+
+    *rbuflen = 0;
+    ibuf += 2;
+
+    memcpy( &vid, ibuf, sizeof( vid ));
+    ibuf += sizeof( vid );
+    if (NULL == ( vol = getvolbyvid( vid )) ) {
+        return( AFPERR_PARAM );
+    }
+
+    memcpy( &did, ibuf, sizeof( did ));
+    ibuf += sizeof( did );
+    if (NULL == ( dir = dirlookup( vol, did )) ) {
+       return afp_errno;
+    }
+
+    if (NULL == ( s_path = cname( vol, dir, &ibuf ))) {
+       return get_afp_errno(AFPERR_NOOBJ);
+    }
+    
+    return ad_rmvcomment(vol, s_path);
+}
index f766c7579c8290d5bdb4f2177acde7e9bad2588f..3f80b9f7a3a39857e05060e209581ba419f71b9c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: desktop.h,v 1.3 2003-03-09 19:55:33 didg Exp $
+ * $Id: desktop.h,v 1.4 2005-04-28 20:49:41 bfernhomberg Exp $
  *
  * Copyright (c) 1990,1991 Regents of The University of Michigan.
  * All Rights Reserved.
 #include "globals.h"
 #include "volume.h"
 
-/* various finder info bits */
-#define FINDERINFO_FRFLAGOFF   8
-#define FINDERINFO_FRVIEWOFF  14 
-#define FINDERINFO_INVISIBLE  (1<<14)
-#define FINDERINFO_CLOSEDVIEW 0x100   
-
 struct savedt {
     u_char     sdt_creator[ 4 ];
     int                sdt_fd;
@@ -46,13 +40,8 @@ struct savedt {
 typedef unsigned char CreatorType[4];
 
 extern char    *dtfile __P((const struct vol *, u_char [], char *));
-extern char    *mtoupath __P((const struct vol *, char *, int utf8));
-extern char    *utompath __P((const struct vol *, char *, int utf8));
-extern u_char  ucreator[];
-
-#define validupath(vol, name) ((((vol)->v_flags & AFPVOL_USEDOTS) ? \
-   (strncasecmp((name),".Apple", 6) && \
-    strcasecmp((name), ".Parent")) : (name)[0] != '.'))
+extern char    *mtoupath __P((const struct vol *, char *, cnid_t, int utf8));
+extern char    *utompath __P((const struct vol *, char *, cnid_t, int utf8));
 
 /* FP functions */
 extern int     afp_opendt __P((AFPObj *, char *, int, char *, int *));
index eb16cdd25091de3d5ff5f2ec6989ff049e292524..7af402a5307bd9861f7e69e727f5583f9040a3b2 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: directory.c,v 1.76 2003-06-06 20:36:59 srittau Exp $
+ * $Id: directory.c,v 1.77 2005-04-28 20:49:41 bfernhomberg Exp $
  *
  * Copyright (c) 1990,1993 Regents of The University of Michigan.
  * All Rights Reserved.  See COPYRIGHT.
 #include "config.h"
 #endif /* HAVE_CONFIG_H */
 
-#include <atalk/logger.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <errno.h>
-#include <sys/time.h>
-#include <sys/param.h>
-#include <netatalk/endian.h>
-#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 <dirent.h>
-#ifdef HAVE_FCNTL_H
-#include <fcntl.h>
-#endif /* HAVE_FCNTL_H */
-#include <grp.h>
-#include <pwd.h>
-
 /* STDC check */
 #if STDC_HEADERS
 #include <string.h>
@@ -49,6 +26,24 @@ char *strchr (), *strrchr ();
 #define memmove(d,s,n) bcopy ((s), (d), (n))
 #endif /* ! HAVE_MEMCPY */
 #endif /* STDC_HEADERS */
+#ifdef HAVE_STRINGS_H
+#include <strings.h>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <dirent.h>
+
+#include <grp.h>
+#include <pwd.h>
+#include <sys/param.h>
+#include <errno.h>
+#include <utime.h>
+#include <atalk/adouble.h>
+
+#include <atalk/afp.h>
+#include <atalk/util.h>
+#include <atalk/cnid.h>
+#include <atalk/logger.h>
 
 #include "directory.h"
 #include "desktop.h"
@@ -58,6 +53,7 @@ char *strchr (), *strrchr ();
 #include "filedir.h"
 #include "globals.h"
 #include "unix.h"
+#include "mangle.h"
 
 struct dir     *curdir;
 int             afp_errno;
@@ -65,10 +61,10 @@ int             afp_errno;
 #define SENTINEL (&sentinel)
 static struct dir sentinel = { SENTINEL, SENTINEL, NULL, DIRTREE_COLOR_BLACK,
                                  NULL, NULL, NULL, NULL, NULL, 0, 0, 
-                                 0, 0, NULL, NULL};
+                                 0, 0, NULL, NULL, NULL};
 static struct dir rootpar  = { SENTINEL, SENTINEL, NULL, 0,
                                  NULL, NULL, NULL, NULL, NULL, 0, 0, 
-                                 0, 0, NULL, NULL};
+                                 0, 0, NULL, NULL, NULL};
 
 /* (from IM: Toolbox Essentials)
  * dirFinderInfo (DInfo) fields:
@@ -110,8 +106,17 @@ u_int32_t  did;
         rootpar.d_child = vol->v_dir;
         return( &rootpar );
     }
-
+#if 0
+    /* XXX would be nice to check against curdir but we need to keep its volume  */
+    if (vol->curdir && curdir->d_did == did) {
+        dir = curdir;
+    }
+    else {
+        dir = vol->v_root;
+    }
+#endif
     dir = vol->v_root;
+
     afp_errno = AFPERR_NOOBJ;
     while ( dir != SENTINEL ) {
         if (dir->d_did == did)
@@ -122,6 +127,18 @@ u_int32_t  did;
 }
 
 /* ------------------- */
+#ifdef ATACC
+int path_isadir(struct path *o_path)
+{
+    return o_path->d_dir != NULL;
+#if 0
+    return o_path->m_name == '\0' || /* we are in a it */
+           !o_path->st_valid ||      /* in cache but we can't chdir in it */ 
+           (!o_path->st_errno && S_ISDIR(o_path->st.st_mode)); /* not in cache an can't chdir */
+#endif
+}
+#endif
+
 int get_afp_errno(const int param)
 {
     if (afp_errno != AFPERR_DID1)
@@ -161,10 +178,9 @@ struct dir *
             const struct vol   *vol;
 u_int32_t      did;
 {
-#ifdef CNID_DB
     struct dir   *ret;
     char        *upath;
-    u_int32_t   id;
+    cnid_t      id, cnid;
     static char  path[MAXPATHLEN + 1];
     size_t len,  pathlen;
     char         *ptr;
@@ -181,12 +197,12 @@ u_int32_t did;
     utf8 = utf8_encoding();
     maxpath = (utf8)?MAXPATHLEN -7:255;
     id = did;
-    if (NULL == (upath = cnid_resolve(vol->v_db, &id, buffer, buflen)) ) {
+    if (NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, buflen)) ) {
         afp_errno = AFPERR_NOOBJ;
         return NULL;
     }
     ptr = path + MAXPATHLEN;
-    if (NULL == ( mpath = utompath(vol, upath, utf8) ) ) {
+    if (NULL == ( mpath = utompath(vol, upath, did, utf8) ) ) {
         afp_errno = AFPERR_NOOBJ;
         return NULL;
     }
@@ -200,9 +216,10 @@ u_int32_t  did;
         if (ret != NULL) {
             break;
         }
-        if ( NULL == (upath = cnid_resolve(vol->v_db, &id, buffer, buflen))
+        cnid = id;
+        if ( NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, buflen))
              ||
-             NULL == (mpath = utompath(vol, upath, utf8))
+             NULL == (mpath = utompath(vol, upath, cnid, utf8))
         ) {
             afp_errno = AFPERR_NOOBJ;
             return NULL;
@@ -242,10 +259,32 @@ u_int32_t did;
     /* cname is not efficient */
     if (cname( vol, ret, &ptr ) == NULL )
         return NULL;
-#endif
+       
     return dirsearch(vol, did);
 }
 
+/* child addition/removal */
+static void dirchildadd(struct dir *a, struct dir *b) 
+{
+    if (!a->d_child)
+        a->d_child = b;
+    else {
+        b->d_next = a->d_child;
+        b->d_prev = b->d_next->d_prev;
+       b->d_next->d_prev = b;
+       b->d_prev->d_next = b;
+    }
+} 
+
+static void dirchildremove(struct dir *a,struct dir *b)
+{ 
+    if (a->d_child == b) 
+        a->d_child = (b == b->d_next) ? NULL : b->d_next;
+    b->d_next->d_prev = b->d_prev;
+    b->d_prev->d_next = b->d_next;
+    b->d_next = b->d_prev = b;
+}
+
 /* --------------------------- */
 /* rotate the tree to the left */
 static void dir_leftrotate(vol, dir)
@@ -385,7 +424,7 @@ struct dir *dir;
  * different. actually, it has to worry about a bunch of things that
  * insertion doesn't care about. */
 static void dir_remove( vol, dir )
-struct vol     *vol;
+struct vol     *vol _U_;
 struct dir     *dir;
 {
 #ifdef REMOVE_NODES
@@ -401,6 +440,7 @@ struct dir  *dir;
     dirfreename(dir);
     dir->d_m_name = NULL;
     dir->d_u_name = NULL;
+    dir->d_m_name_ucs2 = NULL;
 #else /* ! REMOVE_NODES */
 
     /* go searching for a node with at most one child */
@@ -476,11 +516,14 @@ struct dir        *dir;
         /* set the node's d_name */
         node->d_m_name = save.d_m_name;
         node->d_u_name = save.d_u_name;
+        node->d_m_name_ucs2 = save.d_m_name_ucs2;
     }
 
     if (node->d_color == DIRTREE_COLOR_BLACK)
         dir_rmrecolor(vol, leaf);
 
+    if (node->d_m_name_ucs2)
+        free(node->d_u_name_ucs2);
     if (node->d_u_name != node->d_m_name) {
         free(node->d_u_name);
     }
@@ -541,6 +584,85 @@ struct dir *dir;
     return pdir;
 }
 
+#define ENUMVETO "./../Network Trash Folder/TheVolumeSettingsFolder/TheFindByContentFolder/:2eDS_Store/Contents/Desktop Folder/Trash/Benutzer/"
+
+int
+caseenumerate(const struct vol *vol, struct path *path, struct dir *dir)
+{
+    DIR               *dp;
+    struct dirent     *de;
+    int               ret;
+    static u_int32_t  did = 0;
+    static char              cname[MAXPATHLEN];
+    static char              lname[MAXPATHLEN];
+    ucs2_t           u2_path[MAXPATHLEN];
+    ucs2_t           u2_dename[MAXPATHLEN];
+    char             *tmp, *savepath;
+
+    if (veto_file(ENUMVETO, path->u_name))
+       return -1;
+
+    savepath = path->u_name;
+
+    /* very simple cache */
+    if ( dir->d_did == did && strcmp(lname, path->u_name) == 0) {
+        path->u_name = cname;
+        path->d_dir = NULL;
+        if (of_stat( path ) == 0 ) {
+            return 0;
+        }
+        /* something changed, we cannot stat ... */
+        did = 0;
+    }
+
+    if (NULL == ( dp = opendir( "." )) ) {
+        LOG(log_debug, logtype_afpd, "caseenumerate: opendir failed: %s", dir->d_u_name);
+        return -1;
+    }
+
+
+    /* LOG(log_debug, logtype_afpd, "caseenumerate: for %s", path->u_name); */
+    if ((size_t) -1 == convert_string(vol->v_volcharset, CH_UCS2, path->u_name, strlen(path->u_name), u2_path, sizeof(u2_path)) ) 
+        LOG(log_debug, logtype_afpd, "caseenumerate: conversion failed for %s", path->u_name);
+
+    /*LOG(log_debug, logtype_afpd, "caseenumerate: dir: %s, path: %s", dir->d_u_name, path->u_name); */
+    ret = -1;
+    for ( de = readdir( dp ); de != NULL; de = readdir( dp )) {
+        if (NULL == check_dirent(vol, de->d_name))
+            continue;
+
+        if ((size_t) -1 == convert_string(vol->v_volcharset, CH_UCS2, de->d_name, strlen(de->d_name), u2_dename, sizeof(u2_dename)) )
+            continue;
+
+        if (strcasecmp_w( u2_path, u2_dename) == 0) {
+            tmp = path->u_name;
+            strlcpy(cname, de->d_name, sizeof(cname));
+            path->u_name = cname;
+            path->d_dir = NULL;
+            if (of_stat( path ) == 0 ) {
+                LOG(log_debug, logtype_afpd, "caseenumerate: using dir: %s, path: %s", de->d_name, path->u_name);
+                strlcpy(lname, tmp, sizeof(lname));
+                did = dir->d_did;
+                ret = 0;
+                break;
+            }
+            else 
+                path->u_name = tmp;
+        }
+
+    }
+    closedir(dp);
+
+    if (ret) {
+        /* invalidate cache */
+        memset(cname, 0, sizeof(cname));
+        did = 0;
+        path->u_name = savepath;
+    }
+    /* LOG(log_debug, logtype_afpd, "caseenumerate: path on ret: %s", path->u_name); */
+    return ret;
+}
+
 
 /*
  * attempt to extend the current dir. tree to include path
@@ -552,26 +674,32 @@ struct vol        *vol;
 struct dir     *dir;
 struct path *path;
 {
-    path->u_name = mtoupath(vol, path->m_name, utf8_encoding() );
-    path->dir = NULL;
+    if ( path->u_name == NULL) {
+        path->u_name = mtoupath(vol, path->m_name, dir->d_did, (path->m_type==3) );
+    }
+    path->d_dir = NULL;
 
     if ( path->u_name == NULL) {
         afp_errno = AFPERR_PARAM;
         return NULL;
     }
     if (of_stat( path ) != 0 ) {
-        return( NULL );
+        if (!(vol->v_flags & AFPVOL_CASEINSEN))
+            return NULL;
+       else if(caseenumerate(vol, path, dir) != 0)
+            return(NULL);
     }
 
     if (!S_ISDIR(path->st.st_mode)) {
         return( NULL );
     }
 
+    /* mac name is always with the right encoding (from cname()) */
     if (( dir = adddir( vol, dir, path)) == NULL ) {
         return( NULL );
     }
 
-    path->dir = dir;
+    path->d_dir = dir;
     if ( movecwd( vol, dir ) < 0 ) {
         return( NULL );
     }
@@ -583,7 +711,7 @@ struct path *path;
    system rmdir with afp error code.
    ENOENT is not an error.
  */
-static int netatalk_rmdir(const char *name)
+int netatalk_rmdir(const char *name)
 {
     if (rmdir(name) < 0) {
         switch ( errno ) {
@@ -703,7 +831,7 @@ static int deletedir(char *dir)
 }
 
 /* do a recursive copy. */
-static int copydir(char *src, char *dst, int noadouble)
+static int copydir(const struct vol *vol, char *src, char *dst)
 {
     char spath[MAXPATHLEN + 1], dpath[MAXPATHLEN + 1];
     DIR *dp;
@@ -712,7 +840,6 @@ static int copydir(char *src, char *dst, int noadouble)
     struct utimbuf      ut;
     size_t slen, dlen;
     size_t srem, drem;
-    
     int err;
 
     /* doesn't exist or the path is too long. */
@@ -758,9 +885,9 @@ static int copydir(char *src, char *dst, int noadouble)
             strcpy(dpath + dlen, de->d_name);
 
             if (S_ISDIR(st.st_mode)) {
-                if (AFP_OK != (err = copydir(spath, dpath, noadouble)))
+                if (AFP_OK != (err = copydir(vol, spath, dpath)))
                     goto copydir_done;
-            } else if (AFP_OK != (err = copyfile(spath, dpath, NULL, noadouble))) {
+            } else if (AFP_OK != (err = copyfile(vol, vol, spath, dpath, NULL, NULL))) {
                 goto copydir_done;
 
             } else {
@@ -786,7 +913,7 @@ copydir_done:
 /* --- public functions follow --- */
 
 /* NOTE: we start off with at least one node (the root directory). */
-struct dir *dirinsert( vol, dir )
+static struct dir *dirinsert( vol, dir )
             struct vol *vol;
 struct dir     *dir;
 {
@@ -844,6 +971,77 @@ struct dir *dir;
     return NULL;
 }
 
+/* ---------------------------- */
+struct dir *
+            adddir( vol, dir, path)
+struct vol     *vol;
+struct dir     *dir;
+struct path     *path;
+{
+    struct dir *cdir, *edir;
+    int                upathlen;
+    char        *name;
+    char        *upath;
+    struct stat *st;
+    int         deleted;
+    cnid_t      id;
+
+    upath = path->u_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;
+    }
+    if ((size_t)-1 == convert_string_allocate((utf8_encoding())?CH_UTF8_MAC:vol->v_maccharset, CH_UCS2, path->m_name, strlen(path->m_name), &cdir->d_m_name_ucs2)) {
+       LOG(log_error, logtype_afpd, "Couldn't set UCS2 name for %s", name);
+       cdir->d_m_name_ucs2 = NULL;
+    }
+
+    cdir->d_did = id;
+
+    if ((edir = dirinsert( vol, cdir ))) {
+        /* it's not possible with LASTDID
+           for CNID:
+           - someone else have moved the directory.
+           - it's a symlink inside the share.
+           - it's an ID reused, the old directory was deleted but not
+             the cnid record and the server've reused the inode for 
+             the new dir.
+           for HASH (we should get ride of HASH) 
+           - someone else have moved the directory.
+           - it's an ID reused as above
+           - it's a hash duplicate and we are in big trouble
+        */
+        deleted = (edir->d_m_name == NULL);
+        dirfreename(edir);
+        edir->d_m_name = cdir->d_m_name;
+        edir->d_u_name = cdir->d_u_name;
+        edir->d_m_name_ucs2 = cdir->d_m_name_ucs2;
+        free(cdir);
+        cdir = edir;
+        if (!cdir->d_parent || (cdir->d_parent == dir && !deleted))
+            return cdir;
+        /* the old was not in the same folder */
+        if (!deleted)
+            dirchildremove(cdir->d_parent, cdir);
+    }
+
+    /* parent/child directories */
+    cdir->d_parent = dir;
+    dirchildadd(dir, cdir);
+    return( cdir );
+}
+
 /* free everything down. we don't bother to recolor as this is only
  * called to free the entire tree */
 void dirfreename(struct dir *dir)
@@ -851,6 +1049,8 @@ void dirfreename(struct dir *dir)
     if (dir->d_u_name != dir->d_m_name) {
         free(dir->d_u_name);
     }
+    if (dir->d_m_name_ucs2)
+        free(dir->d_m_name_ucs2); 
     free(dir->d_m_name);
 }
 
@@ -889,7 +1089,7 @@ struct dir *dirnew(const char *m_name, const char *u_name)
         return NULL;
     }
 
-    if (m_name == u_name) {
+    if (m_name == u_name || !strcmp(m_name, u_name)) {
         dir->d_u_name = dir->d_m_name;
     }
     else if ((dir->d_u_name = strdup(u_name)) == NULL) {
@@ -898,11 +1098,59 @@ struct dir *dirnew(const char *m_name, const char *u_name)
         return NULL;
     }
 
+    dir->d_m_name_ucs2 = NULL;
     dir->d_left = dir->d_right = SENTINEL;
     dir->d_next = dir->d_prev = dir;
     return dir;
 }
 
+/* ------------------ */
+static struct path *invalidate (const struct vol *vol, struct dir *dir, struct path *ret)
+{
+    /* it's tricky:
+       movecwd failed some of dir path are not there anymore.
+       FIXME Is it true with other errors?
+       so we remove dir from the cache 
+    */
+    if (dir->d_did == DIRDID_ROOT_PARENT)
+        return NULL;
+    if (afp_errno == AFPERR_ACCESS) {
+        if ( movecwd( vol, dir->d_parent ) < 0 ) {
+            return NULL;               
+        }
+        /* FIXME should we set these?, don't need to call stat() after:
+           ret->st_valid = 1;
+           ret->st_errno = EACCES;
+       */
+       ret->m_name = dir->d_m_name;
+       ret->u_name = dir->d_u_name;
+       ret->d_dir = dir;
+       return ret;
+    } else if (afp_errno == AFPERR_NOOBJ) {
+       if ( movecwd( vol, dir->d_parent ) < 0 ) {
+           return NULL;                
+       }
+       strcpy(ret->m_name, dir->d_m_name);
+       if (dir->d_m_name == dir->d_u_name) {
+           ret->u_name = ret->m_name;
+       }
+       else {
+           size_t tp = strlen(ret->m_name)+1;
+           
+           ret->u_name =  ret->m_name +tp;
+           strcpy(ret->u_name, dir->d_u_name);
+       }
+       /* FIXME should we set :
+          ret->st_valid = 1;
+          ret->st_errno = ENOENT;
+       */
+       dir_invalidate(vol, dir);
+       return ret;
+    }
+    dir_invalidate(vol, dir);
+    return NULL;
+}
+
 /* -------------------------------------------------- */
 /* cname 
  return
@@ -942,7 +1190,7 @@ const struct vol   *vol;
 struct dir     *dir;
 char   **cpath;
 {
-    struct dir            *cdir;
+    struct dir            *cdir, *scdir=NULL;
     static char                   path[ MAXPATHLEN + 1];
     static struct path ret;
 
@@ -953,15 +1201,21 @@ char     **cpath;
     u_int16_t   len16;
     int         size = 0;
     char        sep;
+    int         toUTF8 = 0;
                
     data = *cpath;
     afp_errno = AFPERR_NOOBJ;
+    memset(&ret, 0, sizeof(ret));
     switch (ret.m_type = *data) { /* path type */
     case 2:
        data++;
        len = (unsigned char) *data++;
        size = 2;
        sep = 0;
+       if (afp_version >= 30) {
+           ret.m_type = 3;
+           toUTF8 = 1;
+       }
        break;
     case 3:
        if (afp_version >= 30) {
@@ -985,51 +1239,14 @@ char     **cpath;
     *cpath += len + size;
     *path = '\0';
     ret.m_name = path;
-    ret.st_errno = 0;
-    ret.st_valid = 0;
-    ret.dir = NULL;
     for ( ;; ) {
         if ( len == 0 ) {
             if (movecwd( vol, dir ) < 0 ) {
-               /* it's tricky:
-                  movecwd failed some of dir path are not there anymore.
-                  FIXME Is it true with other errors?
-                  so we remove dir from the cache 
-               */
-               if (dir->d_did == DIRDID_ROOT_PARENT)
-                   return NULL;
-               if (afp_errno == AFPERR_ACCESS) {
-                    if ( movecwd( vol, dir->d_parent ) < 0 ) {
-                        return NULL;                   
-                   }
-                   ret.m_name = dir->d_m_name;
-                   ret.u_name = dir->d_u_name;
-                   ret.dir = dir;
-                   return &ret;
-               } else if (afp_errno == AFPERR_NOOBJ) {
-                    if ( movecwd( vol, dir->d_parent ) < 0 ) {
-                        return NULL;                   
-                   }
-                   strcpy(path, dir->d_m_name);
-                   if (dir->d_m_name == dir->d_u_name) {
-                       ret.u_name = path;
-                   }
-                   else {
-                       size_t tp = strlen(path)+1;
-
-                       strcpy(path +tp, dir->d_u_name);
-                       ret.u_name =  path +tp;
-                       
-                   }
-                   dir_invalidate(vol, dir);
-                   return &ret;
-               }
-               dir_invalidate(vol, dir);
-               return NULL;
+                return invalidate(vol, dir, &ret );
             }
             if (*path == '\0') {
                ret.u_name = ".";
-               ret.dir = dir;
+               ret.d_dir = dir;
             }               
             return &ret;
         }
@@ -1066,54 +1283,115 @@ char   **cpath;
 
         *p = '\0';
 
-        if ( p != path ) { /* we got something */
-            if ( !extend ) {
-                cdir = dir->d_child;
+        if ( p == path ) { /* end of the name parameter */
+            continue;
+        }
+        ret.u_name = NULL;
+        if (afp_version >= 30) {
+            char *t;
+            cnid_t fileid;
+                
+            if (toUTF8) {
+                static char    temp[ MAXPATHLEN + 1];
+
+                /* not an UTF8 name */
+                if (mtoUTF8(vol, path, strlen(path), temp, MAXPATHLEN) == (size_t)-1) {
+                    afp_errno = AFPERR_PARAM;
+                    return( NULL );
+                }
+                strcpy(path, temp);
+            }
+            /* check for OS X mangled filename :( */
+           
+            t = demangle_osx(vol, path, dir->d_did, &fileid);
+            if (t != path) {
+                ret.u_name = t;
+                /* duplicate work but we can't reuse all convert_char we did in demangle_osx 
+                 * flags weren't the same
+                 */
+                 if ( (t = utompath(vol, ret.u_name, fileid, utf8_encoding())) ) {
+                     /* at last got our view of mac name */
+                     strcpy(path,t);
+                 }                    
+            }
+        }
+        if ( !extend ) {
+            ucs2_t *tmpname;
+            cdir = dir->d_child;
+            scdir = NULL;
+           if ( cdir && (vol->v_flags & AFPVOL_CASEINSEN) &&
+                    (size_t)-1 != convert_string_allocate(((ret.m_type == 3)?CH_UTF8_MAC:vol->v_maccharset), 
+                                                          CH_UCS2, path, strlen(path), (char **)&tmpname) )
+            {
                 while (cdir) {
-                    if ( strcmp( cdir->d_m_name, path ) == 0 ) {
-                        break;
+                    if (!cdir->d_m_name_ucs2) {
+                        LOG(log_error, logtype_afpd, "cname: no UCS2 name for %s (did %u)!!!", cdir->d_m_name, ntohl(cdir->d_did) );
+                        /* this shouldn't happen !!!! */
+                        goto noucsfallback;
                     }
-                    cdir = (cdir == dir->d_child->d_prev) ? NULL :
-                           cdir->d_next;
+
+                    if ( strcmp_w( cdir->d_m_name_ucs2, tmpname ) == 0 ) {
+                         break;
+                    }
+                    if ( strcasecmp_w( cdir->d_m_name_ucs2, tmpname ) == 0 ) {
+                         scdir = cdir;
+                    }
+                    cdir = (cdir == dir->d_child->d_prev) ? NULL :cdir->d_next;
                 }
-                if ( cdir == NULL ) {
-                    ++extend;
-                    /* if dir == curdir it always succeed,
-                       even if curdir is deleted. 
-                       it's not a pb because it will fail in extenddir
-                    */
-                    if ( movecwd( vol, dir ) < 0 ) {
-                       /* dir is not valid anymore 
-                          we delete dir from the cache and abort.
-                       */
-                       if ( dir->d_did == DIRDID_ROOT_PARENT) {
-                           afp_errno = AFPERR_NOOBJ;
-                           return NULL;
-                       }
-                       if (afp_errno == AFPERR_ACCESS)
-                           return NULL;
-                       dir_invalidate(vol, dir);
-                        return NULL;
+                free(tmpname);
+            }
+            else {
+noucsfallback:
+                while (cdir) {
+                    if ( strcmp( cdir->d_m_name, path ) == 0 ) {
+                         break;
                     }
-                    cdir = extenddir( vol, dir, &ret );
+                    cdir = (cdir == dir->d_child->d_prev) ? NULL :cdir->d_next;
                 }
+            }
 
-            } else {
-                cdir = extenddir( vol, dir, &ret );
+            if (cdir == NULL && scdir != NULL) {
+                cdir = scdir;
+                /* LOG(log_debug, logtype_afpd, "cname: using casediff for %s, (%s = %s)", fullpathname(cdir->d_u_name), cdir->d_m_name, path ); */
             }
 
             if ( cdir == NULL ) {
-
-                if ( len > 0 || !ret.u_name) {
+                ++extend;
+                /* if dir == curdir it always succeed,
+                 even if curdir is deleted. 
+                 it's not a pb because it will fail in extenddir
+                */
+                if ( movecwd( vol, dir ) < 0 ) {
+                    /* dir is not valid anymore 
+                       we delete dir from the cache and abort.
+                    */
+                    if ( dir->d_did == DIRDID_ROOT_PARENT) {
+                        afp_errno = AFPERR_NOOBJ;
+                        return NULL;
+                    }
+                    if (afp_errno == AFPERR_ACCESS)
+                       return NULL;
+                    dir_invalidate(vol, dir);
                     return NULL;
                 }
+                cdir = extenddir( vol, dir, &ret );
+            }
 
-            } else {
-                dir = cdir;    
-                *path = '\0';
+        } else {
+            cdir = extenddir( vol, dir, &ret );
+        } /* if (!extend) */
+
+        if ( cdir == NULL ) {
+
+            if ( len > 0 || !ret.u_name) {
+                return NULL;
             }
+
+        } else {
+            dir = cdir;        
+            *path = '\0';
         }
-    }
+    } /* for (;;) */
 }
 
 /*
@@ -1153,7 +1431,7 @@ struct dir        *dir;
         }
         *--p = '/';
         p -= n;
-        strncpy( p, u, n );
+        memcpy( p, u, n );
     }
     if ( d != curdir ) {
         n = strlen( vol->v_path );
@@ -1163,7 +1441,7 @@ struct dir        *dir;
         }
         *--p = '/';
         p -= n;
-        strncpy( p, vol->v_path, n );
+        memcpy( p, vol->v_path, n );
     }
     if ( chdir( p ) < 0 ) {
         switch (errno) {
@@ -1221,6 +1499,32 @@ struct maccess ma;
 
 }
 
+/* --------------------- */
+void setdiroffcnt(struct dir *dir, struct stat *st,  u_int32_t count)
+{
+    dir->offcnt = count;
+    dir->ctime = st->st_ctime;
+    dir->d_flags &= ~DIRF_CNID;
+}
+
+/* ---------------------  
+ * is our cached offspring count valid?
+*/
+
+int diroffcnt(struct dir *dir, struct stat *st)
+{
+    return st->st_ctime == dir->ctime;
+}
+
+/* ---------------------  
+ * is our cached also for reenumerate id?
+*/
+
+int dirreenumerate(struct dir *dir, struct stat *st)
+{
+    return st->st_ctime == dir->ctime && (dir->d_flags & DIRF_CNID);
+}
+
 /* ------------------------------ 
    (".", curdir)
    (name, dir) with curdir:name == dir, from afp_enumerate
@@ -1239,6 +1543,7 @@ int getdirparams(const struct vol *vol,
     u_int16_t          ashort;
     int                 ret;
     u_int32_t           utf8 = 0;
+    cnid_t              pdid;
     struct stat *st = &s_path->st;
     char *upath = s_path->u_name;
     
@@ -1247,13 +1552,21 @@ int getdirparams(const struct vol *vol,
                   (1 << DIRPBIT_MDATE) |
                   (1 << DIRPBIT_BDATE) |
                   (1 << DIRPBIT_FINFO)))) {
-        memset(&ad, 0, sizeof(ad));
-       if ( !ad_open( upath, ADFLAGS_HF|ADFLAGS_DIR, O_RDONLY,
-                  DIRBITS | 0777, &ad)) {
+
+        ad_init(&ad, vol->v_adouble, vol->v_ad_options);
+       if ( !ad_metadata( upath, ADFLAGS_DIR, &ad) ) {
             isad = 1;
         }
     }
-
+    
+    if ( dir->d_did == DIRDID_ROOT) {
+        pdid = DIRDID_ROOT_PARENT;
+    } else if (dir->d_did == DIRDID_ROOT_PARENT) {
+        pdid = 0;
+    } else {
+        pdid = dir->d_parent->d_did;
+    }
+    
     data = buf;
     while ( bitmap != 0 ) {
         while (( bitmap & 1 ) == 0 ) {
@@ -1276,15 +1589,8 @@ int getdirparams(const struct vol *vol,
             break;
 
         case DIRPBIT_PDID :
-            if ( dir->d_did == DIRDID_ROOT) {
-                aint = DIRDID_ROOT_PARENT;
-            } else if (dir->d_did == DIRDID_ROOT_PARENT) {
-                aint = 0;
-            } else {
-                aint = dir->d_parent->d_did;
-            }
-            memcpy( data, &aint, sizeof( aint ));
-            data += sizeof( aint );
+            memcpy( data, &pdid, sizeof( pdid ));
+            data += sizeof( pdid );
             break;
 
         case DIRPBIT_CDATE :
@@ -1348,12 +1654,11 @@ int getdirparams(const struct vol *vol,
         case DIRPBIT_OFFCNT :
             ashort = 0;
             /* this needs to handle current directory access rights */
-            if (st->st_ctime == dir->ctime) {
+            if (diroffcnt(dir, st)) {
                 ashort = (dir->offcnt > 0xffff)?0xffff:dir->offcnt;
             }
             else if ((ret = for_each_dirent(vol, upath, NULL,NULL)) >= 0) {
-                dir->offcnt = ret;
-                dir->ctime = st->st_ctime;
+               setdiroffcnt(dir, st,  ret);
                 ashort = (dir->offcnt > 0xffff)?0xffff:dir->offcnt;
             }
             ashort = htons( ashort );
@@ -1428,8 +1733,7 @@ int getdirparams(const struct vol *vol,
             *data++ = ma.ma_group;
             *data++ = ma.ma_owner;
             break;
-
-
+            
         default :
             if ( isad ) {
                 ad_close( &ad, ADFLAGS_HF );
@@ -1442,12 +1746,12 @@ int getdirparams(const struct vol *vol,
     if ( l_nameoff ) {
         ashort = htons( data - buf );
         memcpy( l_nameoff, &ashort, sizeof( ashort ));
-        data = set_name(vol, data, dir->d_m_name, 0);
+        data = set_name(vol, data, pdid, 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, pdid, dir->d_m_name, dir->d_did, utf8);
     }
     if ( isad ) {
         ad_close( &ad, ADFLAGS_HF );
@@ -1465,16 +1769,16 @@ int path_error(struct path *path, int error)
  */
     if (path_isadir(path))
         return afp_errno;
-    if (path->st_errno)
+    if (path->st_valid && path->st_errno)
         return error;
     return AFPERR_BADTYPE ;
 }
 
 /* ----------------------------- */
 int afp_setdirparams(obj, ibuf, ibuflen, rbuf, rbuflen )
-AFPObj      *obj;
-char   *ibuf, *rbuf;
-int            ibuflen, *rbuflen;
+AFPObj  *obj;
+char   *ibuf, *rbuf _U_;
+int    ibuflen _U_, *rbuflen;
 {
     struct vol *vol;
     struct dir *dir;
@@ -1511,7 +1815,10 @@ int              ibuflen, *rbuflen;
     }
 
     if ( *path->m_name != '\0' ) {
-       return path_error(path, AFPERR_NOOBJ);
+        rc = path_error(path, AFPERR_NOOBJ);
+        /* maybe we are trying to set perms back */
+        if (rc != AFPERR_ACCESS)
+            return rc;
     }
 
     /*
@@ -1537,12 +1844,28 @@ struct path Cur_Path = {
     0,
     "",  /* mac name */
     ".", /* unix name */
-    0,  /* stat is not set */
-    0,  /* */
+    0,   /* id */
+    NULL,/* struct dir */
+    0,   /* stat is not set */
 };
 
+/* ------------------ */
+static int set_dir_errors(struct path *path, const char *where, int err)
+{
+    switch ( err ) {
+    case EPERM :
+    case EACCES :
+        return AFPERR_ACCESS;
+    case EROFS :
+        return AFPERR_VLOCK;
+    }
+    LOG(log_error, logtype_afpd, "setdirparam(%s): %s: %s", fullpathname(path->u_name), where, strerror(err) );
+    return AFPERR_PARAM;
+}
+/* ------------------ */
 int setdirparams(const struct vol *vol, 
-                 struct path *path, u_int16_t bitmap, char *buf )
+                 struct path *path, u_int16_t d_bitmap, char *buf )
 {
     struct maccess     ma;
     struct adouble     ad;
@@ -1550,15 +1873,125 @@ int setdirparams(const struct vol *vol,
     struct timeval      tv;
 
     char                *upath;
-    int                        bit = 0, aint, isad = 1;
+    struct dir          *dir;
+    int                        bit, aint, isad = 1;
+    int                 cdate, bdate;
+    int                 owner, group;
     u_int16_t          ashort, bshort;
     int                 err = AFP_OK;
     int                 change_mdate = 0;
     int                 change_parent_mdate = 0;
     int                 newdate = 0;
+    u_int16_t           bitmap = d_bitmap;
+    u_char              finder_buf[32];
+    u_int32_t          upriv;
+    mode_t              mpriv;          /* uninitialized, OK 310105 */
+    u_int16_t           upriv_bit = 0;
 
+    bit = 0;
     upath = path->u_name;
-    memset(&ad, 0, sizeof(ad));
+    dir   = path->d_dir;
+    while ( bitmap != 0 ) {
+        while (( bitmap & 1 ) == 0 ) {
+            bitmap = bitmap>>1;
+            bit++;
+        }
+
+        switch( bit ) {
+        case DIRPBIT_ATTR :
+            change_mdate = 1;
+            memcpy( &ashort, buf, sizeof( ashort ));
+            buf += sizeof( ashort );
+            break;
+        case DIRPBIT_CDATE :
+            change_mdate = 1;
+            memcpy(&cdate, buf, sizeof(cdate));
+            buf += sizeof( cdate );
+            break;
+        case DIRPBIT_MDATE :
+            memcpy(&newdate, buf, sizeof(newdate));
+            buf += sizeof( newdate );
+            break;
+        case DIRPBIT_BDATE :
+            change_mdate = 1;
+            memcpy(&bdate, buf, sizeof(bdate));
+            buf += sizeof( bdate );
+            break;
+        case DIRPBIT_FINFO :
+            change_mdate = 1;
+            memcpy( finder_buf, buf, 32 );
+            buf += 32;
+            break;
+        case DIRPBIT_UID :     /* What kind of loser mounts as root? */
+            change_parent_mdate = 1;
+            memcpy( &owner, buf, sizeof(owner));
+            buf += sizeof( owner );
+            break;
+        case DIRPBIT_GID :
+            change_parent_mdate = 1;
+            memcpy( &group, buf, sizeof( group ));
+            buf += sizeof( group );
+            break;
+        case DIRPBIT_ACCESS :
+            change_mdate = 1;
+            change_parent_mdate = 1;
+            ma.ma_user = *buf++;
+            ma.ma_world = *buf++;
+            ma.ma_group = *buf++;
+            ma.ma_owner = *buf++;
+            mpriv = mtoumode( &ma );
+            if (dir_rx_set(mpriv) && setdirmode( vol, upath, mpriv) < 0 ) {
+                err = set_dir_errors(path, "setdirmode", errno);
+                bitmap = 0;
+            }
+            break;
+        /* Ignore what the client thinks we should do to the
+           ProDOS information block.  Skip over the data and
+           report nothing amiss. <shirsch@ibm.net> */
+        case DIRPBIT_PDINFO :
+            if (afp_version < 30) {
+                buf += 6;
+            }
+            else {
+                err = AFPERR_BITMAP;
+                bitmap = 0;
+            }
+            break;
+       case DIRPBIT_UNIXPR :
+           if (vol_unix_priv(vol)) {
+               /* Skip UID and GID for now, there seems to be no way to set them from an OSX client anyway */
+                buf += sizeof( aint );
+                buf += sizeof( aint );
+
+                change_mdate = 1;
+                change_parent_mdate = 1;
+                memcpy( &upriv, buf, sizeof( upriv ));
+                buf += sizeof( upriv );
+                upriv = ntohl (upriv);
+                if (dir_rx_set(upriv)) {
+                    /* maybe we are trying to set perms back */
+                    if ( setdirunixmode(vol, upath, upriv) < 0 ) {
+                        bitmap = 0;
+                        err = set_dir_errors(path, "setdirmode", errno);
+                    }
+                }
+                else {
+                    /* do it later */
+                   upriv_bit = 1;
+                }
+                break;
+            }
+            /* fall through */
+        default :
+            err = AFPERR_BITMAP;
+            bitmap = 0;
+            break;
+        }
+
+        bitmap = bitmap>>1;
+        bit++;
+    }
+    ad_init(&ad, vol->v_adouble, vol->v_ad_options);
 
     if (ad_open( upath, vol_noadouble(vol)|ADFLAGS_HF|ADFLAGS_DIR,
                  O_RDWR|O_CREAT, 0666, &ad) < 0) {
@@ -1570,8 +2003,9 @@ int setdirparams(const struct vol *vol,
          * note: we also don't need to worry about mdate. also, be quiet
          *       if we're using the noadouble option.
          */
-        if (!vol_noadouble(vol) && (bitmap &
-                                    ~((1<<DIRPBIT_ACCESS)|(1<<DIRPBIT_UID)|(1<<DIRPBIT_GID)|
+        if (!vol_noadouble(vol) && (d_bitmap &
+                                    ~((1<<DIRPBIT_ACCESS)|(1<<DIRPBIT_UNIXPR)|
+                                      (1<<DIRPBIT_UID)|(1<<DIRPBIT_GID)|
                                       (1<<DIRPBIT_MDATE)|(1<<DIRPBIT_PDINFO)))) {
             return AFPERR_ACCESS;
         }
@@ -1582,13 +2016,13 @@ int setdirparams(const struct vol *vol,
          * Check to see if a create was necessary. If it was, we'll want
          * to set our name, etc.
          */
-        if ( ad_get_HF_flags( &ad ) & O_CREAT ) {
-            ad_setentrylen( &ad, ADEID_NAME, strlen( curdir->d_m_name ));
-            memcpy( ad_entry( &ad, ADEID_NAME ), curdir->d_m_name,
-                    ad_getentrylen( &ad, ADEID_NAME ));
+        if ( (ad_get_HF_flags( &ad ) & O_CREAT)) {
+            ad_setname(&ad, curdir->d_m_name);
         }
     }
 
+    bit = 0;
+    bitmap = d_bitmap;
     while ( bitmap != 0 ) {
         while (( bitmap & 1 ) == 0 ) {
             bitmap = bitmap>>1;
@@ -1597,262 +2031,125 @@ int setdirparams(const struct vol *vol,
 
         switch( bit ) {
         case DIRPBIT_ATTR :
-            change_mdate = 1;
             if (isad) {
-                memcpy( &ashort, buf, sizeof( ashort ));
                 ad_getattr(&ad, &bshort);
+               if ((bshort & htons(ATTRBIT_INVISIBLE)) != 
+                    (ashort & htons(ATTRBIT_INVISIBLE) & htons(ATTRBIT_SETCLR)) )
+                   change_parent_mdate = 1;
                 if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
                     bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
                 } else {
                     bshort &= ~ashort;
                 }
                 ad_setattr(&ad, bshort);
-                if ((ashort & htons(ATTRBIT_INVISIBLE)))
-                  change_parent_mdate = 1;
             }
-            buf += sizeof( ashort );
             break;
-
         case DIRPBIT_CDATE :
-            change_mdate = 1;
             if (isad) {
-                memcpy(&aint, buf, sizeof(aint));
-                ad_setdate(&ad, AD_DATE_CREATE, aint);
+                ad_setdate(&ad, AD_DATE_CREATE, cdate);
             }
-            buf += sizeof( aint );
             break;
-
         case DIRPBIT_MDATE :
-            memcpy(&newdate, buf, sizeof(newdate));
-            buf += sizeof( newdate );
             break;
-
         case DIRPBIT_BDATE :
-            change_mdate = 1;
             if (isad) {
-                memcpy(&aint, buf, sizeof(aint));
-                ad_setdate(&ad, AD_DATE_BACKUP, aint);
+                ad_setdate(&ad, AD_DATE_BACKUP, bdate);
             }
-            buf += sizeof( aint );
             break;
-
         case DIRPBIT_FINFO :
-            change_mdate = 1;
-            /*
-             * Alright, we admit it, this is *really* sick!
-             * The 4 bytes that we don't copy, when we're dealing
-             * with the root of a volume, are the directory's
-             * location information. This eliminates that annoying
-             * behavior one sees when mounting above another mount
-             * point.
-             */
             if (isad) {
-                if (  curdir->d_did == DIRDID_ROOT ) {
-                    memcpy( ad_entry( &ad, ADEID_FINDERI ), buf, 10 );
-                    memcpy( ad_entry( &ad, ADEID_FINDERI ) + 14, buf + 14, 18 );
+                if (  dir->d_did == DIRDID_ROOT ) {
+                    /*
+                     * Alright, we admit it, this is *really* sick!
+                     * The 4 bytes that we don't copy, when we're dealing
+                     * with the root of a volume, are the directory's
+                     * location information. This eliminates that annoying
+                     * behavior one sees when mounting above another mount
+                     * point.
+                     */
+                    memcpy( ad_entry( &ad, ADEID_FINDERI ), finder_buf, 10 );
+                    memcpy( ad_entry( &ad, ADEID_FINDERI ) + 14, finder_buf + 14, 18 );
                 } else {
-                    memcpy( ad_entry( &ad, ADEID_FINDERI ), buf, 32 );
+                    memcpy( ad_entry( &ad, ADEID_FINDERI ), finder_buf, 32 );
                 }
             }
-            buf += 32;
             break;
-
         case DIRPBIT_UID :     /* What kind of loser mounts as root? */
-            change_parent_mdate = 1;
-            memcpy( &aint, buf, sizeof(aint));
-            buf += sizeof( aint );
-            if ( (curdir->d_did == DIRDID_ROOT) &&
-                    (setdeskowner( ntohl(aint), -1 ) < 0)) {
-                switch ( errno ) {
-                case EPERM :
-                case EACCES :
-                    err = AFPERR_ACCESS;
-                    goto setdirparam_done;
-                    break;
-                case EROFS :
-                    err = AFPERR_VLOCK;
-                    goto setdirparam_done;
-                    break;
-                default :
-                    LOG(log_error, logtype_afpd, "setdirparam: setdeskowner: %s",
-                        strerror(errno) );
-                    if (!isad) {
-                        err = AFPERR_PARAM;
-                        goto setdirparam_done;
-                    }
-                    break;
+            if ( (dir->d_did == DIRDID_ROOT) &&
+                    (setdeskowner( ntohl(owner), -1 ) < 0)) {
+                err = set_dir_errors(path, "setdeskowner", errno);
+                if (isad && err == AFPERR_PARAM) {
+                    err = AFP_OK; /* ???*/
                 }
-            }
-            if ( setdirowner( ntohl(aint), -1, vol_noadouble(vol) ) < 0 ) {
-                switch ( errno ) {
-                case EPERM :
-                case EACCES :
-                    err = AFPERR_ACCESS;
+                else {
                     goto setdirparam_done;
-                    break;
-                case EROFS :
-                    err = AFPERR_VLOCK;
-                    goto setdirparam_done;
-                    break;
-                default :
-                    LOG(log_error, logtype_afpd, "setdirparam: setdirowner: %s",
-                        strerror(errno) );
-                    break;
                 }
             }
+            if ( setdirowner(vol, upath, ntohl(owner), -1 ) < 0 ) {
+                err = set_dir_errors(path, "setdirowner", errno);
+                goto setdirparam_done;
+            }
             break;
+
         case DIRPBIT_GID :
-            change_parent_mdate = 1;
-            memcpy( &aint, buf, sizeof( aint ));
-            buf += sizeof( aint );
-            if (curdir->d_did == DIRDID_ROOT)
-                setdeskowner( -1, ntohl(aint) );
+            if (dir->d_did == DIRDID_ROOT)
+                setdeskowner( -1, ntohl(group) ); 
 
 #if 0       /* don't error if we can't set the desktop owner. */
-            switch ( errno ) {
-            case EPERM :
-            case EACCES :
-                err = AFPERR_ACCESS;
-                goto setdirparam_done;
-                break;
-            case EROFS :
-                err = AFPERR_VLOCK;
-                goto setdirparam_done;
-                break;
-            default :
-                LOG(log_error, logtype_afpd, "setdirparam: setdeskowner: %m" );
-                if (!isad) {
-                    err = AFPERR_PARAM;
+                err = set_dir_errors(path, "setdeskowner", errno);
+                if (isad && err == AFPERR_PARAM) {
+                    err = AFP_OK; /* ???*/
+                }
+                else {
                     goto setdirparam_done;
                 }
-                break;
-            }
 #endif /* 0 */
 
-            if ( setdirowner( -1, ntohl(aint), vol_noadouble(vol) ) < 0 ) {
-                switch ( errno ) {
-                case EPERM :
-                case EACCES :
-                    err = AFPERR_ACCESS;
-                    goto setdirparam_done;
-                    break;
-                case EROFS :
-                    err = AFPERR_VLOCK;
-                    goto setdirparam_done;
-                    break;
-                default :
-                    LOG(log_error, logtype_afpd, "setdirparam: setdirowner: %s",
-                        strerror(errno) );
-                    break;
-                }
+            if ( setdirowner(vol, upath, -1, ntohl(group) ) < 0 ) {
+                err = set_dir_errors(path, "setdirowner", errno);
+                goto setdirparam_done;
             }
             break;
 
         case DIRPBIT_ACCESS :
-            change_mdate = 1;
-            change_parent_mdate = 1;
-            ma.ma_user = *buf++;
-            ma.ma_world = *buf++;
-            ma.ma_group = *buf++;
-            ma.ma_owner = *buf++;
-
-            if (curdir->d_did == DIRDID_ROOT)
-                setdeskmode(mtoumode( &ma ));
-#if 0 /* don't error if we can't set the desktop mode */
-            switch ( errno ) {
-            case EPERM :
-            case EACCES :
-                err = AFPERR_ACCESS;
-                goto setdirparam_done;
-            case EROFS :
-                err = AFPERR_VLOCK;
-                goto setdirparam_done;
-            default :
-                LOG(log_error, logtype_afpd, "setdirparam: setdeskmode: %s",
-                    strerror(errno) );
-                break;
-                err = AFPERR_PARAM;
-                goto setdirparam_done;
-            }
-#endif /* 0 */
-
-            if ( setdirmode( mtoumode( &ma ), vol_noadouble(vol),
-                         (vol->v_flags & AFPVOL_DROPBOX)) < 0 ) {
-                switch ( errno ) {
-                case EPERM :
-                case EACCES :
+            if (dir->d_did == DIRDID_ROOT) {
+                setdeskmode(mpriv);
+                if (!dir_rx_set(mpriv)) {
+                    /* we can't remove read and search for owner on volume root */
                     err = AFPERR_ACCESS;
                     goto setdirparam_done;
-                case EROFS :
-                    err = AFPERR_VLOCK;
-                    goto setdirparam_done;
-                default :
-                    LOG(log_error, logtype_afpd, "setdirparam: setdirmode: %s",
-                        strerror(errno) );
-                    err = AFPERR_PARAM;
-                    goto setdirparam_done;
                 }
             }
-            break;
-
-        /* Ignore what the client thinks we should do to the
-           ProDOS information block.  Skip over the data and
-           report nothing amiss. <shirsch@ibm.net> */
-        case DIRPBIT_PDINFO :
-            if (afp_version < 30) {
-                buf += 6;
-                break;
-            }
-
-       case DIRPBIT_UNIXPR :
-           /* Skip UID and GID for now, there seems to be now way to set them from an OSX client anyway */
-            buf += sizeof( aint );
-            buf += sizeof( aint );
 
-            change_mdate = 1;
-            change_parent_mdate = 1;
-            memcpy( &aint, buf, sizeof( aint ));
-            buf += sizeof( aint );
-           aint = ntohl (aint);
-            if (curdir->d_did == DIRDID_ROOT)
-                setdeskmode( aint );
-#if 0 /* don't error if we can't set the desktop mode */
-            switch ( errno ) {
-            case EPERM :
-            case EACCES :
-                err = AFPERR_ACCESS;
-                goto setdirparam_done;
-            case EROFS :
-                err = AFPERR_VLOCK;
+            if (!dir_rx_set(mpriv) && setdirmode( vol, upath, mpriv) < 0 ) {
+                err = set_dir_errors(path, "setdirmode", errno);
                 goto setdirparam_done;
-            default :
-                LOG(log_error, logtype_afpd, "setdirparam: setdeskmode: %s",
-                    strerror(errno) );
-                break;
-                err = AFPERR_PARAM;
+            }
+            break;
+        case DIRPBIT_PDINFO :
+            if (afp_version >= 30) {
+                err = AFPERR_BITMAP;
                 goto setdirparam_done;
             }
-#endif /* 0 */
+            break;
+       case DIRPBIT_UNIXPR :
+           if (vol_unix_priv(vol)) {
+                if (dir->d_did == DIRDID_ROOT) {
+                    setdeskmode( upriv );
+                    if (!dir_rx_set(upriv)) {
+                        /* we can't remove read and search for owner on volume root */
+                        err = AFPERR_ACCESS;
+                        goto setdirparam_done;
+                    }
+                }
 
-            if ( setdirunixmode( aint, vol_noadouble(vol),
-                         (vol->v_flags & AFPVOL_DROPBOX)) < 0 ) {
-                switch ( errno ) {
-                case EPERM :
-                case EACCES :
-                    err = AFPERR_ACCESS;
-                    goto setdirparam_done;
-                case EROFS :
-                    err = AFPERR_VLOCK;
-                    goto setdirparam_done;
-                default :
-                    LOG(log_error, logtype_afpd, "setdirparam: setdirmode: %s",
-                        strerror(errno) );
-                    err = AFPERR_PARAM;
+                if ( upriv_bit && setdirunixmode(vol, upath, upriv) < 0 ) {
+                    err = set_dir_errors(path, "setdirmode", errno);
                     goto setdirparam_done;
                 }
+                break;
             }
-            break;
-
+            /* fall through */
         default :
             err = AFPERR_BITMAP;
             goto setdirparam_done;
@@ -1875,14 +2172,22 @@ setdirparam_done:
     }
 
     if ( isad ) {
+        if (path->st_valid && !path->st_errno) {
+            struct stat *st = &path->st;
+
+            if (dir && dir->d_parent) {
+                ad_setid(&ad, st->st_dev, st->st_ino,  dir->d_did, dir->d_parent->d_did, vol->v_stamp);
+            }
+        }
         ad_flush( &ad, ADFLAGS_HF );
         ad_close( &ad, ADFLAGS_HF );
     }
 
-    if (change_parent_mdate && curdir->d_did != DIRDID_ROOT
+    if (change_parent_mdate && dir->d_did != DIRDID_ROOT
             && gettimeofday(&tv, NULL) == 0) {
-       if (!movecwd(vol, curdir->d_parent)) {
+       if (!movecwd(vol, dir->d_parent)) {
            newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
+           /* be careful with bitmap because now dir is null */
            bitmap = 1<<DIRPBIT_MDATE;
            setdirparams(vol, &Cur_Path, bitmap, (char *)&newdate);
            /* should we reset curdir ?*/
@@ -1893,9 +2198,9 @@ setdirparam_done:
 }
 
 int afp_createdir(obj, ibuf, ibuflen, rbuf, rbuflen )
-AFPObj      *obj;
+AFPObj  *obj;
 char   *ibuf, *rbuf;
-int            ibuflen, *rbuflen;
+int    ibuflen _U_, *rbuflen;
 {
     struct adouble     ad;
     struct vol         *vol;
@@ -1956,17 +2261,16 @@ int             ibuflen, *rbuflen;
         return( AFPERR_PARAM );
     }
 
-    memset(&ad, 0, sizeof(ad));
+    ad_init(&ad, vol->v_adouble, vol->v_ad_options);
     if (ad_open( ".", vol_noadouble(vol)|ADFLAGS_HF|ADFLAGS_DIR,
                  O_RDWR|O_CREAT, 0666, &ad ) < 0)  {
         if (vol_noadouble(vol))
             goto createdir_done;
         return( AFPERR_ACCESS );
     }
+    ad_setname(&ad, s_path->m_name);
+    ad_setid( &ad, s_path->st.st_dev, s_path->st.st_ino, dir->d_did, did, vol->v_stamp);
 
-    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_flush( &ad, ADFLAGS_HF );
     ad_close( &ad, ADFLAGS_HF );
 
@@ -1983,10 +2287,10 @@ createdir_done:
  * newparent curdir
  *
 */
-int renamedir(src, dst, dir, newparent, newname, noadouble)
+int renamedir(vol, src, dst, dir, newparent, newname)
+const struct vol *vol;
 char   *src, *dst, *newname;
 struct dir     *dir, *newparent;
-const int noadouble;
 {
     struct adouble     ad;
     struct dir         *parent;
@@ -2008,7 +2312,7 @@ const int noadouble;
         case EXDEV:
             /* this needs to copy and delete. bleah. that means we have
              * to deal with entire directory hierarchies. */
-            if ((err = copydir(src, dst, noadouble)) < 0) {
+            if ((err = copydir(vol, src, dst)) < 0) {
                 deletedir(dst);
                 return err;
             }
@@ -2020,18 +2324,21 @@ const int noadouble;
         }
     }
 
-    memset(&ad, 0, sizeof(ad));
+    vol->vfs->rf_renamedir(vol, src, dst);
+
     len = strlen( newname );
     /* rename() succeeded so we need to update our tree even if we can't open
-     * .Parent
+     * metadata
     */
-    if ( !ad_open( dst, ADFLAGS_HF|ADFLAGS_DIR, O_RDWR, 0, &ad)) {
-        ad_setentrylen( &ad, ADEID_NAME, len );
-        memcpy( ad_entry( &ad, ADEID_NAME ), newname, len );
+    
+    ad_init(&ad, vol->v_adouble, vol->v_ad_options);
+
+    if (!ad_open( dst, ADFLAGS_HF|ADFLAGS_DIR, O_RDWR, 0, &ad)) {
+        ad_setname(&ad, newname);
         ad_flush( &ad, ADFLAGS_HF );
         ad_close( &ad, ADFLAGS_HF );
     }
-    
+
     if (dir->d_m_name == dir->d_u_name)
         dir->d_u_name = NULL;
 
@@ -2056,6 +2363,13 @@ const int noadouble;
         strcpy( dir->d_u_name, dst );
     }
 
+    if (dir->d_m_name_ucs2)
+       free(dir->d_m_name_ucs2);
+
+    dir->d_m_name_ucs2 = NULL;
+    if ((size_t)-1 == convert_string_allocate((utf8_encoding())?CH_UTF8_MAC:vol->v_maccharset, CH_UCS2, dir->d_m_name, strlen(dir->d_m_name), (char**)&dir->d_m_name_ucs2))
+        dir->d_m_name_ucs2 = NULL;
+
     if (( parent = dir->d_parent ) == NULL ) {
         return( AFP_OK );
     }
@@ -2070,12 +2384,9 @@ const int noadouble;
     return( AFP_OK );
 }
 
-#define DOT_APPLEDOUBLE_LEN 13
 /* delete an empty directory */
-int deletecurdir( vol, path, pathlen )
+int deletecurdir( vol)
 const struct vol       *vol;
-char *path;
-int pathlen;
 {
     struct dirent *de;
     struct stat st;
@@ -2091,9 +2402,8 @@ int pathlen;
 
     fdir = curdir;
 
-    memset(&ad, 0, sizeof(ad));
-    if ( ad_open( ".", ADFLAGS_HF|ADFLAGS_DIR, O_RDONLY,
-                  DIRBITS | 0777, &ad) == 0 ) {
+    ad_init(&ad, vol->v_adouble, vol->v_ad_options);
+    if ( ad_metadata( ".", ADFLAGS_DIR, &ad) == 0 ) {
 
         ad_getattr(&ad, &ashort);
         ad_close( &ad, ADFLAGS_HF );
@@ -2101,34 +2411,9 @@ int pathlen;
             return  AFPERR_OLOCK;
         }
     }
-
-    /* delete stray .AppleDouble files. this happens to get .Parent files
-       as well. */
-    if ((dp = opendir(".AppleDouble"))) {
-        strcpy(path, ".AppleDouble/");
-        while ((de = readdir(dp))) {
-            /* skip this and previous directory */
-            if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
-                continue;
-
-            /* bail if the file exists in the current directory.
-             * note: this will not fail with dangling symlinks */
-            if (stat(de->d_name, &st) == 0) {
-                closedir(dp);
-                return AFPERR_DIRNEMPT;
-            }
-
-            strcpy(path + DOT_APPLEDOUBLE_LEN, de->d_name);
-            if ((err = netatalk_unlink(path))) {
-                closedir(dp);
-                return err;
-            }
-        }
-        closedir(dp);
-    }
-
-    if ( (err = netatalk_rmdir( ".AppleDouble" ))  ) {
-       return err;
+    err = vol->vfs->rf_deletecurdir(vol);
+    if (err) {
+        return err;
     }
 
     /* now get rid of dangling symlinks */
@@ -2158,9 +2443,7 @@ int pathlen;
 
     if ( !(err = netatalk_rmdir(fdir->d_u_name))) {
         dirchildremove(curdir, fdir);
-#ifdef CNID_DB
-        cnid_delete(vol->v_db, fdir->d_did);
-#endif /* CNID_DB */
+        cnid_delete(vol->v_cdb, fdir->d_did);
         dir_remove( vol, fdir );
         err = AFP_OK;
     }
@@ -2176,9 +2459,9 @@ delete_done:
 }
 
 int afp_mapid(obj, ibuf, ibuflen, rbuf, rbuflen )
-AFPObj      *obj;
+AFPObj  *obj;
 char   *ibuf, *rbuf;
-int            ibuflen, *rbuflen;
+int    ibuflen _U_, *rbuflen;
 {
     struct passwd      *pw;
     struct group       *gr;
@@ -2207,7 +2490,8 @@ int               ibuflen, *rbuflen;
             if (( pw = getpwuid( id )) == NULL ) {
                 return( AFPERR_NOITEM );
             }
-            name = pw->pw_name;
+           len = convert_string_allocate( obj->options.unixcharset, ((!utf8)?obj->options.maccharset:CH_UTF8_MAC),
+                                            pw->pw_name, strlen(pw->pw_name), &name);
             break;
 
         case 2 :
@@ -2215,7 +2499,8 @@ int               ibuflen, *rbuflen;
             if (NULL == ( gr = (struct group *)getgrgid( id ))) {
                 return( AFPERR_NOITEM );
             }
-            name = gr->gr_name;
+           len = convert_string_allocate( obj->options.unixcharset, (!utf8)?obj->options.maccharset:CH_UTF8_MAC,
+                                            gr->gr_name, strlen(gr->gr_name), &name);
             break;
 
         default :
@@ -2241,13 +2526,15 @@ int             ibuflen, *rbuflen;
         memcpy( rbuf, name, len );
     }
     *rbuflen += len;
+    if (name)
+       free(name);
     return( AFP_OK );
 }
 
 int afp_mapname(obj, ibuf, ibuflen, rbuf, rbuflen )
-AFPObj      *obj;
+AFPObj  *obj _U_;
 char   *ibuf, *rbuf;
-int            ibuflen, *rbuflen;
+int    ibuflen _U_, *rbuflen;
 {
     struct passwd      *pw;
     struct group       *gr;
@@ -2309,9 +2596,9 @@ int               ibuflen, *rbuflen;
   variable DID support 
 */
 int afp_closedir(obj, ibuf, ibuflen, rbuf, rbuflen )
-AFPObj      *obj;
-char   *ibuf, *rbuf;
-int            ibuflen, *rbuflen;
+AFPObj  *obj _U_;
+char   *ibuf _U_, *rbuf _U_;
+int    ibuflen _U_, *rbuflen;
 {
 #if 0
     struct vol   *vol;
@@ -2348,9 +2635,9 @@ int               ibuflen, *rbuflen;
  * there's a pb again with case but move it to cname
 */
 int afp_opendir(obj, ibuf, ibuflen, rbuf, rbuflen )
-AFPObj      *obj;
+AFPObj  *obj _U_;
 char   *ibuf, *rbuf;
-int            ibuflen, *rbuflen;
+int    ibuflen  _U_, *rbuflen;
 {
     struct vol         *vol;
     struct dir         *parentdir;
index d23768289cd034308ef59760275af4e87c6658d9..4a8dad4f5b1534c98dc21d882c79bfe1f9dd2b36 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: directory.h,v 1.17 2003-06-06 20:36:59 srittau Exp $
+ * $Id: directory.h,v 1.18 2005-04-28 20:49:41 bfernhomberg Exp $
  *
  * Copyright (c) 1990,1991 Regents of The University of Michigan.
  * All Rights Reserved.
@@ -57,46 +57,33 @@ struct dir {
 
     char       *d_m_name;            /* mac name */
     char        *d_u_name;            /* unix name */
+    ucs2_t     *d_m_name_ucs2;       /* mac name as UCS2 */
 };
 
 struct path {
     int         m_type;             /* mac name type (long name, unicode */
     char       *m_name;            /* mac name */
     char        *u_name;            /* unix name */
-    struct dir  *dir;               /* */
+    cnid_t     id;                 /* file id (only for getmetadata) */
+    struct dir  *d_dir;             /* */
     int         st_valid;           /* does st_errno and st set */
     int         st_errno;
     struct stat st;
 };
 
-#define path_isadir(o_path) \
-       ((o_path)->dir != NULL)
+#ifndef ATACC
+static __inline__ int path_isadir(struct path *o_path)
+{
+    return o_path->d_dir != NULL;
 #if 0
-       ((o_path)->m_name == '\0' || /* we are in a it */ \
-        !(o_path)->st_valid ||      /* in cache but we can't chdir in it */ \
-        (!(o_path)->st_errno && S_ISDIR((o_path)->st.st_mode)) /* not in cache an can't chdir */ \
-       )
+    return o_path->m_name == '\0' || /* we are in a it */
+           !o_path->st_valid ||      /* in cache but we can't chdir in it */ 
+           (!o_path->st_errno && S_ISDIR(o_path->st.st_mode)); /* not in cache an can't chdir */
+#endif
+}
+#else
+extern int path_isadir(struct path *o_path);
 #endif
-          
-/* child addition/removal macros */
-#define dirchildadd(a, b) do { \
-       if (!(a)->d_child) \
-               (a)->d_child = (b); \
-       else { \
-               (b)->d_next = (a)->d_child; \
-               (b)->d_prev = (b)->d_next->d_prev; \
-               (b)->d_next->d_prev = (b); \
-               (b)->d_prev->d_next = (b); \
-       } \
-} while (0)
-
-#define dirchildremove(a,b) do { \
-       if ((a)->d_child == (b)) \
-               (a)->d_child = ((b) == (b)->d_next) ? NULL : (b)->d_next; \
-       (b)->d_next->d_prev = (b)->d_prev; \
-       (b)->d_prev->d_next = (b)->d_next; \
-        (b)->d_next = (b)->d_prev = (b); \
-} while (0)
 
 #define DIRTREE_COLOR_RED    0
 #define DIRTREE_COLOR_BLACK  1
@@ -115,6 +102,10 @@ struct path {
 #define DIRF_AFS       (1<<0)
 #define DIRF_UFS       (2<<0)
 
+#define DIRF_OFFCNT     (1<<4) /* offsprings count is valid */
+#define DIRF_CNID      (1<<5)  /* renumerate id */
+
+
 #define AFPDIR_READ    (1<<0)
 
 /* directory bits */
@@ -149,6 +140,8 @@ struct path {
 /* file/directory ids. what a mess. we scramble things in a vain attempt
  * to get something meaningful */
 #ifndef AFS
+
+#if 0
 #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)
@@ -156,6 +149,10 @@ struct path {
                                       & 0x00ffffff)
 #define CNID_FILE(a)  (((a) & 0x1) << 31)
 #define CNID(a,b)     (CNID_DEV(a) | CNID_INODE(a) | CNID_FILE(b))
+#endif
+
+#define CNID(a,b)     ((a)->st_ino & 0xffffffff)
+
 #else /* AFS */
 #define CNID(a,b)     (((a)->st_ino & 0x7fffffff) | CNID_FILE(b))
 #endif /* AFS */
@@ -183,9 +180,8 @@ extern struct dir       *dirsearch_byname __P((struct dir *,const char *));
 extern struct dir      *adddir __P((struct vol *, struct dir *, 
                                                struct path *));
 
-extern struct dir       *dirinsert __P((struct vol *, struct dir *));
 extern int              movecwd __P((const struct vol *, struct dir *));
-extern int              deletecurdir __P((const struct vol *, char *, int));
+extern int              deletecurdir __P((const struct vol *));
 extern struct path      *cname __P((const struct vol *, struct dir *,
                              char **));
 extern mode_t           mtoumode __P((struct maccess *));
@@ -193,10 +189,13 @@ extern void             utommode __P((struct stat *, struct maccess *));
 extern int getdirparams __P((const struct vol *, u_int16_t, struct path *,
                                  struct dir *, char *, int *));
 extern int setdirparams __P((const struct vol *, struct path *, u_int16_t, char *));
-extern int renamedir __P((char *, char *, struct dir *,
-                              struct dir *, char *, const int));
+extern int renamedir __P((const struct vol *, char *, char *, struct dir *,
+                              struct dir *, char *));
 extern int path_error __P((struct path *, int error));
 
+extern void setdiroffcnt __P((struct dir *dir, struct stat *st,  u_int32_t count));
+extern int dirreenumerate __P((struct dir *dir, struct stat *st));
+
 typedef int (*dir_loop)(struct dirent *, char *, void *);
 
 extern int  for_each_dirent __P((const struct vol *, char *, dir_loop , void *));
@@ -204,8 +203,10 @@ extern int  for_each_dirent __P((const struct vol *, char *, dir_loop , void *))
 extern int  check_access __P((char *name , int mode));
 extern int file_access   __P((struct path *path, int mode));
 
+extern int netatalk_rmdir __P((const char *name));
 extern int netatalk_unlink __P((const char *name));
 
+extern int caseenumerate __P((const struct vol *, struct path *, struct dir *));
 /* from enumerate.c */
 extern char *check_dirent __P((const struct vol *, char *));
 
index 01f9628ef65ad79239f9bfc05d829dda52a0d33e..463e59aad34dfb788a5e06109f25fd0355db972e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: enumerate.c,v 1.41 2003-05-20 14:46:50 didg Exp $
+ * $Id: enumerate.c,v 1.42 2005-04-28 20:49:41 bfernhomberg Exp $
  *
  * Copyright (c) 1990,1993 Regents of The University of Michigan.
  * All Rights Reserved.  See COPYRIGHT.
 #include <errno.h>
 
 #include <atalk/logger.h>
-#include <sys/types.h>
-#include <sys/stat.h>
 #include <sys/file.h>
 #include <sys/param.h>
 
-#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"
 
 #define min(a,b)       ((a)<(b)?(a):(b))
 
-/* ---------------------------- */
-struct dir *
-            adddir( vol, dir, path)
-struct vol     *vol;
-struct dir     *dir;
-struct path     *path;
-{
-    struct dir *cdir, *edir;
-    int                upathlen;
-    char        *name;
-    char        *upath;
-    struct stat *st;
-    int         deleted;
-
-    upath = path->u_name;
-    name  = path->m_name;    
-    st    = &path->st;
-    upathlen = strlen(upath);
-    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;
-
-    if ((edir = dirinsert( vol, cdir ))) {
-        /* it's not possible with LASTDID
-           for CNID:
-           - someone else have moved the directory.
-           - it's a symlink inside the share.
-           - it's an ID reused, the old directory was deleted but not
-             the cnid record and the server've reused the inode for 
-             the new dir.
-           for HASH (we should get ride of HASH) 
-           - someone else have moved the directory.
-           - it's an ID reused as above
-           - it's a hash duplicate and we are in big trouble
-        */
-        deleted = (edir->d_m_name == NULL);
-        dirfreename(edir);
-        edir->d_m_name = cdir->d_m_name;
-        edir->d_u_name = cdir->d_u_name;
-        free(cdir);
-        cdir = edir;
-        if (!cdir->d_parent || (cdir->d_parent == dir && !deleted))
-            return cdir;
-        /* the old was not in the same folder */
-        if (!deleted)
-            dirchildremove(cdir->d_parent, cdir);
-    }
-
-    /* parent/child directories */
-    cdir->d_parent = dir;
-    dirchildadd(dir, cdir);
-    return( cdir );
-}
 /*
  * Struct to save directory reading context in. Used to prevent
  * O(n^2) searches on a directory.
@@ -108,7 +45,7 @@ struct savedir {
 };
 #define SDBUFBRK       2048
 
-static int enumerate_loop(struct dirent *de, char *mname, void *data)
+static int enumerate_loop(struct dirent *de, char *mname _U_, void *data)
 {
     struct savedir *sd = data; 
     char *start, *end;
@@ -117,7 +54,7 @@ static int enumerate_loop(struct dirent *de, char *mname, void *data)
     end = sd->sd_buf + sd->sd_buflen;
     len = strlen(de->d_name);
     *(sd->sd_last)++ = len;
-    lenm = strlen(mname);
+    lenm = 0; /* strlen(mname);*/
     if ( sd->sd_last + len +lenm + 4 > end ) {
         char *buf;
 
@@ -136,11 +73,11 @@ static int enumerate_loop(struct dirent *de, char *mname, void *data)
 
     memcpy( sd->sd_last, de->d_name, len + 1 );
     sd->sd_last += len + 1;
-
+#if 0
     *(sd->sd_last)++ = lenm;
     memcpy( sd->sd_last, mname, lenm + 1 );
     sd->sd_last += lenm + 1;
-    
+#endif    
     return 0;
 }
 
@@ -160,25 +97,27 @@ static int enumerate_loop(struct dirent *de, char *mname, void *data)
 */
 char *check_dirent(const struct vol *vol, char *name)
 {
-    char *m_name = NULL;
 
     if (!strcmp(name, "..") || !strcmp(name, "."))
         return NULL;
 
-    if (!(validupath(vol, name)))
+    if (!vol->vfs->validupath(vol, 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;
 }
 
 /* ----------------------------- */
@@ -208,11 +147,18 @@ for_each_dirent(const struct vol *vol, char *name, dir_loop fn, void *data)
     return ret;
 }
 
+/* This is the maximal length of a single entry for a file/dir in the reply
+   block if all bits in the file/dir bitmap are set: header(4) + params(104) +
+   macnamelength(1) + macname(31) + utf8(4) + utf8namelen(2) + utf8name(255) +
+   oddpadding(1) */
+
+#define REPLY_PARAM_MAXLEN (4 + 104 + 1 + MACFILELEN + 4 + 2 + 255 + 1)
+
 /* ----------------------------- */
 static int enumerate(obj, ibuf, ibuflen, rbuf, rbuflen, ext )
-AFPObj       *obj;
+AFPObj       *obj _U_;
 char        *ibuf, *rbuf;
-unsigned int ibuflen, *rbuflen;
+unsigned int ibuflen _U_, *rbuflen;
 int     ext;
 {
     static struct savedir      sd = { 0, 0, 0, NULL, NULL, 0 };
@@ -305,7 +251,7 @@ int     ext;
     header = (ext)?4:2;
     header *=sizeof( u_char );
     
-    maxsz = min(maxsz, *rbuflen);
+    maxsz = min(maxsz, *rbuflen - REPLY_PARAM_MAXLEN);
     o_path = cname( vol, dir, &ibuf );
 
     if (afp_errno == AFPERR_NOOBJ) 
@@ -345,8 +291,7 @@ int     ext;
                 return AFPERR_NODIR;
             }
         }
-        curdir->ctime  = o_path->st.st_ctime; /* play safe */
-        curdir->offcnt = ret;
+        setdiroffcnt(curdir, &o_path->st,  ret);
         *sd.sd_last = 0;
 
         sd.sd_last = sd.sd_buf;
@@ -364,18 +309,16 @@ int     ext;
         sd.sd_last = sd.sd_buf;
     }
     while ( sd.sd_sindex < sindex ) {
-        len = *(sd.sd_last)++;
+        len = (unsigned char)*(sd.sd_last)++;
         if ( len == 0 ) {
             sd.sd_did = 0;     /* invalidate sd struct to force re-read */
             return( AFPERR_NOOBJ );
         }
         sd.sd_last += len + 1;
-        len = *(sd.sd_last)++;
-        sd.sd_last += len + 1;
         sd.sd_sindex++;
     }
 
-    while (( len = *(sd.sd_last)) != 0 ) {
+    while (( len = (unsigned char)*(sd.sd_last)) != 0 ) {
         /*
          * If we've got all we need, send it.
          */
@@ -393,10 +336,9 @@ int     ext;
         if (*sd.sd_last == 0) {
             /* stat() already failed on this one */
             sd.sd_last += len + 1;
-            len = *(sd.sd_last)++;
-            sd.sd_last += len + 1;
             continue;
         }
+        memset(&s_path, 0, sizeof(s_path));
         s_path.u_name = sd.sd_last;
         if (of_stat( &s_path) < 0 ) {
             /*
@@ -410,16 +352,12 @@ int     ext;
              */
             *sd.sd_last = 0;
             sd.sd_last += len + 1;
-            len = *(sd.sd_last)++;
-            sd.sd_last += len + 1;
             curdir->offcnt--;          /* a little lie */
             continue;
         }
 
         sd.sd_last += len + 1;
-        len = *(sd.sd_last)++;
-        s_path.m_name = sd.sd_last;
-        sd.sd_last += len + 1;
+        s_path.m_name = NULL;
         /*
          * If a fil/dir is not a dir, it's a file. This is slightly
          * inaccurate, since that means /dev/null is a file, /dev/printer
@@ -430,14 +368,9 @@ int     ext;
                 continue;
             }
             dir = dirsearch_byname(curdir, s_path.u_name);
-            if (!dir) {
-                if (s_path.m_name == NULL || (dir = adddir( vol, curdir, &s_path)) == NULL) {
+            if (!dir && NULL == (dir = adddir( vol, curdir, &s_path) ) ) {
                     return AFPERR_MISC;
                 }
-            }
-            else {
-                s_path.m_name = NULL;
-            }
             if (AFP_OK != ( ret = getdirparams(vol, dbitmap, &s_path, dir,
                                      data + header , &esz ))) {
                 return( ret );
@@ -447,9 +380,6 @@ int     ext;
             if ( fbitmap == 0 ) {
                 continue;
             }
-            if (s_path.m_name == NULL ) {
-                return AFPERR_MISC;
-            }
             if (AFP_OK != ( ret = getfilparams(vol, fbitmap, &s_path, curdir, 
                                      data + header , &esz )) ) {
                 return( ret );
index 58f32d6ac002813b1e38b383ee562e51e4ad7d16..96970807805b98ff327650f1ca6ea218d4611f43 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: file.c,v 1.95 2003-06-09 14:42:39 srittau Exp $
+ * $Id: file.c,v 1.96 2005-04-28 20:49:41 bfernhomberg Exp $
  *
  * Copyright (c) 1990,1993 Regents of The University of Michigan.
  * All Rights Reserved.  See COPYRIGHT.
@@ -11,9 +11,6 @@
 
 #include <stdio.h>
 #include <stdlib.h>
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif /* HAVE_UNISTD_H */
 
 /* STDC check */
 #if STDC_HEADERS
 #define strrchr index
 #endif /* HAVE_STRCHR */
 char *strchr (), *strrchr ();
+
 #ifndef HAVE_MEMCPY
 #define memcpy(d,s,n) bcopy ((s), (d), (n))
 #define memmove(d,s,n) bcopy ((s), (d), (n))
 #endif /* ! HAVE_MEMCPY */
 #endif /* STDC_HEADERS */
 
+#include <atalk/adouble.h>
 #include <utime.h>
-#ifdef HAVE_FCNTL_H
-#include <fcntl.h>
-#endif /* HAVE_FCNTL_H */
 #include <dirent.h>
-#include <sys/mman.h>
 #include <errno.h>
 
 #include <atalk/logger.h>
-#include <sys/types.h>
-#include <sys/time.h>
 #include <sys/param.h>
-#include <sys/stat.h>
 
-#include <netatalk/endian.h>
-#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"
@@ -79,37 +68,63 @@ char *strchr (), *strrchr ();
  *                           putawayID    4  home directory id
  */
 
-const u_char ufinderi[] = {
-                              'T', 'E', 'X', 'T', 'U', 'N', 'I', 'X',
+const u_char ufinderi[ADEDLEN_FINDERI] = {
                               0, 0, 0, 0, 0, 0, 0, 0,
+                              1, 0, 0, 0, 0, 0, 0, 0,
                               0, 0, 0, 0, 0, 0, 0, 0,
                               0, 0, 0, 0, 0, 0, 0, 0
                           };
 
-/* FIXME mpath : unix or mac name ? (for now it's mac name ) */
-void *get_finderinfo(const char *mpath, struct adouble *adp, void *data)
+static const u_char old_ufinderi[] = {
+                              'T', 'E', 'X', 'T', 'U', 'N', 'I', 'X'
+                          };
+
+/* ---------------------- 
+*/
+static int default_type(void *finder) 
+{
+    if (!memcmp(finder, ufinderi, 8) || !memcmp(finder, old_ufinderi, 8))
+        return 1;
+    return 0;
+}
+
+/* FIXME path : unix or mac name ? (for now it's unix name ) */
+void *get_finderinfo(const char *upath, struct adouble *adp, void *data)
 {
     struct extmap      *em;
+    void                *ad_finder = NULL;
+    int                 chk_ext = 0;
+    
+    if (adp)
+        ad_finder = ad_entry(adp, ADEID_FINDERI);
 
-    if (adp) {
-        memcpy(data, ad_entry(adp, ADEID_FINDERI), 32);
+    if (ad_finder) {
+        memcpy(data, ad_finder, ADEDLEN_FINDERI);
+        /* default type ? */
+        if (default_type(ad_finder)) 
+            chk_ext = 1;
     }
     else {
-        memcpy(data, ufinderi, 32);
+        memcpy(data, ufinderi, ADEDLEN_FINDERI);
+        chk_ext = 1;
+        if (*upath == '.') { /* make it invisible */
+            u_int16_t ashort;
+            
+            ashort = htons(FINDERINFO_INVISIBLE);
+            memcpy(data + FINDERINFO_FRFLAGOFF, &ashort, sizeof(ashort));
+        }
     }
-
-    if ((!adp  || !memcmp(ad_entry(adp, ADEID_FINDERI),ufinderi , 8 )) 
-               && (em = getextmap( mpath ))
-    ) {
+    /** Only enter if no appledouble information and no finder information found. */
+    if (chk_ext && (em = getextmap( upath ))) {
         memcpy(data, em->em_type, sizeof( em->em_type ));
-        memcpy(data + 4, em->em_creator, sizeof(em->em_creator));
+        memcpy((char *)data + 4, em->em_creator, sizeof(em->em_creator));
     }
     return data;
 }
 
 /* ---------------------
 */
-char *set_name(const struct vol *vol, char *data, char *name, u_int32_t utf8) 
+char *set_name(const struct vol *vol, char *data, cnid_t pid, char *name, cnid_t id, u_int32_t utf8) 
 {
     u_int32_t   aint;
     char        *tp = NULL;
@@ -124,7 +139,7 @@ char *set_name(const struct vol *vol, char *data, char *name, u_int32_t utf8)
            
             /* global static variable... */
             tp = strdup(name);
-            if (!(u = mtoupath(vol, name, 1)) || !(m = utompath(vol, u, 0))) {
+            if (!(u = mtoupath(vol, name, pid, 1)) || !(m = utompath(vol, u, id, 0))) {
                aint = 0;
             }
             else {
@@ -143,7 +158,7 @@ char *set_name(const struct vol *vol, char *data, char *name, u_int32_t utf8)
         if (aint > 255)  /* FIXME safeguard, anyway if no ascii char it's game over*/
            aint = 255;
 
-        utf8 = 0;         /* htonl(utf8) */
+        utf8 = vol->v_mac?htonl(vol->v_mac->kTextEncoding):0;         /* htonl(utf8) */
         memcpy(data, &utf8, sizeof(utf8));
         data += sizeof(utf8);
         
@@ -171,80 +186,51 @@ char *set_name(const struct vol *vol, char *data, char *name, u_int32_t utf8)
                                  (1 << FILPBIT_FINFO) |\
                                  (1 << FILPBIT_RFLEN) |\
                                  (1 << FILPBIT_EXTRFLEN) |\
-                                 (1 << FILPBIT_PDINFO)))
+                                 (1 << FILPBIT_PDINFO) |\
+                                 (1 << FILPBIT_UNIXPR)))
 
 /* -------------------------- */
 u_int32_t get_id(struct vol *vol, struct adouble *adp,  const struct stat *st,
-             const cnid_t did, const char *upath, const int len) 
+             const cnid_t did, char *upath, const int len) 
 {
 u_int32_t aint = 0;
 
-#ifdef CNID_DB
+#if AD_VERSION > AD_VERSION1
 
-    aint = cnid_add(vol->v_db, st, did, upath, len, aint);
-    /* Throw errors if cnid_add fails. */
-    if (aint == CNID_INVALID) {
-        switch (errno) {
-        case CNID_ERR_CLOSE: /* the db is closed */
-            break;
-        case CNID_ERR_PARAM:
-            LOG(log_error, logtype_afpd, "get_id: Incorrect parameters passed to cnid_add");
-            afp_errno = AFPERR_PARAM;
-            return CNID_INVALID;
-        case CNID_ERR_PATH:
-            afp_errno = AFPERR_PARAM;
-            return CNID_INVALID;
-        default:
-            afp_errno = AFPERR_MISC;
-            return CNID_INVALID;
-        }
+    if ((aint = ad_getid(adp, st->st_dev, st->st_ino, did, vol->v_stamp))) {
+       return aint;
     }
-#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.
-         */
-#ifdef USE_LASTDID
-        if ( S_ISDIR(st->st_mode)) {
-            aint = htonl( vol->v_lastdid++ );
-        }
-        else
-        {
-            aint = htonl(( st->st_dev << 16 ) | (st->st_ino & 0x0000ffff));
-        }
-#else /* USE_LASTDID */
-        {
-            struct stat        lst;
-            const struct stat *lstp;
+#endif
 
-            lstp = lstat(upath, &lst) < 0 ? st : &lst;
-            aint = htonl(CNID(lstp, 1));
+    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) {
+            case CNID_ERR_CLOSE: /* the db is closed */
+                break;
+            case CNID_ERR_PARAM:
+                LOG(log_error, logtype_afpd, "get_id: Incorrect parameters passed to cnid_add");
+                afp_errno = AFPERR_PARAM;
+                return CNID_INVALID;
+            case CNID_ERR_PATH:
+                afp_errno = AFPERR_PARAM;
+                return CNID_INVALID;
+            default:
+                afp_errno = AFPERR_MISC;
+                return CNID_INVALID;
+            }
+        }
+#if AD_VERSION > AD_VERSION1
+        else if (adp ) {
+            /* update the ressource fork
+             * for a folder adp is always null
+             */
+            if (ad_setid(adp, st->st_dev, st->st_ino, aint, did, vol->v_stamp)) {
+                ad_flush(adp, ADFLAGS_HF);
+            }
         }
-#endif /* USE_LASTDID */
+#endif    
     }
     return aint;
 }
@@ -259,6 +245,7 @@ int getmetadata(struct vol *vol,
     char                *utf_nameoff = NULL;
     int                        bit = 0;
     u_int32_t          aint;
+    cnid_t              id = 0;
     u_int16_t          ashort;
     u_char              achar, fdType[4];
     u_int32_t           utf8 = 0;
@@ -273,6 +260,20 @@ int getmetadata(struct vol *vol,
     st = &path->st;
 
     data = buf;
+
+    if ( ((bitmap & ( (1 << FILPBIT_FINFO)|(1 << FILPBIT_LNAME)|(1 <<FILPBIT_PDINFO) ) ) && !path->m_name)
+         || (bitmap & ( (1 << FILPBIT_LNAME) ) && utf8_encoding()) /* FIXME should be m_name utf8 filename */
+         || (bitmap & (1 << FILPBIT_FNUM))) {
+        if (!path->id)
+            id = get_id(vol, adp, st, dir->d_did, upath, strlen(upath));
+        else 
+            id = path->id;
+        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;
@@ -337,14 +338,8 @@ int getmetadata(struct vol *vol,
             break;
 
         case FILPBIT_FINFO :
-           get_finderinfo(path->m_name, adp, (char *)data);
-            if (!adp) {
-                if (*upath == '.') { /* make it invisible */
-                    ashort = htons(FINDERINFO_INVISIBLE);
-                    memcpy(data + FINDERINFO_FRFLAGOFF, &ashort, sizeof(ashort));
-                }
-            }
-            data += 32;
+           get_finderinfo(upath, adp, (char *)data);
+            data += ADEDLEN_FINDERI;
             break;
 
         case FILPBIT_LNAME :
@@ -358,11 +353,8 @@ int getmetadata(struct vol *vol,
             break;
 
         case FILPBIT_FNUM :
-            aint = get_id(vol, adp, st, dir->d_did, upath, strlen(upath));
-            if (aint == 0)
-                return afp_errno;
-            memcpy(data, &aint, sizeof( aint ));
-            data += sizeof( aint );
+            memcpy(data, &id, sizeof( id ));
+            data += sizeof( id );
             break;
 
         case FILPBIT_DFLEN :
@@ -464,6 +456,9 @@ int getmetadata(struct vol *vol,
             data += sizeof( aint );
             break;
         case FILPBIT_UNIXPR :
+            /* accessmode may change st_mode with ACLs */
+            accessmode( upath, &ma, dir , st);
+
             aint = htonl(st->st_uid);
             memcpy( data, &aint, sizeof( aint ));
             data += sizeof( aint );
@@ -471,18 +466,29 @@ int getmetadata(struct vol *vol,
             memcpy( data, &aint, sizeof( aint ));
             data += sizeof( aint );
 
-            aint = htonl(st->st_mode);
+           /* FIXME: ugly hack
+               type == slnk indicates an OSX style symlink, 
+               we have to add S_IFLNK to the mode, otherwise
+               10.3 clients freak out. */
+
+           aint = st->st_mode;
+           if (adp) {
+               memcpy(fdType, ad_entry( adp, ADEID_FINDERI ), 4 );
+                if ( memcmp( fdType, "slnk", 4 ) == 0 ) {
+                   aint |= S_IFLNK;
+               }
+           }
+            aint = htonl(aint);
+
             memcpy( data, &aint, sizeof( aint ));
             data += sizeof( aint );
 
-            accessmode( upath, &ma, dir , st);
-
             *data++ = ma.ma_user;
             *data++ = ma.ma_world;
             *data++ = ma.ma_group;
             *data++ = ma.ma_owner;
             break;
-
+            
         default :
             return( AFPERR_BITMAP );
         }
@@ -492,12 +498,12 @@ int getmetadata(struct vol *vol,
     if ( l_nameoff ) {
         ashort = htons( data - buf );
         memcpy(l_nameoff, &ashort, sizeof( ashort ));
-        data = set_name(vol, data, path->m_name, 0);
+        data = set_name(vol, data, dir->d_did, 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, dir->d_did, path->m_name, id, utf8);
     }
     *buflen = data - buf;
     return (AFP_OK);
@@ -529,14 +535,26 @@ int getfilparams(struct vol *vol,
            attrbits = ((of->of_ad->ad_df.adf_refcount > 0) ? ATTRBIT_DOPEN : 0);
            attrbits |= ((of->of_ad->ad_hf.adf_refcount > of->of_ad->ad_df.adf_refcount)? ATTRBIT_ROPEN : 0);
         } else {
-            memset(&ad, 0, sizeof(ad));
+            ad_init(&ad, vol->v_adouble, vol->v_ad_options);
             adp = &ad;
         }
 
-        if ( ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, adp) < 0 ) {
-             adp = NULL;
+        if ( ad_metadata( upath, 0, adp) < 0 ) {
+            switch (errno) {
+            case EACCES:
+                LOG(log_error, logtype_afpd, "getfilparams(%s): %s: check resource fork permission?",
+                upath, strerror(errno));
+                return AFPERR_ACCESS;
+            case EIO:
+                LOG(log_error, logtype_afpd, "getfilparams(%s): bad resource fork", upath);
+                /* fall through */
+            case ENOENT:
+            default:
+                adp = NULL;
+                break;
+            }
         }
-        else {
+        if (adp) {
            /* FIXME 
               we need to check if the file is open by another process.
               it's slow so we only do it if we have to:
@@ -545,8 +563,12 @@ int getfilparams(struct vol *vol,
            */
            if ((bitmap & (1 << FILPBIT_ATTR))) {
                 if (!(attrbits & ATTRBIT_ROPEN)) {
+                    attrbits |= ad_testlock(adp, ADEID_RFORK, AD_FILELOCK_OPEN_RD) > 0? ATTRBIT_ROPEN : 0;
+                    attrbits |= ad_testlock(adp, ADEID_RFORK, AD_FILELOCK_OPEN_WR) > 0? ATTRBIT_ROPEN : 0;
                 }
                 if (!(attrbits & ATTRBIT_DOPEN)) {
+                    attrbits |= ad_testlock(adp, ADEID_DFORK, AD_FILELOCK_OPEN_RD) > 0? ATTRBIT_DOPEN : 0;
+                    attrbits |= ad_testlock(adp, ADEID_DFORK, AD_FILELOCK_OPEN_WR) > 0? ATTRBIT_DOPEN : 0;
                 }
            }
        }
@@ -564,9 +586,9 @@ int getfilparams(struct vol *vol,
 
 /* ----------------------------- */
 int afp_createfile(obj, ibuf, ibuflen, rbuf, rbuflen )
-AFPObj      *obj;
-char   *ibuf, *rbuf;
-int            ibuflen, *rbuflen;
+AFPObj  *obj;
+char   *ibuf, *rbuf _U_;
+int    ibuflen _U_, *rbuflen;
 {
     struct adouble     ad, *adp;
     struct vol         *vol;
@@ -619,7 +641,7 @@ int         ibuflen, *rbuflen;
     if ((of = of_findname(s_path))) {
         adp = of->of_ad;
     } else {
-        memset(&ad, 0, sizeof(ad));
+        ad_init(&ad, vol->v_adouble, vol->v_ad_options);
         adp = &ad;
     }
     if ( creatf) {
@@ -667,9 +689,7 @@ int         ibuflen, *rbuflen;
     }
 
     path = s_path->m_name;
-    ad_setentrylen( adp, ADEID_NAME, strlen( path ));
-    memcpy(ad_entry( adp, ADEID_NAME ), path,
-           ad_getentrylen( adp, ADEID_NAME ));
+    ad_setname(adp, path);
     ad_flush( adp, ADFLAGS_DF|ADFLAGS_HF );
     ad_close( adp, ADFLAGS_DF|ADFLAGS_HF );
 
@@ -692,9 +712,9 @@ createfile_done:
 }
 
 int afp_setfilparams(obj, ibuf, ibuflen, rbuf, rbuflen )
-AFPObj      *obj;
-char   *ibuf, *rbuf;
-int            ibuflen, *rbuflen;
+AFPObj  *obj;
+char   *ibuf, *rbuf _U_;
+int    ibuflen _U_, *rbuflen;
 {
     struct vol *vol;
     struct dir *dir;
@@ -757,123 +777,108 @@ int             ibuflen, *rbuflen;
 
 /*
  * cf AFP3.0.pdf page 252 for change_mdate and change_parent_mdate logic  
- *
+ * 
 */
 extern struct path Cur_Path;
 
 int setfilparams(struct vol *vol,
-                 struct path *path, u_int16_t bitmap, char *buf )
+                 struct path *path, u_int16_t f_bitmap, char *buf )
 {
     struct adouble     ad, *adp;
-    struct ofork        *of;
     struct extmap      *em;
-    int                        bit = 0, isad = 1, err = AFP_OK;
+    int                        bit, isad = 1, err = AFP_OK;
     char                *upath;
-    u_char              achar, *fdType, xyy[4];
+    u_char              achar, *fdType, xyy[4]; /* uninitialized, OK 310105 */
     u_int16_t          ashort, bshort;
     u_int32_t          aint;
+    u_int32_t          upriv;
+    u_int16_t           upriv_bit = 0;
+    
     struct utimbuf     ut;
 
     int                 change_mdate = 0;
     int                 change_parent_mdate = 0;
     int                 newdate = 0;
     struct timeval      tv;
-
+    uid_t              f_uid;
+    gid_t              f_gid;
+    u_int16_t           bitmap = f_bitmap;
+    u_int32_t           cdate,bdate;
+    u_char              finder_buf[32];
 
 #ifdef DEBUG
     LOG(log_info, logtype_afpd, "begin setfilparams:");
 #endif /* DEBUG */
 
     upath = path->u_name;
-    if ((of = of_findname(path))) {
-        adp = of->of_ad;
-    } else {
-        memset(&ad, 0, sizeof(ad));
-        adp = &ad;
-    }
+    adp = of_ad(vol, path, &ad);
+    
 
     if (!vol_unix_priv(vol) && check_access(upath, OPENACC_WR ) < 0) {
         return AFPERR_ACCESS;
     }
 
-    if (ad_open( upath, vol_noadouble(vol) | ADFLAGS_HF,
-                 O_RDWR|O_CREAT, 0666, adp) < 0) {
-        /* for some things, we don't need an adouble header */
-        if (bitmap & ~(1<<FILPBIT_MDATE)) {
-            return vol_noadouble(vol) ? AFP_OK : AFPERR_ACCESS;
-        }
-        isad = 0;
-    } else if ((ad_get_HF_flags( adp ) & O_CREAT) ) {
-        ad_setentrylen( adp, ADEID_NAME, strlen( path->m_name ));
-        memcpy(ad_entry( adp, ADEID_NAME ), path->m_name,
-               ad_getentrylen( adp, ADEID_NAME ));
-    }
-
+    /* with unix priv maybe we have to change adouble file priv first */
+    bit = 0;
     while ( bitmap != 0 ) {
         while (( bitmap & 1 ) == 0 ) {
             bitmap = bitmap>>1;
             bit++;
         }
-
         switch(  bit ) {
         case FILPBIT_ATTR :
             change_mdate = 1;
             memcpy(&ashort, buf, sizeof( ashort ));
-            ad_getattr(adp, &bshort);
-            if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
-                bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
-            } else {
-                bshort &= ~ashort;
-            }
-            if ((ashort & htons(ATTRBIT_INVISIBLE)))
-                change_parent_mdate = 1;
-            ad_setattr(adp, bshort);
             buf += sizeof( ashort );
             break;
-
         case FILPBIT_CDATE :
             change_mdate = 1;
-            memcpy(&aint, buf, sizeof(aint));
-            ad_setdate(adp, AD_DATE_CREATE, aint);
-            buf += sizeof( aint );
+            memcpy(&cdate, buf, sizeof(cdate));
+            buf += sizeof( cdate );
             break;
-
         case FILPBIT_MDATE :
             memcpy(&newdate, buf, sizeof( newdate ));
             buf += sizeof( newdate );
             break;
-
         case FILPBIT_BDATE :
             change_mdate = 1;
-            memcpy(&aint, buf, sizeof(aint));
-            ad_setdate(adp, AD_DATE_BACKUP, aint);
-            buf += sizeof( aint );
+            memcpy(&bdate, buf, sizeof( bdate));
+            buf += sizeof( bdate );
             break;
-
         case FILPBIT_FINFO :
             change_mdate = 1;
-
-            if (!memcmp( ad_entry( adp, ADEID_FINDERI ), ufinderi, 8 )
-                    && ( 
-                     ((em = getextmap( path->m_name )) &&
-                      !memcmp(buf, em->em_type, sizeof( em->em_type )) &&
-                      !memcmp(buf + 4, em->em_creator,sizeof( em->em_creator)))
-                     || ((em = getdefextmap()) &&
-                      !memcmp(buf, em->em_type, sizeof( em->em_type )) &&
-                      !memcmp(buf + 4, em->em_creator,sizeof( em->em_creator)))
-            )) {
-                memcpy(buf, ufinderi, 8 );
-            }
-
-            memcpy(ad_entry( adp, ADEID_FINDERI ), buf, 32 );
+            memcpy(finder_buf, buf, 32 );
             buf += 32;
             break;
+        case FILPBIT_UNIXPR :
+            if (!vol_unix_priv(vol)) {
+               /* this volume doesn't use unix priv */
+               err = AFPERR_BITMAP;
+               bitmap = 0;
+               break;
+            }
+            change_mdate = 1;
+            change_parent_mdate = 1;
 
-            /* Client needs to set the ProDOS file info for this file.
-               Use a defined string for TEXT to support crlf
-               translations and convert all else into pXYY per Inside
-               Appletalk.  Always set the creator as "pdos".  Changes
-               from original by Marsha Jackson. */
+            memcpy( &aint, buf, sizeof( aint ));
+            f_uid = ntohl (aint);
+            buf += sizeof( aint );
+            memcpy( &aint, buf, sizeof( aint ));
+            f_gid = ntohl (aint);
+            buf += sizeof( aint );
+            setfilowner(vol, f_uid, f_gid, path);
+
+            memcpy( &upriv, buf, sizeof( upriv ));
+            buf += sizeof( upriv );
+            upriv = ntohl (upriv);
+            if ((upriv & S_IWUSR)) {
+               setfilunixmode(vol, path, upriv);
+            }
+            else {
+               /* do it later */
+               upriv_bit = 1;
+            }
+            break;
         case FILPBIT_PDINFO :
             if (afp_version < 30) { /* else it's UTF8 name */
                 achar = *buf;
@@ -889,29 +894,92 @@ int setfilparams(struct vol *vol,
                    xyy[2] = *buf++;
                    fdType = xyy;
                }
-                memcpy(ad_entry( adp, ADEID_FINDERI ), fdType, 4 );
-                memcpy(ad_entry( adp, ADEID_FINDERI ) + 4, "pdos", 4 );
                 break;
             }
             /* fallthrough */
-        case FILPBIT_UNIXPR :
-           /* Skip the UIG/GID, no way to set them from OSX clients */
-            buf += sizeof( aint );
-            buf += sizeof( aint );
+        default :
+            err = AFPERR_BITMAP;
+            /* break while loop */
+            bitmap = 0;
+            break;
+        }
 
-            change_mdate = 1;
-            change_parent_mdate = 1;
-            memcpy( &aint, buf, sizeof( aint ));
-            buf += sizeof( aint );
-            aint = ntohl (aint);
+        bitmap = bitmap>>1;
+        bit++;
+    }
+
+    /* second try with adouble open 
+    */
+    if ( ad_open( upath, vol_noadouble(vol) | ADFLAGS_HF,
+                 O_RDWR|O_CREAT, 0666, adp) < 0) {
+        /* for some things, we don't need an adouble header */
+        if (f_bitmap & ~(1<<FILPBIT_MDATE)) {
+            return vol_noadouble(vol) ? AFP_OK : AFPERR_ACCESS;
+        }
+        isad = 0;
+    } else if ((ad_get_HF_flags( adp ) & O_CREAT) ) {
+        ad_setname(adp, path->m_name);
+    }
+    
+    bit = 0;
+    bitmap = f_bitmap;
+    while ( bitmap != 0 ) {
+        while (( bitmap & 1 ) == 0 ) {
+            bitmap = bitmap>>1;
+            bit++;
+        }
 
-            setfilemode(path, aint);
+        switch(  bit ) {
+        case FILPBIT_ATTR :
+            ad_getattr(adp, &bshort);
+            if ((bshort & htons(ATTRBIT_INVISIBLE)) !=
+                (ashort & htons(ATTRBIT_INVISIBLE) & htons(ATTRBIT_SETCLR)) )
+                change_parent_mdate = 1;
+            if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
+                bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
+            } else {
+                bshort &= ~ashort;
+            }
+            ad_setattr(adp, bshort);
+            break;
+        case FILPBIT_CDATE :
+            ad_setdate(adp, AD_DATE_CREATE, cdate);
+            break;
+        case FILPBIT_MDATE :
+            break;
+        case FILPBIT_BDATE :
+            ad_setdate(adp, AD_DATE_BACKUP, bdate);
             break;
+        case FILPBIT_FINFO :
+            if (default_type( ad_entry( adp, ADEID_FINDERI ))
+                    && ( 
+                     ((em = getextmap( path->m_name )) &&
+                      !memcmp(finder_buf, em->em_type, sizeof( em->em_type )) &&
+                      !memcmp(finder_buf + 4, em->em_creator,sizeof( em->em_creator)))
+                     || ((em = getdefextmap()) &&
+                      !memcmp(finder_buf, em->em_type, sizeof( em->em_type )) &&
+                      !memcmp(finder_buf + 4, em->em_creator,sizeof( em->em_creator)))
+            )) {
+                memcpy(finder_buf, ufinderi, 8 );
+            }
+            memcpy(ad_entry( adp, ADEID_FINDERI ), finder_buf, 32 );
+            break;
+        case FILPBIT_UNIXPR :
+            if (upriv_bit) {
+               setfilunixmode(vol, path, upriv);
+            }
+            break;
+        case FILPBIT_PDINFO :
+            if (afp_version < 30) { /* else it's UTF8 name */
+                memcpy(ad_entry( adp, ADEID_FINDERI ), fdType, 4 );
+                memcpy(ad_entry( adp, ADEID_FINDERI ) + 4, "pdos", 4 );
+                break;
+            }
+            /* fallthrough */
         default :
             err = AFPERR_BITMAP;
             goto setfilparam_done;
         }
-
         bitmap = bitmap>>1;
         bit++;
     }
@@ -955,13 +1023,11 @@ setfilparam_done:
  * adp         adouble struct of src file, if open, or & zeroed one
  *
  */
-int renamefile(src, dst, newname, noadouble, adp )
+int renamefile(vol, src, dst, newname, adp )
+const struct vol *vol;
 char   *src, *dst, *newname;
-const int         noadouble;
 struct adouble    *adp;
 {
-    char       adsrc[ MAXPATHLEN + 1];
-    int                len;
     int                rc;
 
 #ifdef DEBUG
@@ -986,48 +1052,20 @@ struct adouble    *adp;
                /* FIXME  warning in syslog so admin'd know there's a conflict ?*/
                return AFPERR_OLOCK; /* little lie */
            }
-            if (AFP_OK != ( rc = copyfile(src, dst, newname, noadouble )) ) {
+            if (AFP_OK != ( rc = copyfile(vol, vol, src, dst, newname, NULL )) ) {
                 /* on error copyfile delete dest */
                 return( rc );
             }
-            return deletefile(NULL, src, 0);
+            return deletefile(vol, src, 0);
         default :
             return( AFPERR_PARAM );
         }
     }
 
-    strcpy( adsrc, ad_path( src, 0 ));
-
-    if (unix_rename( adsrc, ad_path( dst, 0 )) < 0 ) {
-        struct stat st;
+    if (vol->vfs->rf_renamefile(vol, src, dst) < 0 ) {
         int err;
         
         err = errno;        
-       if (errno == ENOENT) {
-           struct adouble    ad;
-
-            if (stat(adsrc, &st)) /* source has no ressource fork, */
-                return AFP_OK;
-            
-            /* We are here  because :
-             * -there's no dest folder. 
-             * -there's no .AppleDouble in the dest folder.
-             * if we use the struct adouble passed in parameter it will not
-             * 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));
-            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 )) ) 
-                   err = 0;
-                else 
-                   err = errno;
-            }
-            else { /* it's something else, bail out */
-               err = errno;
-           }
-       }
        /* try to undo the data fork rename,
         * we know we are on the same device 
        */
@@ -1050,10 +1088,8 @@ struct adouble    *adp;
 
     /* don't care if we can't open the newly renamed ressource fork
      */
-    if ( !ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, adp)) {
-        len = strlen( newname );
-        ad_setentrylen( adp, ADEID_NAME, len );
-        memcpy(ad_entry( adp, ADEID_NAME ), newname, len );
+    if (!ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, adp)) {
+        ad_setname(adp, newname);
         ad_flush( adp, ADFLAGS_HF );
         ad_close( adp, ADFLAGS_HF );
     }
@@ -1064,7 +1100,21 @@ struct adouble    *adp;
     return( AFP_OK );
 }
 
-int copy_path_name(char *newname, char *ibuf)
+/* ---------------- 
+   convert a Mac long name to an utf8 name,
+*/
+size_t mtoUTF8(const struct vol *vol, const char *src, size_t srclen, char *dest, size_t destlen)
+{
+size_t    outlen;
+
+    if ((size_t)-1 == (outlen = convert_string ( vol->v_maccharset, CH_UTF8_MAC, src, srclen, dest, destlen)) ) {
+       return -1;
+    }
+    return outlen;
+}
+
+/* ---------------- */
+int copy_path_name(const struct vol *vol, char *newname, char *ibuf)
 {
 char        type = *ibuf;
 size_t      plen = 0;
@@ -1078,8 +1128,16 @@ u_int32_t   hint;
     switch (type) {
     case 2:
         if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
-            strncpy( newname, ibuf, plen );
-            newname[ plen ] = '\0';
+            if (afp_version >= 30) {
+                /* convert it to UTF8 
+                */
+                if ((plen = mtoUTF8(vol, ibuf, plen, newname, AFPOBJ_TMPSIZ)) == (size_t)-1)
+                   return -1;
+            }
+            else {
+                strncpy( newname, ibuf, plen );
+                newname[ plen ] = '\0';
+            }
             if (strlen(newname) != plen) {
                 /* there's \0 in newname, e.g. it's a pathname not
                  * only a filename. 
@@ -1114,11 +1172,11 @@ u_int32_t   hint;
 /* -----------------------------------
 */
 int afp_copyfile(obj, ibuf, ibuflen, rbuf, rbuflen )
-AFPObj      *obj;
-char   *ibuf, *rbuf;
-int            ibuflen, *rbuflen;
+AFPObj  *obj;
+char   *ibuf, *rbuf _U_;
+int    ibuflen _U_, *rbuflen;
 {
-    struct vol *vol;
+    struct vol *s_vol, *d_vol;
     struct dir *dir;
     char       *newname, *p, *upath;
     struct path *s_path;
@@ -1126,6 +1184,9 @@ int               ibuflen, *rbuflen;
     int         err, retvalue = AFP_OK;
     u_int16_t  svid, dvid;
 
+    struct adouble ad, *adp;
+    int denyreadset;
+    
 #ifdef DEBUG
     LOG(log_info, logtype_afpd, "begin afp_copyfile:");
 #endif /* DEBUG */
@@ -1135,13 +1196,13 @@ int             ibuflen, *rbuflen;
 
     memcpy(&svid, ibuf, sizeof( svid ));
     ibuf += sizeof( svid );
-    if (NULL == ( vol = getvolbyvid( svid )) ) {
+    if (NULL == ( s_vol = getvolbyvid( svid )) ) {
         return( AFPERR_PARAM );
     }
 
     memcpy(&sdid, ibuf, sizeof( sdid ));
     ibuf += sizeof( sdid );
-    if (NULL == ( dir = dirlookup( vol, sdid )) ) {
+    if (NULL == ( dir = dirlookup( s_vol, sdid )) ) {
         return afp_errno;
     }
 
@@ -1150,7 +1211,7 @@ int               ibuflen, *rbuflen;
     memcpy(&ddid, ibuf, sizeof( ddid ));
     ibuf += sizeof( ddid );
 
-    if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
+    if (NULL == ( s_path = cname( s_vol, dir, &ibuf )) ) {
         return get_afp_errno(AFPERR_PARAM);
     }
     if ( path_isadir(s_path) ) {
@@ -1163,13 +1224,22 @@ int             ibuflen, *rbuflen;
      *      and locks need to stay coherent. as a result,
      *      we just balk if the file is opened already. */
 
-    newname = obj->newtmp;
-    strcpy( newname, s_path->m_name );
+    adp = of_ad(s_vol, s_path, &ad);
 
-    if (of_findname(s_path))
+    if (ad_open(s_path->u_name , ADFLAGS_DF |ADFLAGS_HF | ADFLAGS_NOHF, O_RDONLY, 0, adp) < 0) {
         return AFPERR_DENYCONF;
+    }
+    denyreadset = (getforkmode(adp, ADEID_DFORK, AD_FILELOCK_DENY_RD) != 0 || 
+                  getforkmode(adp, ADEID_RFORK, AD_FILELOCK_DENY_RD) != 0 );
+    ad_close( adp, ADFLAGS_DF |ADFLAGS_HF );
+    if (denyreadset) {
+        return AFPERR_DENYCONF;
+    }
 
-    p = ctoupath( vol, curdir, newname );
+    newname = obj->newtmp;
+    strcpy( newname, s_path->m_name );
+
+    p = ctoupath( s_vol, curdir, newname );
     if (!p) {
         return AFPERR_PARAM;
     
@@ -1177,36 +1247,35 @@ int             ibuflen, *rbuflen;
 #ifdef FORCE_UIDGID
     /* FIXME svid != dvid && dvid's user can't read svid */
 #endif
-    if (NULL == ( vol = getvolbyvid( dvid )) ) {
+    if (NULL == ( d_vol = getvolbyvid( dvid )) ) {
         return( AFPERR_PARAM );
     }
 
-    if (vol->v_flags & AFPVOL_RO)
+    if (d_vol->v_flags & AFPVOL_RO)
         return AFPERR_VLOCK;
 
-    if (NULL == ( dir = dirlookup( vol, ddid )) ) {
+    if (NULL == ( dir = dirlookup( d_vol, ddid )) ) {
         return afp_errno;
     }
 
-    if (( s_path = cname( vol, dir, &ibuf )) == NULL ) {
+    if (( s_path = cname( d_vol, dir, &ibuf )) == NULL ) {
         return get_afp_errno(AFPERR_NOOBJ); 
     }
     if ( *s_path->m_name != '\0' ) {
-#if 0
-        return (path_isadir( s_path))? AFPERR_PARAM:AFPERR_BADTYPE ;
-#endif        
        path_error(s_path, AFPERR_PARAM);
     }
 
     /* one of the handful of places that knows about the path type */
-    if (copy_path_name(newname, ibuf) < 0) {
+    if (copy_path_name(d_vol, newname, ibuf) < 0) {
         return( AFPERR_PARAM );
     }
-
-    if (NULL == (upath = mtoupath(vol, newname, utf8_encoding()))) {
+    /* newname is always only a filename so curdir *is* its
+     * parent folder
+    */
+    if (NULL == (upath = mtoupath(d_vol, newname, curdir->d_did, utf8_encoding()))) {
         return( AFPERR_PARAM );
     }
-    if ( (err = copyfile(p, upath , newname, vol_noadouble(vol))) < 0 ) {
+    if ( (err = copyfile(s_vol, d_vol, p, upath , newname, adp)) < 0 ) {
         return err;
     }
     curdir->offcnt++;
@@ -1217,7 +1286,7 @@ int               ibuflen, *rbuflen;
     }
 #endif /* DROPKLUDGE */
 
-    setvoltime(obj, vol );
+    setvoltime(obj, d_vol );
 
 #ifdef DEBUG
     LOG(log_info, logtype_afpd, "end afp_copyfile:");
@@ -1226,7 +1295,7 @@ int               ibuflen, *rbuflen;
     return( retvalue );
 }
 
-
+/* ----------------------- */
 static __inline__ int copy_all(const int dfd, const void *buf,
                                size_t buflen)
 {
@@ -1241,14 +1310,8 @@ static __inline__ int copy_all(const int dfd, const void *buf,
             switch (errno) {
             case EINTR:
                 continue;
-            case EDQUOT:
-            case EFBIG:
-            case ENOSPC:
-                return AFPERR_DFULL;
-            case EROFS:
-                return AFPERR_VLOCK;
             default:
-                return AFPERR_PARAM;
+                return -1;
             }
         }
         buflen -= cc;
@@ -1258,50 +1321,56 @@ static __inline__ int copy_all(const int dfd, const void *buf,
     LOG(log_info, logtype_afpd, "end copy_all:");
 #endif /* DEBUG */
 
-    return AFP_OK;
+    return 0;
 }
 
 /* -------------------------- */
 static int copy_fd(int dfd, int sfd)
 {
     ssize_t cc;
-    int     err = AFP_OK;
+    int     err = 0;
     char    filebuf[8192];
-
-#ifdef SENDFILE_FLAVOR_LINUX
+    
+#if 0 /* ifdef SENDFILE_FLAVOR_LINUX */
+    /* doesn't work With 2.6 FIXME, only check for EBADFD ? */
+    off_t   offset = 0;
+    size_t  size;
     struct stat         st;
+    #define BUF 128*1024*1024
 
     if (fstat(sfd, &st) == 0) {
-        if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
-            switch (errno) {
-            case EINVAL:  /* there's no guarantee that all fs support sendfile */
-                break;
-            case EDQUOT:
-            case EFBIG:
-            case ENOSPC:
-                return AFPERR_DFULL;
-            case EROFS:
-                return AFPERR_VLOCK;
-            default:
-                return AFPERR_PARAM;
+        
+        while (1) {
+            if ( offset >= st.st_size) {
+               return 0;
+            }
+            size = (st.st_size -offset > BUF)?BUF:st.st_size -offset;
+            if ((cc = sys_sendfile(dfd, sfd, &offset, size)) < 0) {
+                switch (errno) {
+                case ENOSYS:
+                case EINVAL:  /* there's no guarantee that all fs support sendfile */
+                    goto no_sendfile;
+                default:
+                    return -1;
+                }
             }
-        }
-        else {
-           return AFP_OK;
         }
     }
-#endif /* SENDFILE_FLAVOR_LINUX */
+    no_sendfile:
+    lseek(sfd, offset, SEEK_SET);
+#endif 
 
     while (1) {
         if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
             if (errno == EINTR)
                 continue;
-            err = AFPERR_PARAM;
+            err = -1;
             break;
         }
 
-        if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0))
+        if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0)) {
             break;
+        }
     }
     return err;
 }
@@ -1310,86 +1379,117 @@ static int copy_fd(int dfd, int sfd)
  * if newname is NULL (from directory.c) we don't want to copy ressource fork.
  * because we are doing it elsewhere.
  */
-int copyfile(src, dst, newname, noadouble )
+int copyfile(s_vol, d_vol, src, dst, newname, adp )
+const struct vol *s_vol, *d_vol;
 char   *src, *dst, *newname;
-const int   noadouble;
+struct adouble *adp;
 {
     struct adouble     ads, add;
-    int                        len, err = AFP_OK;
+    int                        err = 0;
+    int                 ret_err = 0;
     int                 adflags;
+    int                 noadouble = vol_noadouble(d_vol);
+    struct stat         st;
     
 #ifdef DEBUG
     LOG(log_info, logtype_afpd, "begin copyfile:");
 #endif /* DEBUG */
 
-    memset(&ads, 0, sizeof(ads));
-    memset(&add, 0, sizeof(add));
+    if (adp == NULL) {
+        ad_init(&ads, s_vol->v_adouble, s_vol->v_ad_options); 
+        adp = &ads;
+    }
+    ad_init(&add, d_vol->v_adouble, d_vol->v_ad_options);
     adflags = ADFLAGS_DF;
     if (newname) {
         adflags |= ADFLAGS_HF;
     }
 
-    if (ad_open(src , adflags | ADFLAGS_NOHF, O_RDONLY, 0, &ads) < 0) {
-        switch ( errno ) {
-        case ENOENT :
-            return( AFPERR_NOOBJ );
-        case EACCES :
-            return( AFPERR_ACCESS );
-        default :
-            return( AFPERR_PARAM );
-        }
+    if (ad_open(src , adflags | ADFLAGS_NOHF, O_RDONLY, 0, adp) < 0) {
+        ret_err = errno;
+        goto done;
+    }
+
+    if (ad_hfileno(adp) == -1) {
+        /* no resource fork, don't create one for dst file */
+        adflags &= ~ADFLAGS_HF;
     }
+
     if (ad_open(dst , adflags | noadouble, O_RDWR|O_CREAT|O_EXCL, 0666, &add) < 0) {
-        ad_close( &ads, adflags );
-        if (EEXIST != (err = errno)) {
-            deletefile(NULL, dst, 0);
-        }
-        switch ( err ) {
-        case EEXIST :
-            return AFPERR_EXIST;
-        case ENOENT :
-            return( AFPERR_NOOBJ );
-        case EACCES :
-            return( AFPERR_ACCESS );
-        case EROFS:
-            return AFPERR_VLOCK;
-        default :
-            return( AFPERR_PARAM );
+        ret_err = errno;
+        ad_close( adp, adflags );
+        if (EEXIST != ret_err) {
+            deletefile(d_vol, dst, 0);
+            goto done;
         }
+        return AFPERR_EXIST;
     }
-    if (ad_hfileno(&ads) == -1 || AFP_OK == (err = copy_fd(ad_hfileno(&add), ad_hfileno(&ads)))){
+    if (ad_hfileno(adp) == -1 || 0 == (err = copy_fd(ad_hfileno(&add), ad_hfileno(adp)))){
         /* copy the data fork */
-       err = copy_fd(ad_dfileno(&add), ad_dfileno(&ads));
+       err = copy_fd(ad_dfileno(&add), ad_dfileno(adp));
     }
 
-    if (newname) {
-        len = strlen( newname );
-        ad_setentrylen( &add, ADEID_NAME, len );
-        memcpy(ad_entry( &add, ADEID_NAME ), newname, len );
+    /* Now, reopen destination file */
+    if (err < 0) {
+       ret_err = errno;
+    }
+    ad_close( adp, adflags );
+
+    if (ad_close( &add, adflags ) <0) {
+        deletefile(d_vol, dst, 0);
+        ret_err = errno;
+        goto done;
+    } 
+    else {
+       ad_init(&add, d_vol->v_adouble, d_vol->v_ad_options);
+       if (ad_open(dst , adflags | noadouble, O_RDWR, 0666, &add) < 0) {
+           ret_err = errno;
+       }
+    }
+
+    if (!ret_err && newname) {
+        ad_setname(&add, newname);
     }
 
-    ad_close( &ads, adflags );
     ad_flush( &add, adflags );
     if (ad_close( &add, adflags ) <0) {
-       err = errno;
+       ret_err = errno;
     }
-    if (err != AFP_OK) {
-        deletefile(NULL, dst, 0);
-        switch ( err ) {
-        case ENOENT :
-            return( AFPERR_NOOBJ );
-        case EACCES :
-            return( AFPERR_ACCESS );
-        default :
-            return( AFPERR_PARAM );
-        }
+    if (ret_err) {
+        deletefile(d_vol, dst, 0);
+    }
+    else if (!stat(src, &st)) {
+        /* set dest modification date to src date */
+        struct utimbuf ut;
+
+        /* ADS here ? */
+       ut.actime = ut.modtime = st.st_mtime;
+       utime(dst, &ut);
+       /* FIXME netatalk doesn't use resource fork file date
+        * but maybe we should set its modtime too.
+       */
     }
 
 #ifdef DEBUG
     LOG(log_info, logtype_afpd, "end copyfile:");
 #endif /* DEBUG */
 
-    return( AFP_OK );
+done:
+    switch ( ret_err ) {
+    case 0:
+        return AFP_OK;
+    case EDQUOT:
+    case EFBIG:
+    case ENOSPC:
+        return AFPERR_DFULL;
+    case ENOENT:
+        return AFPERR_NOOBJ;
+    case EACCES:
+        return AFPERR_ACCESS;
+    case EROFS:
+        return AFPERR_VLOCK;
+    }
+    return AFPERR_PARAM;
 }
 
 
@@ -1404,11 +1504,12 @@ const int   noadouble;
    WRITE lock on read only file.
 */
 int deletefile( vol, file, checkAttrib )
-struct vol      *vol;
+const struct vol      *vol;
 char           *file;
 int         checkAttrib;
 {
     struct adouble     ad;
+    struct adouble      *adp = &ad;
     int                        adflags, err = AFP_OK;
 
 #ifdef DEBUG
@@ -1417,8 +1518,8 @@ int         checkAttrib;
 
     /* try to open both forks at once */
     adflags = ADFLAGS_DF|ADFLAGS_HF;
+    ad_init(&ad, vol->v_adouble, vol->v_ad_options);  /* OK */
     while(1) {
-        memset(&ad, 0, sizeof(ad));
         if ( ad_open( file, adflags, O_RDONLY, 0, &ad ) < 0 ) {
             switch (errno) {
             case ENOENT:
@@ -1430,7 +1531,8 @@ int         checkAttrib;
                 continue;
 
             case EACCES:
-                return AFPERR_ACCESS;
+                adp = NULL; /* maybe it's a file we no rw mode for us */
+                break;      /* was return AFPERR_ACCESS;*/
             case EROFS:
                 return AFPERR_VLOCK;
             default:
@@ -1442,17 +1544,31 @@ int         checkAttrib;
     /*
      * Does kFPDeleteInhibitBit (bit 8) set?
      */
-    if (checkAttrib && (adflags & ADFLAGS_HF)) {
+    if (checkAttrib) {
         u_int16_t   bshort;
+        
+        if (adp && (adflags & ADFLAGS_HF)) {
 
-        ad_getattr(&ad, &bshort);
-        if ((bshort & htons(ATTRBIT_NODELETE))) {
-            ad_close( &ad, adflags );
-            return(AFPERR_OLOCK);
+            ad_getattr(&ad, &bshort);
+            if ((bshort & htons(ATTRBIT_NODELETE))) {
+                ad_close( &ad, adflags );
+                return(AFPERR_OLOCK);
+            }
+        }
+        else if (!adp) {
+            /* was EACCESS error try to get only metadata */
+            ad_init(&ad, vol->v_adouble, vol->v_ad_options);  /* OK */
+            if ( ad_metadata( file , 0, &ad) == 0 ) {
+                ad_getattr(&ad, &bshort);
+                ad_close( &ad, ADFLAGS_HF );
+                if ((bshort & htons(ATTRBIT_NODELETE))) {
+                    return  AFPERR_OLOCK;
+                }
+            }
         }
     }
     
-    if ((adflags & ADFLAGS_HF) ) {
+    if (adp && (adflags & ADFLAGS_HF) ) {
         /* FIXME we have a pb here because we want to know if a file is open 
          * there's a 'priority inversion' if you can't open the ressource fork RW
          * you can delete it if it's open because you can't get a write lock.
@@ -1468,21 +1584,18 @@ int         checkAttrib;
         }
     }
 
-    if (ad_tmplock( &ad, ADEID_DFORK, ADLOCK_WR, 0, 0, 0 ) < 0) {
+    if (adp && ad_tmplock( &ad, ADEID_DFORK, ADLOCK_WR, 0, 0, 0 ) < 0) {
         err = AFPERR_BUSY;
     }
-    else if (!(err = netatalk_unlink( ad_path( file, ADFLAGS_HF)) ) &&
-             !(err = netatalk_unlink( file )) ) {
-#ifdef CNID_DB /* get rid of entry */
+    else if (!(err = vol->vfs->rf_deletefile(vol, file)) && !(err = netatalk_unlink( file )) ) {
         cnid_t id;
-        if (vol && (id = cnid_get(vol->v_db, curdir->d_did, file, strlen(file)))) 
+        if (checkAttrib && (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 */
+    if (adp)
+        ad_close( &ad, adflags );  /* ad_close removes locks if any */
 
 #ifdef DEBUG
     LOG(log_info, logtype_afpd, "end deletefile:");
@@ -1492,12 +1605,11 @@ int         checkAttrib;
 }
 
 /* ------------------------------------ */
-#ifdef CNID_DB
 /* return a file id */
 int afp_createid(obj, ibuf, ibuflen, rbuf, rbuflen )
-AFPObj      *obj;
+AFPObj  *obj _U_;
 char   *ibuf, *rbuf;
-int            ibuflen, *rbuflen;
+int    ibuflen _U_, *rbuflen;
 {
     struct stat         *st;
     struct vol         *vol;
@@ -1523,7 +1635,7 @@ int               ibuflen, *rbuflen;
         return( AFPERR_PARAM);
     }
 
-    if (vol->v_db == NULL) {
+    if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
         return AFPERR_NOOP;
     }
 
@@ -1558,7 +1670,7 @@ int               ibuflen, *rbuflen;
             return AFPERR_PARAM;
     }
     st = &s_path->st;
-    if ((id = cnid_lookup(vol->v_db, st, did, upath, len = strlen(upath)))) {
+    if ((id = cnid_lookup(vol->v_cdb, st, did, upath, len = strlen(upath)))) {
         memcpy(rbuf, &id, sizeof(id));
         *rbuflen = sizeof(id);
         return AFPERR_EXISTID;
@@ -1576,19 +1688,99 @@ int             ibuflen, *rbuflen;
     return afp_errno;
 }
 
+/* ------------------------------- */
+struct reenum {
+    struct vol *vol;
+    cnid_t     did;
+};
+
+static int reenumerate_loop(struct dirent *de, char *mname _U_, void *data)
+{
+    struct path   path;
+    struct reenum *param = data;
+    struct vol    *vol = param->vol;  
+    cnid_t        did  = param->did;
+    cnid_t       aint;
+    
+    memset(&path, 0, sizeof(path));
+
+    if ( stat(de->d_name, &path.st)<0 )
+        return 0;
+    
+    /* update or add to cnid */
+    aint = cnid_add(vol->v_cdb, &path.st, did, de->d_name, strlen(de->d_name), 0); /* ignore errors */
+
+#if AD_VERSION > AD_VERSION1
+    if (aint != CNID_INVALID && !S_ISDIR(path.st.st_mode)) {
+        struct adouble  ad, *adp;
+
+        path.st_errno = 0;
+        path.st_valid = 1;
+        path.u_name = de->d_name;
+            
+        adp = of_ad(vol, &path, &ad);
+            
+        if ( ad_open( de->d_name, ADFLAGS_HF, O_RDWR, 0, adp ) < 0 ) {
+            return 0;
+        }
+        if (ad_setid(adp, path.st.st_dev, path.st.st_ino, aint, did, vol->v_stamp)) {
+            ad_flush(adp, ADFLAGS_HF);
+        }
+        ad_close(adp, ADFLAGS_HF);
+    }
+#endif /* AD_VERSION > AD_VERSION1 */
+
+    return 0;
+}
+
+/* --------------------
+ * Ok the db is out of synch with the dir.
+ * but if it's a deleted file we don't want to do it again and again.
+*/
+static int
+reenumerate_id(struct vol *vol, char *name, struct dir *dir)
+{
+    int             ret;
+    struct reenum   data;
+    struct stat     st;
+    
+    if (vol->v_cdb == NULL) {
+       return -1;
+    }
+    
+    /* FIXME use of_statdir ? */
+    if (stat(name, &st)) {
+       return -1;
+    }
+
+    if (dirreenumerate(dir, &st)) {
+        /* we already did it once and the dir haven't been modified */
+       return dir->offcnt;
+    }
+    
+    data.vol = vol;
+    data.did = dir->d_did;
+    if ((ret = for_each_dirent(vol, name, reenumerate_loop, (void *)&data)) >= 0) {
+        setdiroffcnt(curdir, &st,  ret);
+        dir->d_flags |= DIRF_CNID;
+    }
+
+    return ret;
+}
+
 /* ------------------------------
    resolve a file id */
 int afp_resolveid(obj, ibuf, ibuflen, rbuf, rbuflen )
-AFPObj      *obj;
+AFPObj  *obj _U_;
 char   *ibuf, *rbuf;
-int            ibuflen, *rbuflen;
+int    ibuflen _U_, *rbuflen;
 {
     struct vol         *vol;
     struct dir         *dir;
     char               *upath;
     struct path         path;
-    int                 err, buflen;
-    cnid_t             id;
+    int                 err, buflen, retry=0;
+    cnid_t             id, cnid;
     u_int16_t          vid, bitmap;
 
     static char buffer[12 + MAXPATHLEN + 1];
@@ -1608,14 +1800,21 @@ int             ibuflen, *rbuflen;
         return( AFPERR_PARAM);
     }
 
-    if (vol->v_db == NULL) {
+    if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
         return AFPERR_NOOP;
     }
 
     memcpy(&id, ibuf, sizeof( id ));
     ibuf += sizeof(id);
-
-    if (NULL == (upath = cnid_resolve(vol->v_db, &id, buffer, len)) ) {
+    cnid = id;
+    
+    if (!id) {
+        /* some MacOS versions after a catsearch do a *lot* of afp_resolveid with 0 */
+        return AFPERR_NOID;
+    }
+retry:
+    memset(&path, 0, sizeof(path));
+    if (NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, len)) ) {
         return AFPERR_NOID; /* was AFPERR_BADID, but help older Macs */
     }
 
@@ -1623,7 +1822,32 @@ int              ibuflen, *rbuflen;
         return AFPERR_NOID; /* idem AFPERR_PARAM */
     }
     path.u_name = upath;
-    if (movecwd(vol, dir) < 0 || of_stat(&path) < 0) {
+    if (movecwd(vol, dir) < 0) {
+        switch (errno) {
+        case EACCES:
+        case EPERM:
+            return AFPERR_ACCESS;
+        case ENOENT:
+            return AFPERR_NOID;
+        default:
+            return AFPERR_PARAM;
+        }
+    }
+
+    if ( of_stat(&path) < 0 ) {
+#ifdef ESTALE
+        /* with nfs and our working directory is deleted */
+       if (errno == ESTALE) {
+           errno = ENOENT;
+       }
+#endif 
+       if ( errno == ENOENT && !retry) {
+           /* cnid db is out of sync, reenumerate the directory and update ids */
+           reenumerate_id(vol, ".", dir);
+           id = cnid;
+           retry = 1;
+           goto retry;
+        }
         switch (errno) {
         case EACCES:
         case EPERM:
@@ -1634,15 +1858,17 @@ int             ibuflen, *rbuflen;
             return AFPERR_PARAM;
         }
     }
+
     /* directories are bad */
     if (S_ISDIR(path.st.st_mode))
         return AFPERR_BADTYPE;
 
     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;
     }
+    path.id = cnid;
     if (AFP_OK != (err = getfilparams(vol, bitmap, &path , curdir, 
                             rbuf + sizeof(bitmap), &buflen))) {
         return err;
@@ -1659,9 +1885,9 @@ int               ibuflen, *rbuflen;
 
 /* ------------------------------ */
 int afp_deleteid(obj, ibuf, ibuflen, rbuf, rbuflen )
-AFPObj      *obj;
-char   *ibuf, *rbuf;
-int            ibuflen, *rbuflen;
+AFPObj  *obj _U_;
+char   *ibuf, *rbuf _U_;
+int    ibuflen _U_, *rbuflen;
 {
     struct stat         st;
     struct vol         *vol;
@@ -1688,7 +1914,7 @@ int               ibuflen, *rbuflen;
         return( AFPERR_PARAM);
     }
 
-    if (vol->v_db == NULL) {
+    if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
         return AFPERR_NOOP;
     }
 
@@ -1699,7 +1925,7 @@ int               ibuflen, *rbuflen;
     ibuf += sizeof(id);
     fileid = id;
 
-    if (NULL == (upath = cnid_resolve(vol->v_db, &id, buffer, len)) ) {
+    if (NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, len)) ) {
         return AFPERR_NOID;
     }
 
@@ -1713,6 +1939,9 @@ int               ibuflen, *rbuflen;
         case EACCES:
         case EPERM:
             return AFPERR_ACCESS;
+#ifdef ESTALE
+       case ESTALE:
+#endif 
         case ENOENT:
             /* still try to delete the id */
             err = AFPERR_NOOBJ;
@@ -1724,7 +1953,7 @@ int               ibuflen, *rbuflen;
     else if (S_ISDIR(st.st_mode)) /* directories are bad */
         return AFPERR_BADTYPE;
 
-    if (cnid_delete(vol->v_db, fileid)) {
+    if (cnid_delete(vol->v_cdb, fileid)) {
         switch (errno) {
         case EROFS:
             return AFPERR_VLOCK;
@@ -1742,14 +1971,59 @@ int             ibuflen, *rbuflen;
 
     return err;
 }
-#endif /* CNID_DB */
+
+/* ------------------------------ */
+static struct adouble *find_adouble(struct path *path, struct ofork **of, struct adouble *adp)
+{
+    int             ret;
+
+    if (path->st_errno) {
+        switch (path->st_errno) {
+        case ENOENT:
+            afp_errno = AFPERR_NOID;
+            break;
+        case EPERM:
+        case EACCES:
+            afp_errno = AFPERR_ACCESS;
+            break;
+        default:
+            afp_errno = AFPERR_PARAM;
+            break;
+        }
+        return NULL;
+    }
+    /* we use file_access both for legacy Mac perm and
+     * for unix privilege, rename will take care of folder perms
+    */
+    if (file_access(path, OPENACC_WR ) < 0) {
+        afp_errno = AFPERR_ACCESS;
+        return NULL;
+    }
+    
+    if ((*of = of_findname(path))) {
+        /* reuse struct adouble so it won't break locks */
+        adp = (*of)->of_ad;
+    }
+    else {
+        ret = ad_open( path->u_name, ADFLAGS_HF, O_RDONLY, 0, adp);
+        if ( !ret && ad_hfileno(adp) != -1 && !(adp->ad_hf.adf_flags & ( O_RDWR | O_WRONLY))) {
+            /* from AFP spec.
+             * The user must have the Read & Write privilege for both files in order to use this command.
+             */
+            ad_close(adp, ADFLAGS_HF);
+            afp_errno = AFPERR_ACCESS;
+            return NULL;
+        }
+    }
+    return adp;
+}
 
 #define APPLETEMP ".AppleTempXXXXXX"
 
 int afp_exchangefiles(obj, ibuf, ibuflen, rbuf, rbuflen )
-AFPObj      *obj;
-char   *ibuf, *rbuf;
-int            ibuflen, *rbuflen;
+AFPObj  *obj;
+char   *ibuf, *rbuf _U_ ;
+int    ibuflen _U_, *rbuflen;
 {
     struct stat         srcst, destst;
     struct vol         *vol;
@@ -1760,18 +2034,19 @@ int             ibuflen, *rbuflen;
     int                 err;
     struct adouble     ads;
     struct adouble     add;
-    struct adouble     *adsp;
-    struct adouble     *addp;
-    struct ofork       *s_of;
-    struct ofork       *d_of;
+    struct adouble     *adsp = NULL;
+    struct adouble     *addp = NULL;
+    struct ofork       *s_of = NULL;
+    struct ofork       *d_of = NULL;
     int                 crossdev;
     
-#ifdef CNID_DB
     int                 slen, dlen;
-#endif /* CNID_DB */
     u_int32_t          sid, did;
     u_int16_t          vid;
 
+    uid_t              uid;
+    gid_t              gid;
+
 #ifdef DEBUG
     LOG(log_info, logtype_afpd, "begin afp_exchangefiles:");
 #endif /* DEBUG */
@@ -1786,7 +2061,7 @@ int               ibuflen, *rbuflen;
         return( AFPERR_PARAM);
     }
 
-    if (vol->v_flags & AFPVOL_RO)
+    if ((vol->v_flags & AFPVOL_RO))
         return AFPERR_VLOCK;
 
     /* source and destination dids */
@@ -1805,133 +2080,120 @@ int           ibuflen, *rbuflen;
     }
 
     if ( path_isadir(path) ) {
-        return( AFPERR_BADTYPE );   /* it's a dir */
+        return AFPERR_BADTYPE;   /* it's a dir */
     }
 
-    upath = path->u_name;
-    switch (path->st_errno) {
-        case 0:
-             break;
-        case ENOENT:
-            return AFPERR_NOID;
-        case EPERM:
-        case EACCES:
-            return AFPERR_ACCESS;
-        default:
-            return AFPERR_PARAM;
-    }
-    memset(&ads, 0, sizeof(ads));
-    adsp = &ads;
-    if ((s_of = of_findname(path))) {
-            /* reuse struct adouble so it won't break locks */
-            adsp = s_of->of_ad;
-    }
-    memcpy(&srcst, &path->st, sizeof(struct stat));
     /* save some stuff */
+    srcst = path->st;
     sdir = curdir;
     spath = obj->oldtmp;
     supath = obj->newtmp;
     strcpy(spath, path->m_name);
-    strcpy(supath, upath); /* this is for the cnid changing */
-    p = absupath( vol, sdir, upath);
+    strcpy(supath, path->u_name); /* this is for the cnid changing */
+    p = absupath( vol, sdir, supath);
     if (!p) {
         /* pathname too long */
         return AFPERR_PARAM ;
     }
+    
+    ad_init(&ads, vol->v_adouble, vol->v_ad_options);
+    if (!(adsp = find_adouble( path, &s_of, &ads))) {
+        return afp_errno;
+    }
 
+    /* ***** from here we may have resource fork open **** */
+    
     /* 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 */
+        err = afp_errno; /* was AFPERR_PARAM */
+        goto err_exchangefile;
     }
 
     if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
-        return get_afp_errno(AFPERR_NOOBJ); 
+        err = get_afp_errno(AFPERR_NOOBJ); 
+        goto err_exchangefile;
     }
 
     if ( path_isadir(path) ) {
-        return( AFPERR_BADTYPE );
+        err = AFPERR_BADTYPE;
+        goto err_exchangefile;
     }
 
     /* FPExchangeFiles is the only call that can return the SameObj
      * error */
-    if ((curdir == sdir) && strcmp(spath, path->m_name) == 0)
-        return AFPERR_SAMEOBJ;
-
-    switch (path->st_errno) {
-        case 0:
-             break;
-        case ENOENT:
-            return AFPERR_NOID;
-        case EPERM:
-        case EACCES:
-            return AFPERR_ACCESS;
-        default:
-            return AFPERR_PARAM;
+    if ((curdir == sdir) && strcmp(spath, path->m_name) == 0) {
+        err = AFPERR_SAMEOBJ;
+        goto err_exchangefile;
     }
-    memset(&add, 0, sizeof(add));
-    addp = &add;
-    if ((d_of = of_findname( path))) {
-            /* reuse struct adouble so it won't break locks */
-            addp = d_of->of_ad;
+
+    ad_init(&add, vol->v_adouble, vol->v_ad_options);
+    if (!(addp = find_adouble( path, &d_of, &add))) {
+        err = afp_errno;
+        goto err_exchangefile;
     }
-    memcpy(&destst, &path->st, sizeof(struct stat));
+    destst = path->st;
 
     /* they are not on the same device and at least one is open
+     * FIXME broken for for crossdev and adouble v2
+     * return an error 
     */
     crossdev = (srcst.st_dev != destst.st_dev);
-    if ((d_of || s_of)  && crossdev)
-        return AFPERR_MISC;
-    
-    upath = path->u_name;
-#ifdef CNID_DB
+    if (/* (d_of || s_of)  && */ crossdev) {
+        err = AFPERR_MISC;
+        goto err_exchangefile;
+    }
+
     /* look for destination id. */
-    did = cnid_lookup(vol->v_db, &destst, curdir->d_did, upath,
-                      dlen = strlen(upath));
-#endif /* CNID_DB */
+    upath = path->u_name;
+    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
      * will also be inaccessible from AFP. */
     memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
-    if (!mktemp(temp))
-        return AFPERR_MISC;
+    if (!mktemp(temp)) {
+        err = AFPERR_MISC;
+        goto err_exchangefile;
+    }
+    
+    if (crossdev) {
+        /* FIXME we need to close fork for copy, both s_of and d_of are null */
+       ad_close(adsp, ADFLAGS_HF);
+       ad_close(addp, ADFLAGS_HF);
+    }
 
     /* now, quickly rename the file. we error if we can't. */
-    if ((err = renamefile(p, temp, temp, vol_noadouble(vol), adsp)) < 0)
+    if ((err = renamefile(vol, p, temp, temp, adsp)) != AFP_OK)
         goto err_exchangefile;
     of_rename(vol, s_of, sdir, spath, curdir, temp);
 
     /* rename destination to source */
-    if ((err = renamefile(upath, p, spath, vol_noadouble(vol), addp)) < 0)
+    if ((err = renamefile(vol, upath, p, spath, addp)) != AFP_OK)
         goto err_src_to_tmp;
     of_rename(vol, d_of, curdir, path->m_name, sdir, spath);
 
     /* rename temp to destination */
-    if ((err = renamefile(temp, upath, path->m_name, vol_noadouble(vol), adsp)) < 0)
+    if ((err = renamefile(vol, temp, upath, path->m_name, adsp)) != AFP_OK)
         goto err_dest_to_src;
     of_rename(vol, s_of, curdir, temp, curdir, path->m_name);
 
-#ifdef CNID_DB
     /* id's need switching. src -> dest and dest -> src. 
      * we need to re-stat() if it was a cross device copy.
     */
     if (sid) {
-       cnid_delete(vol->v_db, sid);
+       cnid_delete(vol->v_cdb, sid);
     }
     if (did) {
-       cnid_delete(vol->v_db, did);
+       cnid_delete(vol->v_cdb, did);
     }
     if ((did && ( (crossdev && stat( upath, &srcst) < 0) || 
-                cnid_update(vol->v_db, did, &srcst, curdir->d_did,upath, dlen) < 0))
+                cnid_update(vol->v_cdb, did, &srcst, curdir->d_did,upath, dlen) < 0))
        ||
        (sid && ( (crossdev && stat(p, &destst) < 0) ||
-                cnid_update(vol->v_db, sid, &destst, sdir->d_did,supath, slen) < 0))
+                cnid_update(vol->v_cdb, sid, &destst, sdir->d_did,supath, slen) < 0))
     ) {
         switch (errno) {
         case EPERM:
@@ -1943,34 +2205,86 @@ int             ibuflen, *rbuflen;
         }
         goto err_temp_to_dest;
     }
-#endif /* CNID_DB */
+    
+    /* here we need to reopen if crossdev */
+    if (sid && ad_setid(addp, destst.st_dev, destst.st_ino,  sid, sdir->d_did, vol->v_stamp)) 
+    {
+       ad_flush( addp, ADFLAGS_HF );
+    }
+        
+    if (did && ad_setid(adsp, srcst.st_dev, srcst.st_ino,  did, curdir->d_did, vol->v_stamp)) 
+    {
+       ad_flush( adsp, ADFLAGS_HF );
+    }
+
+    /* change perms, src gets dest perm and vice versa */
+
+    uid = geteuid();
+    gid = getegid();
+    if (seteuid(0)) {
+        LOG(log_error, logtype_afpd, "seteuid failed %s", strerror(errno));
+        err = AFP_OK; /* ignore error */
+        goto err_temp_to_dest;
+    }
+
+    /*
+     * we need to exchange ACL entries as well
+     */
+    /* exchange_acls(vol, p, upath); */
+
+    path->st = srcst;
+    path->st_valid = 1;
+    path->st_errno = 0;
+    path->m_name = NULL;
+    path->u_name = upath;
+
+    setfilunixmode(vol, path, destst.st_mode);
+    setfilowner(vol, destst.st_uid, destst.st_gid, path);
+
+    path->st = destst;
+    path->st_valid = 1;
+    path->st_errno = 0;
+    path->u_name = p;
+
+    setfilunixmode(vol, path, srcst.st_mode);
+    setfilowner(vol, srcst.st_uid, srcst.st_gid, path);
+
+    if ( setegid(gid) < 0 || seteuid(uid) < 0) {
+        LOG(log_error, logtype_afpd, "can't seteuid back %s", strerror(errno));
+        exit(EXITERR_SYS);
+    }
 
 #ifdef DEBUG
     LOG(log_info, logtype_afpd, "ending afp_exchangefiles:");
 #endif /* DEBUG */
 
-    return AFP_OK;
-
+    err = AFP_OK;
+    goto err_exchangefile;
 
     /* 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);
+    renamefile(vol, upath, temp, temp, adsp);
     of_rename(vol, s_of, curdir, upath, curdir, temp);
 
 err_dest_to_src:
     /* rename source back to dest */
-    renamefile(p, upath, path->m_name, vol_noadouble(vol), addp);
+    renamefile(vol, p, upath, path->m_name, addp);
     of_rename(vol, d_of, sdir, spath, curdir, path->m_name);
 
 err_src_to_tmp:
     /* rename temp back to source */
-    renamefile(temp, p, spath, vol_noadouble(vol), adsp);
+    renamefile(vol, temp, p, spath, adsp);
     of_rename(vol, s_of, curdir, temp, sdir, spath);
 
 err_exchangefile:
+    if ( !s_of && adsp && ad_hfileno(adsp) != -1 ) {
+       ad_close(adsp, ADFLAGS_HF);
+    }
+    if ( !d_of && addp && ad_hfileno(addp) != -1 ) {
+       ad_close(addp, ADFLAGS_HF);
+    }
+
     return err;
 }
index ed6b1a93b5612780162852ca1eba97b5fef3afc5..fe9bd8e6848ddf57c495b6d4b9a759881126689d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: file.h,v 1.17 2003-06-05 09:17:11 didg Exp $
+ * $Id: file.h,v 1.18 2005-04-28 20:49:42 bfernhomberg Exp $
  *
  * Copyright (c) 1990,1991 Regents of The University of Michigan.
  * All Rights Reserved.
@@ -75,7 +75,52 @@ struct extmap {
 };
 
 #define kTextEncodingUTF8 0x08000103
-extern char *set_name   __P((const struct vol *, char *, char *, u_int32_t ) );
+
+typedef enum {
+                                        /* Mac OS encodings*/
+  kTextEncodingMacRoman         = 0L,
+  kTextEncodingMacJapanese      = 1,
+  kTextEncodingMacChineseTrad   = 2,
+  kTextEncodingMacKorean        = 3,
+  kTextEncodingMacArabic        = 4,
+  kTextEncodingMacHebrew        = 5,
+  kTextEncodingMacGreek         = 6,
+  kTextEncodingMacCyrillic      = 7,
+  kTextEncodingMacDevanagari    = 9,
+  kTextEncodingMacGurmukhi      = 10,
+  kTextEncodingMacGujarati      = 11,
+  kTextEncodingMacOriya         = 12,
+  kTextEncodingMacBengali       = 13,
+  kTextEncodingMacTamil         = 14,
+  kTextEncodingMacTelugu        = 15,
+  kTextEncodingMacKannada       = 16,
+  kTextEncodingMacMalayalam     = 17,
+  kTextEncodingMacSinhalese     = 18,
+  kTextEncodingMacBurmese       = 19,
+  kTextEncodingMacKhmer         = 20,
+  kTextEncodingMacThai          = 21,
+  kTextEncodingMacLaotian       = 22,
+  kTextEncodingMacGeorgian      = 23,
+  kTextEncodingMacArmenian      = 24,
+  kTextEncodingMacChineseSimp   = 25,
+  kTextEncodingMacTibetan       = 26,
+  kTextEncodingMacMongolian     = 27,
+  kTextEncodingMacEthiopic      = 28,
+  kTextEncodingMacCentralEurRoman = 29,
+  kTextEncodingMacVietnamese    = 30,
+  kTextEncodingMacExtArabic     = 31,   /* The following use script code 0, smRoman*/
+  kTextEncodingMacSymbol        = 33,
+  kTextEncodingMacDingbats      = 34,
+  kTextEncodingMacTurkish       = 35,
+  kTextEncodingMacCroatian      = 36,
+  kTextEncodingMacIcelandic     = 37,
+  kTextEncodingMacRomanian      = 38,
+  kTextEncodingMacCeltic        = 39,
+  kTextEncodingMacGaelic        = 40,
+  kTextEncodingMacKeyboardGlyphs = 41,
+} kTextEncoding_t;
+
+extern char *set_name   __P((const struct vol *, char *, cnid_t, char *, cnid_t, u_int32_t ) );
 
 extern struct extmap   *getextmap __P((const char *));
 extern struct extmap   *getdefextmap __P((void));
@@ -84,29 +129,25 @@ extern int getfilparams __P((struct vol *, u_int16_t, struct path *,
                                  struct dir *, char *buf, int *));
 
 extern int setfilparams __P((struct vol *, struct path *, u_int16_t, char *));
-extern int renamefile   __P((char *, char *, char *, const int, struct adouble *));
-extern int copyfile     __P((char *, char *, char *, const int));
-extern int deletefile   __P((struct vol *, char *, int));
+extern int renamefile   __P((const struct vol *, char *, char *, char *, struct adouble *));
+extern int copyfile     __P((const struct vol *, const struct vol *, char *, char *, char *, struct adouble *));
+extern int deletefile   __P((const struct vol *, char *, int));
 
 extern void *get_finderinfo __P((const char *, struct adouble *, void *));
-extern int  copy_path_name __P((char *, char *i));
+
+extern size_t mtoUTF8   __P((const struct vol *, const char *, size_t , char *, size_t ));
+extern int  copy_path_name __P((const struct vol *, char *, char *i));
 
 extern u_int32_t get_id  __P((struct vol *, struct adouble *, const struct stat *,
-                                const cnid_t , const char *, const int ));
+                                const cnid_t , char *, const int ));
 
 /* FP functions */
 extern int      afp_exchangefiles __P((AFPObj *, char *, int, char *, int *));
 extern int     afp_setfilparams __P((AFPObj *, char *, int, char *, int *));
 extern int     afp_copyfile __P((AFPObj *, char *, int, char *, int *));
 extern int     afp_createfile __P((AFPObj *, char *, int, char *, int *));
-#ifdef CNID_DB
 extern int      afp_createid __P((AFPObj *, char *, int, char *, int *));
 extern int      afp_resolveid __P((AFPObj *, char *, int, char *, int *));
 extern int      afp_deleteid __P((AFPObj *, char *, int, char *, int *));
-#else /* CNID_DB */
-#define afp_createid      afp_null
-#define afp_resolveid     afp_null
-#define afp_deleteid      afp_null
-#endif /* AD_VERSION > AD_VERSION1 */
 
 #endif
index d068182c96b424a32812ce0d669b163c791f1edd..f4e4ba75414d2260d6dc3f29a46e7a4dd08c2330 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: filedir.c,v 1.47 2003-06-05 09:17:11 didg Exp $
+ * $Id: filedir.c,v 1.48 2005-04-28 20:49:42 bfernhomberg Exp $
  *
  * Copyright (c) 1990,1993 Regents of The University of Michigan.
  * All Rights Reserved.  See COPYRIGHT.
@@ -9,25 +9,8 @@
 #include "config.h"
 #endif /* HAVE_CONFIG_H */
 
-#include <errno.h>
-#include <atalk/logger.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/param.h>
-#include <netatalk/endian.h>
-#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
-#include <fcntl.h>
-#endif /* HAVE_FCNTL_H */
-#include <dirent.h>
-
 /* STDC check */
 #if STDC_HEADERS
 #include <string.h>
@@ -43,9 +26,18 @@ char *strchr (), *strrchr ();
 #endif /* ! HAVE_MEMCPY */
 #endif /* STDC_HEADERS */
 
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif /* HAVE_UNISTD_H */
+#ifdef HAVE_STRINGS_H
+#include <strings.h>
+#endif
+#include <dirent.h>
+#include <errno.h>
+#include <sys/param.h>
+#include <atalk/adouble.h>
+
+#include <atalk/afp.h>
+#include <atalk/util.h>
+#include <atalk/cnid.h>
+#include <atalk/logger.h>
 
 #include "directory.h"
 #include "desktop.h"
@@ -81,7 +73,7 @@ more information */
         return AFPERR_NOOBJ ;
     }
 
-    adpath = ad_path( upath, ADFLAGS_HF );
+    adpath = vol->vfs->ad_path( upath, ADFLAGS_HF );
     /* FIXME dirsearch doesn't move cwd to did ! */
     if (( dir = dirlookup( vol, did )) == NULL ) {
         LOG(log_error, logtype_afpd, "matchfile2dirperms: Unable to get directory info.");
@@ -101,29 +93,29 @@ more information */
             if (lchown(upath, sb.st_uid, sb.st_gid) < 0)
             {
                 LOG(log_error, logtype_afpd,
-                    "matchfile2dirperms: Error changing owner/gid of %s: %s",
+                    "matchfile2dirperms(%s): Error changing owner/gid: %s",
                     upath, strerror(errno));
                 ret = AFPERR_ACCESS;
             }
             else if (chmod(upath,(st.st_mode&~default_options.umask)| S_IRGRP| S_IROTH) < 0)
             {
                 LOG(log_error, logtype_afpd,
-                    "matchfile2dirperms Error adding file read permissions: %s",
-                    strerror(errno));
+                    "matchfile2dirperms(%s): Error adding file read permissions: %s",
+                    upath, strerror(errno));
                 ret = AFPERR_ACCESS;
             }
             else if (lchown(adpath, sb.st_uid, sb.st_gid) < 0)
             {
                 LOG(log_error, logtype_afpd,
-                    "matchfile2dirperms: Error changing AppleDouble owner/gid %s: %s",
+                    "matchfile2dirperms(%s): Error changing AppleDouble owner/gid: %s",
                     adpath, strerror(errno));
                 ret = AFPERR_ACCESS;
             }
             else if (chmod(adpath, (st.st_mode&~default_options.umask)| S_IRGRP| S_IROTH) < 0)
             {
                 LOG(log_error, logtype_afpd,
-                    "matchfile2dirperms:  Error adding AD file read permissions: %s",
-                    strerror(errno));
+                    "matchfile2dirperms(%s):  Error adding AD file read permissions: %s",
+                    adpath, strerror(errno));
                 ret = AFPERR_ACCESS;
             }
             seteuid(uid); 
@@ -138,9 +130,9 @@ more information */
 #endif
 
 int afp_getfildirparams(obj, ibuf, ibuflen, rbuf, rbuflen )
-AFPObj      *obj;
+AFPObj  *obj _U_;
 char   *ibuf, *rbuf;
-int            ibuflen, *rbuflen;
+int    ibuflen _U_, *rbuflen;
 {
     struct stat                *st;
     struct vol         *vol;
@@ -160,7 +152,10 @@ int                ibuflen, *rbuflen;
     memcpy( &vid, ibuf, sizeof( vid ));
     ibuf += sizeof( vid );
     if (NULL == ( vol = getvolbyvid( vid )) ) {
-        return( AFPERR_PARAM );
+        /* was AFPERR_PARAM but it helps OS 10.3 when a volume has been removed
+         * from the list.
+         */ 
+        return( AFPERR_ACCESS );
     }
 
     memcpy( &did, ibuf, sizeof( did ));
@@ -185,10 +180,10 @@ int               ibuflen, *rbuflen;
     if (!s_path->st_valid) {
         /* it's a dir and it should be there
          * because we chdir in it in cname or
-         * it's curdir (maybe deleted, but then we can't know)
-         * 
+         * it's curdir (maybe deleted, but then we can't know).
+         * So we need to try harder.
          */
-        of_stat(s_path);
+        of_statdir(vol, s_path);
     }
     if ( s_path->st_errno != 0 ) {
         return( AFPERR_NOOBJ );
@@ -197,7 +192,7 @@ int         ibuflen, *rbuflen;
     buflen = 0;
     if (S_ISDIR(st->st_mode)) {
         if (dbitmap) {
-            dir = s_path->dir;
+            dir = s_path->d_dir;
             if (!dir) 
                 return AFPERR_NOOBJ;
 
@@ -233,9 +228,9 @@ int         ibuflen, *rbuflen;
 }
 
 int afp_setfildirparams(obj, ibuf, ibuflen, rbuf, rbuflen )
-AFPObj      *obj;
-char   *ibuf, *rbuf;
-int            ibuflen, *rbuflen;
+AFPObj  *obj;
+char   *ibuf, *rbuf _U_;
+int    ibuflen _U_, *rbuflen;
 {
     struct stat        *st;
     struct vol *vol;
@@ -280,7 +275,7 @@ int         ibuflen, *rbuflen;
         /* it's a dir and it should be there
          * because we chdir in it in cname
          */
-        of_stat(path);
+        of_statdir(vol, path);
     }
 
     if ( path->st_errno != 0 ) {
@@ -310,7 +305,7 @@ int         ibuflen, *rbuflen;
 }
 
 /* -------------------------------------------- 
-   Factorise some check on a pathname
+   Factorise some checks on a pathname
 */
 int check_name(const struct vol *vol, char *name)
 {
@@ -321,7 +316,7 @@ int check_name(const struct vol *vol, char *name)
     if ((vol->v_flags & AFPVOL_NOHEX) && strchr(name, '/'))
         return AFPERR_PARAM;
 
-    if (!validupath(vol, name))
+    if (!vol->vfs->validupath(vol, name))
         return AFPERR_EXIST;
 
     /* check for vetoed filenames */
@@ -345,28 +340,24 @@ int         isdir;
     char            *p;
     char            *upath;
     int             rc;
-    struct stat     *st;
+    struct stat     *st, nst;
     int             adflags;
     struct adouble     ad;
     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, vol->v_ad_options);
     adp = &ad;
     adflags = 0;
     
     if (!isdir) {
-#ifdef CNID_DB
-        p = mtoupath(vol, oldname, utf8_encoding());
+        p = mtoupath(vol, oldname, sdir->d_did, utf8_encoding());
         if (!p) { 
             return AFPERR_PARAM; /* can't convert */
         }
-        id = cnid_get(vol->v_db, sdir->d_did, p, strlen(p));
-#endif /* CNID_DB */
+        id = cnid_get(vol->v_cdb, sdir->d_did, p, strlen(p));
         p = ctoupath( vol, sdir, oldname );
         if (!p) { 
             return AFPERR_PARAM; /* pathname too long */
@@ -379,9 +370,7 @@ int         isdir;
         }
     }
     else {
-#ifdef CNID_DB
         id = sdir->d_did; /* we already have the CNID */
-#endif /* CNID_DB */
         p = ctoupath( vol, sdir->d_parent, oldname );
         if (!p) {
             return AFPERR_PARAM;
@@ -394,7 +383,7 @@ int         isdir;
      * we are in the dest folder so we need to use p for ad_open
     */
     
-    if (!ad_open(p, ADFLAGS_HF |adflags, O_RDONLY, 0666, adp)) {
+    if (!ad_metadata(p, adflags, adp)) {
     u_int16_t bshort;
 
         ad_getattr(adp, &bshort);
@@ -403,7 +392,7 @@ int         isdir;
             return(AFPERR_OLOCK);
     }
 
-    if (NULL == (upath = mtoupath(vol, newname, utf8_encoding()))){ 
+    if (NULL == (upath = mtoupath(vol, newname, curdir->d_did, utf8_encoding()))){ 
         return AFPERR_PARAM;
     }
     path.u_name = upath;
@@ -413,15 +402,18 @@ int         isdir;
     }
 
     /* source == destination. we just silently accept this. */
-    if (curdir == sdir) {
+    if ((!isdir && curdir == sdir) || (isdir && curdir == sdir->d_parent)) {
         if (strcmp(oldname, newname) == 0)
             return AFP_OK;
 
-        /* deal with case insensitive, case-preserving filesystems. */
-        if ((stat(upath, st) == 0) && strdiacasecmp(oldname, newname))
-            return AFPERR_EXIST;
-
-    } else if (stat(upath, st ) == 0)
+        if (stat(upath, st) == 0 || caseenumerate(vol, &path, curdir) == 0) {
+            if (!stat(p, &nst) && !(nst.st_dev == st->st_dev && nst.st_ino == st->st_ino) ) {
+                /* not the same file */
+                return AFPERR_EXIST;
+            }
+            errno = 0;
+        }
+    } else if (stat(upath, st ) == 0 || caseenumerate(vol, &path, curdir) == 0)
         return AFPERR_EXIST;
 
     if ( !isdir ) {
@@ -430,22 +422,20 @@ int         isdir;
         if (of_findname(&path)) {
             rc = AFPERR_EXIST; /* was AFPERR_BUSY; */
         } else {
-            rc = renamefile( p, upath, newname,vol_noadouble(vol), adp );
+            rc = renamefile(vol, p, upath, newname, adp );
             if (rc == AFP_OK)
                 of_rename(vol, opened, sdir, oldname, curdir, newname);
         }
     } else {
-        rc = renamedir(p, upath, sdir, curdir, newname, vol_noadouble(vol));
+        rc = renamedir(vol, p, upath, sdir, curdir, newname);
     }
-    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;
@@ -453,9 +443,9 @@ int         isdir;
 
 /* -------------------------------------------- */
 int afp_rename(obj, ibuf, ibuflen, rbuf, rbuflen )
-AFPObj      *obj;
-char   *ibuf, *rbuf;
-int            ibuflen, *rbuflen;
+AFPObj  *obj;
+char   *ibuf, *rbuf _U_;
+int    ibuflen _U_, *rbuflen;
 {
     struct vol *vol;
     struct dir *sdir;
@@ -501,7 +491,7 @@ int         ibuflen, *rbuflen;
         strcpy(oldname, path->m_name); /* an extra copy for of_rename */
         if (isdir) {
             /* curdir parent dir, need to move sdir back */
-            sdir = path->dir;
+            sdir = path->d_dir;
         }
     }
     else {
@@ -516,7 +506,7 @@ int         ibuflen, *rbuflen;
     }
 
     /* another place where we know about the path type */
-    if ((plen = copy_path_name(newname, ibuf)) < 0) {
+    if ((plen = copy_path_name(vol, newname, ibuf)) < 0) {
         return( AFPERR_PARAM );
     }
 
@@ -539,9 +529,9 @@ int         ibuflen, *rbuflen;
 
 /* ------------------------------- */
 int afp_delete(obj, ibuf, ibuflen, rbuf, rbuflen )
-AFPObj      *obj;
-char   *ibuf, *rbuf;
-int            ibuflen, *rbuflen;
+AFPObj  *obj;
+char   *ibuf, *rbuf _U_;
+int    ibuflen _U_, *rbuflen;
 {
     struct vol         *vol;
     struct dir         *dir;
@@ -582,7 +572,7 @@ int         ibuflen, *rbuflen;
            rc = AFPERR_ACCESS;
        }
        else {
-            rc = deletecurdir( vol, obj->oldtmp, AFPOBJ_TMPSIZ);
+            rc = deletecurdir( vol);
         }
     } else if (of_findname(s_path)) {
         rc = AFPERR_BUSY;
@@ -600,6 +590,7 @@ int         ibuflen, *rbuflen;
 
     return( rc );
 }
+/* ------------------------ */
 char *absupath( vol, dir, u )
 const struct vol       *vol;
 struct dir     *dir;
@@ -617,7 +608,7 @@ char        *u;
     *p = '\0';
     len = strlen( u );
     p -= len;
-    strncpy( p, u, len );
+    memcpy( p, u, len );
     if (dir) for ( d = dir; d->d_parent; d = d->d_parent ) {
         u = d->d_u_name;
         len = strlen( u );
@@ -629,7 +620,7 @@ char        *u;
         }
         *--p = '/';
         p -= len;
-        strncpy( p, u, len );
+        memcpy( p, u, len );
     }
     len = strlen( vol->v_path );
     if (p -len -1 < path) {
@@ -637,24 +628,27 @@ char      *u;
     }
     *--p = '/';
     p -= len;
-    strncpy( p, vol->v_path, len );
+    memcpy( p, vol->v_path, len );
 
     return( p );
 }
 
+/* ------------------------
+ * FIXME dir could be NULL
+*/
 char *ctoupath( vol, dir, name )
 const struct vol       *vol;
 struct dir     *dir;
 char   *name;
 {
-    return absupath(vol, dir, mtoupath(vol, name, utf8_encoding()));
+    return absupath(vol, dir, mtoupath(vol, name, dir->d_did, utf8_encoding()));
 }
 
 /* ------------------------- */
 int afp_moveandrename(obj, ibuf, ibuflen, rbuf, rbuflen )
-AFPObj      *obj;
-char   *ibuf, *rbuf;
-int            ibuflen, *rbuflen;
+AFPObj  *obj;
+char   *ibuf, *rbuf _U_;
+int    ibuflen  _U_, *rbuflen;
 {
     struct vol *vol;
     struct dir *sdir, *ddir;
@@ -662,6 +656,7 @@ int         ibuflen, *rbuflen;
     char       *oldname, *newname;
     struct path *path;
     int                did;
+    int                pdid;
     int         plen;
     u_int16_t  vid;
     int         rc;
@@ -707,7 +702,7 @@ int         ibuflen, *rbuflen;
     isdir = path_isadir(path);
     if ( *path->m_name != '\0' ) {
         if (isdir) {
-            sdir = path->dir;
+            sdir = path->d_dir;
        }
         strcpy(oldname, path->m_name); /* an extra copy for of_rename */
     } else {
@@ -721,12 +716,13 @@ int               ibuflen, *rbuflen;
     if (NULL == ( path = cname( vol, ddir, &ibuf ))) {
         return( AFPERR_NOOBJ );
     }
+    pdid = curdir->d_did;
     if ( *path->m_name != '\0' ) {
         return path_error(path, AFPERR_NOOBJ);
     }
 
     /* one more place where we know about path type */
-    if ((plen = copy_path_name(newname, ibuf)) < 0) {
+    if ((plen = copy_path_name(vol, newname, ibuf)) < 0) {
         return( AFPERR_PARAM );
     }
 
@@ -737,7 +733,7 @@ int         ibuflen, *rbuflen;
     rc = moveandrename(vol, sdir, oldname, newname, isdir);
 
     if ( rc == AFP_OK ) {
-        char *upath = mtoupath(vol, newname, utf8_encoding());
+        char *upath = mtoupath(vol, newname, pdid, utf8_encoding());
         
         if (NULL == upath) {
             return AFPERR_PARAM;
@@ -746,6 +742,7 @@ int         ibuflen, *rbuflen;
         sdir->offcnt--;
 #ifdef DROPKLUDGE
         if (vol->v_flags & AFPVOL_DROPBOX) {
+            /* FIXME did is not always the source id */
             if ((retvalue=matchfile2dirperms (upath, vol, did)) != AFP_OK) {
                 return retvalue;
             }
@@ -757,7 +754,7 @@ int         ibuflen, *rbuflen;
                 int  admode = ad_mode("", 0777);
 
                 setfilmode(upath, admode, NULL);
-                setfilmode(ad_path( upath, ADFLAGS_HF ), ad_hf_mode(admode), NULL);
+                vol->vfs->rf_setfilmode(vol, upath, admode, NULL);
             }
         setvoltime(obj, vol );
     }
index 66b2c267ea2786c4cf0b9f5a2940860cfb351dd2..1825bbfaf7d27cfd3eda91e786b16a93717d4b2d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: fork.c,v 1.53 2003-09-03 17:40:02 didg Exp $
+ * $Id: fork.c,v 1.54 2005-04-28 20:49:43 bfernhomberg Exp $
  *
  * Copyright (c) 1990,1993 Regents of The University of Michigan.
  * All Rights Reserved.  See COPYRIGHT.
 #endif /* HAVE_CONFIG_H */
 
 #include <stdio.h>
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif /* HAVE_UNISTD_H */
-#ifdef HAVE_FCNTL_H
-#include <fcntl.h>
-#endif /* HAVE_FCNTL_H */
+
 #include <dirent.h>
 #include <string.h>
 #include <errno.h>
+
+#include <atalk/adouble.h>
 #include <atalk/logger.h>
 
 #include <sys/param.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/time.h>
 #include <sys/socket.h>
 
-#include <netatalk/endian.h>
 #include <netatalk/at.h>
 
 #include <atalk/dsi.h>
 #include <atalk/atp.h>
 #include <atalk/asp.h>
 #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"
 #include "desktop.h"
 #include "volume.h"
 
+#ifdef DEBUG1
+#define Debug(a) ((a)->options.flags & OPTION_DEBUG)
+#else
+#define Debug(a) (0)
+#endif
+
 struct ofork           *writtenfork;
 extern int getmetadata(struct vol *vol,
                  u_int16_t bitmap,
@@ -86,7 +83,7 @@ const u_int16_t     attrbits;
     vol = ofork->of_vol;
     dir = ofork->of_dir;
 
-    if (NULL == (path.u_name = mtoupath(vol, ofork->of_name, utf8_encoding()))) {
+    if (NULL == (path.u_name = mtoupath(vol, ofork->of_name, dir->d_did, utf8_encoding()))) {
         return( AFPERR_MISC );
     }
     path.m_name = ofork->of_name;
@@ -181,11 +178,13 @@ static int setforkmode(struct adouble *adp, int eid, int ofrefnum, int what)
 
 /* -------------------------
 */
-static int getforkmode(struct adouble *adp, int eid, int what)
+int getforkmode(struct adouble *adp, int eid, int what)
 {
     return ad_testlock(adp, eid,  what);
 }
 
+/* -------------------------
+*/
 static int fork_setmode(struct adouble *adp, int eid, int access, int ofrefnum)
 {
     int ret;
@@ -252,19 +251,17 @@ static int fork_setmode(struct adouble *adp, int eid, int access, int ofrefnum)
                 return ret;
         }
     }
-
     if ( access == (OPENACC_WR | OPENACC_RD | OPENACC_DWR | OPENACC_DRD)) {
         return ad_excl_lock(adp, eid);
     }
-
     return 0;
 }
 
 /* ----------------------- */
 int afp_openfork(obj, ibuf, ibuflen, rbuf, rbuflen )
-AFPObj      *obj;
+AFPObj  *obj _U_;
 char   *ibuf, *rbuf;
-int            ibuflen, *rbuflen;
+int    ibuflen _U_, *rbuflen;
 {
     struct vol         *vol;
     struct dir         *dir;
@@ -324,7 +321,7 @@ int         ibuflen, *rbuflen;
     case EACCES:
         return (access & OPENACC_WR) ? AFPERR_LOCK : AFPERR_ACCESS;
     default:
-        LOG(log_error, logtype_afpd, "afp_openfork: ad_open: %s", strerror(errno) );
+        LOG(log_error, logtype_afpd, "afp_openfork(%s): ad_open: %s", s_path->m_name, strerror(errno) );
         return AFPERR_PARAM;
     }
     /* FIXME should we check it first ? */
@@ -405,7 +402,7 @@ int         ibuflen, *rbuflen;
                 goto openfork_err;
                 break;
             default:
-                LOG(log_error, logtype_afpd, "afp_openfork: ad_open: %s", strerror(errno) );
+                LOG(log_error, logtype_afpd, "afp_openfork(%s): ad_open: %s", s_path->m_name, strerror(errno) );
                 ret = AFPERR_PARAM;
                 goto openfork_err;
                 break;
@@ -452,7 +449,7 @@ int         ibuflen, *rbuflen;
                 goto openfork_err;
                 break;
             default:
-                LOG(log_error, logtype_afpd, "afp_openfork: ad_open: %s", strerror(errno) );
+                LOG(log_error, logtype_afpd, "afp_openfork(%s): ad_open: %s", s_path->m_name, strerror(errno) );
                 goto openfork_err;
                 break;
             }
@@ -464,10 +461,9 @@ int                ibuflen, *rbuflen;
     }
 
     if ((adflags & ADFLAGS_HF) && (ad_get_HF_flags( ofork->of_ad) & O_CREAT)) {
-        ad_setentrylen( ofork->of_ad, ADEID_NAME, strlen( path ));
-        memcpy(ad_entry( ofork->of_ad, ADEID_NAME ), path,
-               ad_getentrylen( ofork->of_ad, ADEID_NAME ));
-        ad_flush( ofork->of_ad, adflags );
+        if (ad_setname(ofork->of_ad, path)) {
+            ad_flush( ofork->of_ad, adflags );
+        }
     }
 
     if (( ret = getforkparams(ofork, bitmap, rbuf + 2 * sizeof( u_int16_t ),
@@ -518,7 +514,7 @@ int         ibuflen, *rbuflen;
                 break;
             default:
                 *rbuflen = 0;
-                LOG(log_error, logtype_afpd, "afp_openfork: ad_lock: %s", strerror(ret) );
+                LOG(log_error, logtype_afpd, "afp_openfork(%s): ad_lock: %s", s_path->m_name, strerror(ret) );
                 return( AFPERR_PARAM );
             }
         }
@@ -540,9 +536,9 @@ openfork_err:
 }
 
 int afp_setforkparams(obj, ibuf, ibuflen, rbuf, rbuflen )
-AFPObj      *obj;
-char   *ibuf, *rbuf;
-int            ibuflen, *rbuflen;
+AFPObj  *obj _U_;
+char   *ibuf, *rbuf _U_;
+int    ibuflen, *rbuflen;
 {
     struct ofork       *ofork;
     off_t              size;
@@ -563,7 +559,7 @@ int         ibuflen, *rbuflen;
 
     *rbuflen = 0;
     if (NULL == ( ofork = of_find( ofrefnum )) ) {
-        LOG(log_error, logtype_afpd, "afp_setforkparams: of_find could not locate open fork refnum: %u", ofrefnum );
+        LOG(log_error, logtype_afpd, "afp_setforkparams: of_find(%d) could not locate fork", ofrefnum );
         return( AFPERR_PARAM );
     }
 
@@ -634,7 +630,7 @@ int         ibuflen, *rbuflen;
             goto afp_setfork_err;
 
         if (ad_flush( ofork->of_ad, ADFLAGS_HF ) < 0) {
-            LOG(log_error, logtype_afpd, "afp_setforkparams: ad_flush: %s",strerror(errno) );
+            LOG(log_error, logtype_afpd, "afp_setforkparams(%s): ad_flush: %s", ofork->of_name, strerror(errno) );
             return AFPERR_PARAM;
         }
     } else
@@ -642,7 +638,7 @@ int         ibuflen, *rbuflen;
 
 #ifdef AFS
     if ( flushfork( ofork ) < 0 ) {
-        LOG(log_error, logtype_afpd, "afp_setforkparams: flushfork: %s", strerror(errno) );
+        LOG(log_error, logtype_afpd, "afp_setforkparams(%s): flushfork: %s", ofork->of_name, strerror(errno) );
     }
 #endif /* AFS */
 
@@ -680,9 +676,9 @@ afp_setfork_err:
 
 /* ---------------------- */
 static int byte_lock(obj, ibuf, ibuflen, rbuf, rbuflen, is64 )
-AFPObj  *obj;
+AFPObj  *obj _U_;
 char   *ibuf, *rbuf;
-int    ibuflen, *rbuflen;
+int    ibuflen _U_, *rbuflen;
 int     is64;
 {
     struct ofork       *ofork;
@@ -702,7 +698,7 @@ int     is64;
     ibuf += sizeof(ofrefnum);
 
     if (NULL == ( ofork = of_find( ofrefnum )) ) {
-        LOG(log_error, logtype_afpd, "afp_bytelock: of_find");
+        LOG(log_error, logtype_afpd, "afp_bytelock: of_find(%d) could not locate fork", ofrefnum );
         return( AFPERR_PARAM );
     }
 
@@ -787,23 +783,18 @@ struct ofork      *of;
 {
     struct extmap      *em;
 
-    if ( ad_hfileno( of->of_ad ) == -1 ||
-            memcmp( ufinderi, ad_entry( of->of_ad, ADEID_FINDERI ),
-                    8) == 0 ) {
-        if (NULL == ( em = getextmap( of->of_name )) ||
-                memcmp( "TEXT", em->em_type, sizeof( em->em_type )) == 0 ) {
-            return( 1 );
-        } else {
-            return( 0 );
-        }
-    } else {
-        if ( memcmp( ufinderi,
-                     ad_entry( of->of_ad, ADEID_FINDERI ), 4 ) == 0 ) {
-            return( 1 );
-        } else {
-            return( 0 );
-        }
+    if ( ad_hfileno( of->of_ad ) == -1 || !memcmp( ufinderi, ad_entry( of->of_ad, ADEID_FINDERI),8)) {
+        /* no resource fork or no finderinfo, use our files extension mapping */
+        if (!( em = getextmap( of->of_name )) || memcmp( "TEXT", em->em_type, sizeof( em->em_type ))) {
+            return 0;
+        } 
+        /* file type is TEXT */
+        return 1;
+
+    } else if ( !memcmp( "TEXT", ad_entry( of->of_ad, ADEID_FINDERI ), 4 )) {
+        return 1;
     }
+    return 0;
 }
 
 
@@ -818,7 +809,7 @@ static __inline__ ssize_t read_file(struct ofork *ofork, int eid,
 
     cc = ad_read(ofork->of_ad, eid, offset, rbuf, *rbuflen);
     if ( cc < 0 ) {
-        LOG(log_error, logtype_afpd, "afp_read: ad_read: %s", strerror(errno) );
+        LOG(log_error, logtype_afpd, "afp_read(%s): ad_read: %s", ofork->of_name, strerror(errno) );
         *rbuflen = 0;
         return( AFPERR_PARAM );
     }
@@ -876,13 +867,12 @@ static __inline__ ssize_t read_file(struct ofork *ofork, int eid,
  * with dsi, should we check that reqcount < server quantum? 
 */
 static int read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, is64)
-AFPObj      *obj;
+AFPObj  *obj;
 char   *ibuf, *rbuf;
-int            ibuflen, *rbuflen;
-int is64;
+int    ibuflen _U_, *rbuflen;
+int     is64;
 {
     struct ofork       *ofork;
-    off_t              size;
     off_t              offset, saveoff, reqcount, savereqcount;
     int                        cc, err, eid, xlate = 0;
     u_int16_t          ofrefnum;
@@ -893,7 +883,7 @@ int is64;
     ibuf += sizeof( u_short );
 
     if (NULL == ( ofork = of_find( ofrefnum )) ) {
-        LOG(log_error, logtype_afpd, "afp_read: of_find");
+        LOG(log_error, logtype_afpd, "afp_read: of_find(%d) could not locate fork", ofrefnum );
         err = AFPERR_PARAM;
         goto afp_read_err;
     }
@@ -936,14 +926,6 @@ int is64;
         goto afp_read_err;
     }
 
-    /* reqcount isn't always truthful. we need to deal with that. */
-    size = ad_size(ofork->of_ad, eid);
-
-    if (offset >= size) {
-        err = AFPERR_EOF;
-        goto afp_read_err;
-    }
-
     savereqcount = reqcount;
     saveoff = offset;
     if (ad_tmplock(ofork->of_ad, eid, ADLOCK_RD, saveoff, savereqcount,ofork->of_refnum) < 0) {
@@ -953,21 +935,26 @@ int is64;
 
 #define min(a,b)       ((a)<(b)?(a):(b))
     *rbuflen = min( reqcount, *rbuflen );
-    err = read_file(ofork, eid, offset, nlmask, nlchar, rbuf, rbuflen,
-                    xlate);
+    err = read_file(ofork, eid, offset, nlmask, nlchar, rbuf, rbuflen, xlate);
     if (err < 0)
         goto afp_read_done;
 
     /* dsi can stream requests. we can only do this if we're not checking
      * for an end-of-line character. oh well. */
     if ((obj->proto == AFPPROTO_DSI) && (*rbuflen < reqcount) && !nlmask) {
-        DSI *dsi = obj->handle;
+        DSI    *dsi = obj->handle;
+        off_t  size;
+        int    non_blocking = 0;
 
+#ifdef DEBUG1
         if (obj->options.flags & OPTION_DEBUG) {
-            printf( "(read) reply: %d/%d, %d\n", *rbuflen,
-                    (int) reqcount, dsi->clientID);
+            printf( "(read) reply: %d/%d, %d\n", *rbuflen,(int) reqcount, dsi->clientID);
             bprint(rbuf, *rbuflen);
         }
+#endif        
+        /* reqcount isn't always truthful. we need to deal with that. */
+        size = ad_size(ofork->of_ad, eid);
+
         /* subtract off the offset */
         size -= offset;
         if (reqcount > size) {
@@ -985,14 +972,14 @@ int is64;
 
         /* due to the nature of afp packets, we have to exit if we get
            an error. we can't do this with translation on. */
-#ifdef HAVE_SENDFILE_READ
-        if (!(xlate || (obj->options.flags & OPTION_DEBUG))) {
-            if (ad_readfile(ofork->of_ad, eid, dsi->socket, offset,
-                            dsi->datasize) < 0) {
-                if (errno == EINVAL)
+#if 0 /* ifdef WITH_SENDFILE */
+        /* FIXME with OS X deadlock partial workaround we can't use sendfile */
+        if (!(xlate || Debug(obj) )) {
+            if (ad_readfile(ofork->of_ad, eid, dsi->socket, offset, dsi->datasize) < 0) {
+                if (errno == EINVAL || errno == ENOSYS)
                     goto afp_read_loop;
                 else {
-                    LOG(log_error, logtype_afpd, "afp_read: ad_readfile: %s", strerror(errno));
+                    LOG(log_error, logtype_afpd, "afp_read(%s): ad_readfile: %s", ofork->of_name, strerror(errno));
                     goto afp_read_exit;
                 }
             }
@@ -1002,35 +989,45 @@ int is64;
         }
 
 afp_read_loop:
-#endif /* HAVE_SENDFILE_READ */
+#endif 
 
+        /* fill up our buffer. */
+        if (*rbuflen) {
+            /* set to non blocking mode */
+            non_blocking = 1;
+            dsi_block(dsi, 1);
+        }
         /* fill up our buffer. */
         while (*rbuflen > 0) {
-            cc = read_file(ofork, eid, offset, nlmask, nlchar, rbuf,
-                           rbuflen, xlate);
+            cc = read_file(ofork, eid, offset, nlmask, nlchar, rbuf,rbuflen, xlate);
             if (cc < 0)
                 goto afp_read_exit;
 
             offset += *rbuflen;
+#ifdef DEBUG1
             if (obj->options.flags & OPTION_DEBUG) {
                 printf( "(read) reply: %d, %d\n", *rbuflen, dsi->clientID);
                 bprint(rbuf, *rbuflen);
             }
-
+#endif
             /* dsi_read() also returns buffer size of next allocation */
             cc = dsi_read(dsi, rbuf, *rbuflen); /* send it off */
             if (cc < 0)
                 goto afp_read_exit;
             *rbuflen = cc;
         }
+        if (non_blocking) {
+            /* set back to blocking mode */
+            dsi_block(dsi, 0);
+        }
         dsi_readdone(dsi);
         goto afp_read_done;
 
 afp_read_exit:
-        LOG(log_error, logtype_afpd, "afp_read: %s", strerror(errno));
+        LOG(log_error, logtype_afpd, "afp_read(%s): %s", ofork->of_name, strerror(errno));
         dsi_readdone(dsi);
         ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount,ofork->of_refnum);
-        obj->exit(1);
+        obj->exit(EXITERR_CLNT);
     }
 
 afp_read_done:
@@ -1062,9 +1059,9 @@ int       ibuflen, *rbuflen;
 
 /* ---------------------- */
 int afp_flush(obj, ibuf, ibuflen, rbuf, rbuflen )
-AFPObj      *obj;
-char   *ibuf, *rbuf;
-int            ibuflen, *rbuflen;
+AFPObj  *obj _U_;
+char   *ibuf, *rbuf _U_;
+int    ibuflen _U_, *rbuflen;
 {
     struct vol *vol;
     u_int16_t vid;
@@ -1082,9 +1079,9 @@ int               ibuflen, *rbuflen;
 }
 
 int afp_flushfork(obj, ibuf, ibuflen, rbuf, rbuflen )
-AFPObj      *obj;
-char   *ibuf, *rbuf;
-int            ibuflen, *rbuflen;
+AFPObj  *obj _U_;
+char   *ibuf, *rbuf _U_;
+int    ibuflen _U_, *rbuflen;
 {
     struct ofork       *ofork;
     u_int16_t          ofrefnum;
@@ -1094,12 +1091,12 @@ int             ibuflen, *rbuflen;
     memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
 
     if (NULL == ( ofork = of_find( ofrefnum )) ) {
-        LOG(log_error, logtype_afpd, "afp_flushfork: of_find");
+        LOG(log_error, logtype_afpd, "afp_flushfork: of_find(%d) could not locate fork", ofrefnum );
         return( AFPERR_PARAM );
     }
 
     if ( flushfork( ofork ) < 0 ) {
-        LOG(log_error, logtype_afpd, "afp_flushfork: %s", strerror(errno) );
+        LOG(log_error, logtype_afpd, "afp_flushfork(%s): %s", ofork->of_name, strerror(errno) );
     }
 
     return( AFP_OK );
@@ -1115,8 +1112,8 @@ struct ofork      *ofork;
 
     if ( ad_dfileno( ofork->of_ad ) != -1 &&
             fsync( ad_dfileno( ofork->of_ad )) < 0 ) {
-        LOG(log_error, logtype_afpd, "flushfork: dfile(%d) %s",
-            ad_dfileno(ofork->of_ad), strerror(errno) );
+        LOG(log_error, logtype_afpd, "flushfork(%s): dfile(%d) %s",
+            ofork->of_name, ad_dfileno(ofork->of_ad), strerror(errno) );
         err = -1;
     }
 
@@ -1141,21 +1138,19 @@ struct ofork    *ofork;
             err = -1;
 
         if (err < 0)
-            LOG(log_error, logtype_afpd, "flushfork: hfile(%d) %s",
-                ad_hfileno(ofork->of_ad), strerror(errno) );
+            LOG(log_error, logtype_afpd, "flushfork(%s): hfile(%d) %s",
+                ofork->of_name, ad_hfileno(ofork->of_ad), strerror(errno) );
     }
 
     return( err );
 }
 
 int afp_closefork(obj, ibuf, ibuflen, rbuf, rbuflen )
-AFPObj      *obj;
-char   *ibuf, *rbuf;
-int            ibuflen, *rbuflen;
+AFPObj  *obj _U_;
+char   *ibuf, *rbuf _U_;
+int    ibuflen _U_, *rbuflen;
 {
     struct ofork       *ofork;
-    struct timeval      tv;
-    int                        adflags, doflush = 0;
     u_int16_t          ofrefnum;
 
     *rbuflen = 0;
@@ -1163,37 +1158,14 @@ int             ibuflen, *rbuflen;
     memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
 
     if (NULL == ( ofork = of_find( ofrefnum )) ) {
-        LOG(log_error, logtype_afpd, "afp_closefork: of_find");
+        LOG(log_error, logtype_afpd, "afp_closefork: of_find(%d) could not locate fork", ofrefnum );
         return( AFPERR_PARAM );
     }
-
-    adflags = 0;
-    if ((ofork->of_flags & AFPFORK_DATA) && (ad_dfileno( ofork->of_ad ) != -1)) {
-            adflags |= ADFLAGS_DF;
-    }
-    if ( (ofork->of_flags & AFPFORK_OPEN) && ad_hfileno( ofork->of_ad ) != -1 ) {
-        adflags |= ADFLAGS_HF;
-        /*
-         * Only set the rfork's length if we're closing the rfork.
-         */
-        if ((ofork->of_flags & AFPFORK_RSRC)) {
-            ad_refresh( ofork->of_ad );
-            if ((ofork->of_flags & AFPFORK_DIRTY) && !gettimeofday(&tv, NULL)) {
-                ad_setdate(ofork->of_ad, AD_DATE_MODIFY | AD_DATE_UNIX,tv.tv_sec);
-               doflush++;
-            }
-            if ( doflush ) {
-                 ad_flush( ofork->of_ad, adflags );
-            }
-        }
-    }
-
-    if ( ad_close( ofork->of_ad, adflags ) < 0 ) {
-        LOG(log_error, logtype_afpd, "afp_closefork: ad_close: %s", strerror(errno) );
+    if ( of_closefork( ofork ) < 0 ) {
+        LOG(log_error, logtype_afpd, "afp_closefork(%s): of_closefork: %s", ofork->of_name, strerror(errno) );
         return( AFPERR_PARAM );
     }
 
-    of_dealloc( ofork );
     return( AFP_OK );
 }
 
@@ -1226,7 +1198,7 @@ static __inline__ ssize_t write_file(struct ofork *ofork, int eid,
         case ENOSPC :
             return( AFPERR_DFULL );
         default :
-            LOG(log_error, logtype_afpd, "afp_write: ad_write: %s", strerror(errno) );
+            LOG(log_error, logtype_afpd, "afp_write(%s): ad_write: %s", ofork->of_name, strerror(errno) );
             return( AFPERR_PARAM );
         }
     }
@@ -1241,7 +1213,7 @@ static __inline__ ssize_t write_file(struct ofork *ofork, int eid,
 static int write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, is64)
 AFPObj              *obj;
 char                *ibuf, *rbuf;
-int                 ibuflen, *rbuflen;
+int                 ibuflen _U_, *rbuflen;
 int                 is64;
 {
     struct ofork       *ofork;
@@ -1261,7 +1233,7 @@ int                 is64;
     reqcount = get_off_t(&ibuf, is64);
 
     if (NULL == ( ofork = of_find( ofrefnum )) ) {
-        LOG(log_error, logtype_afpd, "afp_write: of_find");
+        LOG(log_error, logtype_afpd, "afp_write: of_find(%d) could not locate fork", ofrefnum );
         err = AFPERR_PARAM;
         goto afp_write_err;
     }
@@ -1324,11 +1296,12 @@ int                 is64;
             return( AFPERR_PARAM );
         }
 
+#ifdef DEBUG1
         if (obj->options.flags & OPTION_DEBUG) {
             printf("(write) len: %d\n", *rbuflen);
             bprint(rbuf, *rbuflen);
         }
-
+#endif
         if ((cc = write_file(ofork, eid, offset, rbuf, *rbuflen,
                              xlate)) < 0) {
             *rbuflen = 0;
@@ -1345,8 +1318,7 @@ int                 is64;
 
             /* find out what we have already and write it out. */
             cc = dsi_writeinit(dsi, rbuf, *rbuflen);
-            if (!cc ||
-                    (cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
+            if (!cc || (cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
                 dsi_writeflush(dsi);
                 *rbuflen = 0;
                 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
@@ -1383,11 +1355,12 @@ int                 is64;
             /* loop until everything gets written. currently
                     * dsi_write handles the end case by itself. */
             while ((cc = dsi_write(dsi, rbuf, *rbuflen))) {
+#ifdef DEBUG1
                 if ( obj->options.flags & OPTION_DEBUG ) {
                     printf("(write) command cont'd: %d\n", cc);
                     bprint(rbuf, cc);
                 }
-
+#endif
                 if ((cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
                     dsi_writeflush(dsi);
                     *rbuflen = 0;
@@ -1441,9 +1414,9 @@ int                 ibuflen, *rbuflen;
 
 /* ---------------------------- */
 int afp_getforkparams(obj, ibuf, ibuflen, rbuf, rbuflen )
-AFPObj      *obj;
+AFPObj  *obj _U_;
 char   *ibuf, *rbuf;
-int            ibuflen, *rbuflen;
+int    ibuflen _U_, *rbuflen;
 {
     struct ofork       *ofork;
     int                        buflen, ret;
@@ -1459,7 +1432,7 @@ int               ibuflen, *rbuflen;
 
     *rbuflen = 0;
     if (NULL == ( ofork = of_find( ofrefnum )) ) {
-        LOG(log_error, logtype_afpd, "afp_getforkparams: of_find");
+        LOG(log_error, logtype_afpd, "afp_getforkparams: of_find(%d) could not locate fork", ofrefnum );
         return( AFPERR_PARAM );
     }
     attrbits = ((ofork->of_ad->ad_df.adf_refcount > 0) ? ATTRBIT_DOPEN : 0);
@@ -1467,7 +1440,7 @@ int               ibuflen, *rbuflen;
 
     if ( ad_hfileno( ofork->of_ad ) != -1 ) {
         if ( ad_refresh( ofork->of_ad ) < 0 ) {
-            LOG(log_error, logtype_afpd, "getforkparams: ad_refresh: %s", strerror(errno) );
+            LOG(log_error, logtype_afpd, "getforkparams(%s): ad_refresh: %s", ofork->of_name, strerror(errno) );
             return( AFPERR_PARAM );
         }
     }
index 8c00a38d213a27ed09620309d10c5406d6386860..785071987310be644cf58668c327c25ad7f23ef8 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: fork.h,v 1.8 2003-01-16 21:18:15 didg Exp $
+ * $Id: fork.h,v 1.9 2005-04-28 20:49:43 bfernhomberg Exp $
  *
  * Copyright (c) 1990,1993 Regents of The University of Michigan.
  * All Rights Reserved.  See COPYRIGHT.
@@ -68,8 +68,13 @@ extern int          of_rename    __P((const struct vol *,
 extern int          of_flush     __P((const struct vol *));
 extern void         of_pforkdesc __P((FILE *));
 extern int          of_stat      __P((struct path *));
+extern int          of_statdir   __P((const struct vol *vol, struct path *));
+extern int          of_closefork __P((struct ofork *ofork));
+extern void         of_closevol  __P((const struct vol *vol));
+extern struct adouble *of_ad     __P((const struct vol *, struct path *, struct adouble *));
 /* in fork.c */
 extern int          flushfork    __P((struct ofork *));
+extern int          getforkmode  __P((struct adouble *, int , int ));
 
 /* FP functions */
 extern int     afp_openfork __P((AFPObj *, char *, int, char *, int *));
index 9312c38a0b73bbffd996c70a1e0edd4afcb5832f..0dd634157a6aa9f28763f26e54d5261aee80f589 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: globals.h,v 1.20 2003-08-30 16:10:32 bfernhomberg Exp $
+ * $Id: globals.h,v 1.21 2005-04-28 20:49:43 bfernhomberg Exp $
  *
  * Copyright (c) 1990,1993 Regents of The University of Michigan.
  * All Rights Reserved.  See COPYRIGHT.
@@ -23,6 +23,8 @@
 #include <netatalk/at.h>
 #include <atalk/afp.h>
 #include <atalk/compat.h>
+#include <atalk/unicode.h>
+#include <atalk/uam.h>
 
 /* test for inline */
 #ifndef __inline__
@@ -37,6 +39,7 @@
 #define OPTION_PROXY         (1 << 3)
 #define OPTION_CUSTOMICON    (1 << 4)
 #define OPTION_NOSLP         (1 << 5)
+#define OPTION_ANNOUNCESSH   (1 << 6)
 
 #ifdef FORCE_UIDGID
 /* set up a structure for this */
@@ -48,19 +51,31 @@ typedef struct uidgidset_t {
 
 /* a couple of these options could get stuck in unions to save
  * space. */
+struct afp_volume_name {
+    time_t     mtime;
+    char       *name;
+    char       *full_name;
+    int        loaded;
+};
+
 struct afp_options {
     int connections, port, transports, tickleval, timeout, server_notif, flags;
     unsigned char passwdbits, passwdminlen, loginmaxfail;
     u_int32_t server_quantum;
     char hostname[MAXHOSTNAMELEN + 1], *server, *ipaddr, *configfile;
     struct at_addr ddpaddr;
-    char *uampath, *nlspath, *fqdn;
-    char *pidfile, *defaultvol, *systemvol;
+    char *uampath, *fqdn;
+    char *pidfile;
+    struct afp_volume_name defaultvol, systemvol, uservol;
+    int  closevol;
+
     char *guest, *loginmesg, *keyfile, *passwdfile;
     char *uamlist;
     char *authprintdir;
     char *signature;
     char *k5service, *k5realm, *k5keytab;
+    char *unixcodepage,*maccodepage;
+    charset_t maccharset, unixcharset; 
     mode_t umask;
     mode_t save_mask;
     int    sleep;
@@ -84,6 +99,7 @@ typedef struct AFPObj {
     /* to prevent confusion, only use these in afp_* calls */
     char oldtmp[AFPOBJ_TMPSIZ + 1], newtmp[AFPOBJ_TMPSIZ + 1];
     void *uam_cookie; /* cookie for uams */
+    struct session_info  sinfo;
 
 #ifdef FORCE_UIDGID
     int                 force_uid;
@@ -97,6 +113,10 @@ extern unsigned char        nologin;
 extern struct dir      *curdir;
 extern char            getwdbuf[];
 
+/* FIXME CNID */
+extern char             Cnid_srv[MAXHOSTNAMELEN + 1];
+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 *));
@@ -104,7 +124,7 @@ extern int afp_options_parseline __P((char *, struct afp_options *));
 extern void afp_options_free __P((struct afp_options *,
                                       const struct afp_options *));
 extern void setmessage __P((const char *));
-extern void readmessage __P((void));
+extern void readmessage __P((AFPObj *));
 
 /* gettok.c */
 extern void initline   __P((int, char *));
index f31dd8440a84e76069fb26bce4a5f9ec285a8d29..dde51781e429197a46a60838275205f613e64b30 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: main.c,v 1.21 2003-05-16 15:29:27 didg Exp $
+ * $Id: main.c,v 1.22 2005-04-28 20:49:43 bfernhomberg Exp $
  *
  * Copyright (c) 1990,1993 Regents of The University of Michigan.
  * All Rights Reserved.  See COPYRIGHT.
 #include <stdio.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 <signal.h>
 
-#include <sys/types.h>
-#include <sys/stat.h>
 #include <sys/param.h>
 #include <sys/uio.h>
 #include <atalk/logger.h>
 
 #include <errno.h>
 
-#include <netatalk/endian.h>
+#include <atalk/adouble.h>
+
 #include <netatalk/at.h>
 #include <atalk/compat.h>
 #include <atalk/dsi.h>
 #include <atalk/atp.h>
 #include <atalk/asp.h>
 #include <atalk/afp.h>
-#include <atalk/adouble.h>
 #include <atalk/paths.h>
 #include <atalk/util.h>
 #include <atalk/server_child.h>
@@ -80,13 +72,13 @@ static void afp_exit(const int i)
     exit(i);
 }
 
-/* ------------------ 
+/* ------------------
    initialize fd set we are waiting for.
 */
 static void set_fd(int ipc_fd)
 {
     AFPConfig   *config;
-    
+
     FD_ZERO(&save_rfds);
     for (config = configs; config; config = config->next) {
         if (config->fd < 0) /* for proxies */
@@ -97,22 +89,26 @@ static void set_fd(int ipc_fd)
         FD_SET(ipc_fd, &save_rfds);
     }
 }
-
 /* ------------------ */
 static void afp_goaway(int sig)
 {
+
 #ifndef NO_DDP
     asp_kill(sig);
 #endif /* ! NO_DDP */
+
     dsi_kill(sig);
     switch( sig ) {
     case SIGTERM :
         LOG(log_info, logtype_afpd, "shutting down on signal %d", sig );
         break;
+    case SIGUSR1 :
     case SIGHUP :
         /* w/ a configuration file, we can force a re-read if we want */
         nologin++;
-        if ((nologin + 1) & 1) {
+        auth_unload();
+        if (sig == SIGHUP || ((nologin + 1) & 1)) {
             AFPConfig *config;
 
             LOG(log_info, logtype_afpd, "re-reading configuration file");
@@ -120,15 +116,20 @@ static void afp_goaway(int sig)
                 if (config->server_cleanup)
                     config->server_cleanup(config);
 
+            /* configfree close atp socket used for DDP tickle, there's an issue
+             * with atp tid.
+            */
             configfree(configs, NULL);
             if (!(configs = configinit(&default_options))) {
                 LOG(log_error, logtype_afpd, "config re-read: no servers configured");
-                afp_exit(1);
+                afp_exit(EXITERR_CONF);
             }
             set_fd(Ipc_fd);
         } else {
             LOG(log_info, logtype_afpd, "disallowing logins");
-            auth_unload();
+        }
+        if (sig == SIGHUP) {
+            nologin = 0;
         }
         break;
     default :
@@ -160,6 +161,7 @@ char        **av;
     void                *ipc;
     struct sigaction   sv;
     sigset_t            sigs;
+    int                 ret;
 
 #ifdef TRU64
     argc = ac;
@@ -167,9 +169,12 @@ char       **av;
     set_auth_parameters( ac, av );
 #endif /* TRU64 */
 
+#ifdef DEBUG1
+    fault_setup(NULL);
+#endif
     afp_options_init(&default_options);
     if (!afp_options_parse(ac, av, &default_options))
-        exit(1);
+        exit(EXITERR_CONF);
 
     /* Save the user's current umask for use with CNID (and maybe some 
      * other things, too). */
@@ -178,43 +183,80 @@ char      **av;
     switch(server_lock("afpd", default_options.pidfile,
                        default_options.flags & OPTION_DEBUG)) {
     case -1: /* error */
-        exit(1);
+        exit(EXITERR_SYS);
     case 0: /* child */
         break;
     default: /* server */
         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. */
     if (!(server_children = server_child_alloc(default_options.connections,
                             CHILD_NFORKS))) {
         LOG(log_error, logtype_afpd, "main: server_child alloc: %s", strerror(errno) );
-        afp_exit(1);
+        afp_exit(EXITERR_SYS);
     }
-
+    
+#ifdef AFP3x
+    /* linux at least up to 2.4.22 send a SIGXFZ for vfat fs,
+       even if the file is open with O_LARGEFILE ! */
+#ifdef SIGXFSZ
+    signal(SIGXFSZ , SIG_IGN); 
+#endif
+#endif    
+    
     memset(&sv, 0, sizeof(sv));
     sv.sa_handler = child_handler;
     sigemptyset( &sv.sa_mask );
+    sigaddset(&sv.sa_mask, SIGALRM);
+    sigaddset(&sv.sa_mask, SIGHUP);
+    sigaddset(&sv.sa_mask, SIGTERM);
+    sigaddset(&sv.sa_mask, SIGUSR1);
+    
     sv.sa_flags = SA_RESTART;
     if ( sigaction( SIGCHLD, &sv, 0 ) < 0 ) {
         LOG(log_error, logtype_afpd, "main: sigaction: %s", strerror(errno) );
-        afp_exit(1);
+        afp_exit(EXITERR_SYS);
     }
 
     sv.sa_handler = afp_goaway;
     sigemptyset( &sv.sa_mask );
+    sigaddset(&sv.sa_mask, SIGALRM);
+    sigaddset(&sv.sa_mask, SIGTERM);
     sigaddset(&sv.sa_mask, SIGHUP);
+    sigaddset(&sv.sa_mask, SIGCHLD);
+    sv.sa_flags = SA_RESTART;
+    if ( sigaction( SIGUSR1, &sv, 0 ) < 0 ) {
+        LOG(log_error, logtype_afpd, "main: sigaction: %s", strerror(errno) );
+        afp_exit(EXITERR_SYS);
+    }
+
+    sigemptyset( &sv.sa_mask );
+    sigaddset(&sv.sa_mask, SIGALRM);
     sigaddset(&sv.sa_mask, SIGTERM);
+    sigaddset(&sv.sa_mask, SIGUSR1);
+    sigaddset(&sv.sa_mask, SIGCHLD);
     sv.sa_flags = SA_RESTART;
     if ( sigaction( SIGHUP, &sv, 0 ) < 0 ) {
         LOG(log_error, logtype_afpd, "main: sigaction: %s", strerror(errno) );
-        afp_exit(1);
+        afp_exit(EXITERR_SYS);
     }
+
+
+    sigemptyset( &sv.sa_mask );
+    sigaddset(&sv.sa_mask, SIGALRM);
+    sigaddset(&sv.sa_mask, SIGHUP);
+    sigaddset(&sv.sa_mask, SIGUSR1);
+    sigaddset(&sv.sa_mask, SIGCHLD);
+    sv.sa_flags = SA_RESTART;
     if ( sigaction( SIGTERM, &sv, 0 ) < 0 ) {
         LOG(log_error, logtype_afpd, "main: sigaction: %s", strerror(errno) );
-        afp_exit(1);
+        afp_exit(EXITERR_SYS);
     }
 
     /* afpd.conf: not in config file: lockfile, connections, configfile
@@ -226,12 +268,19 @@ char      **av;
      */
 
     sigemptyset(&sigs);
+    sigaddset(&sigs, SIGALRM);
     sigaddset(&sigs, SIGHUP);
+    sigaddset(&sigs, SIGUSR1);
+#if 0
+    /* don't block SIGTERM */
     sigaddset(&sigs, SIGTERM);
+#endif
+    sigaddset(&sigs, SIGCHLD);
+
     sigprocmask(SIG_BLOCK, &sigs, NULL);
     if (!(configs = configinit(&default_options))) {
-        LOG(log_error, logtype_afpd, "main: no servers configured: %s\n", strerror(errno));
-        afp_exit(1);
+        LOG(log_error, logtype_afpd, "main: no servers configured: %s", strerror(errno));
+        afp_exit(EXITERR_CONF);
     }
     sigprocmask(SIG_UNBLOCK, &sigs, NULL);
 
@@ -249,7 +298,10 @@ char       **av;
      * solution. */
     while (1) {
         rfds = save_rfds;
-        if (select(FD_SETSIZE, &rfds, NULL, NULL, NULL) < 0) {
+        sigprocmask(SIG_UNBLOCK, &sigs, NULL);
+        ret = select(FD_SETSIZE, &rfds, NULL, NULL, NULL);
+        sigprocmask(SIG_BLOCK, &sigs, NULL);
+        if (ret < 0) {
             if (errno == EINTR)
                 continue;
             LOG(log_error, logtype_afpd, "main: can't wait for input: %s", strerror(errno));
@@ -257,12 +309,13 @@ char      **av;
         }
         if (Ipc_fd >=0 && FD_ISSET(Ipc_fd, &rfds)) {
             server_ipc_read(server_children);
-       }
+        }
         for (config = configs; config; config = config->next) {
             if (config->fd < 0)
                 continue;
-            if (FD_ISSET(config->fd, &rfds))
+            if (FD_ISSET(config->fd, &rfds)) {
                 config->server_start(config, configs, server_children);
+            }
         }
     }
 
index 1923355fae2e468ca01aea021dbd7da67387d6b0..eb1f39eff254279c1388d18b84f1616eb143d691 100644 (file)
@@ -1,5 +1,5 @@
 /* 
- * $Id: mangle.c,v 1.16 2003-03-09 20:37:27 didg Exp $ 
+ * $Id: mangle.c,v 1.17 2005-04-28 20:49:44 bfernhomberg 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"
+#include "desktop.h"
+#include <atalk/util.h>  
 
-char *
-demangle(const struct vol *vol, char *mfilename) {
-       char *filename = NULL;
-       char *ext = NULL;
-       size_t ext_len = 0;
-       char *mangle;
-
-       /* Is this really a mangled file? */
-       mangle = strstr(mfilename, MANGLE_CHAR);
-       if (!mangle) {
-           return mfilename;
-       }
+#define hextoint( c )   ( isdigit( c ) ? c - '0' : c + 10 - 'A' )
+#define isuxdigit(x)    (isdigit(x) || (isupper(x) && isxdigit(x)))
 
-       if (NULL != (ext = strrchr(mfilename, '.')) ) {
-           ext_len = strlen(ext);
-       }
-       if (strlen(mangle) != strlen(MANGLE_CHAR) + MANGLE_LENGTH + ext_len) {
-           return mfilename;
-       }
+static size_t mangle_extension(const struct vol *vol, const char* uname,
+                              char* extension, charset_t charset)
+{
+  char *p = strrchr(uname, '.');
+
+  if (p && p != uname) {
+    u_int16_t flags = CONV_FORCE | CONV_UNESCAPEHEX;
+    size_t len = convert_charset(vol->v_volcharset, charset,
+                                vol->v_maccharset, p, strlen(p),
+                                extension, MAX_EXT_LENGTH, &flags);
+
+    if (len != (size_t)-1) return len;
+  }
+  return 0;
+}
+
+static char *demangle_checks ( const struct vol *vol, char* uname, char * mfilename, size_t prefix, char * ext)
+{
+    u_int16_t flags;
+    static char buffer[MAXPATHLEN +1];
+    size_t len;
+    size_t mfilenamelen;
 
-       filename = cnid_mangle_get(vol->v_db, mfilename);
+    /* We need to check, whether we really need to demangle the filename       */
+    /* i.e. it's not just a file with a valid #HEX in the name ...             */
+    /* but we don't want to miss valid demangle as well.                       */
+
+    /* check whether file extensions match */
+    {
+      char buf[MAX_EXT_LENGTH + 1];
+      size_t ext_len = mangle_extension(vol, uname, buf, CH_UTF8_MAC);
+
+      if (ext_len) {
+       buf[ext_len] = '\0';
+       if (strcmp(ext, buf)) return mfilename;
+      } else {
+       if (*ext) return mfilename;
+      }
+    }
+
+    /* First we convert the unix name to our volume maccharset         */
+    /* This assumes, OSX will not send us a mangled name for *any*     */
+    /* other reason than a hint/filename mismatch on the OSX side!! */
+    /* If the filename needed mangling, we'll get the mac filename     */
+    /* till the first unconvertable char, so these have to     match   */
+    /* the mangled name we got ..                                      */
+
+    flags = CONV_IGNORE | CONV_UNESCAPEHEX;
+    if ( (size_t) -1 == (len = convert_charset(vol->v_volcharset, vol->v_maccharset, 0, 
+                                     uname, strlen(uname), buffer, MAXPATHLEN, &flags)) ) {
+       return mfilename;
+    }
+    /* If the filename is too long we also needed to mangle */
+    mfilenamelen = strlen(mfilename);
+    if ( len >= vol->max_filename || mfilenamelen == MACFILELEN ) {
+        flags |= CONV_REQMANGLE;
+        len = prefix;
+    }
+    
+    /* Ok, mangling was needed, now we do some further checks    */
+    /* this is still necessary, as we might have a file abcde:xx */
+    /* with id 12, mangled to abcde#12, and a passed filename    */
+    /* abcd#12                                                      */ 
+    /* if we only checked if "prefix" number of characters match */
+    /* we get a false postive in above case                         */
 
-       /* 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;
+    if ( (flags & CONV_REQMANGLE) ) {
+        if (len) { 
+            /* convert the buffer to UTF8_MAC ... */
+            if ((size_t) -1 == (len = convert_charset(vol->v_maccharset, CH_UTF8_MAC, 0, 
+                               buffer, len, buffer, MAXPATHLEN, &flags)) ) {
+                return mfilename;
+            }
+            /* Now compare the two names, they have to match the number of characters in buffer */
+            /* prefix can be longer than len, OSX might send us the first character(s) of a     */
+            /* decomposed char as the *last* character(s) before the #, so our match below will */
+            /* still work, but leaves room for a race ... FIXME                                    */
+            if ( (prefix >= len || mfilenamelen == MACFILELEN) 
+                 && !strncmp (mfilename, buffer, len)) {
+                 return uname;
+            }
+        }
+        else {
+            /* We couldn't convert the name to maccharset at all, so we'd expect a name */
+            /* in the "???#ID" form ... */
+            if ( !strncmp("???", mfilename, prefix)) {
+                return uname;
+            }
+            /* ..but OSX might send us only the first characters of a decomposed character. */
+            /*  So convert to UTF8_MAC again, now at least the prefix number of          */
+            /* characters have to match ... again a possible race FIXME                          */
+            
+            if ( (size_t) -1 == (len = convert_charset(vol->v_volcharset, CH_UTF8_MAC, 0, 
+                                 uname, strlen(uname), buffer, MAXPATHLEN, &flags)) ) {
+               return mfilename;
+           }
+
+            if ( !strncmp (mfilename, buffer, prefix) ) {
+                return uname;
+            }
+        }
+    }
+    return mfilename;
+}
+
+/* -------------------------------------------------------
+*/
+static char *
+private_demangle(const struct vol *vol, char *mfilename, cnid_t did, cnid_t *osx) 
+{
+    char *t;
+    char *u_name;
+    u_int32_t id, file_id;
+    static char buffer[12 + MAXPATHLEN + 1];
+    int len = 12 + MAXPATHLEN + 1;
+    struct dir *dir;
+    size_t prefix;
+
+    id = file_id = 0;
+
+    t = strchr(mfilename, MANGLE_CHAR);
+    if (t == NULL) {
+        return mfilename;
+    }
+    prefix = t - mfilename;
+    /* FIXME 
+     * is prefix == 0 a valid mangled filename ?
+    */
+    /* may be a mangled filename */
+    t++;
+    if (*t == '0') { /* can't start with a 0 */
+        return mfilename;
+    }
+    while(isuxdigit(*t)) {
+        id = (id *16) + hextoint(*t);
+        t++;
+    }
+    if ((*t != 0 && *t != '.') || strlen(t) > MAX_EXT_LENGTH || id < 17) {
+        return mfilename;
+    }
+
+    file_id = id = htonl(id);
+    if (osx) {
+        *osx = id;
+    }
+
+    /* is it a dir?, there's a conflict with pre OSX 'trash #2'  */
+    if ((dir = dirsearch(vol, id))) {
+        if (dir->d_parent && dir->d_parent->d_did != did) {
+            /* not in the same folder, there's a race with outdate cache
+             * but we have to live with it, hopefully client will recover
+            */
+            return mfilename;
+        }
+        if (!osx) {
+            /* it's not from cname so mfilename and dir must be the same */
+            if (!strcmp(dir->d_m_name, mfilename)) {
+                return dir->d_u_name;
+            }
+        } 
+        else {
+           return demangle_checks (vol, dir->d_u_name, mfilename, prefix, t);
        }
-       return filename;
+    }
+    else if (NULL != (u_name = cnid_resolve(vol->v_cdb, &id, buffer, len)) ) {
+        if (id != did) {
+            return mfilename;
+        }
+        if (!osx) {
+            /* convert back to mac name and check it's the same */
+            t = utompath(vol, u_name, file_id, utf8_encoding());
+            if (!strcmp(t, mfilename)) {
+                return u_name;
+            }
+        }
+        else {
+            return demangle_checks (vol, u_name, mfilename, prefix, t);
+        }
+    }
+
+    return mfilename;
+}
+
+/* -------------------------------------------------------
+*/
+char *
+demangle(const struct vol *vol, char *mfilename, cnid_t did)
+{
+    return private_demangle(vol, mfilename, did, NULL);
 }
 
+/* -------------------------------------------------------
+ * OS X  
+*/
+char *
+demangle_osx(const struct vol *vol, char *mfilename, cnid_t did, cnid_t *fileid) 
+{
+    return private_demangle(vol, mfilename, did, fileid);
+}
+
+
 /* -----------------------
    with utf8 filename not always round trip
-   filename   mac filename too long or with unmatchable utf8 replaced with _
+   filename   mac filename too long or first chars if unmatchable chars.
    uname      unix filename 
+   id         file/folder ID or 0
+   
 */
 char *
-mangle(const struct vol *vol, char *filename, char *uname, int flags) {
-    char *ext = NULL;
-    char *tf = NULL;
+mangle(const struct vol *vol, char *filename, size_t filenamelen, char *uname, cnid_t id, int flags) {
     char *m = NULL;
-    static char mfilename[MAX_LENGTH + 1];
+    static char mfilename[MAXPATHLEN + 1];
     char mangle_suffix[MANGLE_LENGTH + 1];
-    size_t ext_len = 0;
-    int mangle_suffix_int = 0;
-
+    char ext[MAX_EXT_LENGTH];
+    size_t ext_len;
+    size_t maxlen;
+    int k;
+    
+    maxlen = (flags & 2)?255:MACFILELEN; /* was vol->max_filename */
     /* Do we really need to mangle this filename? */
-    if (!flags && strlen(filename) <= vol->max_filename) {
+    if (!(flags & 1) && filenamelen <= maxlen) {
        return filename;
     }
-    /* First, attempt to locate a file extension. */
-    if (NULL != (ext = strrchr(filename, '.')) ) {
-       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, MAX_LENGTH - strlen(MANGLE_CHAR) - MANGLE_LENGTH - ext_len);
-       m[MAX_LENGTH - strlen(MANGLE_CHAR) - MANGLE_LENGTH - ext_len] = '\0';
-
-       strcat(m, MANGLE_CHAR);
-       (void)sprintf(mangle_suffix, "%03d", mangle_suffix_int);
-       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 (!id) {
+        /* we don't have the file id! only catsearch call mangle with id == 0 */
+        return NULL;
     }
+    /* First, attempt to locate a file extension. */
+    ext_len = mangle_extension(vol, uname, ext, (flags & 2) ? CH_UTF8_MAC : vol->v_maccharset);
+    m = mfilename;
+    k = sprintf(mangle_suffix, "%c%X", MANGLE_CHAR, ntohl(id));
 
-    if (cnid_mangle_add(vol->v_db, m, uname) < 0) {
-       return filename;
+    if (filenamelen + k + ext_len > maxlen) {
+      u_int16_t opt = CONV_FORCE | CONV_UNESCAPEHEX;
+      size_t n = convert_charset(vol->v_volcharset,
+                                (flags & 2) ? CH_UTF8_MAC : vol->v_maccharset,
+                                vol->v_maccharset, uname, strlen(uname),
+                                m, maxlen - k - ext_len, &opt);
+      m[n != (size_t)-1 ? n : 0] = 0;
+    } else {
+      strlcpy(m, filename, filenamelen + 1);
+    }
+    if (*m == 0) {
+        strcat(m, "???");
+    }
+    strcat(m, mangle_suffix);
+    if (ext_len) {
+       strncat(m, ext, ext_len);
     }
 
     return m;
 }
-#endif /* FILE_MANGLING */
index 85ce372a3073834fa10fff781ddcbb04bb4f3ff7..8d944d133eeb6f948e0051ca2f23bf543ec231cf 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: mangle.h,v 1.5 2003-06-02 06:54:23 didg Exp $
+ * $Id: mangle.h,v 1.6 2005-04-28 20:49:44 bfernhomberg Exp $
  *
  */
 
@@ -9,25 +9,23 @@
 #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 *demangle __P((const struct vol *, char *));
+extern char *mangle __P((const struct vol *, char *, size_t, char *, cnid_t, int));
+extern char *demangle __P((const struct vol *, char *, cnid_t did));
+extern char *demangle_osx __P((const struct vol *, char *, cnid_t did, cnid_t *fileid));
 
 #endif /* AFPD_MANGLE_H */
index 0918e421c573a386f17aac768b93a00289d04a96..00c6c327257586df0fbf798f35d4d1c626dde829 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: messages.c,v 1.17 2003-06-02 06:54:23 didg Exp $
+ * $Id: messages.c,v 1.18 2005-04-28 20:49:44 bfernhomberg Exp $
  *
  * Copyright (c) 1997 Adrian Sun (asun@zoology.washington.edu)
  * All Rights Reserved.  See COPYRIGHT.
@@ -9,37 +9,46 @@
 #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 <string.h>
 #include <errno.h>
+#include <stdlib.h>
 #include <atalk/afp.h>
+#include <atalk/dsi.h>
+#include <atalk/util.h>
 #include <atalk/logger.h>
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif /* HAVE_UNISTD_H */
 #include "globals.h"
 #include "misc.h"
 
+
 #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);
+    strlcpy(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] */
@@ -64,7 +73,7 @@ void readmessage(void)
     /* if either message.pid or message exists */
     if (message!=NULL) {
         /* added while loop to get characters and put in servermesg */
-        while ((( c=fgetc(message)) != EOF) && (i < (MAXMESGSIZE - 1))) {
+        while ((( c=fgetc(message)) != EOF) && (i < (maxmsgsize - 1))) {
             if ( c == '\n')  c = ' ';
             servermesg[i++] = c;
         }
@@ -81,7 +90,8 @@ void readmessage(void)
                                strerror(errno));
         }
 
-        rc = unlink(filename);
+        if ( 0 < (rc = unlink(filename)) )
+           LOG(log_error, logtype_afpd, "File '%s' could not be deleted", strerror(errno));
 
         /* Drop privs again, failing this is very bad */
         if (seteuid(euid) < 0) {
@@ -106,10 +116,18 @@ void readmessage(void)
 int afp_getsrvrmesg(obj, ibuf, ibuflen, rbuf, rbuflen)
 AFPObj *obj;
 char *ibuf, *rbuf;
-int ibuflen, *rbuflen;
+int ibuflen _U_, *rbuflen;
 {
     char *message;
     u_int16_t type, bitmap;
+    u_int16_t msgsize;
+    size_t outlen = 0;
+    size_t msglen = 0;
+    int utf8 = 0;
+
+    *rbuflen = 0;
+
+    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));
@@ -122,27 +140,51 @@ int ibuflen, *rbuflen;
         message = servermesg;
         break;
     default:
-        *rbuflen = 0;
         return AFPERR_BITMAP;
     }
 
     /* output format:
      * message type:   2 bytes
      * bitmap:         2 bytes
-     * message length: 1 byte
-     * message:        up to 199 bytes
+     * message length: 1 byte ( 2 bytes for utf8)
+     * message:        up to 199 bytes (dsi attn_quantum for utf8)
      */
     memcpy(rbuf, &type, sizeof(type));
     rbuf += sizeof(type);
+    *rbuflen += sizeof(type);
     memcpy(rbuf, &bitmap, sizeof(bitmap));
     rbuf += sizeof(bitmap);
-    *rbuflen = strlen(message);
-    if (*rbuflen > MAXMESGSIZE)
-        *rbuflen = MAXMESGSIZE;
-    *rbuf++ = *rbuflen;
-    memcpy(rbuf, message, *rbuflen);
-
-    *rbuflen += 5;
+    *rbuflen += sizeof(bitmap);
+
+    utf8 = ntohs(bitmap) & 2; 
+    msglen = strlen(message);
+    if (msglen > msgsize)
+        msglen = msgsize;
+
+    if (msglen) { 
+        if ( (size_t)-1 == (outlen = convert_string(obj->options.unixcharset, utf8?CH_UTF8_MAC:obj->options.maccharset,
+                                                    message, msglen, localized_message, msgsize)) )
+        {
+           memcpy(rbuf+((utf8)?2:1), message, msglen); /*FIXME*/
+           outlen = msglen;
+        }
+        else
+        {
+           memcpy(rbuf+((utf8)?2:1), localized_message, outlen);
+        }
+    }
+    
+    if ( utf8 ) {
+       /* UTF8 message, 2 byte length */
+       msgsize = htons(outlen);
+       memcpy(rbuf, &msgsize, sizeof(msgsize));
+       *rbuflen += sizeof(msgsize);
+    }
+    else {
+        *rbuf = outlen;
+       *rbuflen += 1;
+    }
+    *rbuflen += outlen;
 
     return AFP_OK;
 }
index 749ddf5c1952a466a4675d2d9b1c3edf2542644a..d7c1125959fa006409da99073a6d4a6f221f608a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: nfsquota.c,v 1.11 2003-12-28 13:51:12 srittau Exp $
+ * $Id: nfsquota.c,v 1.12 2005-04-28 20:49:44 bfernhomberg Exp $
  *
  * parts of this are lifted from the bsd quota program and are
  * therefore under the following copyright:
@@ -18,8 +18,8 @@
 #include "config.h"
 #endif /* HAVE_CONFIG_H */
 
+#ifndef NO_QUOTA_SUPPORT
 #include <stdio.h>
-
 /* STDC check */
 #if STDC_HEADERS
 #include <string.h>
@@ -34,26 +34,27 @@ char *strchr (), *strrchr ();
 #define memmove(d,s,n) bcopy ((s), (d), (n))
 #endif /* ! HAVE_MEMCPY */
 #endif /* STDC_HEADERS */
-
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <sys/param.h> /* for DEV_BSIZE */
-#include <sys/time.h>
-#include <atalk/logger.h>
-
+#include <sys/time.h>  /* <rpc/rpc.h> on ultrix doesn't include this */
 #ifdef HAVE_NETDB_H
 #include <netdb.h>
 #endif /* HAVE_NETDB_H */
 #include <netinet/in.h>
+#ifndef PORTMAP
+#define PORTMAP 1
+#endif
 #include <rpc/rpc.h>
 #include <rpc/pmap_prot.h>
 #include <rpcsvc/rquota.h>
 
+
 #include <atalk/afp.h>
+#include <atalk/logger.h>
 
 #include "unix.h"
 
-#ifndef NO_QUOTA_SUPPORT
 /* lifted (with modifications) from the bsd quota program */
 static int
 callaurpc(vol, prognum, versnum, procnum, inproc, in, outproc, out)
@@ -104,7 +105,7 @@ char *in, *out;
 #define GQR_RQUOTA getquota_rslt_u.gqr_rquota
 #endif /* USE_OLD_RQUOTA */
 
-int getnfsquota(const struct vol *vol, const int uid, const u_int32_t bsize,
+int getnfsquota(struct vol *vol, const int uid, const u_int32_t bsize,
                 struct dqblk *dqp)
 {
 
@@ -142,7 +143,7 @@ int getnfsquota(const struct vol *vol, const int uid, const u_int32_t bsize,
         break;
 
     case Q_EPERM:
-        LOG(log_error, logtype_afpd, "nfsquota: quota permission error, host: %s\n",
+        LOG(log_error, logtype_afpd, "nfsquota: quota permission error, host: %s",
             vol->v_gvs);
         break;
 
@@ -163,22 +164,22 @@ int getnfsquota(const struct vol *vol, const int uid, const u_int32_t bsize,
             gq_rslt.GQR_RQUOTA.rq_bhardlimit*NFS_BSIZE;
         dqp->dqb_bsoftlimit =
             gq_rslt.GQR_RQUOTA.rq_bsoftlimit*NFS_BSIZE;
-#ifdef HAVE_STRUCT_IF_DQBLK
-       dqp->dqb_curspace =
-#else
         dqp->dqb_curblocks =
-#endif
             gq_rslt.GQR_RQUOTA.rq_curblocks*NFS_BSIZE;
 
+#ifdef ultrix
+        dqp->dqb_bwarn = gq_rslt.GQR_RQUOTA.rq_btimeleft;
+#else /* ultrix */
         dqp->dqb_btimelimit =
             tv.tv_sec + gq_rslt.GQR_RQUOTA.rq_btimeleft;
+#endif /* ultrix */
 
         *hostpath = ':';
         return AFP_OK;
         break;
 
     default:
-        LOG(log_info, logtype_afpd, "bad rpc result, host: %s\n", vol->v_gvs);
+        LOG(log_info, logtype_afpd, "bad rpc result, host: %s", vol->v_gvs);
         break;
     }
 
diff --git a/etc/afpd/nls/.cvsignore b/etc/afpd/nls/.cvsignore
deleted file mode 100644 (file)
index df423a7..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-Makefile
-Makefile.in
-makecode
-parsecode
-.deps
-.libs
-maccode.*
diff --git a/etc/afpd/nls/Makefile.am b/etc/afpd/nls/Makefile.am
deleted file mode 100644 (file)
index fd931ba..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-# Makefile.am for etc/afpd/nls/
-
-pkgconfdir = @PKGCONFDIR@
-nlsdir = @NLSDIR@
-
-bin_PROGRAMS = makecode parsecode
-
-makecode_SOURCES = makecode.c
-parsecode_SOURCES = parsecode.c
-
-MACCODES =                             \
-       maccode.identity                \
-       maccode.437                     \
-       maccode.850                     \
-       maccode.iso8859-1               \
-       maccode.iso8859-1.adapted       \
-       maccode.koi8-r
-
-INCLUDES = -I$(top_srcdir)/sys -I$(top_srcdir)/etc/afpd
-
-$(MACCODES): makecode
-       ./makecode $@
-
-nls_DATA = $(MACCODES)
-
-CLEANFILES = $(MACCODES)
diff --git a/etc/afpd/nls/makecode.c b/etc/afpd/nls/makecode.c
deleted file mode 100644 (file)
index 9968dbe..0000000
+++ /dev/null
@@ -1,229 +0,0 @@
-/*
- * $Id: makecode.c,v 1.8 2003-06-06 20:18:39 srittau Exp $
- *
- * quick-and-dirty way of creating code pages
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif /* HAVE_CONFIG_H */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-
-#include <netatalk/endian.h>
-#include "codepage.h"
-
-/* passthrough map */
-static const unsigned char identity_map[] = {
-    0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
-    0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,
-    0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
-    0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F,
-    0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7,
-    0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF,
-    0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7,
-    0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF,
-    0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
-    0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
-    0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7,
-    0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
-    0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7,
-    0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
-    0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
-    0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF,
-};
-
-/* map of cp10000 (mac roman) to iso-latin-1 */
-static const unsigned char mac_to_isolatin1_map[] = {
-    0xC4, 0xC5, 0xC7, 0xC9, 0xD1, 0xD6, 0xDC, 0xE1,
-    0xE0, 0xE2, 0xE4, 0xE3, 0xE5, 0xE7, 0xE9, 0xE8,
-    0xEA, 0xEB, 0xED, 0xEC, 0xEE, 0xEF, 0xF1, 0xF3,
-    0xF2, 0xF4, 0xF6, 0xF5, 0xFA, 0xF9, 0xFB, 0xFC,
-    0x00, 0xB0, 0xA2, 0xA3, 0xA7, 0xB7, 0xB6, 0xDF,
-    0xAE, 0xA9, 0x00, 0xB4, 0xA8, 0x00, 0xC6, 0xD8,
-    0x00, 0xB1, 0x00, 0x00, 0xA5, 0xB5, 0xF0, 0x00,
-    0x00, 0x00, 0x00, 0xAA, 0xBA, 0x00, 0xE6, 0xF8,
-    0xBF, 0xA1, 0xAC, 0x00, 0x00, 0x00, 0x00, 0xAB,
-    0xBB, 0x00, 0xA0, 0xC0, 0xC3, 0xD5, 0x00, 0x00,
-    0xAD, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF7, 0x00,
-    0xFF, 0x00, 0x00, 0xA4, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0xB8, 0x00, 0x00, 0xC2, 0xCA, 0xC1,
-    0xCB, 0xC8, 0xCD, 0xCE, 0xCF, 0xCC, 0xD3, 0xD4,
-    0x00, 0xD2, 0xDA, 0xDB, 0xD9
-    /*, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-      0x00, 0x00, 0x00, 0x00, 0x00 */
-};
-
-/* map of cp10000 (mac roman) to iso-latin-1 adapted */
-static const unsigned char mac_to_isolatin1_adapted_map[] = {
-    0xC4, 0xC5, 0xC7, 0xC9, 0xD1, 0xD6, 0xDC, 0xE1,
-    0xE0, 0xE2, 0xE4, 0xE3, 0xE5, 0xE7, 0xE9, 0xE8,
-    0xEA, 0xEB, 0xED, 0xEC, 0xEE, 0xEF, 0xF1, 0xF3,
-    0xF2, 0xF4, 0xF6, 0xF5, 0xFA, 0xF9, 0xFB, 0xFC,
-    0x00, 0xB0, 0xA2, 0xA3, 0xA7, 0xB7, 0xB6, 0xDF,
-    0xAE, 0xA9, 0xFE, 0xB4, 0xA8, 0x00, 0xC6, 0xD8,
-    0x00, 0xB1, 0x00, 0x00, 0xA5, 0xB5, 0xF0, 0x00,
-    0x00, 0x00, 0x00, 0xAA, 0xBA, 0x00, 0xE6, 0xF8,
-    0xBF, 0xA1, 0xAC, 0x00, 0xFD, 0x00, 0x00, 0xAB,
-    0xBB, 0x00, 0xA0, 0xC0, 0xC3, 0xD5, 0x00, 0x00,
-    0xAD, 0xAF, 0xB2, 0xB3, 0xDD, 0xDE, 0xF7, 0xB0,
-    0xFF, 0x00, 0x00, 0xA4, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0xB8, 0x00, 0x00, 0xC2, 0xCA, 0xC1,
-    0xCB, 0xC8, 0xCD, 0xCE, 0xCF, 0xCC, 0xD3, 0xD4,
-    0x00, 0xD2, 0xDA, 0xDB, 0xD9
-    /*, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-      0x00, 0x00, 0x00, 0x00, 0x00 */
-};
-
-/* Map of CP10000 (Mac Roman) to MSDOS CP 437 */
-static const unsigned char mac_to_cp437_map[] = {
-    0x8e, 0x8f, 0x80, 0x90, 0xa5, 0x99, 0x9a, 0xa0,
-    0x85, 0x83, 0x84, 0xe0, 0x86, 0x87, 0x82, 0x8a,
-    0x88, 0x89, 0xa1, 0x8d, 0x8c, 0x8b, 0xa4, 0xa2,
-    0x95, 0x93, 0x94, 0xe5, 0xa3, 0x97, 0x96, 0x81,
-    0xc5, 0xf8, 0x9b, 0x9c, 0xb6, 0xf9, 0xb8, 0xe1,
-    0xc9, 0xe9, 0xcb, 0xd9, 0xc0, 0xd8, 0x92, 0xe8,
-    0xec, 0xf1, 0xf3, 0xf2, 0x9d, 0xe6, 0xeb, 0xe4,
-    0xef, 0xe3, 0xf4, 0xa6, 0xa7, 0xea, 0x91, 0xed,
-    0xa8, 0xad, 0xaa, 0xfb, 0x9f, 0xf7, 0xdd, 0xae,
-    0xaf, 0xb0, 0xff, 0xd6, 0xd2, 0xb1, 0xb2, 0xb7,
-    0xb4, 0xc4, 0xb5, 0xb9, 0xba, 0xbb, 0xf6, 0xbc,
-    0x98, 0xbd, 0xf5, 0xfe, 0xbe, 0xbf, 0xc1, 0xc2,
-    0xce, 0xfa, 0xc3, 0xc6, 0xc7, 0xc8, 0xee, 0xca,
-    0xcc, 0xcd, 0xb3, 0xd7, 0xcf, 0xd0, 0xd1, 0xd3,
-    0xdb, 0xda, 0xa9, 0xab, 0xac, 0xd4, 0xd5, 0xdc,
-    0xde, 0xdf, 0xfc, 0xfd, 0xe7, 0xe2, 0xf0, 0x9e
-};
-
-/* Map of CP10000 (Mac Roman) to MSDOS CP 850 */
-static const unsigned char mac_to_cp850_map[] = {
-    0x8e, 0x8f, 0x80, 0x90, 0xa5, 0x99, 0x9a, 0xa0,
-    0x85, 0x83, 0x84, 0xc6, 0x86, 0x87, 0x82, 0x8a,
-    0x88, 0x89, 0xa1, 0x8d, 0x8c, 0x8b, 0xa4, 0xa2,
-    0x95, 0x93, 0x94, 0xe4, 0xa3, 0x97, 0x96, 0x81,
-    0xc5, 0xf8, 0xbd, 0x9c, 0xf5, 0xb0, 0xf4, 0xe1,
-    0xa9, 0xb8, 0xb1, 0xef, 0xf9, 0xca, 0x92, 0x9d,
-    0xb2, 0xf1, 0xb3, 0xb4, 0xbe, 0xe6, 0xd0, 0xba,
-    0xbb, 0xcb, 0xdd, 0xa6, 0xa7, 0xbc, 0x91, 0x9b,
-    0xa8, 0xad, 0xaa, 0xd9, 0x9f, 0xf2, 0xfe, 0xae,
-    0xaf, 0xdc, 0xff, 0xb7, 0xc7, 0xe5, 0xc0, 0xc1,
-    0xc2, 0xc4, 0xc3, 0x9e, 0xab, 0xac, 0xf6, 0xbf,
-    0x98, 0xed, 0xc8, 0xcf, 0xc9, 0xcc, 0xcd, 0xce,
-    0xd1, 0xfa, 0xd5, 0xda, 0xdb, 0xb6, 0xd2, 0xb5,
-    0xd3, 0xd4, 0xd6, 0xd7, 0xd8, 0xde, 0xe0, 0xe2,
-    0xf0, 0xe3, 0xe9, 0xea, 0xeb, 0xfb, 0xdf, 0xe7,
-    0xee, 0xe8, 0xec, 0xf3, 0xf7, 0xfc, 0xfd, 0xb9
-};
-
-
-
-/* Map of CP10000 (Mac Roman) to koi8-r */
-static const unsigned char mac_to_koi8_r_map[] = {
-    225, 226, 247, 231, 228, 229, 246, 250,
-    233, 234, 235, 236, 237, 238, 239, 240,
-    242, 243, 244, 245, 230, 232, 227, 254,
-    251, 253, 255, 249, 248, 252, 224, 241,
-    160, 161, 162, 163, 164, 165, 166, 167,
-    168, 191, 170, 171, 172, 173, 174, 175,
-    176, 177, 178, 179, 180, 181, 182, 183,
-    184, 185, 186, 187, 188, 189, 190, 191,
-    192, 193, 194, 195, 196, 197, 198, 199,
-    200, 201, 202, 203, 204, 205, 206, 207,
-    208, 209, 210, 211, 212, 213, 214, 215,
-    216, 217, 218, 219, 220, 179, 163, 209,
-    193, 194, 215, 199, 196, 197, 214, 218,
-    201, 202, 203, 204, 205, 206, 207, 208,
-    210, 211, 212, 213, 198, 200, 195, 222,
-    219, 221, 223, 217, 216, 220, 192, 255
-};
-
-struct mac_code {
-    char *m_name;
-    const unsigned char *m_map;
-    u_int16_t m_len;
-    const char *m_id;
-};
-
-static struct mac_code names[] = {
-    {"maccode.identity", identity_map, sizeof(identity_map), "identity"},
-    {"maccode.437", mac_to_cp437_map, sizeof(mac_to_cp437_map), "cp437"},
-    {"maccode.850", mac_to_cp850_map, sizeof(mac_to_cp850_map), "cp850"},
-    {"maccode.iso8859-1", mac_to_isolatin1_map, sizeof(mac_to_isolatin1_map), "iso8859-1"},
-    {"maccode.iso8859-1.adapted", mac_to_isolatin1_adapted_map, sizeof(mac_to_isolatin1_adapted_map), "iso8859-1-adapted"},
-    {"maccode.koi8-r",mac_to_koi8_r_map,sizeof(mac_to_koi8_r_map),"koi8-r"},
-    {NULL, NULL, 0, NULL}
-};
-
-int main(int argc, char **argv)
-{
-    unsigned char buf[CODEPAGE_FILE_HEADER_SIZE];
-    u_int16_t id;
-    int i, j;
-    FILE *fp;
-
-    if (argc != 2) {
-        fprintf(stderr, "Usage: %s MACCODE\n", argv[0]);
-        return 1;
-    }
-
-    for (i = 0; names[i].m_name; i++) {
-        if (!strcmp(names[i].m_name, argv[1]))
-            break;
-    }
-
-    if (!names[i].m_name) {
-        fprintf(stderr, "unknown codepage\n");
-        return 1;
-    }
-
-
-    if ((fp = fopen(names[i].m_name, "w")) == NULL) {
-        fprintf(stderr, "can't open %s: %s\n",
-                names[i].m_name, strerror(errno));
-        return 1;
-    }
-
-    memset(buf, 0, CODEPAGE_FILE_HEADER_SIZE);
-
-    id = htons(CODEPAGE_FILE_ID); /* file id */
-    memcpy(buf, &id, sizeof(id));
-    *(buf + 2) = CODEPAGE_FILE_VERSION; /* version */
-    if ((j = strlen(names[i].m_id)) & 1) /* pad to even boundary */
-        j++;
-    *(buf + 3) = j; /* length of name */
-
-    *(buf + 4) = 1; /* default quantum. this should be modified to
-                     * deal with multibyte characters */
-
-    /* rules */
-    *(buf + 5) = CODEPAGE_RULE_MTOU | CODEPAGE_RULE_UTOM;
-
-    /* offset to data */
-    id = htons(CODEPAGE_FILE_HEADER_SIZE + j);
-    memcpy(buf + 6, &id, sizeof(id));
-
-    /* size of data */
-    id = htons(names[i].m_len);
-    memcpy(buf + 8, &id, sizeof(id));
-
-    /* write it out */
-    fwrite(buf, CODEPAGE_FILE_HEADER_SIZE, 1, fp);
-
-    /* we either keep or drop the null byte to keep the name on an
-     * even boundary */
-    fwrite(names[i].m_id, j, 1, fp);
-
-    /* we typically only map characters > 0x7F */
-    for (j = 0; j < names[i].m_len; j++) {
-        buf[0] = CODEPAGE_RULE_MTOU | CODEPAGE_RULE_UTOM;
-        buf[1] = j + 0x80;
-        buf[2] = names[i].m_map[j];
-        fwrite(buf, 3, 1, fp);
-    }
-    fclose(fp);
-
-    return 0;
-}
diff --git a/etc/afpd/nls/parsecode.c b/etc/afpd/nls/parsecode.c
deleted file mode 100644 (file)
index dcb1bf5..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <netatalk/endian.h>
-#include "codepage.h"
-
-int main(int argc, char **argv)
-{
-    unsigned char name[255 + 1], buf[CODEPAGE_FILE_HEADER_SIZE];
-    unsigned char quantum, rules;
-    u_int16_t id;
-    FILE *fp;
-
-    if (argc != 2) {
-        fprintf(stderr, "%s <codepage>\n", *argv);
-        return -1;
-    }
-
-    if ((fp = fopen(argv[1], "r")) == NULL) {
-        fprintf(stderr, "%s: can't open file.\n", *argv);
-        return -1;
-    }
-
-    if (fread(buf, CODEPAGE_FILE_HEADER_SIZE, 1, fp) != 1) {
-        fprintf(stderr, "%s: can't get header.\n", *argv);
-        goto fail_end;
-    }
-
-    /* id */
-    memcpy(&id, buf, sizeof(id));
-    id = ntohs(id);
-    if (id != CODEPAGE_FILE_ID) {
-        fprintf(stderr, "%s: wrong file type.\n", *argv);
-        goto fail_end;
-    }
-
-    /* version */
-    if (*(buf + 2) != CODEPAGE_FILE_VERSION) {
-        fprintf(stderr, "%s: wrong file version.\n", *argv);
-        goto fail_end;
-    }
-
-    /* size of name */
-    id = *(buf + 3);
-
-    /* quantum and rules */
-    quantum = *(buf + 4);
-    rules = *(buf + 5);
-
-    fread(name, id, 1, fp);
-    if (name[id - 1] != '\0') /* name isn't null-padded */
-        name[id] = '\0';
-    printf("codepage: %s [", name);
-
-    /* move to the data */
-    memcpy(&id, buf + 6, sizeof(id));
-    id = ntohs(id);
-    fseek(fp, id, SEEK_SET);
-
-    /* size of data */
-    memcpy(&id, buf + 8, sizeof(id));
-    id = ntohs(id);
-    printf("size=%d]\n", id);
-    printf("---------\n");
-
-    while (fread(buf, 1 + 2*quantum, 1, fp) == 1) {
-        printf("0x%02x: 0x%02X 0x%02X\n", buf[0], buf[1], buf[1 + quantum]);
-    }
-    fclose(fp);
-    return 0;
-
-fail_end:
-    fclose(fp);
-    return -1;
-}
index abfa5ec03c3c321de33407024719a886326c946f..cb5d1dfe1a19dea9da516775563985e82b4db075 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: ofork.c,v 1.20 2002-10-11 14:18:34 didg Exp $
+ * $Id: ofork.c,v 1.21 2005-04-28 20:49:44 bfernhomberg Exp $
  *
  * Copyright (c) 1996 Regents of The University of Michigan.
  * All Rights Reserved.  See COPYRIGHT.
 
 #include <stdio.h>
 #include <stdlib.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
 #include <string.h>
 #include <sys/stat.h> /* works around a bug */
 #include <sys/param.h>
 #include <atalk/logger.h>
 #include <errno.h>
 
-#include <atalk/adouble.h>
+#include <atalk/util.h>
 
 #include "globals.h"
 #include "volume.h"
@@ -66,6 +69,7 @@ static __inline__ void of_unhash(struct ofork *of)
     }
 }
 
+#ifdef DEBUG1
 void of_pforkdesc( f )
 FILE   *f;
 {
@@ -80,6 +84,7 @@ FILE  *f;
         }
     }
 }
+#endif
 
 int of_flush(const struct vol *vol)
 {
@@ -101,7 +106,7 @@ int of_rename(vol, s_of, olddir, oldpath, newdir, newpath)
 const struct vol *vol;
 struct ofork *s_of;
 struct dir *olddir, *newdir;
-const char *oldpath, *newpath;
+const char *oldpath _U_, *newpath;
 {
     struct ofork *of, *next, *d_ofork;
 
@@ -115,7 +120,7 @@ const char *oldpath, *newpath;
         if (vol == of->of_vol && olddir == of->of_dir &&
                 s_of->key.dev == of->key.dev && 
                 s_of->key.inode == of->key.inode ) {
-            strncpy( of->of_name, newpath, of->of_namelen);
+            strlcpy( of->of_name, newpath, of->of_namelen);
             if (newdir != olddir) {
                 of->of_d_prev->of_d_next = of->of_d_next;
                 of->of_d_next->of_d_prev = of->of_d_prev;
@@ -215,7 +220,7 @@ struct stat     *st;
 
         /* initialize to zero. This is important to ensure that
            ad_open really does reinitialize the structure. */
-        memset( ad, 0, sizeof( struct adouble ) );
+        ad_init(ad, vol->v_adouble, vol->v_ad_options);
     } else {
         /* Increase the refcount on this struct adouble. This is
            decremented again in oforc_dealloc. */
@@ -248,7 +253,7 @@ struct stat     *st;
         oforks[ of_refnum ] = NULL;
         return NULL;
     }
-    strncpy( of->of_name, path, of->of_namelen = 255 + 1);
+    strlcpy( of->of_name, path, of->of_namelen = 255 + 1);
     *ofrefnum = refnum;
     of->of_refnum = refnum;
     of->key.dev = st->st_dev;
@@ -281,6 +286,36 @@ int ret;
    return ret;
 }
 
+/* -------------------------- */
+int of_statdir  (const struct vol *vol, struct path *path)
+{
+static char pathname[ MAXPATHLEN + 1];
+int ret;
+
+    if (*path->m_name) {
+        /* not curdir */
+        return of_stat (path);
+    }
+    path->st_errno = 0;
+    path->st_valid = 1;
+    /* FIXME, what about: we don't have r-x perm anymore ? */
+    strcpy(pathname, "../");
+    strlcat(pathname, path->d_dir->d_u_name, MAXPATHLEN);
+
+    if (!(ret = stat(pathname, &path->st)))
+        return 0;
+        
+    path->st_errno = errno;
+    /* hmm, can't stat curdir anymore */
+    if (errno == EACCES && curdir->d_parent ) {
+       if (movecwd(vol, curdir->d_parent)) 
+           return -1;
+       path->st_errno = 0;
+       if ((ret = stat(path->d_dir->d_u_name, &path->st)) < 0) 
+           path->st_errno = errno;
+    }
+    return ret;
+}
 
 /* -------------------------- */
 struct ofork *
@@ -337,3 +372,76 @@ struct ofork       *of;
 
     free( of );
 }
+
+/* --------------------------- */
+int of_closefork(struct ofork *ofork)
+{
+    struct timeval      tv;
+    int                        adflags, doflush = 0;
+
+    adflags = 0;
+    if ((ofork->of_flags & AFPFORK_DATA) && (ad_dfileno( ofork->of_ad ) != -1)) {
+            adflags |= ADFLAGS_DF;
+    }
+    if ( (ofork->of_flags & AFPFORK_OPEN) && ad_hfileno( ofork->of_ad ) != -1 ) {
+        adflags |= ADFLAGS_HF;
+        /*
+         * Only set the rfork's length if we're closing the rfork.
+         */
+        if ((ofork->of_flags & AFPFORK_RSRC)) {
+            ad_refresh( ofork->of_ad );
+            if ((ofork->of_flags & AFPFORK_DIRTY) && !gettimeofday(&tv, NULL)) {
+                ad_setdate(ofork->of_ad, AD_DATE_MODIFY | AD_DATE_UNIX,tv.tv_sec);
+               doflush++;
+            }
+            if ( doflush ) {
+                 ad_flush( ofork->of_ad, adflags );
+            }
+        }
+    }
+
+    if ( ad_close( ofork->of_ad, adflags ) < 0 ) {
+        return -1;
+    }
+    of_dealloc( ofork );
+    return 0;
+}
+
+/* ----------------------
+
+*/
+struct adouble *of_ad(const struct vol *vol, struct path *path, struct adouble *ad)
+{
+    struct ofork        *of;
+    struct adouble      *adp;
+
+    if ((of = of_findname(path))) {
+        adp = of->of_ad;
+    } else {
+        ad_init(ad, vol->v_adouble, vol->v_ad_options);
+        adp = ad;
+    }
+    return adp;
+}
+
+/* ---------------------- 
+   close all forks for a volume
+*/
+void of_closevol(const struct vol *vol)
+{
+    int        refnum;
+
+    if (!oforks)
+        return;
+
+    for ( refnum = 0; refnum < nforks; refnum++ ) {
+        if (oforks[ refnum ] != NULL && oforks[refnum]->of_vol == vol) {
+            if (of_closefork( oforks[ refnum ]) < 0 ) {
+                LOG(log_error, logtype_afpd, "of_closevol: %s", strerror(errno) );
+            }
+        }
+    }
+    return;
+}
+
diff --git a/etc/afpd/precompose.c b/etc/afpd/precompose.c
deleted file mode 100644 (file)
index 9514726..0000000
+++ /dev/null
@@ -1,2043 +0,0 @@
-/*
- * Canonical Compositions
- *
- */
-/* $XFree86: xc/programs/xterm/precompose.c,v 1.2 2000/11/01 01:12:41 dawes Exp $ */
-
-static const struct {
-  unsigned int replacement;
-  unsigned int base;
-  unsigned int comb; 
-} precompositions[] = {
-{ 0x226E, 0x003C, 0x0338},
-{ 0x2260, 0x003D, 0x0338},
-{ 0x226F, 0x003E, 0x0338},
-{ 0x00C0, 0x0041, 0x0300},
-{ 0x00C1, 0x0041, 0x0301},
-{ 0x00C2, 0x0041, 0x0302},
-{ 0x00C3, 0x0041, 0x0303},
-{ 0x0100, 0x0041, 0x0304},
-{ 0x0102, 0x0041, 0x0306},
-{ 0x0226, 0x0041, 0x0307},
-{ 0x00C4, 0x0041, 0x0308},
-{ 0x1EA2, 0x0041, 0x0309},
-{ 0x00C5, 0x0041, 0x030A},
-{ 0x01CD, 0x0041, 0x030C},
-{ 0x0200, 0x0041, 0x030F},
-{ 0x0202, 0x0041, 0x0311},
-{ 0x1EA0, 0x0041, 0x0323},
-{ 0x1E00, 0x0041, 0x0325},
-{ 0x0104, 0x0041, 0x0328},
-{ 0x1E02, 0x0042, 0x0307},
-{ 0x1E04, 0x0042, 0x0323},
-{ 0x1E06, 0x0042, 0x0331},
-{ 0x0106, 0x0043, 0x0301},
-{ 0x0108, 0x0043, 0x0302},
-{ 0x010A, 0x0043, 0x0307},
-{ 0x010C, 0x0043, 0x030C},
-{ 0x00C7, 0x0043, 0x0327},
-{ 0x1E0A, 0x0044, 0x0307},
-{ 0x010E, 0x0044, 0x030C},
-{ 0x1E0C, 0x0044, 0x0323},
-{ 0x1E10, 0x0044, 0x0327},
-{ 0x1E12, 0x0044, 0x032D},
-{ 0x1E0E, 0x0044, 0x0331},
-{ 0x00C8, 0x0045, 0x0300},
-{ 0x00C9, 0x0045, 0x0301},
-{ 0x00CA, 0x0045, 0x0302},
-{ 0x1EBC, 0x0045, 0x0303},
-{ 0x0112, 0x0045, 0x0304},
-{ 0x0114, 0x0045, 0x0306},
-{ 0x0116, 0x0045, 0x0307},
-{ 0x00CB, 0x0045, 0x0308},
-{ 0x1EBA, 0x0045, 0x0309},
-{ 0x011A, 0x0045, 0x030C},
-{ 0x0204, 0x0045, 0x030F},
-{ 0x0206, 0x0045, 0x0311},
-{ 0x1EB8, 0x0045, 0x0323},
-{ 0x0228, 0x0045, 0x0327},
-{ 0x0118, 0x0045, 0x0328},
-{ 0x1E18, 0x0045, 0x032D},
-{ 0x1E1A, 0x0045, 0x0330},
-{ 0x1E1E, 0x0046, 0x0307},
-{ 0x01F4, 0x0047, 0x0301},
-{ 0x011C, 0x0047, 0x0302},
-{ 0x1E20, 0x0047, 0x0304},
-{ 0x011E, 0x0047, 0x0306},
-{ 0x0120, 0x0047, 0x0307},
-{ 0x01E6, 0x0047, 0x030C},
-{ 0x0122, 0x0047, 0x0327},
-{ 0x0124, 0x0048, 0x0302},
-{ 0x1E22, 0x0048, 0x0307},
-{ 0x1E26, 0x0048, 0x0308},
-{ 0x021E, 0x0048, 0x030C},
-{ 0x1E24, 0x0048, 0x0323},
-{ 0x1E28, 0x0048, 0x0327},
-{ 0x1E2A, 0x0048, 0x032E},
-{ 0x00CC, 0x0049, 0x0300},
-{ 0x00CD, 0x0049, 0x0301},
-{ 0x00CE, 0x0049, 0x0302},
-{ 0x0128, 0x0049, 0x0303},
-{ 0x012A, 0x0049, 0x0304},
-{ 0x012C, 0x0049, 0x0306},
-{ 0x0130, 0x0049, 0x0307},
-{ 0x00CF, 0x0049, 0x0308},
-{ 0x1EC8, 0x0049, 0x0309},
-{ 0x01CF, 0x0049, 0x030C},
-{ 0x0208, 0x0049, 0x030F},
-{ 0x020A, 0x0049, 0x0311},
-{ 0x1ECA, 0x0049, 0x0323},
-{ 0x012E, 0x0049, 0x0328},
-{ 0x1E2C, 0x0049, 0x0330},
-{ 0x0134, 0x004A, 0x0302},
-{ 0x1E30, 0x004B, 0x0301},
-{ 0x01E8, 0x004B, 0x030C},
-{ 0x1E32, 0x004B, 0x0323},
-{ 0x0136, 0x004B, 0x0327},
-{ 0x1E34, 0x004B, 0x0331},
-{ 0x0139, 0x004C, 0x0301},
-{ 0x013D, 0x004C, 0x030C},
-{ 0x1E36, 0x004C, 0x0323},
-{ 0x013B, 0x004C, 0x0327},
-{ 0x1E3C, 0x004C, 0x032D},
-{ 0x1E3A, 0x004C, 0x0331},
-{ 0x1E3E, 0x004D, 0x0301},
-{ 0x1E40, 0x004D, 0x0307},
-{ 0x1E42, 0x004D, 0x0323},
-{ 0x01F8, 0x004E, 0x0300},
-{ 0x0143, 0x004E, 0x0301},
-{ 0x00D1, 0x004E, 0x0303},
-{ 0x1E44, 0x004E, 0x0307},
-{ 0x0147, 0x004E, 0x030C},
-{ 0x1E46, 0x004E, 0x0323},
-{ 0x0145, 0x004E, 0x0327},
-{ 0x1E4A, 0x004E, 0x032D},
-{ 0x1E48, 0x004E, 0x0331},
-{ 0x00D2, 0x004F, 0x0300},
-{ 0x00D3, 0x004F, 0x0301},
-{ 0x00D4, 0x004F, 0x0302},
-{ 0x00D5, 0x004F, 0x0303},
-{ 0x014C, 0x004F, 0x0304},
-{ 0x014E, 0x004F, 0x0306},
-{ 0x022E, 0x004F, 0x0307},
-{ 0x00D6, 0x004F, 0x0308},
-{ 0x1ECE, 0x004F, 0x0309},
-{ 0x0150, 0x004F, 0x030B},
-{ 0x01D1, 0x004F, 0x030C},
-{ 0x020C, 0x004F, 0x030F},
-{ 0x020E, 0x004F, 0x0311},
-{ 0x01A0, 0x004F, 0x031B},
-{ 0x1ECC, 0x004F, 0x0323},
-{ 0x01EA, 0x004F, 0x0328},
-{ 0x1E54, 0x0050, 0x0301},
-{ 0x1E56, 0x0050, 0x0307},
-{ 0x0154, 0x0052, 0x0301},
-{ 0x1E58, 0x0052, 0x0307},
-{ 0x0158, 0x0052, 0x030C},
-{ 0x0210, 0x0052, 0x030F},
-{ 0x0212, 0x0052, 0x0311},
-{ 0x1E5A, 0x0052, 0x0323},
-{ 0x0156, 0x0052, 0x0327},
-{ 0x1E5E, 0x0052, 0x0331},
-{ 0x015A, 0x0053, 0x0301},
-{ 0x015C, 0x0053, 0x0302},
-{ 0x1E60, 0x0053, 0x0307},
-{ 0x0160, 0x0053, 0x030C},
-{ 0x1E62, 0x0053, 0x0323},
-{ 0x0218, 0x0053, 0x0326},
-{ 0x015E, 0x0053, 0x0327},
-{ 0x1E6A, 0x0054, 0x0307},
-{ 0x0164, 0x0054, 0x030C},
-{ 0x1E6C, 0x0054, 0x0323},
-{ 0x021A, 0x0054, 0x0326},
-{ 0x0162, 0x0054, 0x0327},
-{ 0x1E70, 0x0054, 0x032D},
-{ 0x1E6E, 0x0054, 0x0331},
-{ 0x00D9, 0x0055, 0x0300},
-{ 0x00DA, 0x0055, 0x0301},
-{ 0x00DB, 0x0055, 0x0302},
-{ 0x0168, 0x0055, 0x0303},
-{ 0x016A, 0x0055, 0x0304},
-{ 0x016C, 0x0055, 0x0306},
-{ 0x00DC, 0x0055, 0x0308},
-{ 0x1EE6, 0x0055, 0x0309},
-{ 0x016E, 0x0055, 0x030A},
-{ 0x0170, 0x0055, 0x030B},
-{ 0x01D3, 0x0055, 0x030C},
-{ 0x0214, 0x0055, 0x030F},
-{ 0x0216, 0x0055, 0x0311},
-{ 0x01AF, 0x0055, 0x031B},
-{ 0x1EE4, 0x0055, 0x0323},
-{ 0x1E72, 0x0055, 0x0324},
-{ 0x0172, 0x0055, 0x0328},
-{ 0x1E76, 0x0055, 0x032D},
-{ 0x1E74, 0x0055, 0x0330},
-{ 0x1E7C, 0x0056, 0x0303},
-{ 0x1E7E, 0x0056, 0x0323},
-{ 0x1E80, 0x0057, 0x0300},
-{ 0x1E82, 0x0057, 0x0301},
-{ 0x0174, 0x0057, 0x0302},
-{ 0x1E86, 0x0057, 0x0307},
-{ 0x1E84, 0x0057, 0x0308},
-{ 0x1E88, 0x0057, 0x0323},
-{ 0x1E8A, 0x0058, 0x0307},
-{ 0x1E8C, 0x0058, 0x0308},
-{ 0x1EF2, 0x0059, 0x0300},
-{ 0x00DD, 0x0059, 0x0301},
-{ 0x0176, 0x0059, 0x0302},
-{ 0x1EF8, 0x0059, 0x0303},
-{ 0x0232, 0x0059, 0x0304},
-{ 0x1E8E, 0x0059, 0x0307},
-{ 0x0178, 0x0059, 0x0308},
-{ 0x1EF6, 0x0059, 0x0309},
-{ 0x1EF4, 0x0059, 0x0323},
-{ 0x0179, 0x005A, 0x0301},
-{ 0x1E90, 0x005A, 0x0302},
-{ 0x017B, 0x005A, 0x0307},
-{ 0x017D, 0x005A, 0x030C},
-{ 0x1E92, 0x005A, 0x0323},
-{ 0x1E94, 0x005A, 0x0331},
-{ 0x00E0, 0x0061, 0x0300},
-{ 0x00E1, 0x0061, 0x0301},
-{ 0x00E2, 0x0061, 0x0302},
-{ 0x00E3, 0x0061, 0x0303},
-{ 0x0101, 0x0061, 0x0304},
-{ 0x0103, 0x0061, 0x0306},
-{ 0x0227, 0x0061, 0x0307},
-{ 0x00E4, 0x0061, 0x0308},
-{ 0x1EA3, 0x0061, 0x0309},
-{ 0x00E5, 0x0061, 0x030A},
-{ 0x01CE, 0x0061, 0x030C},
-{ 0x0201, 0x0061, 0x030F},
-{ 0x0203, 0x0061, 0x0311},
-{ 0x1EA1, 0x0061, 0x0323},
-{ 0x1E01, 0x0061, 0x0325},
-{ 0x0105, 0x0061, 0x0328},
-{ 0x1E03, 0x0062, 0x0307},
-{ 0x1E05, 0x0062, 0x0323},
-{ 0x1E07, 0x0062, 0x0331},
-{ 0x0107, 0x0063, 0x0301},
-{ 0x0109, 0x0063, 0x0302},
-{ 0x010B, 0x0063, 0x0307},
-{ 0x010D, 0x0063, 0x030C},
-{ 0x00E7, 0x0063, 0x0327},
-{ 0x1E0B, 0x0064, 0x0307},
-{ 0x010F, 0x0064, 0x030C},
-{ 0x1E0D, 0x0064, 0x0323},
-{ 0x1E11, 0x0064, 0x0327},
-{ 0x1E13, 0x0064, 0x032D},
-{ 0x1E0F, 0x0064, 0x0331},
-{ 0x00E8, 0x0065, 0x0300},
-{ 0x00E9, 0x0065, 0x0301},
-{ 0x00EA, 0x0065, 0x0302},
-{ 0x1EBD, 0x0065, 0x0303},
-{ 0x0113, 0x0065, 0x0304},
-{ 0x0115, 0x0065, 0x0306},
-{ 0x0117, 0x0065, 0x0307},
-{ 0x00EB, 0x0065, 0x0308},
-{ 0x1EBB, 0x0065, 0x0309},
-{ 0x011B, 0x0065, 0x030C},
-{ 0x0205, 0x0065, 0x030F},
-{ 0x0207, 0x0065, 0x0311},
-{ 0x1EB9, 0x0065, 0x0323},
-{ 0x0229, 0x0065, 0x0327},
-{ 0x0119, 0x0065, 0x0328},
-{ 0x1E19, 0x0065, 0x032D},
-{ 0x1E1B, 0x0065, 0x0330},
-{ 0x1E1F, 0x0066, 0x0307},
-{ 0x01F5, 0x0067, 0x0301},
-{ 0x011D, 0x0067, 0x0302},
-{ 0x1E21, 0x0067, 0x0304},
-{ 0x011F, 0x0067, 0x0306},
-{ 0x0121, 0x0067, 0x0307},
-{ 0x01E7, 0x0067, 0x030C},
-{ 0x0123, 0x0067, 0x0327},
-{ 0x0125, 0x0068, 0x0302},
-{ 0x1E23, 0x0068, 0x0307},
-{ 0x1E27, 0x0068, 0x0308},
-{ 0x021F, 0x0068, 0x030C},
-{ 0x1E25, 0x0068, 0x0323},
-{ 0x1E29, 0x0068, 0x0327},
-{ 0x1E2B, 0x0068, 0x032E},
-{ 0x1E96, 0x0068, 0x0331},
-{ 0x00EC, 0x0069, 0x0300},
-{ 0x00ED, 0x0069, 0x0301},
-{ 0x00EE, 0x0069, 0x0302},
-{ 0x0129, 0x0069, 0x0303},
-{ 0x012B, 0x0069, 0x0304},
-{ 0x012D, 0x0069, 0x0306},
-{ 0x00EF, 0x0069, 0x0308},
-{ 0x1EC9, 0x0069, 0x0309},
-{ 0x01D0, 0x0069, 0x030C},
-{ 0x0209, 0x0069, 0x030F},
-{ 0x020B, 0x0069, 0x0311},
-{ 0x1ECB, 0x0069, 0x0323},
-{ 0x012F, 0x0069, 0x0328},
-{ 0x1E2D, 0x0069, 0x0330},
-{ 0x0135, 0x006A, 0x0302},
-{ 0x01F0, 0x006A, 0x030C},
-{ 0x1E31, 0x006B, 0x0301},
-{ 0x01E9, 0x006B, 0x030C},
-{ 0x1E33, 0x006B, 0x0323},
-{ 0x0137, 0x006B, 0x0327},
-{ 0x1E35, 0x006B, 0x0331},
-{ 0x013A, 0x006C, 0x0301},
-{ 0x013E, 0x006C, 0x030C},
-{ 0x1E37, 0x006C, 0x0323},
-{ 0x013C, 0x006C, 0x0327},
-{ 0x1E3D, 0x006C, 0x032D},
-{ 0x1E3B, 0x006C, 0x0331},
-{ 0x1E3F, 0x006D, 0x0301},
-{ 0x1E41, 0x006D, 0x0307},
-{ 0x1E43, 0x006D, 0x0323},
-{ 0x01F9, 0x006E, 0x0300},
-{ 0x0144, 0x006E, 0x0301},
-{ 0x00F1, 0x006E, 0x0303},
-{ 0x1E45, 0x006E, 0x0307},
-{ 0x0148, 0x006E, 0x030C},
-{ 0x1E47, 0x006E, 0x0323},
-{ 0x0146, 0x006E, 0x0327},
-{ 0x1E4B, 0x006E, 0x032D},
-{ 0x1E49, 0x006E, 0x0331},
-{ 0x00F2, 0x006F, 0x0300},
-{ 0x00F3, 0x006F, 0x0301},
-{ 0x00F4, 0x006F, 0x0302},
-{ 0x00F5, 0x006F, 0x0303},
-{ 0x014D, 0x006F, 0x0304},
-{ 0x014F, 0x006F, 0x0306},
-{ 0x022F, 0x006F, 0x0307},
-{ 0x00F6, 0x006F, 0x0308},
-{ 0x1ECF, 0x006F, 0x0309},
-{ 0x0151, 0x006F, 0x030B},
-{ 0x01D2, 0x006F, 0x030C},
-{ 0x020D, 0x006F, 0x030F},
-{ 0x020F, 0x006F, 0x0311},
-{ 0x01A1, 0x006F, 0x031B},
-{ 0x1ECD, 0x006F, 0x0323},
-{ 0x01EB, 0x006F, 0x0328},
-{ 0x1E55, 0x0070, 0x0301},
-{ 0x1E57, 0x0070, 0x0307},
-{ 0x0155, 0x0072, 0x0301},
-{ 0x1E59, 0x0072, 0x0307},
-{ 0x0159, 0x0072, 0x030C},
-{ 0x0211, 0x0072, 0x030F},
-{ 0x0213, 0x0072, 0x0311},
-{ 0x1E5B, 0x0072, 0x0323},
-{ 0x0157, 0x0072, 0x0327},
-{ 0x1E5F, 0x0072, 0x0331},
-{ 0x015B, 0x0073, 0x0301},
-{ 0x015D, 0x0073, 0x0302},
-{ 0x1E61, 0x0073, 0x0307},
-{ 0x0161, 0x0073, 0x030C},
-{ 0x1E63, 0x0073, 0x0323},
-{ 0x0219, 0x0073, 0x0326},
-{ 0x015F, 0x0073, 0x0327},
-{ 0x1E6B, 0x0074, 0x0307},
-{ 0x1E97, 0x0074, 0x0308},
-{ 0x0165, 0x0074, 0x030C},
-{ 0x1E6D, 0x0074, 0x0323},
-{ 0x021B, 0x0074, 0x0326},
-{ 0x0163, 0x0074, 0x0327},
-{ 0x1E71, 0x0074, 0x032D},
-{ 0x1E6F, 0x0074, 0x0331},
-{ 0x00F9, 0x0075, 0x0300},
-{ 0x00FA, 0x0075, 0x0301},
-{ 0x00FB, 0x0075, 0x0302},
-{ 0x0169, 0x0075, 0x0303},
-{ 0x016B, 0x0075, 0x0304},
-{ 0x016D, 0x0075, 0x0306},
-{ 0x00FC, 0x0075, 0x0308},
-{ 0x1EE7, 0x0075, 0x0309},
-{ 0x016F, 0x0075, 0x030A},
-{ 0x0171, 0x0075, 0x030B},
-{ 0x01D4, 0x0075, 0x030C},
-{ 0x0215, 0x0075, 0x030F},
-{ 0x0217, 0x0075, 0x0311},
-{ 0x01B0, 0x0075, 0x031B},
-{ 0x1EE5, 0x0075, 0x0323},
-{ 0x1E73, 0x0075, 0x0324},
-{ 0x0173, 0x0075, 0x0328},
-{ 0x1E77, 0x0075, 0x032D},
-{ 0x1E75, 0x0075, 0x0330},
-{ 0x1E7D, 0x0076, 0x0303},
-{ 0x1E7F, 0x0076, 0x0323},
-{ 0x1E81, 0x0077, 0x0300},
-{ 0x1E83, 0x0077, 0x0301},
-{ 0x0175, 0x0077, 0x0302},
-{ 0x1E87, 0x0077, 0x0307},
-{ 0x1E85, 0x0077, 0x0308},
-{ 0x1E98, 0x0077, 0x030A},
-{ 0x1E89, 0x0077, 0x0323},
-{ 0x1E8B, 0x0078, 0x0307},
-{ 0x1E8D, 0x0078, 0x0308},
-{ 0x1EF3, 0x0079, 0x0300},
-{ 0x00FD, 0x0079, 0x0301},
-{ 0x0177, 0x0079, 0x0302},
-{ 0x1EF9, 0x0079, 0x0303},
-{ 0x0233, 0x0079, 0x0304},
-{ 0x1E8F, 0x0079, 0x0307},
-{ 0x00FF, 0x0079, 0x0308},
-{ 0x1EF7, 0x0079, 0x0309},
-{ 0x1E99, 0x0079, 0x030A},
-{ 0x1EF5, 0x0079, 0x0323},
-{ 0x017A, 0x007A, 0x0301},
-{ 0x1E91, 0x007A, 0x0302},
-{ 0x017C, 0x007A, 0x0307},
-{ 0x017E, 0x007A, 0x030C},
-{ 0x1E93, 0x007A, 0x0323},
-{ 0x1E95, 0x007A, 0x0331},
-{ 0x1FED, 0x00A8, 0x0300},
-{ 0x0385, 0x00A8, 0x0301},
-{ 0x1FC1, 0x00A8, 0x0342},
-{ 0x1EA6, 0x00C2, 0x0300},
-{ 0x1EA4, 0x00C2, 0x0301},
-{ 0x1EAA, 0x00C2, 0x0303},
-{ 0x1EA8, 0x00C2, 0x0309},
-{ 0x01DE, 0x00C4, 0x0304},
-{ 0x01FA, 0x00C5, 0x0301},
-{ 0x01FC, 0x00C6, 0x0301},
-{ 0x01E2, 0x00C6, 0x0304},
-{ 0x1E08, 0x00C7, 0x0301},
-{ 0x1EC0, 0x00CA, 0x0300},
-{ 0x1EBE, 0x00CA, 0x0301},
-{ 0x1EC4, 0x00CA, 0x0303},
-{ 0x1EC2, 0x00CA, 0x0309},
-{ 0x1E2E, 0x00CF, 0x0301},
-{ 0x1ED2, 0x00D4, 0x0300},
-{ 0x1ED0, 0x00D4, 0x0301},
-{ 0x1ED6, 0x00D4, 0x0303},
-{ 0x1ED4, 0x00D4, 0x0309},
-{ 0x1E4C, 0x00D5, 0x0301},
-{ 0x022C, 0x00D5, 0x0304},
-{ 0x1E4E, 0x00D5, 0x0308},
-{ 0x022A, 0x00D6, 0x0304},
-{ 0x01FE, 0x00D8, 0x0301},
-{ 0x01DB, 0x00DC, 0x0300},
-{ 0x01D7, 0x00DC, 0x0301},
-{ 0x01D5, 0x00DC, 0x0304},
-{ 0x01D9, 0x00DC, 0x030C},
-{ 0x1EA7, 0x00E2, 0x0300},
-{ 0x1EA5, 0x00E2, 0x0301},
-{ 0x1EAB, 0x00E2, 0x0303},
-{ 0x1EA9, 0x00E2, 0x0309},
-{ 0x01DF, 0x00E4, 0x0304},
-{ 0x01FB, 0x00E5, 0x0301},
-{ 0x01FD, 0x00E6, 0x0301},
-{ 0x01E3, 0x00E6, 0x0304},
-{ 0x1E09, 0x00E7, 0x0301},
-{ 0x1EC1, 0x00EA, 0x0300},
-{ 0x1EBF, 0x00EA, 0x0301},
-{ 0x1EC5, 0x00EA, 0x0303},
-{ 0x1EC3, 0x00EA, 0x0309},
-{ 0x1E2F, 0x00EF, 0x0301},
-{ 0x1ED3, 0x00F4, 0x0300},
-{ 0x1ED1, 0x00F4, 0x0301},
-{ 0x1ED7, 0x00F4, 0x0303},
-{ 0x1ED5, 0x00F4, 0x0309},
-{ 0x1E4D, 0x00F5, 0x0301},
-{ 0x022D, 0x00F5, 0x0304},
-{ 0x1E4F, 0x00F5, 0x0308},
-{ 0x022B, 0x00F6, 0x0304},
-{ 0x01FF, 0x00F8, 0x0301},
-{ 0x01DC, 0x00FC, 0x0300},
-{ 0x01D8, 0x00FC, 0x0301},
-{ 0x01D6, 0x00FC, 0x0304},
-{ 0x01DA, 0x00FC, 0x030C},
-{ 0x1EB0, 0x0102, 0x0300},
-{ 0x1EAE, 0x0102, 0x0301},
-{ 0x1EB4, 0x0102, 0x0303},
-{ 0x1EB2, 0x0102, 0x0309},
-{ 0x1EB1, 0x0103, 0x0300},
-{ 0x1EAF, 0x0103, 0x0301},
-{ 0x1EB5, 0x0103, 0x0303},
-{ 0x1EB3, 0x0103, 0x0309},
-{ 0x1E14, 0x0112, 0x0300},
-{ 0x1E16, 0x0112, 0x0301},
-{ 0x1E15, 0x0113, 0x0300},
-{ 0x1E17, 0x0113, 0x0301},
-{ 0x1E50, 0x014C, 0x0300},
-{ 0x1E52, 0x014C, 0x0301},
-{ 0x1E51, 0x014D, 0x0300},
-{ 0x1E53, 0x014D, 0x0301},
-{ 0x1E64, 0x015A, 0x0307},
-{ 0x1E65, 0x015B, 0x0307},
-{ 0x1E66, 0x0160, 0x0307},
-{ 0x1E67, 0x0161, 0x0307},
-{ 0x1E78, 0x0168, 0x0301},
-{ 0x1E79, 0x0169, 0x0301},
-{ 0x1E7A, 0x016A, 0x0308},
-{ 0x1E7B, 0x016B, 0x0308},
-{ 0x1E9B, 0x017F, 0x0307},
-{ 0x1EDC, 0x01A0, 0x0300},
-{ 0x1EDA, 0x01A0, 0x0301},
-{ 0x1EE0, 0x01A0, 0x0303},
-{ 0x1EDE, 0x01A0, 0x0309},
-{ 0x1EE2, 0x01A0, 0x0323},
-{ 0x1EDD, 0x01A1, 0x0300},
-{ 0x1EDB, 0x01A1, 0x0301},
-{ 0x1EE1, 0x01A1, 0x0303},
-{ 0x1EDF, 0x01A1, 0x0309},
-{ 0x1EE3, 0x01A1, 0x0323},
-{ 0x1EEA, 0x01AF, 0x0300},
-{ 0x1EE8, 0x01AF, 0x0301},
-{ 0x1EEE, 0x01AF, 0x0303},
-{ 0x1EEC, 0x01AF, 0x0309},
-{ 0x1EF0, 0x01AF, 0x0323},
-{ 0x1EEB, 0x01B0, 0x0300},
-{ 0x1EE9, 0x01B0, 0x0301},
-{ 0x1EEF, 0x01B0, 0x0303},
-{ 0x1EED, 0x01B0, 0x0309},
-{ 0x1EF1, 0x01B0, 0x0323},
-{ 0x01EE, 0x01B7, 0x030C},
-{ 0x01EC, 0x01EA, 0x0304},
-{ 0x01ED, 0x01EB, 0x0304},
-{ 0x01E0, 0x0226, 0x0304},
-{ 0x01E1, 0x0227, 0x0304},
-{ 0x1E1C, 0x0228, 0x0306},
-{ 0x1E1D, 0x0229, 0x0306},
-{ 0x0230, 0x022E, 0x0304},
-{ 0x0231, 0x022F, 0x0304},
-{ 0x01EF, 0x0292, 0x030C},
-{ 0x0344, 0x0308, 0x0301},
-{ 0x1FBA, 0x0391, 0x0300},
-{ 0x0386, 0x0391, 0x0301},
-{ 0x1FB9, 0x0391, 0x0304},
-{ 0x1FB8, 0x0391, 0x0306},
-{ 0x1F08, 0x0391, 0x0313},
-{ 0x1F09, 0x0391, 0x0314},
-{ 0x1FBC, 0x0391, 0x0345},
-{ 0x1FC8, 0x0395, 0x0300},
-{ 0x0388, 0x0395, 0x0301},
-{ 0x1F18, 0x0395, 0x0313},
-{ 0x1F19, 0x0395, 0x0314},
-{ 0x1FCA, 0x0397, 0x0300},
-{ 0x0389, 0x0397, 0x0301},
-{ 0x1F28, 0x0397, 0x0313},
-{ 0x1F29, 0x0397, 0x0314},
-{ 0x1FCC, 0x0397, 0x0345},
-{ 0x1FDA, 0x0399, 0x0300},
-{ 0x038A, 0x0399, 0x0301},
-{ 0x1FD9, 0x0399, 0x0304},
-{ 0x1FD8, 0x0399, 0x0306},
-{ 0x03AA, 0x0399, 0x0308},
-{ 0x1F38, 0x0399, 0x0313},
-{ 0x1F39, 0x0399, 0x0314},
-{ 0x1FF8, 0x039F, 0x0300},
-{ 0x038C, 0x039F, 0x0301},
-{ 0x1F48, 0x039F, 0x0313},
-{ 0x1F49, 0x039F, 0x0314},
-{ 0x1FEC, 0x03A1, 0x0314},
-{ 0x1FEA, 0x03A5, 0x0300},
-{ 0x038E, 0x03A5, 0x0301},
-{ 0x1FE9, 0x03A5, 0x0304},
-{ 0x1FE8, 0x03A5, 0x0306},
-{ 0x03AB, 0x03A5, 0x0308},
-{ 0x1F59, 0x03A5, 0x0314},
-{ 0x1FFA, 0x03A9, 0x0300},
-{ 0x038F, 0x03A9, 0x0301},
-{ 0x1F68, 0x03A9, 0x0313},
-{ 0x1F69, 0x03A9, 0x0314},
-{ 0x1FFC, 0x03A9, 0x0345},
-{ 0x1FB4, 0x03AC, 0x0345},
-{ 0x1FC4, 0x03AE, 0x0345},
-{ 0x1F70, 0x03B1, 0x0300},
-{ 0x03AC, 0x03B1, 0x0301},
-{ 0x1FB1, 0x03B1, 0x0304},
-{ 0x1FB0, 0x03B1, 0x0306},
-{ 0x1F00, 0x03B1, 0x0313},
-{ 0x1F01, 0x03B1, 0x0314},
-{ 0x1FB6, 0x03B1, 0x0342},
-{ 0x1FB3, 0x03B1, 0x0345},
-{ 0x1F72, 0x03B5, 0x0300},
-{ 0x03AD, 0x03B5, 0x0301},
-{ 0x1F10, 0x03B5, 0x0313},
-{ 0x1F11, 0x03B5, 0x0314},
-{ 0x1F74, 0x03B7, 0x0300},
-{ 0x03AE, 0x03B7, 0x0301},
-{ 0x1F20, 0x03B7, 0x0313},
-{ 0x1F21, 0x03B7, 0x0314},
-{ 0x1FC6, 0x03B7, 0x0342},
-{ 0x1FC3, 0x03B7, 0x0345},
-{ 0x1F76, 0x03B9, 0x0300},
-{ 0x03AF, 0x03B9, 0x0301},
-{ 0x1FD1, 0x03B9, 0x0304},
-{ 0x1FD0, 0x03B9, 0x0306},
-{ 0x03CA, 0x03B9, 0x0308},
-{ 0x1F30, 0x03B9, 0x0313},
-{ 0x1F31, 0x03B9, 0x0314},
-{ 0x1FD6, 0x03B9, 0x0342},
-{ 0x1F78, 0x03BF, 0x0300},
-{ 0x03CC, 0x03BF, 0x0301},
-{ 0x1F40, 0x03BF, 0x0313},
-{ 0x1F41, 0x03BF, 0x0314},
-{ 0x1FE4, 0x03C1, 0x0313},
-{ 0x1FE5, 0x03C1, 0x0314},
-{ 0x1F7A, 0x03C5, 0x0300},
-{ 0x03CD, 0x03C5, 0x0301},
-{ 0x1FE1, 0x03C5, 0x0304},
-{ 0x1FE0, 0x03C5, 0x0306},
-{ 0x03CB, 0x03C5, 0x0308},
-{ 0x1F50, 0x03C5, 0x0313},
-{ 0x1F51, 0x03C5, 0x0314},
-{ 0x1FE6, 0x03C5, 0x0342},
-{ 0x1F7C, 0x03C9, 0x0300},
-{ 0x03CE, 0x03C9, 0x0301},
-{ 0x1F60, 0x03C9, 0x0313},
-{ 0x1F61, 0x03C9, 0x0314},
-{ 0x1FF6, 0x03C9, 0x0342},
-{ 0x1FF3, 0x03C9, 0x0345},
-{ 0x1FD2, 0x03CA, 0x0300},
-{ 0x0390, 0x03CA, 0x0301},
-{ 0x1FD7, 0x03CA, 0x0342},
-{ 0x1FE2, 0x03CB, 0x0300},
-{ 0x03B0, 0x03CB, 0x0301},
-{ 0x1FE7, 0x03CB, 0x0342},
-{ 0x1FF4, 0x03CE, 0x0345},
-{ 0x03D3, 0x03D2, 0x0301},
-{ 0x03D4, 0x03D2, 0x0308},
-{ 0x0407, 0x0406, 0x0308},
-{ 0x04D0, 0x0410, 0x0306},
-{ 0x04D2, 0x0410, 0x0308},
-{ 0x0403, 0x0413, 0x0301},
-{ 0x0400, 0x0415, 0x0300},
-{ 0x04D6, 0x0415, 0x0306},
-{ 0x0401, 0x0415, 0x0308},
-{ 0x04C1, 0x0416, 0x0306},
-{ 0x04DC, 0x0416, 0x0308},
-{ 0x04DE, 0x0417, 0x0308},
-{ 0x040D, 0x0418, 0x0300},
-{ 0x04E2, 0x0418, 0x0304},
-{ 0x0419, 0x0418, 0x0306},
-{ 0x04E4, 0x0418, 0x0308},
-{ 0x040C, 0x041A, 0x0301},
-{ 0x04E6, 0x041E, 0x0308},
-{ 0x04EE, 0x0423, 0x0304},
-{ 0x040E, 0x0423, 0x0306},
-{ 0x04F0, 0x0423, 0x0308},
-{ 0x04F2, 0x0423, 0x030B},
-{ 0x04F4, 0x0427, 0x0308},
-{ 0x04F8, 0x042B, 0x0308},
-{ 0x04EC, 0x042D, 0x0308},
-{ 0x04D1, 0x0430, 0x0306},
-{ 0x04D3, 0x0430, 0x0308},
-{ 0x0453, 0x0433, 0x0301},
-{ 0x0450, 0x0435, 0x0300},
-{ 0x04D7, 0x0435, 0x0306},
-{ 0x0451, 0x0435, 0x0308},
-{ 0x04C2, 0x0436, 0x0306},
-{ 0x04DD, 0x0436, 0x0308},
-{ 0x04DF, 0x0437, 0x0308},
-{ 0x045D, 0x0438, 0x0300},
-{ 0x04E3, 0x0438, 0x0304},
-{ 0x0439, 0x0438, 0x0306},
-{ 0x04E5, 0x0438, 0x0308},
-{ 0x045C, 0x043A, 0x0301},
-{ 0x04E7, 0x043E, 0x0308},
-{ 0x04EF, 0x0443, 0x0304},
-{ 0x045E, 0x0443, 0x0306},
-{ 0x04F1, 0x0443, 0x0308},
-{ 0x04F3, 0x0443, 0x030B},
-{ 0x04F5, 0x0447, 0x0308},
-{ 0x04F9, 0x044B, 0x0308},
-{ 0x04ED, 0x044D, 0x0308},
-{ 0x0457, 0x0456, 0x0308},
-{ 0x0476, 0x0474, 0x030F},
-{ 0x0477, 0x0475, 0x030F},
-{ 0x04DA, 0x04D8, 0x0308},
-{ 0x04DB, 0x04D9, 0x0308},
-{ 0x04EA, 0x04E8, 0x0308},
-{ 0x04EB, 0x04E9, 0x0308},
-{ 0xFB2E, 0x05D0, 0x05B7},
-{ 0xFB2F, 0x05D0, 0x05B8},
-{ 0xFB30, 0x05D0, 0x05BC},
-{ 0xFB31, 0x05D1, 0x05BC},
-{ 0xFB4C, 0x05D1, 0x05BF},
-{ 0xFB32, 0x05D2, 0x05BC},
-{ 0xFB33, 0x05D3, 0x05BC},
-{ 0xFB34, 0x05D4, 0x05BC},
-{ 0xFB4B, 0x05D5, 0x05B9},
-{ 0xFB35, 0x05D5, 0x05BC},
-{ 0xFB36, 0x05D6, 0x05BC},
-{ 0xFB38, 0x05D8, 0x05BC},
-{ 0xFB1D, 0x05D9, 0x05B4},
-{ 0xFB39, 0x05D9, 0x05BC},
-{ 0xFB3A, 0x05DA, 0x05BC},
-{ 0xFB3B, 0x05DB, 0x05BC},
-{ 0xFB4D, 0x05DB, 0x05BF},
-{ 0xFB3C, 0x05DC, 0x05BC},
-{ 0xFB3E, 0x05DE, 0x05BC},
-{ 0xFB40, 0x05E0, 0x05BC},
-{ 0xFB41, 0x05E1, 0x05BC},
-{ 0xFB43, 0x05E3, 0x05BC},
-{ 0xFB44, 0x05E4, 0x05BC},
-{ 0xFB4E, 0x05E4, 0x05BF},
-{ 0xFB46, 0x05E6, 0x05BC},
-{ 0xFB47, 0x05E7, 0x05BC},
-{ 0xFB48, 0x05E8, 0x05BC},
-{ 0xFB49, 0x05E9, 0x05BC},
-{ 0xFB2A, 0x05E9, 0x05C1},
-{ 0xFB2B, 0x05E9, 0x05C2},
-{ 0xFB4A, 0x05EA, 0x05BC},
-{ 0xFB1F, 0x05F2, 0x05B7},
-{ 0x0622, 0x0627, 0x0653},
-{ 0x0623, 0x0627, 0x0654},
-{ 0x0625, 0x0627, 0x0655},
-{ 0x0624, 0x0648, 0x0654},
-{ 0x0626, 0x064A, 0x0654},
-{ 0x06C2, 0x06C1, 0x0654},
-{ 0x06D3, 0x06D2, 0x0654},
-{ 0x06C0, 0x06D5, 0x0654},
-{ 0x0958, 0x0915, 0x093C},
-{ 0x0959, 0x0916, 0x093C},
-{ 0x095A, 0x0917, 0x093C},
-{ 0x095B, 0x091C, 0x093C},
-{ 0x095C, 0x0921, 0x093C},
-{ 0x095D, 0x0922, 0x093C},
-{ 0x0929, 0x0928, 0x093C},
-{ 0x095E, 0x092B, 0x093C},
-{ 0x095F, 0x092F, 0x093C},
-{ 0x0931, 0x0930, 0x093C},
-{ 0x0934, 0x0933, 0x093C},
-{ 0x09DC, 0x09A1, 0x09BC},
-{ 0x09DD, 0x09A2, 0x09BC},
-{ 0x09DF, 0x09AF, 0x09BC},
-{ 0x09CB, 0x09C7, 0x09BE},
-{ 0x09CC, 0x09C7, 0x09D7},
-{ 0x0A59, 0x0A16, 0x0A3C},
-{ 0x0A5A, 0x0A17, 0x0A3C},
-{ 0x0A5B, 0x0A1C, 0x0A3C},
-{ 0x0A5E, 0x0A2B, 0x0A3C},
-{ 0x0A33, 0x0A32, 0x0A3C},
-{ 0x0A36, 0x0A38, 0x0A3C},
-{ 0x0B5C, 0x0B21, 0x0B3C},
-{ 0x0B5D, 0x0B22, 0x0B3C},
-{ 0x0B4B, 0x0B47, 0x0B3E},
-{ 0x0B48, 0x0B47, 0x0B56},
-{ 0x0B4C, 0x0B47, 0x0B57},
-{ 0x0B94, 0x0B92, 0x0BD7},
-{ 0x0BCA, 0x0BC6, 0x0BBE},
-{ 0x0BCC, 0x0BC6, 0x0BD7},
-{ 0x0BCB, 0x0BC7, 0x0BBE},
-{ 0x0C48, 0x0C46, 0x0C56},
-{ 0x0CC0, 0x0CBF, 0x0CD5},
-{ 0x0CCA, 0x0CC6, 0x0CC2},
-{ 0x0CC7, 0x0CC6, 0x0CD5},
-{ 0x0CC8, 0x0CC6, 0x0CD6},
-{ 0x0CCB, 0x0CCA, 0x0CD5},
-{ 0x0D4A, 0x0D46, 0x0D3E},
-{ 0x0D4C, 0x0D46, 0x0D57},
-{ 0x0D4B, 0x0D47, 0x0D3E},
-{ 0x0DDA, 0x0DD9, 0x0DCA},
-{ 0x0DDC, 0x0DD9, 0x0DCF},
-{ 0x0DDE, 0x0DD9, 0x0DDF},
-{ 0x0DDD, 0x0DDC, 0x0DCA},
-{ 0x0F69, 0x0F40, 0x0FB5},
-{ 0x0F43, 0x0F42, 0x0FB7},
-{ 0x0F4D, 0x0F4C, 0x0FB7},
-{ 0x0F52, 0x0F51, 0x0FB7},
-{ 0x0F57, 0x0F56, 0x0FB7},
-{ 0x0F5C, 0x0F5B, 0x0FB7},
-{ 0x0F73, 0x0F71, 0x0F72},
-{ 0x0F75, 0x0F71, 0x0F74},
-{ 0x0F81, 0x0F71, 0x0F80},
-{ 0x0FB9, 0x0F90, 0x0FB5},
-{ 0x0F93, 0x0F92, 0x0FB7},
-{ 0x0F9D, 0x0F9C, 0x0FB7},
-{ 0x0FA2, 0x0FA1, 0x0FB7},
-{ 0x0FA7, 0x0FA6, 0x0FB7},
-{ 0x0FAC, 0x0FAB, 0x0FB7},
-{ 0x0F76, 0x0FB2, 0x0F80},
-{ 0x0F78, 0x0FB3, 0x0F80},
-{ 0x1026, 0x1025, 0x102E},
-{ 0x1E38, 0x1E36, 0x0304},
-{ 0x1E39, 0x1E37, 0x0304},
-{ 0x1E5C, 0x1E5A, 0x0304},
-{ 0x1E5D, 0x1E5B, 0x0304},
-{ 0x1E68, 0x1E62, 0x0307},
-{ 0x1E69, 0x1E63, 0x0307},
-{ 0x1EAC, 0x1EA0, 0x0302},
-{ 0x1EB6, 0x1EA0, 0x0306},
-{ 0x1EAD, 0x1EA1, 0x0302},
-{ 0x1EB7, 0x1EA1, 0x0306},
-{ 0x1EC6, 0x1EB8, 0x0302},
-{ 0x1EC7, 0x1EB9, 0x0302},
-{ 0x1ED8, 0x1ECC, 0x0302},
-{ 0x1ED9, 0x1ECD, 0x0302},
-{ 0x1F02, 0x1F00, 0x0300},
-{ 0x1F04, 0x1F00, 0x0301},
-{ 0x1F06, 0x1F00, 0x0342},
-{ 0x1F80, 0x1F00, 0x0345},
-{ 0x1F03, 0x1F01, 0x0300},
-{ 0x1F05, 0x1F01, 0x0301},
-{ 0x1F07, 0x1F01, 0x0342},
-{ 0x1F81, 0x1F01, 0x0345},
-{ 0x1F82, 0x1F02, 0x0345},
-{ 0x1F83, 0x1F03, 0x0345},
-{ 0x1F84, 0x1F04, 0x0345},
-{ 0x1F85, 0x1F05, 0x0345},
-{ 0x1F86, 0x1F06, 0x0345},
-{ 0x1F87, 0x1F07, 0x0345},
-{ 0x1F0A, 0x1F08, 0x0300},
-{ 0x1F0C, 0x1F08, 0x0301},
-{ 0x1F0E, 0x1F08, 0x0342},
-{ 0x1F88, 0x1F08, 0x0345},
-{ 0x1F0B, 0x1F09, 0x0300},
-{ 0x1F0D, 0x1F09, 0x0301},
-{ 0x1F0F, 0x1F09, 0x0342},
-{ 0x1F89, 0x1F09, 0x0345},
-{ 0x1F8A, 0x1F0A, 0x0345},
-{ 0x1F8B, 0x1F0B, 0x0345},
-{ 0x1F8C, 0x1F0C, 0x0345},
-{ 0x1F8D, 0x1F0D, 0x0345},
-{ 0x1F8E, 0x1F0E, 0x0345},
-{ 0x1F8F, 0x1F0F, 0x0345},
-{ 0x1F12, 0x1F10, 0x0300},
-{ 0x1F14, 0x1F10, 0x0301},
-{ 0x1F13, 0x1F11, 0x0300},
-{ 0x1F15, 0x1F11, 0x0301},
-{ 0x1F1A, 0x1F18, 0x0300},
-{ 0x1F1C, 0x1F18, 0x0301},
-{ 0x1F1B, 0x1F19, 0x0300},
-{ 0x1F1D, 0x1F19, 0x0301},
-{ 0x1F22, 0x1F20, 0x0300},
-{ 0x1F24, 0x1F20, 0x0301},
-{ 0x1F26, 0x1F20, 0x0342},
-{ 0x1F90, 0x1F20, 0x0345},
-{ 0x1F23, 0x1F21, 0x0300},
-{ 0x1F25, 0x1F21, 0x0301},
-{ 0x1F27, 0x1F21, 0x0342},
-{ 0x1F91, 0x1F21, 0x0345},
-{ 0x1F92, 0x1F22, 0x0345},
-{ 0x1F93, 0x1F23, 0x0345},
-{ 0x1F94, 0x1F24, 0x0345},
-{ 0x1F95, 0x1F25, 0x0345},
-{ 0x1F96, 0x1F26, 0x0345},
-{ 0x1F97, 0x1F27, 0x0345},
-{ 0x1F2A, 0x1F28, 0x0300},
-{ 0x1F2C, 0x1F28, 0x0301},
-{ 0x1F2E, 0x1F28, 0x0342},
-{ 0x1F98, 0x1F28, 0x0345},
-{ 0x1F2B, 0x1F29, 0x0300},
-{ 0x1F2D, 0x1F29, 0x0301},
-{ 0x1F2F, 0x1F29, 0x0342},
-{ 0x1F99, 0x1F29, 0x0345},
-{ 0x1F9A, 0x1F2A, 0x0345},
-{ 0x1F9B, 0x1F2B, 0x0345},
-{ 0x1F9C, 0x1F2C, 0x0345},
-{ 0x1F9D, 0x1F2D, 0x0345},
-{ 0x1F9E, 0x1F2E, 0x0345},
-{ 0x1F9F, 0x1F2F, 0x0345},
-{ 0x1F32, 0x1F30, 0x0300},
-{ 0x1F34, 0x1F30, 0x0301},
-{ 0x1F36, 0x1F30, 0x0342},
-{ 0x1F33, 0x1F31, 0x0300},
-{ 0x1F35, 0x1F31, 0x0301},
-{ 0x1F37, 0x1F31, 0x0342},
-{ 0x1F3A, 0x1F38, 0x0300},
-{ 0x1F3C, 0x1F38, 0x0301},
-{ 0x1F3E, 0x1F38, 0x0342},
-{ 0x1F3B, 0x1F39, 0x0300},
-{ 0x1F3D, 0x1F39, 0x0301},
-{ 0x1F3F, 0x1F39, 0x0342},
-{ 0x1F42, 0x1F40, 0x0300},
-{ 0x1F44, 0x1F40, 0x0301},
-{ 0x1F43, 0x1F41, 0x0300},
-{ 0x1F45, 0x1F41, 0x0301},
-{ 0x1F4A, 0x1F48, 0x0300},
-{ 0x1F4C, 0x1F48, 0x0301},
-{ 0x1F4B, 0x1F49, 0x0300},
-{ 0x1F4D, 0x1F49, 0x0301},
-{ 0x1F52, 0x1F50, 0x0300},
-{ 0x1F54, 0x1F50, 0x0301},
-{ 0x1F56, 0x1F50, 0x0342},
-{ 0x1F53, 0x1F51, 0x0300},
-{ 0x1F55, 0x1F51, 0x0301},
-{ 0x1F57, 0x1F51, 0x0342},
-{ 0x1F5B, 0x1F59, 0x0300},
-{ 0x1F5D, 0x1F59, 0x0301},
-{ 0x1F5F, 0x1F59, 0x0342},
-{ 0x1F62, 0x1F60, 0x0300},
-{ 0x1F64, 0x1F60, 0x0301},
-{ 0x1F66, 0x1F60, 0x0342},
-{ 0x1FA0, 0x1F60, 0x0345},
-{ 0x1F63, 0x1F61, 0x0300},
-{ 0x1F65, 0x1F61, 0x0301},
-{ 0x1F67, 0x1F61, 0x0342},
-{ 0x1FA1, 0x1F61, 0x0345},
-{ 0x1FA2, 0x1F62, 0x0345},
-{ 0x1FA3, 0x1F63, 0x0345},
-{ 0x1FA4, 0x1F64, 0x0345},
-{ 0x1FA5, 0x1F65, 0x0345},
-{ 0x1FA6, 0x1F66, 0x0345},
-{ 0x1FA7, 0x1F67, 0x0345},
-{ 0x1F6A, 0x1F68, 0x0300},
-{ 0x1F6C, 0x1F68, 0x0301},
-{ 0x1F6E, 0x1F68, 0x0342},
-{ 0x1FA8, 0x1F68, 0x0345},
-{ 0x1F6B, 0x1F69, 0x0300},
-{ 0x1F6D, 0x1F69, 0x0301},
-{ 0x1F6F, 0x1F69, 0x0342},
-{ 0x1FA9, 0x1F69, 0x0345},
-{ 0x1FAA, 0x1F6A, 0x0345},
-{ 0x1FAB, 0x1F6B, 0x0345},
-{ 0x1FAC, 0x1F6C, 0x0345},
-{ 0x1FAD, 0x1F6D, 0x0345},
-{ 0x1FAE, 0x1F6E, 0x0345},
-{ 0x1FAF, 0x1F6F, 0x0345},
-{ 0x1FB2, 0x1F70, 0x0345},
-{ 0x1FC2, 0x1F74, 0x0345},
-{ 0x1FF2, 0x1F7C, 0x0345},
-{ 0x1FB7, 0x1FB6, 0x0345},
-{ 0x1FCD, 0x1FBF, 0x0300},
-{ 0x1FCE, 0x1FBF, 0x0301},
-{ 0x1FCF, 0x1FBF, 0x0342},
-{ 0x1FC7, 0x1FC6, 0x0345},
-{ 0x1FF7, 0x1FF6, 0x0345},
-{ 0x1FDD, 0x1FFE, 0x0300},
-{ 0x1FDE, 0x1FFE, 0x0301},
-{ 0x1FDF, 0x1FFE, 0x0342},
-{ 0x219A, 0x2190, 0x0338},
-{ 0x219B, 0x2192, 0x0338},
-{ 0x21AE, 0x2194, 0x0338},
-{ 0x21CD, 0x21D0, 0x0338},
-{ 0x21CF, 0x21D2, 0x0338},
-{ 0x21CE, 0x21D4, 0x0338},
-{ 0x2204, 0x2203, 0x0338},
-{ 0x2209, 0x2208, 0x0338},
-{ 0x220C, 0x220B, 0x0338},
-{ 0x2224, 0x2223, 0x0338},
-{ 0x2226, 0x2225, 0x0338},
-{ 0x2241, 0x223C, 0x0338},
-{ 0x2244, 0x2243, 0x0338},
-{ 0x2247, 0x2245, 0x0338},
-{ 0x2249, 0x2248, 0x0338},
-{ 0x226D, 0x224D, 0x0338},
-{ 0x2262, 0x2261, 0x0338},
-{ 0x2270, 0x2264, 0x0338},
-{ 0x2271, 0x2265, 0x0338},
-{ 0x2274, 0x2272, 0x0338},
-{ 0x2275, 0x2273, 0x0338},
-{ 0x2278, 0x2276, 0x0338},
-{ 0x2279, 0x2277, 0x0338},
-{ 0x2280, 0x227A, 0x0338},
-{ 0x2281, 0x227B, 0x0338},
-{ 0x22E0, 0x227C, 0x0338},
-{ 0x22E1, 0x227D, 0x0338},
-{ 0x2284, 0x2282, 0x0338},
-{ 0x2285, 0x2283, 0x0338},
-{ 0x2288, 0x2286, 0x0338},
-{ 0x2289, 0x2287, 0x0338},
-{ 0x22E2, 0x2291, 0x0338},
-{ 0x22E3, 0x2292, 0x0338},
-{ 0x22AC, 0x22A2, 0x0338},
-{ 0x22AD, 0x22A8, 0x0338},
-{ 0x22AE, 0x22A9, 0x0338},
-{ 0x22AF, 0x22AB, 0x0338},
-{ 0x22EA, 0x22B2, 0x0338},
-{ 0x22EB, 0x22B3, 0x0338},
-{ 0x22EC, 0x22B4, 0x0338},
-{ 0x22ED, 0x22B5, 0x0338},
-{ 0x3094, 0x3046, 0x3099},
-{ 0x304C, 0x304B, 0x3099},
-{ 0x304E, 0x304D, 0x3099},
-{ 0x3050, 0x304F, 0x3099},
-{ 0x3052, 0x3051, 0x3099},
-{ 0x3054, 0x3053, 0x3099},
-{ 0x3056, 0x3055, 0x3099},
-{ 0x3058, 0x3057, 0x3099},
-{ 0x305A, 0x3059, 0x3099},
-{ 0x305C, 0x305B, 0x3099},
-{ 0x305E, 0x305D, 0x3099},
-{ 0x3060, 0x305F, 0x3099},
-{ 0x3062, 0x3061, 0x3099},
-{ 0x3065, 0x3064, 0x3099},
-{ 0x3067, 0x3066, 0x3099},
-{ 0x3069, 0x3068, 0x3099},
-{ 0x3070, 0x306F, 0x3099},
-{ 0x3071, 0x306F, 0x309A},
-{ 0x3073, 0x3072, 0x3099},
-{ 0x3074, 0x3072, 0x309A},
-{ 0x3076, 0x3075, 0x3099},
-{ 0x3077, 0x3075, 0x309A},
-{ 0x3079, 0x3078, 0x3099},
-{ 0x307A, 0x3078, 0x309A},
-{ 0x307C, 0x307B, 0x3099},
-{ 0x307D, 0x307B, 0x309A},
-{ 0x309E, 0x309D, 0x3099},
-{ 0x30F4, 0x30A6, 0x3099},
-{ 0x30AC, 0x30AB, 0x3099},
-{ 0x30AE, 0x30AD, 0x3099},
-{ 0x30B0, 0x30AF, 0x3099},
-{ 0x30B2, 0x30B1, 0x3099},
-{ 0x30B4, 0x30B3, 0x3099},
-{ 0x30B6, 0x30B5, 0x3099},
-{ 0x30B8, 0x30B7, 0x3099},
-{ 0x30BA, 0x30B9, 0x3099},
-{ 0x30BC, 0x30BB, 0x3099},
-{ 0x30BE, 0x30BD, 0x3099},
-{ 0x30C0, 0x30BF, 0x3099},
-{ 0x30C2, 0x30C1, 0x3099},
-{ 0x30C5, 0x30C4, 0x3099},
-{ 0x30C7, 0x30C6, 0x3099},
-{ 0x30C9, 0x30C8, 0x3099},
-{ 0x30D0, 0x30CF, 0x3099},
-{ 0x30D1, 0x30CF, 0x309A},
-{ 0x30D3, 0x30D2, 0x3099},
-{ 0x30D4, 0x30D2, 0x309A},
-{ 0x30D6, 0x30D5, 0x3099},
-{ 0x30D7, 0x30D5, 0x309A},
-{ 0x30D9, 0x30D8, 0x3099},
-{ 0x30DA, 0x30D8, 0x309A},
-{ 0x30DC, 0x30DB, 0x3099},
-{ 0x30DD, 0x30DB, 0x309A},
-{ 0x30F7, 0x30EF, 0x3099},
-{ 0x30F8, 0x30F0, 0x3099},
-{ 0x30F9, 0x30F1, 0x3099},
-{ 0x30FA, 0x30F2, 0x3099},
-{ 0x30FE, 0x30FD, 0x3099},
-{ 0xFB2C, 0xFB49, 0x05C1},
-{ 0xFB2D, 0xFB49, 0x05C2},
-};
-
-static const struct {
-  unsigned int replacement;
-  unsigned int base;
-  unsigned int comb; 
-} decompositions[] = {
-{ 0x00C0, 0x0041, 0x0300},
-{ 0x00C1, 0x0041, 0x0301},
-{ 0x00C2, 0x0041, 0x0302},
-{ 0x00C3, 0x0041, 0x0303},
-{ 0x00C4, 0x0041, 0x0308},
-{ 0x00C5, 0x0041, 0x030A},
-{ 0x00C7, 0x0043, 0x0327},
-{ 0x00C8, 0x0045, 0x0300},
-{ 0x00C9, 0x0045, 0x0301},
-{ 0x00CA, 0x0045, 0x0302},
-{ 0x00CB, 0x0045, 0x0308},
-{ 0x00CC, 0x0049, 0x0300},
-{ 0x00CD, 0x0049, 0x0301},
-{ 0x00CE, 0x0049, 0x0302},
-{ 0x00CF, 0x0049, 0x0308},
-{ 0x00D1, 0x004E, 0x0303},
-{ 0x00D2, 0x004F, 0x0300},
-{ 0x00D3, 0x004F, 0x0301},
-{ 0x00D4, 0x004F, 0x0302},
-{ 0x00D5, 0x004F, 0x0303},
-{ 0x00D6, 0x004F, 0x0308},
-{ 0x00D9, 0x0055, 0x0300},
-{ 0x00DA, 0x0055, 0x0301},
-{ 0x00DB, 0x0055, 0x0302},
-{ 0x00DC, 0x0055, 0x0308},
-{ 0x00DD, 0x0059, 0x0301},
-{ 0x00E0, 0x0061, 0x0300},
-{ 0x00E1, 0x0061, 0x0301},
-{ 0x00E2, 0x0061, 0x0302},
-{ 0x00E3, 0x0061, 0x0303},
-{ 0x00E4, 0x0061, 0x0308},
-{ 0x00E5, 0x0061, 0x030A},
-{ 0x00E7, 0x0063, 0x0327},
-{ 0x00E8, 0x0065, 0x0300},
-{ 0x00E9, 0x0065, 0x0301},
-{ 0x00EA, 0x0065, 0x0302},
-{ 0x00EB, 0x0065, 0x0308},
-{ 0x00EC, 0x0069, 0x0300},
-{ 0x00ED, 0x0069, 0x0301},
-{ 0x00EE, 0x0069, 0x0302},
-{ 0x00EF, 0x0069, 0x0308},
-{ 0x00F1, 0x006E, 0x0303},
-{ 0x00F2, 0x006F, 0x0300},
-{ 0x00F3, 0x006F, 0x0301},
-{ 0x00F4, 0x006F, 0x0302},
-{ 0x00F5, 0x006F, 0x0303},
-{ 0x00F6, 0x006F, 0x0308},
-{ 0x00F9, 0x0075, 0x0300},
-{ 0x00FA, 0x0075, 0x0301},
-{ 0x00FB, 0x0075, 0x0302},
-{ 0x00FC, 0x0075, 0x0308},
-{ 0x00FD, 0x0079, 0x0301},
-{ 0x00FF, 0x0079, 0x0308},
-{ 0x0100, 0x0041, 0x0304},
-{ 0x0101, 0x0061, 0x0304},
-{ 0x0102, 0x0041, 0x0306},
-{ 0x0103, 0x0061, 0x0306},
-{ 0x0104, 0x0041, 0x0328},
-{ 0x0105, 0x0061, 0x0328},
-{ 0x0106, 0x0043, 0x0301},
-{ 0x0107, 0x0063, 0x0301},
-{ 0x0108, 0x0043, 0x0302},
-{ 0x0109, 0x0063, 0x0302},
-{ 0x010A, 0x0043, 0x0307},
-{ 0x010B, 0x0063, 0x0307},
-{ 0x010C, 0x0043, 0x030C},
-{ 0x010D, 0x0063, 0x030C},
-{ 0x010E, 0x0044, 0x030C},
-{ 0x010F, 0x0064, 0x030C},
-{ 0x0112, 0x0045, 0x0304},
-{ 0x0113, 0x0065, 0x0304},
-{ 0x0114, 0x0045, 0x0306},
-{ 0x0115, 0x0065, 0x0306},
-{ 0x0116, 0x0045, 0x0307},
-{ 0x0117, 0x0065, 0x0307},
-{ 0x0118, 0x0045, 0x0328},
-{ 0x0119, 0x0065, 0x0328},
-{ 0x011A, 0x0045, 0x030C},
-{ 0x011B, 0x0065, 0x030C},
-{ 0x011C, 0x0047, 0x0302},
-{ 0x011D, 0x0067, 0x0302},
-{ 0x011E, 0x0047, 0x0306},
-{ 0x011F, 0x0067, 0x0306},
-{ 0x0120, 0x0047, 0x0307},
-{ 0x0121, 0x0067, 0x0307},
-{ 0x0122, 0x0047, 0x0327},
-{ 0x0123, 0x0067, 0x0327},
-{ 0x0124, 0x0048, 0x0302},
-{ 0x0125, 0x0068, 0x0302},
-{ 0x0128, 0x0049, 0x0303},
-{ 0x0129, 0x0069, 0x0303},
-{ 0x012A, 0x0049, 0x0304},
-{ 0x012B, 0x0069, 0x0304},
-{ 0x012C, 0x0049, 0x0306},
-{ 0x012D, 0x0069, 0x0306},
-{ 0x012E, 0x0049, 0x0328},
-{ 0x012F, 0x0069, 0x0328},
-{ 0x0130, 0x0049, 0x0307},
-{ 0x0134, 0x004A, 0x0302},
-{ 0x0135, 0x006A, 0x0302},
-{ 0x0136, 0x004B, 0x0327},
-{ 0x0137, 0x006B, 0x0327},
-{ 0x0139, 0x004C, 0x0301},
-{ 0x013A, 0x006C, 0x0301},
-{ 0x013B, 0x004C, 0x0327},
-{ 0x013C, 0x006C, 0x0327},
-{ 0x013D, 0x004C, 0x030C},
-{ 0x013E, 0x006C, 0x030C},
-{ 0x0143, 0x004E, 0x0301},
-{ 0x0144, 0x006E, 0x0301},
-{ 0x0145, 0x004E, 0x0327},
-{ 0x0146, 0x006E, 0x0327},
-{ 0x0147, 0x004E, 0x030C},
-{ 0x0148, 0x006E, 0x030C},
-{ 0x014C, 0x004F, 0x0304},
-{ 0x014D, 0x006F, 0x0304},
-{ 0x014E, 0x004F, 0x0306},
-{ 0x014F, 0x006F, 0x0306},
-{ 0x0150, 0x004F, 0x030B},
-{ 0x0151, 0x006F, 0x030B},
-{ 0x0154, 0x0052, 0x0301},
-{ 0x0155, 0x0072, 0x0301},
-{ 0x0156, 0x0052, 0x0327},
-{ 0x0157, 0x0072, 0x0327},
-{ 0x0158, 0x0052, 0x030C},
-{ 0x0159, 0x0072, 0x030C},
-{ 0x015A, 0x0053, 0x0301},
-{ 0x015B, 0x0073, 0x0301},
-{ 0x015C, 0x0053, 0x0302},
-{ 0x015D, 0x0073, 0x0302},
-{ 0x015E, 0x0053, 0x0327},
-{ 0x015F, 0x0073, 0x0327},
-{ 0x0160, 0x0053, 0x030C},
-{ 0x0161, 0x0073, 0x030C},
-{ 0x0162, 0x0054, 0x0327},
-{ 0x0163, 0x0074, 0x0327},
-{ 0x0164, 0x0054, 0x030C},
-{ 0x0165, 0x0074, 0x030C},
-{ 0x0168, 0x0055, 0x0303},
-{ 0x0169, 0x0075, 0x0303},
-{ 0x016A, 0x0055, 0x0304},
-{ 0x016B, 0x0075, 0x0304},
-{ 0x016C, 0x0055, 0x0306},
-{ 0x016D, 0x0075, 0x0306},
-{ 0x016E, 0x0055, 0x030A},
-{ 0x016F, 0x0075, 0x030A},
-{ 0x0170, 0x0055, 0x030B},
-{ 0x0171, 0x0075, 0x030B},
-{ 0x0172, 0x0055, 0x0328},
-{ 0x0173, 0x0075, 0x0328},
-{ 0x0174, 0x0057, 0x0302},
-{ 0x0175, 0x0077, 0x0302},
-{ 0x0176, 0x0059, 0x0302},
-{ 0x0177, 0x0079, 0x0302},
-{ 0x0178, 0x0059, 0x0308},
-{ 0x0179, 0x005A, 0x0301},
-{ 0x017A, 0x007A, 0x0301},
-{ 0x017B, 0x005A, 0x0307},
-{ 0x017C, 0x007A, 0x0307},
-{ 0x017D, 0x005A, 0x030C},
-{ 0x017E, 0x007A, 0x030C},
-{ 0x01A0, 0x004F, 0x031B},
-{ 0x01A1, 0x006F, 0x031B},
-{ 0x01AF, 0x0055, 0x031B},
-{ 0x01B0, 0x0075, 0x031B},
-{ 0x01CD, 0x0041, 0x030C},
-{ 0x01CE, 0x0061, 0x030C},
-{ 0x01CF, 0x0049, 0x030C},
-{ 0x01D0, 0x0069, 0x030C},
-{ 0x01D1, 0x004F, 0x030C},
-{ 0x01D2, 0x006F, 0x030C},
-{ 0x01D3, 0x0055, 0x030C},
-{ 0x01D4, 0x0075, 0x030C},
-{ 0x01D5, 0x00DC, 0x0304},
-{ 0x01D6, 0x00FC, 0x0304},
-{ 0x01D7, 0x00DC, 0x0301},
-{ 0x01D8, 0x00FC, 0x0301},
-{ 0x01D9, 0x00DC, 0x030C},
-{ 0x01DA, 0x00FC, 0x030C},
-{ 0x01DB, 0x00DC, 0x0300},
-{ 0x01DC, 0x00FC, 0x0300},
-{ 0x01DE, 0x00C4, 0x0304},
-{ 0x01DF, 0x00E4, 0x0304},
-{ 0x01E0, 0x0226, 0x0304},
-{ 0x01E1, 0x0227, 0x0304},
-{ 0x01E2, 0x00C6, 0x0304},
-{ 0x01E3, 0x00E6, 0x0304},
-{ 0x01E6, 0x0047, 0x030C},
-{ 0x01E7, 0x0067, 0x030C},
-{ 0x01E8, 0x004B, 0x030C},
-{ 0x01E9, 0x006B, 0x030C},
-{ 0x01EA, 0x004F, 0x0328},
-{ 0x01EB, 0x006F, 0x0328},
-{ 0x01EC, 0x01EA, 0x0304},
-{ 0x01ED, 0x01EB, 0x0304},
-{ 0x01EE, 0x01B7, 0x030C},
-{ 0x01EF, 0x0292, 0x030C},
-{ 0x01F0, 0x006A, 0x030C},
-{ 0x01F4, 0x0047, 0x0301},
-{ 0x01F5, 0x0067, 0x0301},
-{ 0x01F8, 0x004E, 0x0300},
-{ 0x01F9, 0x006E, 0x0300},
-{ 0x01FA, 0x00C5, 0x0301},
-{ 0x01FB, 0x00E5, 0x0301},
-{ 0x01FC, 0x00C6, 0x0301},
-{ 0x01FD, 0x00E6, 0x0301},
-{ 0x01FE, 0x00D8, 0x0301},
-{ 0x01FF, 0x00F8, 0x0301},
-{ 0x0200, 0x0041, 0x030F},
-{ 0x0201, 0x0061, 0x030F},
-{ 0x0202, 0x0041, 0x0311},
-{ 0x0203, 0x0061, 0x0311},
-{ 0x0204, 0x0045, 0x030F},
-{ 0x0205, 0x0065, 0x030F},
-{ 0x0206, 0x0045, 0x0311},
-{ 0x0207, 0x0065, 0x0311},
-{ 0x0208, 0x0049, 0x030F},
-{ 0x0209, 0x0069, 0x030F},
-{ 0x020A, 0x0049, 0x0311},
-{ 0x020B, 0x0069, 0x0311},
-{ 0x020C, 0x004F, 0x030F},
-{ 0x020D, 0x006F, 0x030F},
-{ 0x020E, 0x004F, 0x0311},
-{ 0x020F, 0x006F, 0x0311},
-{ 0x0210, 0x0052, 0x030F},
-{ 0x0211, 0x0072, 0x030F},
-{ 0x0212, 0x0052, 0x0311},
-{ 0x0213, 0x0072, 0x0311},
-{ 0x0214, 0x0055, 0x030F},
-{ 0x0215, 0x0075, 0x030F},
-{ 0x0216, 0x0055, 0x0311},
-{ 0x0217, 0x0075, 0x0311},
-{ 0x0218, 0x0053, 0x0326},
-{ 0x0219, 0x0073, 0x0326},
-{ 0x021A, 0x0054, 0x0326},
-{ 0x021B, 0x0074, 0x0326},
-{ 0x021E, 0x0048, 0x030C},
-{ 0x021F, 0x0068, 0x030C},
-{ 0x0226, 0x0041, 0x0307},
-{ 0x0227, 0x0061, 0x0307},
-{ 0x0228, 0x0045, 0x0327},
-{ 0x0229, 0x0065, 0x0327},
-{ 0x022A, 0x00D6, 0x0304},
-{ 0x022B, 0x00F6, 0x0304},
-{ 0x022C, 0x00D5, 0x0304},
-{ 0x022D, 0x00F5, 0x0304},
-{ 0x022E, 0x004F, 0x0307},
-{ 0x022F, 0x006F, 0x0307},
-{ 0x0230, 0x022E, 0x0304},
-{ 0x0231, 0x022F, 0x0304},
-{ 0x0232, 0x0059, 0x0304},
-{ 0x0233, 0x0079, 0x0304},
-{ 0x0344, 0x0308, 0x0301},
-{ 0x0385, 0x00A8, 0x0301},
-{ 0x0386, 0x0391, 0x0301},
-{ 0x0388, 0x0395, 0x0301},
-{ 0x0389, 0x0397, 0x0301},
-{ 0x038A, 0x0399, 0x0301},
-{ 0x038C, 0x039F, 0x0301},
-{ 0x038E, 0x03A5, 0x0301},
-{ 0x038F, 0x03A9, 0x0301},
-{ 0x0390, 0x03CA, 0x0301},
-{ 0x03AA, 0x0399, 0x0308},
-{ 0x03AB, 0x03A5, 0x0308},
-{ 0x03AC, 0x03B1, 0x0301},
-{ 0x03AD, 0x03B5, 0x0301},
-{ 0x03AE, 0x03B7, 0x0301},
-{ 0x03AF, 0x03B9, 0x0301},
-{ 0x03B0, 0x03CB, 0x0301},
-{ 0x03CA, 0x03B9, 0x0308},
-{ 0x03CB, 0x03C5, 0x0308},
-{ 0x03CC, 0x03BF, 0x0301},
-{ 0x03CD, 0x03C5, 0x0301},
-{ 0x03CE, 0x03C9, 0x0301},
-{ 0x03D3, 0x03D2, 0x0301},
-{ 0x03D4, 0x03D2, 0x0308},
-{ 0x0400, 0x0415, 0x0300},
-{ 0x0401, 0x0415, 0x0308},
-{ 0x0403, 0x0413, 0x0301},
-{ 0x0407, 0x0406, 0x0308},
-{ 0x040C, 0x041A, 0x0301},
-{ 0x040D, 0x0418, 0x0300},
-{ 0x040E, 0x0423, 0x0306},
-{ 0x0419, 0x0418, 0x0306},
-{ 0x0439, 0x0438, 0x0306},
-{ 0x0450, 0x0435, 0x0300},
-{ 0x0451, 0x0435, 0x0308},
-{ 0x0453, 0x0433, 0x0301},
-{ 0x0457, 0x0456, 0x0308},
-{ 0x045C, 0x043A, 0x0301},
-{ 0x045D, 0x0438, 0x0300},
-{ 0x045E, 0x0443, 0x0306},
-{ 0x0476, 0x0474, 0x030F},
-{ 0x0477, 0x0475, 0x030F},
-{ 0x04C1, 0x0416, 0x0306},
-{ 0x04C2, 0x0436, 0x0306},
-{ 0x04D0, 0x0410, 0x0306},
-{ 0x04D1, 0x0430, 0x0306},
-{ 0x04D2, 0x0410, 0x0308},
-{ 0x04D3, 0x0430, 0x0308},
-{ 0x04D6, 0x0415, 0x0306},
-{ 0x04D7, 0x0435, 0x0306},
-{ 0x04DA, 0x04D8, 0x0308},
-{ 0x04DB, 0x04D9, 0x0308},
-{ 0x04DC, 0x0416, 0x0308},
-{ 0x04DD, 0x0436, 0x0308},
-{ 0x04DE, 0x0417, 0x0308},
-{ 0x04DF, 0x0437, 0x0308},
-{ 0x04E2, 0x0418, 0x0304},
-{ 0x04E3, 0x0438, 0x0304},
-{ 0x04E4, 0x0418, 0x0308},
-{ 0x04E5, 0x0438, 0x0308},
-{ 0x04E6, 0x041E, 0x0308},
-{ 0x04E7, 0x043E, 0x0308},
-{ 0x04EA, 0x04E8, 0x0308},
-{ 0x04EB, 0x04E9, 0x0308},
-{ 0x04EC, 0x042D, 0x0308},
-{ 0x04ED, 0x044D, 0x0308},
-{ 0x04EE, 0x0423, 0x0304},
-{ 0x04EF, 0x0443, 0x0304},
-{ 0x04F0, 0x0423, 0x0308},
-{ 0x04F1, 0x0443, 0x0308},
-{ 0x04F2, 0x0423, 0x030B},
-{ 0x04F3, 0x0443, 0x030B},
-{ 0x04F4, 0x0427, 0x0308},
-{ 0x04F5, 0x0447, 0x0308},
-{ 0x04F8, 0x042B, 0x0308},
-{ 0x04F9, 0x044B, 0x0308},
-{ 0x0622, 0x0627, 0x0653},
-{ 0x0623, 0x0627, 0x0654},
-{ 0x0624, 0x0648, 0x0654},
-{ 0x0625, 0x0627, 0x0655},
-{ 0x0626, 0x064A, 0x0654},
-{ 0x06C0, 0x06D5, 0x0654},
-{ 0x06C2, 0x06C1, 0x0654},
-{ 0x06D3, 0x06D2, 0x0654},
-{ 0x0929, 0x0928, 0x093C},
-{ 0x0931, 0x0930, 0x093C},
-{ 0x0934, 0x0933, 0x093C},
-{ 0x0958, 0x0915, 0x093C},
-{ 0x0959, 0x0916, 0x093C},
-{ 0x095A, 0x0917, 0x093C},
-{ 0x095B, 0x091C, 0x093C},
-{ 0x095C, 0x0921, 0x093C},
-{ 0x095D, 0x0922, 0x093C},
-{ 0x095E, 0x092B, 0x093C},
-{ 0x095F, 0x092F, 0x093C},
-{ 0x09CB, 0x09C7, 0x09BE},
-{ 0x09CC, 0x09C7, 0x09D7},
-{ 0x09DC, 0x09A1, 0x09BC},
-{ 0x09DD, 0x09A2, 0x09BC},
-{ 0x09DF, 0x09AF, 0x09BC},
-{ 0x0A33, 0x0A32, 0x0A3C},
-{ 0x0A36, 0x0A38, 0x0A3C},
-{ 0x0A59, 0x0A16, 0x0A3C},
-{ 0x0A5A, 0x0A17, 0x0A3C},
-{ 0x0A5B, 0x0A1C, 0x0A3C},
-{ 0x0A5E, 0x0A2B, 0x0A3C},
-{ 0x0B48, 0x0B47, 0x0B56},
-{ 0x0B4B, 0x0B47, 0x0B3E},
-{ 0x0B4C, 0x0B47, 0x0B57},
-{ 0x0B5C, 0x0B21, 0x0B3C},
-{ 0x0B5D, 0x0B22, 0x0B3C},
-{ 0x0B94, 0x0B92, 0x0BD7},
-{ 0x0BCA, 0x0BC6, 0x0BBE},
-{ 0x0BCB, 0x0BC7, 0x0BBE},
-{ 0x0BCC, 0x0BC6, 0x0BD7},
-{ 0x0C48, 0x0C46, 0x0C56},
-{ 0x0CC0, 0x0CBF, 0x0CD5},
-{ 0x0CC7, 0x0CC6, 0x0CD5},
-{ 0x0CC8, 0x0CC6, 0x0CD6},
-{ 0x0CCA, 0x0CC6, 0x0CC2},
-{ 0x0CCB, 0x0CCA, 0x0CD5},
-{ 0x0D4A, 0x0D46, 0x0D3E},
-{ 0x0D4B, 0x0D47, 0x0D3E},
-{ 0x0D4C, 0x0D46, 0x0D57},
-{ 0x0DDA, 0x0DD9, 0x0DCA},
-{ 0x0DDC, 0x0DD9, 0x0DCF},
-{ 0x0DDD, 0x0DDC, 0x0DCA},
-{ 0x0DDE, 0x0DD9, 0x0DDF},
-{ 0x0F43, 0x0F42, 0x0FB7},
-{ 0x0F4D, 0x0F4C, 0x0FB7},
-{ 0x0F52, 0x0F51, 0x0FB7},
-{ 0x0F57, 0x0F56, 0x0FB7},
-{ 0x0F5C, 0x0F5B, 0x0FB7},
-{ 0x0F69, 0x0F40, 0x0FB5},
-{ 0x0F73, 0x0F71, 0x0F72},
-{ 0x0F75, 0x0F71, 0x0F74},
-{ 0x0F76, 0x0FB2, 0x0F80},
-{ 0x0F78, 0x0FB3, 0x0F80},
-{ 0x0F81, 0x0F71, 0x0F80},
-{ 0x0F93, 0x0F92, 0x0FB7},
-{ 0x0F9D, 0x0F9C, 0x0FB7},
-{ 0x0FA2, 0x0FA1, 0x0FB7},
-{ 0x0FA7, 0x0FA6, 0x0FB7},
-{ 0x0FAC, 0x0FAB, 0x0FB7},
-{ 0x0FB9, 0x0F90, 0x0FB5},
-{ 0x1026, 0x1025, 0x102E},
-{ 0x1E00, 0x0041, 0x0325},
-{ 0x1E01, 0x0061, 0x0325},
-{ 0x1E02, 0x0042, 0x0307},
-{ 0x1E03, 0x0062, 0x0307},
-{ 0x1E04, 0x0042, 0x0323},
-{ 0x1E05, 0x0062, 0x0323},
-{ 0x1E06, 0x0042, 0x0331},
-{ 0x1E07, 0x0062, 0x0331},
-{ 0x1E08, 0x00C7, 0x0301},
-{ 0x1E09, 0x00E7, 0x0301},
-{ 0x1E0A, 0x0044, 0x0307},
-{ 0x1E0B, 0x0064, 0x0307},
-{ 0x1E0C, 0x0044, 0x0323},
-{ 0x1E0D, 0x0064, 0x0323},
-{ 0x1E0E, 0x0044, 0x0331},
-{ 0x1E0F, 0x0064, 0x0331},
-{ 0x1E10, 0x0044, 0x0327},
-{ 0x1E11, 0x0064, 0x0327},
-{ 0x1E12, 0x0044, 0x032D},
-{ 0x1E13, 0x0064, 0x032D},
-{ 0x1E14, 0x0112, 0x0300},
-{ 0x1E15, 0x0113, 0x0300},
-{ 0x1E16, 0x0112, 0x0301},
-{ 0x1E17, 0x0113, 0x0301},
-{ 0x1E18, 0x0045, 0x032D},
-{ 0x1E19, 0x0065, 0x032D},
-{ 0x1E1A, 0x0045, 0x0330},
-{ 0x1E1B, 0x0065, 0x0330},
-{ 0x1E1C, 0x0228, 0x0306},
-{ 0x1E1D, 0x0229, 0x0306},
-{ 0x1E1E, 0x0046, 0x0307},
-{ 0x1E1F, 0x0066, 0x0307},
-{ 0x1E20, 0x0047, 0x0304},
-{ 0x1E21, 0x0067, 0x0304},
-{ 0x1E22, 0x0048, 0x0307},
-{ 0x1E23, 0x0068, 0x0307},
-{ 0x1E24, 0x0048, 0x0323},
-{ 0x1E25, 0x0068, 0x0323},
-{ 0x1E26, 0x0048, 0x0308},
-{ 0x1E27, 0x0068, 0x0308},
-{ 0x1E28, 0x0048, 0x0327},
-{ 0x1E29, 0x0068, 0x0327},
-{ 0x1E2A, 0x0048, 0x032E},
-{ 0x1E2B, 0x0068, 0x032E},
-{ 0x1E2C, 0x0049, 0x0330},
-{ 0x1E2D, 0x0069, 0x0330},
-{ 0x1E2E, 0x00CF, 0x0301},
-{ 0x1E2F, 0x00EF, 0x0301},
-{ 0x1E30, 0x004B, 0x0301},
-{ 0x1E31, 0x006B, 0x0301},
-{ 0x1E32, 0x004B, 0x0323},
-{ 0x1E33, 0x006B, 0x0323},
-{ 0x1E34, 0x004B, 0x0331},
-{ 0x1E35, 0x006B, 0x0331},
-{ 0x1E36, 0x004C, 0x0323},
-{ 0x1E37, 0x006C, 0x0323},
-{ 0x1E38, 0x1E36, 0x0304},
-{ 0x1E39, 0x1E37, 0x0304},
-{ 0x1E3A, 0x004C, 0x0331},
-{ 0x1E3B, 0x006C, 0x0331},
-{ 0x1E3C, 0x004C, 0x032D},
-{ 0x1E3D, 0x006C, 0x032D},
-{ 0x1E3E, 0x004D, 0x0301},
-{ 0x1E3F, 0x006D, 0x0301},
-{ 0x1E40, 0x004D, 0x0307},
-{ 0x1E41, 0x006D, 0x0307},
-{ 0x1E42, 0x004D, 0x0323},
-{ 0x1E43, 0x006D, 0x0323},
-{ 0x1E44, 0x004E, 0x0307},
-{ 0x1E45, 0x006E, 0x0307},
-{ 0x1E46, 0x004E, 0x0323},
-{ 0x1E47, 0x006E, 0x0323},
-{ 0x1E48, 0x004E, 0x0331},
-{ 0x1E49, 0x006E, 0x0331},
-{ 0x1E4A, 0x004E, 0x032D},
-{ 0x1E4B, 0x006E, 0x032D},
-{ 0x1E4C, 0x00D5, 0x0301},
-{ 0x1E4D, 0x00F5, 0x0301},
-{ 0x1E4E, 0x00D5, 0x0308},
-{ 0x1E4F, 0x00F5, 0x0308},
-{ 0x1E50, 0x014C, 0x0300},
-{ 0x1E51, 0x014D, 0x0300},
-{ 0x1E52, 0x014C, 0x0301},
-{ 0x1E53, 0x014D, 0x0301},
-{ 0x1E54, 0x0050, 0x0301},
-{ 0x1E55, 0x0070, 0x0301},
-{ 0x1E56, 0x0050, 0x0307},
-{ 0x1E57, 0x0070, 0x0307},
-{ 0x1E58, 0x0052, 0x0307},
-{ 0x1E59, 0x0072, 0x0307},
-{ 0x1E5A, 0x0052, 0x0323},
-{ 0x1E5B, 0x0072, 0x0323},
-{ 0x1E5C, 0x1E5A, 0x0304},
-{ 0x1E5D, 0x1E5B, 0x0304},
-{ 0x1E5E, 0x0052, 0x0331},
-{ 0x1E5F, 0x0072, 0x0331},
-{ 0x1E60, 0x0053, 0x0307},
-{ 0x1E61, 0x0073, 0x0307},
-{ 0x1E62, 0x0053, 0x0323},
-{ 0x1E63, 0x0073, 0x0323},
-{ 0x1E64, 0x015A, 0x0307},
-{ 0x1E65, 0x015B, 0x0307},
-{ 0x1E66, 0x0160, 0x0307},
-{ 0x1E67, 0x0161, 0x0307},
-{ 0x1E68, 0x1E62, 0x0307},
-{ 0x1E69, 0x1E63, 0x0307},
-{ 0x1E6A, 0x0054, 0x0307},
-{ 0x1E6B, 0x0074, 0x0307},
-{ 0x1E6C, 0x0054, 0x0323},
-{ 0x1E6D, 0x0074, 0x0323},
-{ 0x1E6E, 0x0054, 0x0331},
-{ 0x1E6F, 0x0074, 0x0331},
-{ 0x1E70, 0x0054, 0x032D},
-{ 0x1E71, 0x0074, 0x032D},
-{ 0x1E72, 0x0055, 0x0324},
-{ 0x1E73, 0x0075, 0x0324},
-{ 0x1E74, 0x0055, 0x0330},
-{ 0x1E75, 0x0075, 0x0330},
-{ 0x1E76, 0x0055, 0x032D},
-{ 0x1E77, 0x0075, 0x032D},
-{ 0x1E78, 0x0168, 0x0301},
-{ 0x1E79, 0x0169, 0x0301},
-{ 0x1E7A, 0x016A, 0x0308},
-{ 0x1E7B, 0x016B, 0x0308},
-{ 0x1E7C, 0x0056, 0x0303},
-{ 0x1E7D, 0x0076, 0x0303},
-{ 0x1E7E, 0x0056, 0x0323},
-{ 0x1E7F, 0x0076, 0x0323},
-{ 0x1E80, 0x0057, 0x0300},
-{ 0x1E81, 0x0077, 0x0300},
-{ 0x1E82, 0x0057, 0x0301},
-{ 0x1E83, 0x0077, 0x0301},
-{ 0x1E84, 0x0057, 0x0308},
-{ 0x1E85, 0x0077, 0x0308},
-{ 0x1E86, 0x0057, 0x0307},
-{ 0x1E87, 0x0077, 0x0307},
-{ 0x1E88, 0x0057, 0x0323},
-{ 0x1E89, 0x0077, 0x0323},
-{ 0x1E8A, 0x0058, 0x0307},
-{ 0x1E8B, 0x0078, 0x0307},
-{ 0x1E8C, 0x0058, 0x0308},
-{ 0x1E8D, 0x0078, 0x0308},
-{ 0x1E8E, 0x0059, 0x0307},
-{ 0x1E8F, 0x0079, 0x0307},
-{ 0x1E90, 0x005A, 0x0302},
-{ 0x1E91, 0x007A, 0x0302},
-{ 0x1E92, 0x005A, 0x0323},
-{ 0x1E93, 0x007A, 0x0323},
-{ 0x1E94, 0x005A, 0x0331},
-{ 0x1E95, 0x007A, 0x0331},
-{ 0x1E96, 0x0068, 0x0331},
-{ 0x1E97, 0x0074, 0x0308},
-{ 0x1E98, 0x0077, 0x030A},
-{ 0x1E99, 0x0079, 0x030A},
-{ 0x1E9B, 0x017F, 0x0307},
-{ 0x1EA0, 0x0041, 0x0323},
-{ 0x1EA1, 0x0061, 0x0323},
-{ 0x1EA2, 0x0041, 0x0309},
-{ 0x1EA3, 0x0061, 0x0309},
-{ 0x1EA4, 0x00C2, 0x0301},
-{ 0x1EA5, 0x00E2, 0x0301},
-{ 0x1EA6, 0x00C2, 0x0300},
-{ 0x1EA7, 0x00E2, 0x0300},
-{ 0x1EA8, 0x00C2, 0x0309},
-{ 0x1EA9, 0x00E2, 0x0309},
-{ 0x1EAA, 0x00C2, 0x0303},
-{ 0x1EAB, 0x00E2, 0x0303},
-{ 0x1EAC, 0x1EA0, 0x0302},
-{ 0x1EAD, 0x1EA1, 0x0302},
-{ 0x1EAE, 0x0102, 0x0301},
-{ 0x1EAF, 0x0103, 0x0301},
-{ 0x1EB0, 0x0102, 0x0300},
-{ 0x1EB1, 0x0103, 0x0300},
-{ 0x1EB2, 0x0102, 0x0309},
-{ 0x1EB3, 0x0103, 0x0309},
-{ 0x1EB4, 0x0102, 0x0303},
-{ 0x1EB5, 0x0103, 0x0303},
-{ 0x1EB6, 0x1EA0, 0x0306},
-{ 0x1EB7, 0x1EA1, 0x0306},
-{ 0x1EB8, 0x0045, 0x0323},
-{ 0x1EB9, 0x0065, 0x0323},
-{ 0x1EBA, 0x0045, 0x0309},
-{ 0x1EBB, 0x0065, 0x0309},
-{ 0x1EBC, 0x0045, 0x0303},
-{ 0x1EBD, 0x0065, 0x0303},
-{ 0x1EBE, 0x00CA, 0x0301},
-{ 0x1EBF, 0x00EA, 0x0301},
-{ 0x1EC0, 0x00CA, 0x0300},
-{ 0x1EC1, 0x00EA, 0x0300},
-{ 0x1EC2, 0x00CA, 0x0309},
-{ 0x1EC3, 0x00EA, 0x0309},
-{ 0x1EC4, 0x00CA, 0x0303},
-{ 0x1EC5, 0x00EA, 0x0303},
-{ 0x1EC6, 0x1EB8, 0x0302},
-{ 0x1EC7, 0x1EB9, 0x0302},
-{ 0x1EC8, 0x0049, 0x0309},
-{ 0x1EC9, 0x0069, 0x0309},
-{ 0x1ECA, 0x0049, 0x0323},
-{ 0x1ECB, 0x0069, 0x0323},
-{ 0x1ECC, 0x004F, 0x0323},
-{ 0x1ECD, 0x006F, 0x0323},
-{ 0x1ECE, 0x004F, 0x0309},
-{ 0x1ECF, 0x006F, 0x0309},
-{ 0x1ED0, 0x00D4, 0x0301},
-{ 0x1ED1, 0x00F4, 0x0301},
-{ 0x1ED2, 0x00D4, 0x0300},
-{ 0x1ED3, 0x00F4, 0x0300},
-{ 0x1ED4, 0x00D4, 0x0309},
-{ 0x1ED5, 0x00F4, 0x0309},
-{ 0x1ED6, 0x00D4, 0x0303},
-{ 0x1ED7, 0x00F4, 0x0303},
-{ 0x1ED8, 0x1ECC, 0x0302},
-{ 0x1ED9, 0x1ECD, 0x0302},
-{ 0x1EDA, 0x01A0, 0x0301},
-{ 0x1EDB, 0x01A1, 0x0301},
-{ 0x1EDC, 0x01A0, 0x0300},
-{ 0x1EDD, 0x01A1, 0x0300},
-{ 0x1EDE, 0x01A0, 0x0309},
-{ 0x1EDF, 0x01A1, 0x0309},
-{ 0x1EE0, 0x01A0, 0x0303},
-{ 0x1EE1, 0x01A1, 0x0303},
-{ 0x1EE2, 0x01A0, 0x0323},
-{ 0x1EE3, 0x01A1, 0x0323},
-{ 0x1EE4, 0x0055, 0x0323},
-{ 0x1EE5, 0x0075, 0x0323},
-{ 0x1EE6, 0x0055, 0x0309},
-{ 0x1EE7, 0x0075, 0x0309},
-{ 0x1EE8, 0x01AF, 0x0301},
-{ 0x1EE9, 0x01B0, 0x0301},
-{ 0x1EEA, 0x01AF, 0x0300},
-{ 0x1EEB, 0x01B0, 0x0300},
-{ 0x1EEC, 0x01AF, 0x0309},
-{ 0x1EED, 0x01B0, 0x0309},
-{ 0x1EEE, 0x01AF, 0x0303},
-{ 0x1EEF, 0x01B0, 0x0303},
-{ 0x1EF0, 0x01AF, 0x0323},
-{ 0x1EF1, 0x01B0, 0x0323},
-{ 0x1EF2, 0x0059, 0x0300},
-{ 0x1EF3, 0x0079, 0x0300},
-{ 0x1EF4, 0x0059, 0x0323},
-{ 0x1EF5, 0x0079, 0x0323},
-{ 0x1EF6, 0x0059, 0x0309},
-{ 0x1EF7, 0x0079, 0x0309},
-{ 0x1EF8, 0x0059, 0x0303},
-{ 0x1EF9, 0x0079, 0x0303},
-{ 0x1F00, 0x03B1, 0x0313},
-{ 0x1F01, 0x03B1, 0x0314},
-{ 0x1F02, 0x1F00, 0x0300},
-{ 0x1F03, 0x1F01, 0x0300},
-{ 0x1F04, 0x1F00, 0x0301},
-{ 0x1F05, 0x1F01, 0x0301},
-{ 0x1F06, 0x1F00, 0x0342},
-{ 0x1F07, 0x1F01, 0x0342},
-{ 0x1F08, 0x0391, 0x0313},
-{ 0x1F09, 0x0391, 0x0314},
-{ 0x1F0A, 0x1F08, 0x0300},
-{ 0x1F0B, 0x1F09, 0x0300},
-{ 0x1F0C, 0x1F08, 0x0301},
-{ 0x1F0D, 0x1F09, 0x0301},
-{ 0x1F0E, 0x1F08, 0x0342},
-{ 0x1F0F, 0x1F09, 0x0342},
-{ 0x1F10, 0x03B5, 0x0313},
-{ 0x1F11, 0x03B5, 0x0314},
-{ 0x1F12, 0x1F10, 0x0300},
-{ 0x1F13, 0x1F11, 0x0300},
-{ 0x1F14, 0x1F10, 0x0301},
-{ 0x1F15, 0x1F11, 0x0301},
-{ 0x1F18, 0x0395, 0x0313},
-{ 0x1F19, 0x0395, 0x0314},
-{ 0x1F1A, 0x1F18, 0x0300},
-{ 0x1F1B, 0x1F19, 0x0300},
-{ 0x1F1C, 0x1F18, 0x0301},
-{ 0x1F1D, 0x1F19, 0x0301},
-{ 0x1F20, 0x03B7, 0x0313},
-{ 0x1F21, 0x03B7, 0x0314},
-{ 0x1F22, 0x1F20, 0x0300},
-{ 0x1F23, 0x1F21, 0x0300},
-{ 0x1F24, 0x1F20, 0x0301},
-{ 0x1F25, 0x1F21, 0x0301},
-{ 0x1F26, 0x1F20, 0x0342},
-{ 0x1F27, 0x1F21, 0x0342},
-{ 0x1F28, 0x0397, 0x0313},
-{ 0x1F29, 0x0397, 0x0314},
-{ 0x1F2A, 0x1F28, 0x0300},
-{ 0x1F2B, 0x1F29, 0x0300},
-{ 0x1F2C, 0x1F28, 0x0301},
-{ 0x1F2D, 0x1F29, 0x0301},
-{ 0x1F2E, 0x1F28, 0x0342},
-{ 0x1F2F, 0x1F29, 0x0342},
-{ 0x1F30, 0x03B9, 0x0313},
-{ 0x1F31, 0x03B9, 0x0314},
-{ 0x1F32, 0x1F30, 0x0300},
-{ 0x1F33, 0x1F31, 0x0300},
-{ 0x1F34, 0x1F30, 0x0301},
-{ 0x1F35, 0x1F31, 0x0301},
-{ 0x1F36, 0x1F30, 0x0342},
-{ 0x1F37, 0x1F31, 0x0342},
-{ 0x1F38, 0x0399, 0x0313},
-{ 0x1F39, 0x0399, 0x0314},
-{ 0x1F3A, 0x1F38, 0x0300},
-{ 0x1F3B, 0x1F39, 0x0300},
-{ 0x1F3C, 0x1F38, 0x0301},
-{ 0x1F3D, 0x1F39, 0x0301},
-{ 0x1F3E, 0x1F38, 0x0342},
-{ 0x1F3F, 0x1F39, 0x0342},
-{ 0x1F40, 0x03BF, 0x0313},
-{ 0x1F41, 0x03BF, 0x0314},
-{ 0x1F42, 0x1F40, 0x0300},
-{ 0x1F43, 0x1F41, 0x0300},
-{ 0x1F44, 0x1F40, 0x0301},
-{ 0x1F45, 0x1F41, 0x0301},
-{ 0x1F48, 0x039F, 0x0313},
-{ 0x1F49, 0x039F, 0x0314},
-{ 0x1F4A, 0x1F48, 0x0300},
-{ 0x1F4B, 0x1F49, 0x0300},
-{ 0x1F4C, 0x1F48, 0x0301},
-{ 0x1F4D, 0x1F49, 0x0301},
-{ 0x1F50, 0x03C5, 0x0313},
-{ 0x1F51, 0x03C5, 0x0314},
-{ 0x1F52, 0x1F50, 0x0300},
-{ 0x1F53, 0x1F51, 0x0300},
-{ 0x1F54, 0x1F50, 0x0301},
-{ 0x1F55, 0x1F51, 0x0301},
-{ 0x1F56, 0x1F50, 0x0342},
-{ 0x1F57, 0x1F51, 0x0342},
-{ 0x1F59, 0x03A5, 0x0314},
-{ 0x1F5B, 0x1F59, 0x0300},
-{ 0x1F5D, 0x1F59, 0x0301},
-{ 0x1F5F, 0x1F59, 0x0342},
-{ 0x1F60, 0x03C9, 0x0313},
-{ 0x1F61, 0x03C9, 0x0314},
-{ 0x1F62, 0x1F60, 0x0300},
-{ 0x1F63, 0x1F61, 0x0300},
-{ 0x1F64, 0x1F60, 0x0301},
-{ 0x1F65, 0x1F61, 0x0301},
-{ 0x1F66, 0x1F60, 0x0342},
-{ 0x1F67, 0x1F61, 0x0342},
-{ 0x1F68, 0x03A9, 0x0313},
-{ 0x1F69, 0x03A9, 0x0314},
-{ 0x1F6A, 0x1F68, 0x0300},
-{ 0x1F6B, 0x1F69, 0x0300},
-{ 0x1F6C, 0x1F68, 0x0301},
-{ 0x1F6D, 0x1F69, 0x0301},
-{ 0x1F6E, 0x1F68, 0x0342},
-{ 0x1F6F, 0x1F69, 0x0342},
-{ 0x1F70, 0x03B1, 0x0300},
-{ 0x1F72, 0x03B5, 0x0300},
-{ 0x1F74, 0x03B7, 0x0300},
-{ 0x1F76, 0x03B9, 0x0300},
-{ 0x1F78, 0x03BF, 0x0300},
-{ 0x1F7A, 0x03C5, 0x0300},
-{ 0x1F7C, 0x03C9, 0x0300},
-{ 0x1F80, 0x1F00, 0x0345},
-{ 0x1F81, 0x1F01, 0x0345},
-{ 0x1F82, 0x1F02, 0x0345},
-{ 0x1F83, 0x1F03, 0x0345},
-{ 0x1F84, 0x1F04, 0x0345},
-{ 0x1F85, 0x1F05, 0x0345},
-{ 0x1F86, 0x1F06, 0x0345},
-{ 0x1F87, 0x1F07, 0x0345},
-{ 0x1F88, 0x1F08, 0x0345},
-{ 0x1F89, 0x1F09, 0x0345},
-{ 0x1F8A, 0x1F0A, 0x0345},
-{ 0x1F8B, 0x1F0B, 0x0345},
-{ 0x1F8C, 0x1F0C, 0x0345},
-{ 0x1F8D, 0x1F0D, 0x0345},
-{ 0x1F8E, 0x1F0E, 0x0345},
-{ 0x1F8F, 0x1F0F, 0x0345},
-{ 0x1F90, 0x1F20, 0x0345},
-{ 0x1F91, 0x1F21, 0x0345},
-{ 0x1F92, 0x1F22, 0x0345},
-{ 0x1F93, 0x1F23, 0x0345},
-{ 0x1F94, 0x1F24, 0x0345},
-{ 0x1F95, 0x1F25, 0x0345},
-{ 0x1F96, 0x1F26, 0x0345},
-{ 0x1F97, 0x1F27, 0x0345},
-{ 0x1F98, 0x1F28, 0x0345},
-{ 0x1F99, 0x1F29, 0x0345},
-{ 0x1F9A, 0x1F2A, 0x0345},
-{ 0x1F9B, 0x1F2B, 0x0345},
-{ 0x1F9C, 0x1F2C, 0x0345},
-{ 0x1F9D, 0x1F2D, 0x0345},
-{ 0x1F9E, 0x1F2E, 0x0345},
-{ 0x1F9F, 0x1F2F, 0x0345},
-{ 0x1FA0, 0x1F60, 0x0345},
-{ 0x1FA1, 0x1F61, 0x0345},
-{ 0x1FA2, 0x1F62, 0x0345},
-{ 0x1FA3, 0x1F63, 0x0345},
-{ 0x1FA4, 0x1F64, 0x0345},
-{ 0x1FA5, 0x1F65, 0x0345},
-{ 0x1FA6, 0x1F66, 0x0345},
-{ 0x1FA7, 0x1F67, 0x0345},
-{ 0x1FA8, 0x1F68, 0x0345},
-{ 0x1FA9, 0x1F69, 0x0345},
-{ 0x1FAA, 0x1F6A, 0x0345},
-{ 0x1FAB, 0x1F6B, 0x0345},
-{ 0x1FAC, 0x1F6C, 0x0345},
-{ 0x1FAD, 0x1F6D, 0x0345},
-{ 0x1FAE, 0x1F6E, 0x0345},
-{ 0x1FAF, 0x1F6F, 0x0345},
-{ 0x1FB0, 0x03B1, 0x0306},
-{ 0x1FB1, 0x03B1, 0x0304},
-{ 0x1FB2, 0x1F70, 0x0345},
-{ 0x1FB3, 0x03B1, 0x0345},
-{ 0x1FB4, 0x03AC, 0x0345},
-{ 0x1FB6, 0x03B1, 0x0342},
-{ 0x1FB7, 0x1FB6, 0x0345},
-{ 0x1FB8, 0x0391, 0x0306},
-{ 0x1FB9, 0x0391, 0x0304},
-{ 0x1FBA, 0x0391, 0x0300},
-{ 0x1FBC, 0x0391, 0x0345},
-{ 0x1FC1, 0x00A8, 0x0342},
-{ 0x1FC2, 0x1F74, 0x0345},
-{ 0x1FC3, 0x03B7, 0x0345},
-{ 0x1FC4, 0x03AE, 0x0345},
-{ 0x1FC6, 0x03B7, 0x0342},
-{ 0x1FC7, 0x1FC6, 0x0345},
-{ 0x1FC8, 0x0395, 0x0300},
-{ 0x1FCA, 0x0397, 0x0300},
-{ 0x1FCC, 0x0397, 0x0345},
-{ 0x1FCD, 0x1FBF, 0x0300},
-{ 0x1FCE, 0x1FBF, 0x0301},
-{ 0x1FCF, 0x1FBF, 0x0342},
-{ 0x1FD0, 0x03B9, 0x0306},
-{ 0x1FD1, 0x03B9, 0x0304},
-{ 0x1FD2, 0x03CA, 0x0300},
-{ 0x1FD6, 0x03B9, 0x0342},
-{ 0x1FD7, 0x03CA, 0x0342},
-{ 0x1FD8, 0x0399, 0x0306},
-{ 0x1FD9, 0x0399, 0x0304},
-{ 0x1FDA, 0x0399, 0x0300},
-{ 0x1FDD, 0x1FFE, 0x0300},
-{ 0x1FDE, 0x1FFE, 0x0301},
-{ 0x1FDF, 0x1FFE, 0x0342},
-{ 0x1FE0, 0x03C5, 0x0306},
-{ 0x1FE1, 0x03C5, 0x0304},
-{ 0x1FE2, 0x03CB, 0x0300},
-{ 0x1FE4, 0x03C1, 0x0313},
-{ 0x1FE5, 0x03C1, 0x0314},
-{ 0x1FE6, 0x03C5, 0x0342},
-{ 0x1FE7, 0x03CB, 0x0342},
-{ 0x1FE8, 0x03A5, 0x0306},
-{ 0x1FE9, 0x03A5, 0x0304},
-{ 0x1FEA, 0x03A5, 0x0300},
-{ 0x1FEC, 0x03A1, 0x0314},
-{ 0x1FED, 0x00A8, 0x0300},
-{ 0x1FF2, 0x1F7C, 0x0345},
-{ 0x1FF3, 0x03C9, 0x0345},
-{ 0x1FF4, 0x03CE, 0x0345},
-{ 0x1FF6, 0x03C9, 0x0342},
-{ 0x1FF7, 0x1FF6, 0x0345},
-{ 0x1FF8, 0x039F, 0x0300},
-{ 0x1FFA, 0x03A9, 0x0300},
-{ 0x1FFC, 0x03A9, 0x0345},
-{ 0x219A, 0x2190, 0x0338},
-{ 0x219B, 0x2192, 0x0338},
-{ 0x21AE, 0x2194, 0x0338},
-{ 0x21CD, 0x21D0, 0x0338},
-{ 0x21CE, 0x21D4, 0x0338},
-{ 0x21CF, 0x21D2, 0x0338},
-{ 0x2204, 0x2203, 0x0338},
-{ 0x2209, 0x2208, 0x0338},
-{ 0x220C, 0x220B, 0x0338},
-{ 0x2224, 0x2223, 0x0338},
-{ 0x2226, 0x2225, 0x0338},
-{ 0x2241, 0x223C, 0x0338},
-{ 0x2244, 0x2243, 0x0338},
-{ 0x2247, 0x2245, 0x0338},
-{ 0x2249, 0x2248, 0x0338},
-{ 0x2260, 0x003D, 0x0338},
-{ 0x2262, 0x2261, 0x0338},
-{ 0x226D, 0x224D, 0x0338},
-{ 0x226E, 0x003C, 0x0338},
-{ 0x226F, 0x003E, 0x0338},
-{ 0x2270, 0x2264, 0x0338},
-{ 0x2271, 0x2265, 0x0338},
-{ 0x2274, 0x2272, 0x0338},
-{ 0x2275, 0x2273, 0x0338},
-{ 0x2278, 0x2276, 0x0338},
-{ 0x2279, 0x2277, 0x0338},
-{ 0x2280, 0x227A, 0x0338},
-{ 0x2281, 0x227B, 0x0338},
-{ 0x2284, 0x2282, 0x0338},
-{ 0x2285, 0x2283, 0x0338},
-{ 0x2288, 0x2286, 0x0338},
-{ 0x2289, 0x2287, 0x0338},
-{ 0x22AC, 0x22A2, 0x0338},
-{ 0x22AD, 0x22A8, 0x0338},
-{ 0x22AE, 0x22A9, 0x0338},
-{ 0x22AF, 0x22AB, 0x0338},
-{ 0x22E0, 0x227C, 0x0338},
-{ 0x22E1, 0x227D, 0x0338},
-{ 0x22E2, 0x2291, 0x0338},
-{ 0x22E3, 0x2292, 0x0338},
-{ 0x22EA, 0x22B2, 0x0338},
-{ 0x22EB, 0x22B3, 0x0338},
-{ 0x22EC, 0x22B4, 0x0338},
-{ 0x22ED, 0x22B5, 0x0338},
-{ 0x304C, 0x304B, 0x3099},
-{ 0x304E, 0x304D, 0x3099},
-{ 0x3050, 0x304F, 0x3099},
-{ 0x3052, 0x3051, 0x3099},
-{ 0x3054, 0x3053, 0x3099},
-{ 0x3056, 0x3055, 0x3099},
-{ 0x3058, 0x3057, 0x3099},
-{ 0x305A, 0x3059, 0x3099},
-{ 0x305C, 0x305B, 0x3099},
-{ 0x305E, 0x305D, 0x3099},
-{ 0x3060, 0x305F, 0x3099},
-{ 0x3062, 0x3061, 0x3099},
-{ 0x3065, 0x3064, 0x3099},
-{ 0x3067, 0x3066, 0x3099},
-{ 0x3069, 0x3068, 0x3099},
-{ 0x3070, 0x306F, 0x3099},
-{ 0x3071, 0x306F, 0x309A},
-{ 0x3073, 0x3072, 0x3099},
-{ 0x3074, 0x3072, 0x309A},
-{ 0x3076, 0x3075, 0x3099},
-{ 0x3077, 0x3075, 0x309A},
-{ 0x3079, 0x3078, 0x3099},
-{ 0x307A, 0x3078, 0x309A},
-{ 0x307C, 0x307B, 0x3099},
-{ 0x307D, 0x307B, 0x309A},
-{ 0x3094, 0x3046, 0x3099},
-{ 0x309E, 0x309D, 0x3099},
-{ 0x30AC, 0x30AB, 0x3099},
-{ 0x30AE, 0x30AD, 0x3099},
-{ 0x30B0, 0x30AF, 0x3099},
-{ 0x30B2, 0x30B1, 0x3099},
-{ 0x30B4, 0x30B3, 0x3099},
-{ 0x30B6, 0x30B5, 0x3099},
-{ 0x30B8, 0x30B7, 0x3099},
-{ 0x30BA, 0x30B9, 0x3099},
-{ 0x30BC, 0x30BB, 0x3099},
-{ 0x30BE, 0x30BD, 0x3099},
-{ 0x30C0, 0x30BF, 0x3099},
-{ 0x30C2, 0x30C1, 0x3099},
-{ 0x30C5, 0x30C4, 0x3099},
-{ 0x30C7, 0x30C6, 0x3099},
-{ 0x30C9, 0x30C8, 0x3099},
-{ 0x30D0, 0x30CF, 0x3099},
-{ 0x30D1, 0x30CF, 0x309A},
-{ 0x30D3, 0x30D2, 0x3099},
-{ 0x30D4, 0x30D2, 0x309A},
-{ 0x30D6, 0x30D5, 0x3099},
-{ 0x30D7, 0x30D5, 0x309A},
-{ 0x30D9, 0x30D8, 0x3099},
-{ 0x30DA, 0x30D8, 0x309A},
-{ 0x30DC, 0x30DB, 0x3099},
-{ 0x30DD, 0x30DB, 0x309A},
-{ 0x30F4, 0x30A6, 0x3099},
-{ 0x30F7, 0x30EF, 0x3099},
-{ 0x30F8, 0x30F0, 0x3099},
-{ 0x30F9, 0x30F1, 0x3099},
-{ 0x30FA, 0x30F2, 0x3099},
-{ 0x30FE, 0x30FD, 0x3099},
-{ 0xFB1D, 0x05D9, 0x05B4},
-{ 0xFB1F, 0x05F2, 0x05B7},
-{ 0xFB2A, 0x05E9, 0x05C1},
-{ 0xFB2B, 0x05E9, 0x05C2},
-{ 0xFB2C, 0xFB49, 0x05C1},
-{ 0xFB2D, 0xFB49, 0x05C2},
-{ 0xFB2E, 0x05D0, 0x05B7},
-{ 0xFB2F, 0x05D0, 0x05B8},
-{ 0xFB30, 0x05D0, 0x05BC},
-{ 0xFB31, 0x05D1, 0x05BC},
-{ 0xFB32, 0x05D2, 0x05BC},
-{ 0xFB33, 0x05D3, 0x05BC},
-{ 0xFB34, 0x05D4, 0x05BC},
-{ 0xFB35, 0x05D5, 0x05BC},
-{ 0xFB36, 0x05D6, 0x05BC},
-{ 0xFB38, 0x05D8, 0x05BC},
-{ 0xFB39, 0x05D9, 0x05BC},
-{ 0xFB3A, 0x05DA, 0x05BC},
-{ 0xFB3B, 0x05DB, 0x05BC},
-{ 0xFB3C, 0x05DC, 0x05BC},
-{ 0xFB3E, 0x05DE, 0x05BC},
-{ 0xFB40, 0x05E0, 0x05BC},
-{ 0xFB41, 0x05E1, 0x05BC},
-{ 0xFB43, 0x05E3, 0x05BC},
-{ 0xFB44, 0x05E4, 0x05BC},
-{ 0xFB46, 0x05E6, 0x05BC},
-{ 0xFB47, 0x05E7, 0x05BC},
-{ 0xFB48, 0x05E8, 0x05BC},
-{ 0xFB49, 0x05E9, 0x05BC},
-{ 0xFB4A, 0x05EA, 0x05BC},
-{ 0xFB4B, 0x05D5, 0x05B9},
-{ 0xFB4C, 0x05D1, 0x05BF},
-{ 0xFB4D, 0x05DB, 0x05BF},
-{ 0xFB4E, 0x05E4, 0x05BF},
-};
-
-/* ------------------------ */
-unsigned int do_precomposition(unsigned int base, unsigned int comb) {
-  int min = 0;
-  int max = sizeof(precompositions) / sizeof(precompositions[0]) - 1;
-  int mid;
-  unsigned int sought = (base << 16) | comb, that;
-
-  /* binary search */
-  while (max >= min) {
-    mid = (min + max) / 2;
-    that = (precompositions[mid].base << 16) | (precompositions[mid].comb);
-    if (that < sought) {
-      min = mid + 1;
-    } else if (that > sought) {
-      max = mid - 1;
-    } else {
-      return precompositions[mid].replacement;
-    }
-  }
-  /* no match */
-  return 0;
-}
-
-/* -------------------------- */
-unsigned int do_decomposition(unsigned int base) {
-  int min = 0;
-  int max = sizeof(decompositions) / sizeof(decompositions[0]) - 1;
-  int mid;
-  unsigned int sought = base;
-  unsigned int result, that;
-
-  /* binary search */
-  while (max >= min) {
-    mid = (min + max) / 2;
-    that = decompositions[mid].replacement;
-    if (that < sought) {
-      min = mid + 1;
-    } else if (that > sought) {
-      max = mid - 1;
-    } else {
-      result = (decompositions[mid].base << 16) | (decompositions[mid].comb);
-      return result;
-    }
-  }
-  /* no match */
-  return 0;
-}
index 242c5366c2a6b3630075f7a03751efc87d498931..ea2e6b8bb49798321067c09fc783a6c71226ee1b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: quota.c,v 1.24 2003-12-28 13:51:12 srittau Exp $
+ * $Id: quota.c,v 1.25 2005-04-28 20:49:44 bfernhomberg Exp $
  *
  * Copyright (c) 1990,1993 Regents of The University of Michigan.
  * All Rights Reserved.  See COPYRIGHT.
@@ -9,11 +9,12 @@
 #include "config.h"
 #endif /* HAVE_CONFIG_H */
 
+#ifndef NO_QUOTA_SUPPORT
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
-
+#include <sys/types.h>
 /* STDC check */
 #if STDC_HEADERS
 #include <string.h>
@@ -28,7 +29,6 @@ char *strchr (), *strrchr ();
 #define memmove(d,s,n) bcopy ((s), (d), (n))
 #endif /* ! HAVE_MEMCPY */
 #endif /* STDC_HEADERS */
-
 #include <sys/stat.h>
 #include <sys/time.h>
 #include <sys/param.h>
@@ -38,16 +38,250 @@ char *strchr (), *strrchr ();
 #ifdef HAVE_FCNTL_H
 #include <fcntl.h>
 #endif /* HAVE_FCNTL_H */
-#include <atalk/logger.h>
 
+#include <atalk/logger.h>
 #include <atalk/afp.h>
 
 #include "auth.h"
 #include "volume.h"
 #include "unix.h"
 
-#ifndef NO_QUOTA_SUPPORT
+#define DEBUG_QUOTA 0
+#define WANT_USER_QUOTA 0
+#define WANT_GROUP_QUOTA 1
+
+#ifdef NEED_QUOTACTL_WRAPPER
+int quotactl(int cmd, const char *special, int id, caddr_t addr)
+{
+    return syscall(__NR_quotactl, cmd, special, id, addr);
+}
+#endif /* NEED_QUOTACTL_WRAPPER */
+
+static int overquota( struct dqblk *);
+
+#ifdef linux
+
+#ifdef HAVE_LINUX_XQM_H
+#include <linux/xqm.h>
+#else
+#ifdef HAVE_XFS_XQM_H
+#include <xfs/xqm.h>
+#define HAVE_LINUX_XQM_H
+#endif /* HAVE_XFS_XQM_H */
+#endif /* HAVE_LINUX_XQM_H */
+
+#include <linux/unistd.h>
+
+static int is_xfs = 0;
+
+static int get_linux_xfs_quota(int, char*, uid_t, struct dqblk *);
+static int get_linux_fs_quota(int, char*, uid_t, struct dqblk *);
+
+/* format supported by current kernel */
+static int kernel_iface = IFACE_UNSET;
+
+/*
+**  Check kernel quota version
+**  Taken from quota-tools 3.08 by Jan Kara <jack@suse.cz>
+*/
+static void linuxquota_get_api( void )
+{
+#ifndef LINUX_API_VERSION
+    struct stat st;
+
+    if (stat("/proc/sys/fs/quota", &st) == 0) {
+        kernel_iface = IFACE_GENERIC;
+    }
+    else {
+        struct dqstats_v2 v2_stats;
+        struct sigaction  sig;
+        struct sigaction  oldsig;
+
+        /* This signal handling is needed because old kernels send us SIGSEGV as they try to resolve the device */
+        sig.sa_handler   = SIG_IGN;
+        sig.sa_sigaction = NULL;
+        sig.sa_flags     = 0;
+        sigemptyset(&sig.sa_mask);
+        if (sigaction(SIGSEGV, &sig, &oldsig) < 0) {
+           LOG( log_error, logtype_afpd, "cannot set SEGV signal handler: %s", strerror(errno));
+            goto failure;
+        }
+        if (quotactl(QCMD(Q_V2_GETSTATS, 0), NULL, 0, (void *)&v2_stats) >= 0) {
+            kernel_iface = IFACE_VFSV0;
+        }
+        else if (errno != ENOSYS && errno != ENOTSUP) {
+            /* RedHat 7.1 (2.4.2-2) newquota check 
+             * Q_V2_GETSTATS in it's old place, Q_GETQUOTA in the new place
+             * (they haven't moved Q_GETSTATS to its new value) */
+            int err_stat = 0;
+            int err_quota = 0;
+            char tmp[1024];         /* Just temporary buffer */
+
+            if (quotactl(QCMD(Q_V1_GETSTATS, 0), NULL, 0, tmp))
+                err_stat = errno;
+            if (quotactl(QCMD(Q_V1_GETQUOTA, 0), "/dev/null", 0, tmp))
+                err_quota = errno;
+
+            /* On a RedHat 2.4.2-2     we expect 0, EINVAL
+             * On a 2.4.x              we expect 0, ENOENT
+             * On a 2.4.x-ac   we wont get here */
+            if (err_stat == 0 && err_quota == EINVAL) {
+                kernel_iface = IFACE_VFSV0;
+            }
+            else {
+                kernel_iface = IFACE_VFSOLD;
+            }
+        }
+        else {
+            /* This branch is *not* in quota-tools 3.08
+            ** but without it quota version is not correctly
+            ** identified for the original SuSE 8.0 kernel */
+            unsigned int vers_no;
+            FILE * qf;
+
+            if ((qf = fopen("/proc/fs/quota", "r"))) {
+                if (fscanf(qf, "Version %u", &vers_no) == 1) {
+                    if ( (vers_no == (6*10000 + 5*100 + 0)) ||
+                         (vers_no == (6*10000 + 5*100 + 1)) ) {
+                        kernel_iface = IFACE_VFSV0;
+                    }
+                }
+                fclose(qf);
+            }
+        }
+        if (sigaction(SIGSEGV, &oldsig, NULL) < 0) {
+           LOG(log_error, logtype_afpd, "cannot reset signal handler: %s", strerror(errno));
+            goto failure;
+        }
+    }
+
+failure:
+    if (kernel_iface == IFACE_UNSET)
+       kernel_iface = IFACE_VFSOLD;
 
+#else /* defined LINUX_API_VERSION */
+    kernel_iface = LINUX_API_VERSION;
+#endif
+}
+
+/****************************************************************************/
+
+static int get_linux_quota(int what, char *path, uid_t euser_id, struct dqblk *dp)
+{
+       int r; /* result */
+
+       if ( is_xfs )
+               r=get_linux_xfs_quota(what, path, euser_id, dp);
+       else
+               r=get_linux_fs_quota(what, path, euser_id, dp);
+    
+       return r;
+}
+
+/****************************************************************************
+ Abstract out the XFS Quota Manager quota get call.
+****************************************************************************/
+
+static int get_linux_xfs_quota(what, path, euser_id, dqb)
+int what;
+char *path;
+uid_t euser_id;
+struct dqblk *dqb;
+{
+       int ret = -1;
+#ifdef HAVE_LINUX_XQM_H
+       struct fs_disk_quota D;
+       
+       memset (&D, 0, sizeof(D));
+
+       if ((ret = quotactl(QCMD(Q_XGETQUOTA,(what ? GRPQUOTA : USRQUOTA)), path, euser_id, (caddr_t)&D)))
+               return ret;
+
+       dqb->bsize = (u_int64_t)512;
+        dqb->dqb_bsoftlimit  = (u_int64_t)D.d_blk_softlimit;
+        dqb->dqb_bhardlimit  = (u_int64_t)D.d_blk_hardlimit;
+        dqb->dqb_ihardlimit  = (u_int64_t)D.d_ino_hardlimit;
+        dqb->dqb_isoftlimit  = (u_int64_t)D.d_ino_softlimit;
+        dqb->dqb_curinodes   = (u_int64_t)D.d_icount;
+        dqb->dqb_curblocks   = (u_int64_t)D.d_bcount; 
+#endif
+       return ret;
+}
+
+/*
+** Wrapper for the quotactl(GETQUOTA) call.
+** For API v2 the results are copied back into a v1 structure.
+** Taken from quota-1.4.8 perl module
+*/
+static int get_linux_fs_quota( what, path, euser_id, dqb)
+int what;
+char *path;
+uid_t euser_id;
+struct dqblk *dqb;
+{
+       int ret;
+
+       if (kernel_iface == IFACE_UNSET)
+               linuxquota_get_api();
+
+       if (kernel_iface == IFACE_GENERIC)
+       {
+               struct dqblk_v3 dqb3;
+
+               ret = quotactl(QCMD(Q_V3_GETQUOTA, (what ? GRPQUOTA : USRQUOTA)), path, euser_id, (caddr_t) &dqb3);
+               if (ret == 0)
+               {
+                       dqb->dqb_bhardlimit = dqb3.dqb_bhardlimit;
+                       dqb->dqb_bsoftlimit = dqb3.dqb_bsoftlimit;
+                       dqb->dqb_curblocks  = dqb3.dqb_curspace / DEV_QBSIZE;
+                       dqb->dqb_ihardlimit = dqb3.dqb_ihardlimit;
+                       dqb->dqb_isoftlimit = dqb3.dqb_isoftlimit;
+                       dqb->dqb_curinodes  = dqb3.dqb_curinodes;
+                       dqb->dqb_btime      = dqb3.dqb_btime;
+                       dqb->dqb_itime      = dqb3.dqb_itime;
+                       dqb->bsize          = DEV_QBSIZE;
+               }
+       }
+       else if (kernel_iface == IFACE_VFSV0)
+       {
+               struct dqblk_v2 dqb2;
+
+               ret = quotactl(QCMD(Q_V2_GETQUOTA, (what ? GRPQUOTA : USRQUOTA)), path, euser_id, (caddr_t) &dqb2);
+               if (ret == 0)
+               {
+                       dqb->dqb_bhardlimit = dqb2.dqb_bhardlimit;
+                       dqb->dqb_bsoftlimit = dqb2.dqb_bsoftlimit;
+                       dqb->dqb_curblocks  = dqb2.dqb_curspace / DEV_QBSIZE;
+                       dqb->dqb_ihardlimit = dqb2.dqb_ihardlimit;
+                       dqb->dqb_isoftlimit = dqb2.dqb_isoftlimit;
+                       dqb->dqb_curinodes  = dqb2.dqb_curinodes;
+                       dqb->dqb_btime      = dqb2.dqb_btime;
+                       dqb->dqb_itime      = dqb2.dqb_itime;
+                       dqb->bsize          = DEV_QBSIZE;
+               }
+       }
+       else /* if (kernel_iface == IFACE_VFSOLD) */
+       {
+               struct dqblk_v1 dqb1;
+
+               ret = quotactl(QCMD(Q_V1_GETQUOTA, (what ? GRPQUOTA : USRQUOTA)), path, euser_id, (caddr_t) &dqb1);
+               if (ret == 0)
+               {
+                       dqb->dqb_bhardlimit = dqb1.dqb_bhardlimit;
+                       dqb->dqb_bsoftlimit = dqb1.dqb_bsoftlimit;
+                       dqb->dqb_curblocks  = dqb1.dqb_curblocks;
+                       dqb->dqb_ihardlimit = dqb1.dqb_ihardlimit;
+                       dqb->dqb_isoftlimit = dqb1.dqb_isoftlimit;
+                       dqb->dqb_curinodes  = dqb1.dqb_curinodes;
+                       dqb->dqb_btime      = dqb1.dqb_btime;
+                       dqb->dqb_itime      = dqb1.dqb_itime;
+                       dqb->bsize          = DEV_QBSIZE;
+               }
+       }
+       return ret;
+}
+
+#endif /* linux */
 
 #if defined(HAVE_SYS_MNTTAB_H) || defined(__svr4__)
 /*
@@ -95,6 +329,31 @@ int         *nfs;
 }
 
 #else /* __svr4__ */
+#ifdef ultrix
+/*
+* Return the block-special device name associated with the filesystem
+* on which "file" resides.  Returns NULL on failure.
+*/
+
+static char *
+special( file, nfs )
+char *file;
+int  *nfs;
+{
+    static struct fs_data      fsd;
+
+    if ( getmnt(0, &fsd, 0, STAT_ONE, file ) < 0 ) {
+        LOG(log_info, logtype_afpd, "special: getmnt %s: %s", file, strerror(errno) );
+        return( NULL );
+    }
+
+    /* XXX: does this really detect an nfs mounted fs? */
+    if (strchr(fsd.fd_req.devname, ':'))
+        *nfs = 1;
+    return( fsd.fd_req.devname );
+}
+
+#else /* ultrix */
 #if (defined(HAVE_SYS_MOUNT_H) && !defined(__linux__)) || defined(BSD4_4) || defined(_IBMR2)
 
 static char *
@@ -131,6 +390,7 @@ int *nfs;
     FILE               *mtab;
     dev_t              devno;
     struct mntent      *mnt;
+    int                found=0;
 
     if ( stat( file, &sb ) < 0 ) {
         return( NULL );
@@ -144,8 +404,8 @@ int *nfs;
     while (( mnt = getmntent( mtab )) != NULL ) {
         /* check for local fs */
         if ( (stat( mnt->mnt_fsname, &sb ) == 0) && devno == sb.st_rdev) {
-            endmntent( mtab );
-            return( mnt->mnt_fsname );
+           found = 1;
+           break;
         }
 
         /* check for an nfs mount entry. the alternative is to use
@@ -153,27 +413,43 @@ int *nfs;
         if ((stat(mnt->mnt_dir, &sb) == 0) && (devno == sb.st_dev) &&
                 strchr(mnt->mnt_fsname, ':')) {
             *nfs = 1;
-            endmntent( mtab );
-            return( mnt->mnt_fsname );
+           found = 1;
+           break;
         }
     }
 
     endmntent( mtab );
-    return( NULL );
+
+    if (!found)
+       return (NULL);
+#ifdef linux
+    if (strcmp(mnt->mnt_type, "xfs") == 0)
+       is_xfs = 1;
+#endif
+       
+    return( mnt->mnt_fsname );
 }
 
 #endif /* BSD4_4 */
+#endif /* ultrix */
 #endif /* __svr4__ */
 
 
 static int getfsquota(vol, uid, dq)
-struct vol          *vol;
-const int           uid;
-struct dqblk        *dq;
+struct vol             *vol;
+const int              uid;
+struct dqblk           *dq;
+
 {
+       struct dqblk dqg;
+
 #ifdef __svr4__
-    struct quotctl     qc;
+    struct quotctl      qc;
+#endif
 
+    memset(&dqg, 0, sizeof(dqg));
+       
+#ifdef __svr4__
     qc.op = Q_GETQUOTA;
     qc.uid = uid;
     qc.addr = (caddr_t)dq;
@@ -182,6 +458,11 @@ struct dqblk        *dq;
     }
 
 #else /* __svr4__ */
+#ifdef ultrix
+    if ( quota( Q_GETDLIM, uid, vol->v_gvs, dq ) != 0 ) {
+        return( AFPERR_PARAM );
+    }
+#else /* ultrix */
 
 #ifndef USRQUOTA
 #define USRQUOTA   0
@@ -194,9 +475,6 @@ struct dqblk        *dq;
 #ifndef TRU64
     /* for group quotas. we only use these if the user belongs
     * to one group. */
-    struct dqblk        dqg;
-
-    memset(&dqg, 0, sizeof(dqg));
 #endif /* TRU64 */
 
 #ifdef BSD4_4
@@ -226,45 +504,48 @@ struct dqblk        *dq;
     }
 
 #else /* BSD4_4 */
-    if ( quotactl(QCMD(Q_GETQUOTA, USRQUOTA), vol->v_gvs, uid,
-                  (caddr_t) dq ) != 0 ) {
+    if (get_linux_quota (WANT_USER_QUOTA, vol->v_gvs, uid, dq) !=0) {
         return( AFPERR_PARAM );
     }
 
-    if (ngroups >= 1)
-        quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), vol->v_gvs,
-                 groups[0], (char *) &dqg);
+    if (get_linux_quota(WANT_GROUP_QUOTA, vol->v_gvs, getegid(),  &dqg) != 0) {
+#ifdef DEBUG_QUOTA
+        LOG(log_debug, logtype_afpd, "group quota did not work!" );
+#endif /* DEBUG_QUOTA */
+
+       return AFP_OK; /* no need to check user vs group quota */
+    }
 #endif  /* BSD4_4 */
 
-#ifndef TRU64
-    /* set stuff up for group quotas if necessary */
 
-    /* max(user blocks, group blocks) */
-#ifdef HAVE_STRUCT_IF_DQBLK
-    if (dqg.dqb_curspace && (dq->dqb_curspace < dqg.dqb_curspace))
-        dq->dqb_curspace = dqg.dqb_curspace;
-#else
-    if (dqg.dqb_curblocks && (dq->dqb_curblocks < dqg.dqb_curblocks))
+#ifndef TRU64
+    /* return either the group quota entry or user quota entry,
+       whichever has the least amount of space remaining
+    */
+
+    /* if user space remaining > group space remaining */
+    if( 
+        /* if overquota, free space is 0 otherwise hard-current */
+        ( overquota( dq ) ? 0 : ( dq->dqb_bhardlimit ? dq->dqb_bhardlimit - 
+                                  dq->dqb_curblocks : ~((u_int64_t) 0) ) )
+
+      >
+        
+        ( overquota( &dqg ) ? 0 : ( dqg.dqb_bhardlimit ? dqg.dqb_bhardlimit - 
+                                    dqg.dqb_curblocks : ~((u_int64_t) 0) ) )
+
+      ) /* if */
+    {
+        /* use group quota limits rather than user limits */
         dq->dqb_curblocks = dqg.dqb_curblocks;
-#endif
-
-    /* min(user limit, group limit) */
-    if (dqg.dqb_bhardlimit && (!dq->dqb_bhardlimit ||
-                               (dq->dqb_bhardlimit > dqg.dqb_bhardlimit)))
         dq->dqb_bhardlimit = dqg.dqb_bhardlimit;
-
-    /* ditto */
-    if (dqg.dqb_bsoftlimit && (!dq->dqb_bsoftlimit ||
-                               (dq->dqb_bsoftlimit > dqg.dqb_bsoftlimit)))
         dq->dqb_bsoftlimit = dqg.dqb_bsoftlimit;
-
-    /* ditto */
-    if (dqg.dqb_btimelimit && (!dq->dqb_btimelimit ||
-                               (dq->dqb_btimelimit > dqg.dqb_btimelimit)))
         dq->dqb_btimelimit = dqg.dqb_btimelimit;
+    } /* if */
 
 #endif /* TRU64 */
 
+#endif /* ultrix */
 #endif /* __svr4__ */
 
     return AFP_OK;
@@ -273,8 +554,8 @@ struct dqblk        *dq;
 
 static int getquota( vol, dq, bsize)
 struct vol             *vol;
-struct dqblk   *dq;
-const u_int32_t     bsize;
+struct dqblk           *dq;
+const u_int32_t                bsize;
 {
     char *p;
 
@@ -358,17 +639,24 @@ const u_int32_t     bsize;
 }
 
 static int overquota( dqblk )
-struct dqblk   *dqblk;
+struct dqblk     *dqblk;
 {
     struct timeval     tv;
 
-#ifdef HAVE_STRUCT_IF_DQBLK
-    if ( dqblk->dqb_curspace < dqblk->dqb_bsoftlimit ) {
-#else
-    if ( dqblk->dqb_curblocks < dqblk->dqb_bsoftlimit ) {
-#endif
-        return 0 ;
+    if ( dqblk->dqb_curblocks > dqblk->dqb_bhardlimit &&
+         dqblk->dqb_bhardlimit != 0 ) {
+        return( 1 );
+    }
+
+    if ( dqblk->dqb_curblocks < dqblk->dqb_bsoftlimit ||
+         dqblk->dqb_bsoftlimit == 0 ) {
+        return( 0 );
     }
+#ifdef ultrix
+    if ( dqblk->dqb_bwarn ) {
+        return( 0 );
+    }
+#else /* ultrix */
     if ( gettimeofday( &tv, 0 ) < 0 ) {
         LOG(log_error, logtype_afpd, "overquota: gettimeofday: %s", strerror(errno) );
         return( AFPERR_PARAM );
@@ -376,6 +664,7 @@ struct dqblk        *dqblk;
     if ( dqblk->dqb_btimelimit && dqblk->dqb_btimelimit > tv.tv_sec ) {
         return( 0 );
     }
+#endif /* ultrix */
     return( 1 );
 }
 
@@ -404,45 +693,67 @@ struct dqblk      *dqblk;
 #else 
 #define tobytes(a, b)  dbtob((VolSpace) (a))
 #endif
+
 int uquota_getvolspace( vol, bfree, btotal, bsize)
-const struct vol       *vol;
+struct vol     *vol;
 VolSpace       *bfree, *btotal;
 const u_int32_t bsize;
 {
-    struct dqblk       dqblk;
+       u_int64_t this_bsize;
+       struct dqblk dqblk;
 
-    if (getquota( vol, &dqblk, bsize) != 0 ) {
-        return( AFPERR_PARAM );
-    }
+       this_bsize = bsize;
+                       
+       if (getquota( vol, &dqblk, bsize) != 0 ) {
+               return( AFPERR_PARAM );
+       }
 
-    /* no limit set for this user. it might be set in the future. */
-    if (dqblk.dqb_bsoftlimit == 0 && dqblk.dqb_bhardlimit == 0) {
-        *btotal = *bfree = ~((VolSpace) 0);
-    } else if ( overquota( &dqblk )) {
-#ifdef HAVE_STRUCT_IF_DQBLK
-        if ( tobytes( dqblk.dqb_curspace, bsize ) > tobytes( dqblk.dqb_bhardlimit, bsize ) ) {
-            *btotal = tobytes( dqblk.dqb_curspace, bsize );
-#else
-        if ( tobytes( dqblk.dqb_curblocks, bsize ) > tobytes( dqblk.dqb_bhardlimit, bsize ) ) {
-            *btotal = tobytes( dqblk.dqb_curblocks, bsize );
+#ifdef linux
+       this_bsize = dqblk.bsize;
 #endif
-            *bfree = 0;
-        }
-        else {
-            *btotal = tobytes( dqblk.dqb_bhardlimit, bsize );
-            *bfree = tobytes( dqblk.dqb_bhardlimit, bsize ) -
-#ifdef HAVE_STRUCT_IF_DQBLK
-                     tobytes( dqblk.dqb_curspace, bsize );
-#else
-                     tobytes( dqblk.dqb_curblocks, bsize );
+
+#if DEBUG_QUOTA
+        LOG(log_info, logtype_afpd, "after calling getquota in uquota_getvolspace!" );
+        LOG(log_info, logtype_afpd, "dqb_ihardlimit: %u", dqblk.dqb_ihardlimit );
+        LOG(log_info, logtype_afpd, "dqb_isoftlimit: %u", dqblk.dqb_isoftlimit );
+        LOG(log_info, logtype_afpd, "dqb_curinodes : %u", dqblk.dqb_curinodes );
+        LOG(log_info, logtype_afpd, "dqb_bhardlimit: %u", dqblk.dqb_bhardlimit );
+        LOG(log_info, logtype_afpd, "dqb_bsoftlimit: %u", dqblk.dqb_bsoftlimit );
+        LOG(log_info, logtype_afpd, "dqb_curblocks : %u", dqblk.dqb_curblocks );
+        LOG(log_info, logtype_afpd, "dqb_btime     : %u", dqblk.dqb_btime );
+        LOG(log_info, logtype_afpd, "dqb_itime     : %u", dqblk.dqb_itime );
+        LOG(log_info, logtype_afpd, "bsize/this_bsize : %u/%u", bsize, this_bsize );
+       LOG(log_info, logtype_afpd, "dqblk.dqb_bhardlimit size: %u", tobytes( dqblk.dqb_bhardlimit, this_bsize ));
+       LOG(log_info, logtype_afpd, "dqblk.dqb_bsoftlimit size: %u", tobytes( dqblk.dqb_bsoftlimit, this_bsize ));
+       LOG(log_info, logtype_afpd, "dqblk.dqb_curblocks  size: %u", tobytes( dqblk.dqb_curblocks, this_bsize ));
+#endif /* DEBUG_QUOTA */ 
+
+       /* no limit set for this user. it might be set in the future. */
+       if (dqblk.dqb_bsoftlimit == 0 && dqblk.dqb_bhardlimit == 0) {
+               *btotal = *bfree = ~((VolSpace) 0);
+       } else if ( overquota( &dqblk )) {
+               if ( tobytes( dqblk.dqb_curblocks, this_bsize ) > tobytes( dqblk.dqb_bsoftlimit, this_bsize ) ) {
+                       *btotal = tobytes( dqblk.dqb_curblocks, this_bsize );
+                       *bfree = 0;
+               }
+               else {
+                       *btotal = tobytes( dqblk.dqb_bsoftlimit, this_bsize );
+                       *bfree  = tobytes( dqblk.dqb_bsoftlimit, this_bsize ) -
+                                 tobytes( dqblk.dqb_curblocks, this_bsize );
+               }
+       } else {
+               *btotal = tobytes( dqblk.dqb_bhardlimit, this_bsize );
+               *bfree  = tobytes( dqblk.dqb_bhardlimit, this_bsize  ) -
+                         tobytes( dqblk.dqb_curblocks, this_bsize );
+       }
+
+#if DEBUG_QUOTA
+        LOG(log_info, logtype_afpd, "bfree          : %u", *bfree );
+        LOG(log_info, logtype_afpd, "btotal         : %u", *btotal );
+        LOG(log_info, logtype_afpd, "bfree          : %uKB", *bfree/1024 );
+        LOG(log_info, logtype_afpd, "btotal         : %uKB", *btotal/1024 );
 #endif
-        }
-    } else {
-        *btotal = tobytes( dqblk.dqb_bsoftlimit, bsize );
-        *bfree = tobytes( dqblk.dqb_bsoftlimit, bsize  ) -
-                 tobytes( dqblk.dqb_curblocks, bsize );
-    }
 
-    return( AFP_OK );
+       return( AFP_OK );
 }
 #endif
index d831c91ecef6c6974f0d383cd9b7bad3b903e700..e7cf092b543783fe8c534f567913e237e193db43 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: status.c,v 1.15 2003-06-09 14:42:40 srittau Exp $
+ * $Id: status.c,v 1.16 2005-04-28 20:49:44 bfernhomberg Exp $
  *
  * Copyright (c) 1990,1993 Regents of The University of Michigan.
  * All Rights Reserved.  See COPYRIGHT.
 #include <atalk/atp.h>
 #include <atalk/asp.h>
 #include <atalk/nbp.h>
+#include <atalk/unicode.h>
 
 #include "globals.h"  /* includes <netdb.h> */
 #include "status.h"
 #include "afp_config.h"
 #include "icon.h"
 
+static   size_t maxstatuslen = 0;
+
 static void status_flags(char *data, const int notif, const int ipok,
-                         const unsigned char passwdbits, const int dirsrvcs)
+                         const unsigned char passwdbits, const int dirsrvcs _U_)
 {
     u_int16_t           status;
 
@@ -59,18 +62,20 @@ static void status_flags(char *data, const int notif, const int ipok,
         status |= AFPSRVRINFO_SRVNOTIFY;
     }
     status |= AFPSRVRINFO_FASTBOZO;
-    if (dirsrvcs)
-       status |= AFPSRVRINFO_SRVRDIR;
+    status |= AFPSRVRINFO_SRVRDIR; /* AFP 3.1 specs says we need to specify this, but may set the count to 0 */
+    /* We don't set the UTF8 name flag here, we don't know whether we have enough space ... */
+
     status = htons(status);
     memcpy(data + AFPSTATUS_FLAGOFF, &status, sizeof(status));
 }
 
-static int status_server(char *data, const char *server)
+static int status_server(char *data, const char *server, const struct afp_options *options)
 {
     char                *start = data;
     char                *Obj, *Type, *Zone;
+    char               buf[32];
     u_int16_t           status;
-    int                        len;
+    size_t             len;
 
     /* make room for all offsets before server name */
     data += AFPSTATUS_PRELEN;
@@ -78,21 +83,29 @@ static int status_server(char *data, const char *server)
     /* extract the obj part of the server */
     Obj = (char *) server;
     nbp_name(server, &Obj, &Type, &Zone);
-    len = strlen(Obj);
-    *data++ = len;
-    memcpy( data, Obj, len );
+    if ((size_t)-1 == (len = convert_string( 
+                       options->unixcharset, options->maccharset, 
+                       Obj, strlen(Obj), buf, 31)) ) {
+       len = MIN(strlen(Obj), 31);
+       *data++ = len;
+       memcpy( data, Obj, len );
+       LOG ( log_error, logtype_afpd, "Could not set servername, using fallback");
+    } else {
+       *data++ = len;
+       memcpy( data, buf, len );
+    }
     if ((len + 1) & 1) /* pad server name and length byte to even boundary */
         len++;
     data += len;
 
-    /* Make room for signature and net address offset. Save location of
-     * signature offset. We're also making room for directory names offset
+    /* make room for signature and net address offset. save location of
+     * signature offset. we're also making room for directory names offset
      * and the utf-8 server name offset.
      *
-     * NOTE: Technically, we don't need to reserve space for the
+     * NOTE: technically, we don't need to reserve space for the
      * signature and net address offsets if they're not going to be
-     * used. As there are no offsets after them, it doesn't hurt to
-     * have them specified though. So, we just do that to simplify
+     * used. as there are no offsets after them, it doesn't hurt to
+     * have them specified though. so, we just do that to simplify
      * things.  
      *
      * NOTE2: AFP3.1 Documentation states that the directory names offset
@@ -112,7 +125,7 @@ static void status_machine(char *data)
 #ifdef AFS
     const char         *machine = "afs";
 #else /* !AFS */
-    const char         *machine = "unix";
+    const char         *machine = "Netatalk";
 #endif /* AFS */
 
     memcpy(&status, start + AFPSTATUS_MACHOFF, sizeof(status));
@@ -125,6 +138,14 @@ static void status_machine(char *data)
     memcpy(start + AFPSTATUS_VERSOFF, &status, sizeof(status));
 }
 
+/* -------------------------------- 
+ * it turns out that a server signature screws up separate
+ * servers running on the same machine. to work around that, 
+ * i add in an increment.
+ * Not great, server signature are config dependent but well.
+ */
+static int           Id = 0;
 
 /* server signature is a 16-byte quantity */
 static u_int16_t status_signature(char *data, int *servoffset, DSI *dsi,
@@ -135,7 +156,6 @@ static u_int16_t status_signature(char *data, int *servoffset, DSI *dsi,
     int                  i;
     u_int16_t            offset, sigoff;
     long                 hostid;
-    static int           id = 0;
 #ifdef BSD4_4
     int                  mib[2];
     size_t               len;
@@ -193,8 +213,8 @@ server_signature_hostid:
     /* it turns out that a server signature screws up separate
      * servers running on the same machine. to work around that, 
      * i add in an increment */
-    hostid += id;
-    id++;
+    hostid += Id;
+    Id++;
     for (i = 0; i < 16; i += sizeof(hostid)) {
         memcpy(data, &hostid, sizeof(hostid));
         data += sizeof(hostid);
@@ -208,12 +228,13 @@ server_signature_done:
     return sigoff;
 }
 
-static int status_netaddress(char *data, int *servoffset,
+static size_t status_netaddress(char *data, int *servoffset,
                              const ASP asp, const DSI *dsi,
-                             const char *fqdn)
+                             const struct afp_options *options)
 {
     char               *begin;
     u_int16_t          offset;
+    size_t             addresses_len = 0;
 
     begin = data;
 
@@ -232,16 +253,8 @@ static int status_netaddress(char *data, int *servoffset,
     /* number of addresses. this currently screws up if we have a dsi
        connection, but we don't have the ip address. to get around this,
        we turn off the status flag for tcp/ip. */
-    *data++ = ((fqdn && dsi)? 1 : 0) + (dsi ? 1 : 0) + (asp ? 1 : 0);
-
-    /* handle DNS names */
-    if (fqdn && dsi) {
-        int len = strlen(fqdn);
-        *data++ = len +2;
-        *data++ = 0x04;
-        memcpy(data, fqdn, len);
-        data += len;
-    }
+    *data++ = ((options->fqdn && dsi)? 1 : 0) + (dsi ? 1 : 0) + (asp ? 1 : 0) +
+              (((options->flags & OPTION_ANNOUNCESSH) && options->fqdn && dsi)? 1 : 0);
 
     /* ip address */
     if (dsi) {
@@ -253,6 +266,7 @@ static int status_netaddress(char *data, int *servoffset,
             memcpy(data, &inaddr->sin_addr.s_addr,
                    sizeof(inaddr->sin_addr.s_addr));
             data += sizeof(inaddr->sin_addr.s_addr);
+            addresses_len += 7;
         } else {
             /* ip address + port */
             *data++ = 8;
@@ -262,6 +276,34 @@ static int status_netaddress(char *data, int *servoffset,
             data += sizeof(inaddr->sin_addr.s_addr);
             memcpy(data, &inaddr->sin_port, sizeof(inaddr->sin_port));
             data += sizeof(inaddr->sin_port);
+            addresses_len += 9;
+        }
+    }
+
+    /* handle DNS names */
+    if (options->fqdn && dsi) {
+        size_t len = strlen(options->fqdn);
+        if ( len + 2 + addresses_len < maxstatuslen - offset) {
+            *data++ = len +2;
+            *data++ = 0x04;
+            memcpy(data, options->fqdn, len);
+            data += len;
+            addresses_len += len+2;
+        }
+
+        /* Annouce support for SSH tunneled AFP session, 
+         * this feature is available since 10.3.2.
+         * According to the specs (AFP 3.1 p.225) this should
+         * be an IP+Port style value, but it only works with 
+         * a FQDN. OSX Server uses FQDN as well.
+         */
+        if ( len + 2 + addresses_len < maxstatuslen - offset) {
+            if (options->flags & OPTION_ANNOUNCESSH) {
+                *data++ = len +2;
+                *data++ = 0x05;
+                memcpy(data, options->fqdn, len);
+                data += len;
+            }
         }
     }
 
@@ -291,8 +333,8 @@ static int status_netaddress(char *data, int *servoffset,
     return (data - begin);
 }
 
-static int status_directorynames(char *data, int *diroffset, 
-                                const DSI *dsi, 
+static size_t status_directorynames(char *data, int *diroffset, 
+                                const DSI *dsi _U_
                                 const struct afp_options *options)
 {
     char *begin = data;
@@ -310,7 +352,7 @@ static int status_directorynames(char *data, int *diroffset,
      */
     if (options->k5service && options->k5realm && options->fqdn) {
        /* should k5princ be utf8 encoded? */
-       u_int8_t len;
+       size_t len;
        char *p = strchr( options->fqdn, ':' );
        if (p) 
            *p = '\0';
@@ -318,15 +360,21 @@ static int status_directorynames(char *data, int *diroffset,
                        + strlen( options->fqdn )
                        + strlen( options->k5realm );
        len+=2; /* '/' and '@' */
-       *data++ = 1; /* DirectoryNamesCount */
-       *data++ = len;
-       snprintf( data, len + 1, "%s/%s@%s", options->k5service,
+       if ( len > 255 || len+2 > maxstatuslen - offset) {
+           *data++ = 0;
+           LOG ( log_error, logtype_afpd, "status: could not set directory service list, no more room");
+       }        
+       else {
+           *data++ = 1; /* DirectoryNamesCount */
+           *data++ = len;
+           snprintf( data, len + 1, "%s/%s@%s", options->k5service,
                                options->fqdn, options->k5realm );
-       data += len;
-       if (p)
-           *p = ':';
+           data += len;
+           if (p)
+               *p = ':';
+       }
     } else {
-       memset(begin + *diroffset, 0, sizeof(offset));
+       *data++ = 0;
     }
 
     /* Calculate and store offset for UTF8ServerName */
@@ -338,28 +386,56 @@ static int status_directorynames(char *data, int *diroffset,
     return (data - begin);
 }
 
-static int status_utf8servername(char *data, int *nameoffset,
-                                const DSI *dsi,
+static size_t status_utf8servername(char *data, int *nameoffset,
+                                const DSI *dsi _U_,
                                 const struct afp_options *options)
 {
+    char *Obj, *Type, *Zone;
+    u_int16_t namelen;
+    size_t len;
     char *begin = data;
-    u_int16_t offset;
+    u_int16_t offset, status;
 
     memcpy(&offset, data + *nameoffset, sizeof(offset));
     offset = ntohs(offset);
     data += offset;
 
-    /* FIXME: For now we set the UTF-8 ServerName offset to 0
-     * It's irrelevent anyway until we set the appropriate Flags value.
-     * Later this can be set to something meaningful.
-     *
+    /* FIXME:
      * What is the valid character range for an nbpname?
      *
      * Apple's server likes to use the non-qualified hostname
      * This obviously won't work very well if multiple servers are running
      * on the box.
      */
-    memset(begin + *nameoffset, 0, sizeof(offset));
+
+    /* extract the obj part of the server */
+    Obj = (char *) (options->server ? options->server : options->hostname);
+    nbp_name(options->server ? options->server : options->hostname, &Obj, &Type, &Zone);
+
+    if ((size_t) -1 == (len = convert_string (
+                                       options->unixcharset, CH_UTF8_MAC, 
+                                       Obj, strlen(Obj), data+sizeof(namelen), maxstatuslen-offset )) ) {
+       LOG ( log_error, logtype_afpd, "Could not set utf8 servername");
+
+       /* set offset to 0 */
+       memset(begin + *nameoffset, 0, sizeof(offset));
+        data = begin + offset;
+    }
+    else {
+       namelen = htons(len);
+       memcpy( data, &namelen, sizeof(namelen));
+       data += sizeof(namelen);
+       data += len;
+       offset = htons(offset);
+       memcpy(begin + *nameoffset, &offset, sizeof(u_int16_t));
+        
+        /* Now set the flag ... */
+       memcpy(&status, begin + AFPSTATUS_FLAGOFF, sizeof(status));
+       status = ntohs(status);
+       status |= AFPSRVRINFO_SRVUTF8;
+       status = htons(status);
+       memcpy(begin + AFPSTATUS_FLAGOFF, &status, sizeof(status));
+    }
 
     /* return length of buffer */
     return (data - begin);
@@ -390,27 +466,39 @@ static void status_icon(char *data, const unsigned char *icondata,
         memcpy(sigdata, &ret, sizeof(ret));
 }
 
+/* ---------------------
+*/
+void status_reset()
+{
+    Id = 0;
+}
+
+
+/* ---------------------
+ */
 void status_init(AFPConfig *aspconfig, AFPConfig *dsiconfig,
                  const struct afp_options *options)
 {
     ASP asp;
     DSI *dsi;
-    char *status;
-    int statuslen, c, sigoff;
+    u_int8_t *status = NULL;
+    size_t statuslen;
+    int c, sigoff;
 
     if (!(aspconfig || dsiconfig) || !options)
         return;
 
     if (aspconfig) {
-        asp = aspconfig->obj.handle;
         status = aspconfig->status;
+        maxstatuslen=sizeof(aspconfig->status);
+        asp = aspconfig->obj.handle;
     } else
         asp = NULL;
-
+       
     if (dsiconfig) {
+        status = dsiconfig->status;
+        maxstatuslen=sizeof(dsiconfig->status);
         dsi = dsiconfig->obj.handle;
-        if (!aspconfig)
-            status = dsiconfig->status;
     } else
         dsi = NULL;
 
@@ -437,10 +525,10 @@ void status_init(AFPConfig *aspconfig, AFPConfig *dsiconfig,
     status_flags(status, options->server_notif, options->fqdn ||
                  (dsiconfig && dsi->server.sin_addr.s_addr),
                  options->passwdbits, 
-                 (options->k5service && options->k5realm && options->fqdn));
+                (options->k5service && options->k5realm && options->fqdn));
     /* returns offset to signature offset */
     c = status_server(status, options->server ? options->server :
-                      options->hostname);
+                      options->hostname, options);
     status_machine(status);
     status_versions(status);
     status_uams(status, options->uamlist);
@@ -452,17 +540,19 @@ void status_init(AFPConfig *aspconfig, AFPConfig *dsiconfig,
     sigoff = status_signature(status, &c, dsi, options);
     /* c now contains the offset where the netaddress offset lives */
 
-    status_netaddress(status, &c, asp, dsi, options->fqdn);
+    status_netaddress(status, &c, asp, dsi, options);
     /* c now contains the offset where the Directory Names Count offset lives */
 
-    status_directorynames(status, &c, dsi, options);
+    statuslen = status_directorynames(status, &c, dsi, options);
     /* c now contains the offset where the UTF-8 ServerName offset lives */
 
-    statuslen = status_utf8servername(status, &c, dsi, options);
-
+    if ( statuslen < maxstatuslen) 
+        statuslen = status_utf8servername(status, &c, dsi, options);
 
 #ifndef NO_DDP
     if (aspconfig) {
+        if (dsiconfig) /* status is dsiconfig->status */
+            memcpy(aspconfig->status, status, statuslen);
         asp_setstatus(asp, status, statuslen);
         aspconfig->signature = status + sigoff;
         aspconfig->statuslen = statuslen;
@@ -470,11 +560,6 @@ void status_init(AFPConfig *aspconfig, AFPConfig *dsiconfig,
 #endif /* ! NO_DDP */
 
     if (dsiconfig) {
-        if (aspconfig) { /* copy to dsiconfig */
-            memcpy(dsiconfig->status, status, ATP_MAXDATA);
-            status = dsiconfig->status;
-        }
-
         if ((options->flags & OPTION_CUSTOMICON) == 0) {
             status_icon(status, apple_tcp_icon, sizeof(apple_tcp_icon), 0);
         }
@@ -486,9 +571,9 @@ void status_init(AFPConfig *aspconfig, AFPConfig *dsiconfig,
 
 /* this is the same as asp/dsi_getstatus */
 int afp_getsrvrinfo(obj, ibuf, ibuflen, rbuf, rbuflen )
-AFPObj      *obj;
-char   *ibuf, *rbuf;
-int            ibuflen, *rbuflen;
+AFPObj  *obj;
+char   *ibuf _U_, *rbuf;
+int    ibuflen _U_, *rbuflen;
 {
     AFPConfig *config = obj->config;
 
index 15dc25494327afc94c5ba3a1e9600aa6fa7f6896..e67c30a0a27b981fd5eb55817bb84b20e60a830e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: status.h,v 1.6 2003-04-16 22:45:10 samnoble Exp $
+ * $Id: status.h,v 1.7 2005-04-28 20:49:44 bfernhomberg Exp $
  */
 
 #ifndef AFPD_STATUS_H
@@ -41,6 +41,7 @@
 
 extern void status_versions __P((char * /*status*/));
 extern void status_uams __P((char * /*status*/, const char * /*authlist*/));
+extern void status_reset __P((void ));
 extern void status_init __P((AFPConfig *, AFPConfig *,
                                  const struct afp_options *));
 extern int      afp_getsrvrinfo __P((AFPObj *, char *, int, char *, int *));
index c58c8ecfb436f622efbcaa80222d082ba38c84b1..d762f1216330365875eca14a3c6865a48348055c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: switch.c,v 1.12 2002-11-15 10:59:11 srittau Exp $
+ * $Id: switch.c,v 1.13 2005-04-28 20:49:44 bfernhomberg Exp $
  *
  * Copyright (c) 1990,1991 Regents of The University of Michigan.
  * All Rights Reserved.
@@ -48,9 +48,9 @@
 #include "misc.h"
 
 static int afp_null(obj, ibuf, ibuflen, rbuf, rbuflen )
-AFPObj      *obj;
-char   *ibuf, *rbuf;
-int            ibuflen, *rbuflen;
+AFPObj  *obj _U_;
+char   *ibuf, *rbuf _U_;
+int    ibuflen _U_, *rbuflen;
 {
     LOG(log_info, logtype_afpd, "afp_null handle %d", *ibuf );
     *rbuflen = 0;
index 08ba1cdac08a767d8c4a9a6218a7739dcf2171c0..c7d3eb91c71c140709c689143a615901b3aed078 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: uam.c,v 1.24 2003-04-16 22:45:11 samnoble Exp $
+ * $Id: uam.c,v 1.25 2005-04-28 20:49:44 bfernhomberg Exp $
  *
  * Copyright (c) 1999 Adrian Sun (asun@zoology.washington.edu)
  * All Rights Reserved.  See COPYRIGHT.
@@ -56,6 +56,12 @@ char *strchr (), *strrchr ();
 #include "auth.h"
 #include "uam_auth.h"
 
+#ifdef AFP3x
+#define utf8_encoding() (afp_version >= 30)
+#else
+#define utf8_encoding() (0)
+#endif
+
 #ifdef TRU64
 #include <netdb.h>
 #include <sia.h>
@@ -87,8 +93,7 @@ struct uam_mod *uam_load(const char *path, const char *name)
         goto uam_load_fail;
     }
 
-    strncpy(buf, name, sizeof(buf));
-    buf[sizeof(buf) - 1] = '\0';
+    strlcpy(buf, name, sizeof(buf));
     if ((p = strchr(buf, '.')))
         *p = '\0';
 
@@ -148,6 +153,7 @@ int uam_register(const int type, const char *path, const char *name, ...)
 {
     va_list ap;
     struct uam_obj *uam;
+    int ret;
 
     if (!name)
         return -1;
@@ -197,13 +203,13 @@ int uam_register(const int type, const char *path, const char *name, ...)
     va_end(ap);
 
     /* attach to other uams */
-    if (auth_register(type, uam) < 0) {
+    ret = auth_register(type, uam);
+    if ( ret) {
         free(uam->uam_path);
         free(uam);
-        return -1;
     }
 
-    return 0;
+    return ret;
 }
 #endif
 
@@ -287,31 +293,44 @@ void uam_unregister(const int type, const char *name)
 
 /* --- helper functions for plugin uams --- */
 
-struct passwd *uam_getname(char *name, const int len)
+struct passwd *uam_getname(void *private, char *name, const int len)
 {
+    AFPObj *obj = private;
     struct passwd *pwent;
-    char *user;
-    int i;
+    static char username[256];
+    static char user[256];
+    static char pwname[256];
+    char *p;
+    size_t namelen, gecoslen = 0, pwnamelen = 0;
 
     if ((pwent = getpwnam(name)))
         return pwent;
 
 #ifndef NO_REAL_USER_NAME
-    for (i = 0; i < len; i++)
-        name[i] = tolower(name[i]);
+
+    if ( (size_t) -1 == (namelen = convert_string((utf8_encoding())?CH_UTF8_MAC:obj->options.maccharset,
+                               CH_UCS2, name, strlen(name), username, sizeof(username))))
+       return NULL;
 
     setpwent();
     while ((pwent = getpwent())) {
-        if ((user = strchr(pwent->pw_gecos, ',')))
-            *user = '\0';
-        user = pwent->pw_gecos;
+        if ((p = strchr(pwent->pw_gecos, ',')))
+            *p = '\0';
+
+       if ((size_t)-1 == ( gecoslen = convert_string(obj->options.unixcharset, CH_UCS2, 
+                               pwent->pw_gecos, strlen(pwent->pw_gecos), user, sizeof(username))) )
+               continue;
+       if ((size_t)-1 == ( pwnamelen = convert_string(obj->options.unixcharset, CH_UCS2, 
+                               pwent->pw_name, strlen(pwent->pw_name), pwname, sizeof(username))) )
+               continue;
+
 
         /* check against both the gecos and the name fields. the user
          * might have just used a different capitalization. */
-        if ((strncasecmp(user, name, len) == 0) ||
-                (strncasecmp(pwent->pw_name, name, len) == 0)) {
-            strncpy(name, pwent->pw_name, len);
-            name[len - 1] = '\0';
+
+       if ( (namelen == gecoslen && strncasecmp_w((ucs2_t*)user, (ucs2_t*)username, len) == 0) || 
+               ( namelen == pwnamelen && strncasecmp_w ( (ucs2_t*) pwname, (ucs2_t*) username, len) == 0)) {
+            strlcpy(name, pwent->pw_name, len);
             break;
         }
     }
@@ -334,7 +353,6 @@ int uam_checkuser(const struct passwd *pwd)
                LOG(log_info, logtype_afpd, "uam_checkuser: User %s does not have a shell", pwd->pw_name);
                return -1;
        }
-#endif
 
     while ((p = getusershell())) {
         if ( strcmp( p, pwd->pw_shell ) == 0 )
@@ -342,7 +360,6 @@ int uam_checkuser(const struct passwd *pwd)
     }
     endusershell();
 
-#ifndef DISABLE_SHELLCHECK
     if (!p) {
         LOG(log_info, logtype_afpd, "illegal shell %s for %s", pwd->pw_shell, pwd->pw_name);
         return -1;
@@ -352,27 +369,57 @@ int uam_checkuser(const struct passwd *pwd)
     return 0;
 }
 
+int uam_random_string (AFPObj *obj, char *buf, int len)
+{
+    u_int32_t result;
+    int ret;
+    int fd;
+
+    if ( (len <= 0) || (len % sizeof(result)))
+            return -1;
+
+    /* construct a random number */
+    if ((fd = open("/dev/urandom", O_RDONLY)) < 0) {
+        struct timeval tv;
+        struct timezone tz;
+        int i;
+
+        if (gettimeofday(&tv, &tz) < 0)
+            return -1;
+        srandom(tv.tv_sec + (unsigned long) obj + (unsigned long) obj->handle);
+        for (i = 0; i < len; i += sizeof(result)) {
+            result = random();
+            memcpy(buf + i, &result, sizeof(result));
+        }
+    } else {
+        ret = read(fd, buf, len);
+        close(fd);
+        if (ret <= 0)
+            return -1;
+    }
+    return 0;
+}
+
 /* afp-specific functions */
 int uam_afpserver_option(void *private, const int what, void *option,
                          int *len)
 {
 AFPObj *obj = private;
     char **buf = (char **) option; /* most of the options are this */
-    int32_t result;
-    int fd;
+    struct session_info **sinfo = (struct session_info **) option;
 
     if (!obj || !option)
         return -1;
 
     switch (what) {
     case UAM_OPTION_USERNAME:
-        *buf = (void *) obj->username;
+        *buf = obj->username;
         if (len)
             *len = sizeof(obj->username) - 1;
         break;
 
     case UAM_OPTION_GUEST:
-        *buf = (void *) obj->options.guest;
+        *buf = obj->options.guest;
         if (len)
             *len = strlen(obj->options.guest);
         break;
@@ -383,7 +430,7 @@ AFPObj *obj = private;
 
         switch (*len) {
         case UAM_PASSWD_FILENAME:
-            *buf = (void *) obj->options.passwdfile;
+            *buf = obj->options.passwdfile;
             *len = strlen(obj->options.passwdfile);
             break;
 
@@ -411,40 +458,22 @@ AFPObj *obj = private;
         break;
 
     case UAM_OPTION_RANDNUM: /* returns a random number in 4-byte units. */
-        if (!len || (*len < 0) || (*len % sizeof(result)))
+        if (!len)
             return -1;
 
-        /* construct a random number */
-        if ((fd = open("/dev/urandom", O_RDONLY)) < 0) {
-            struct timeval tv;
-            struct timezone tz;
-            char *randnum = (char *) option;
-            int i;
-
-            if (gettimeofday(&tv, &tz) < 0)
-                return -1;
-            srandom(tv.tv_sec + (unsigned long) obj + (unsigned long) obj->handle);
-            for (i = 0; i < *len; i += sizeof(result)) {
-                result = random();
-                memcpy(randnum + i, &result, sizeof(result));
-            }
-        } else {
-            result = read(fd, option, *len);
-            close(fd);
-            if (result < 0)
-                return -1;
-        }
+        return uam_random_string(obj, option, *len);
         break;
 
     case UAM_OPTION_HOSTNAME:
-        *buf = (void *) obj->options.hostname;
+        *buf = obj->options.hostname;
         if (len)
             *len = strlen(obj->options.hostname);
         break;
 
     case UAM_OPTION_PROTOCOL:
-        *buf = (void *) obj->proto;
+        *((int *) option) = obj->proto;
         break;
+        
     case UAM_OPTION_CLIENTNAME:
         {
             struct DSI *dsi = obj->handle;
@@ -454,9 +483,9 @@ AFPObj *obj = private;
                                 sizeof( struct in_addr ),
                                 dsi->client.sin_family );
             if( hp )
-                *buf = (void *) hp->h_name;
+                *buf = hp->h_name;
             else
-                *buf = (void *) inet_ntoa( dsi->client.sin_addr );
+                *buf = inet_ntoa( dsi->client.sin_addr );
         }
         break;
     case UAM_OPTION_COOKIE:
@@ -469,8 +498,29 @@ AFPObj *obj = private;
     case UAM_OPTION_KRB5SERVICE:
        *buf = obj->options.k5service;
         if (len)
-            *len = strlen(obj->options.k5service);
+            *len = (*buf)?strlen(*buf):0;
        break;
+    case UAM_OPTION_KRB5REALM:
+       *buf = obj->options.k5realm;
+        if (len)
+            *len = (*buf)?strlen(*buf):0;
+       break;
+    case UAM_OPTION_FQDN:
+       *buf = obj->options.fqdn;
+        if (len)
+            *len = (*buf)?strlen(*buf):0;
+       break;
+    case UAM_OPTION_MACCHARSET:
+        *((int *) option) = obj->options.maccharset;
+        *len = sizeof(obj->options.maccharset);
+        break;
+    case UAM_OPTION_UNIXCHARSET:
+        *((int *) option) = obj->options.unixcharset;
+        *len = sizeof(obj->options.unixcharset);
+        break;
+    case UAM_OPTION_SESSIONINFO:
+        *sinfo = &(obj->sinfo);
+        break;
     default:
         return -1;
         break;
@@ -572,7 +622,7 @@ int uam_sia_validate_user(sia_collect_func_t * collect, int argc, char **argv,
 #endif /* TRU64 */
 
 /* --- papd-specific functions (just placeholders) --- */
-void append(void *pf, char *data, int len)
+void append(void *pf  _U_, char *data _U_, int len _U_)
 {
     return;
 }
index fe9fe08d846dc531f381afccfff2226bb107d684..7f663f81336c93ed5273aa3cda60daf71db6a4dd 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: uam_auth.h,v 1.4 2002-10-17 18:01:54 didg Exp $
+ * $Id: uam_auth.h,v 1.5 2005-04-28 20:49:45 bfernhomberg Exp $
  *
  * Copyright (c) 1999 Adrian Sun (asun@zoology.washington.edu)
  * All Rights Reserved.  See COPYRIGHT.
@@ -64,4 +64,7 @@ int auth_register __P((const int, struct uam_obj *));
 struct uam_obj *auth_uamfind __P((const int, const char *, const int));
 void auth_unload __P((void));
 
+/* uam.c */
+int uam_random_string __P((AFPObj *,char *, int));
+
 #endif /* uam_auth.h */
index 0a3a135a5c594a20daeb347961f86997e5bc6e9e..817ac6590802568e718675b67d954a052838a160 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: uid.c,v 1.13 2002-08-30 19:32:41 didg Exp $
+ * $Id: uid.c,v 1.14 2005-04-28 20:49:45 bfernhomberg Exp $
  * code: jeff@univrel.pr.uconn.edu
  *
  * These functions are abstracted here, so that all calls for resolving
@@ -40,7 +40,8 @@ uidgidset *pair;
 void restore_uidgid ( pair )
 uidgidset *pair;
 {
-    int                uid, gid;   
+    uid_t uid
+    gid_t gid;   
     
     uid = geteuid ();
     gid = getegid ();
index 22019e563a77fe2144c52cf153ec7ecc5b79a68a..c6bc78882a987b04e7d91316add197f0f5a39bee 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: unix.c,v 1.45 2003-06-06 21:18:00 srittau Exp $
+ * $Id: unix.c,v 1.46 2005-04-28 20:49:45 bfernhomberg Exp $
  *
  * Copyright (c) 1990,1993 Regents of The University of Michigan.
  * All Rights Reserved.  See COPYRIGHT.
 
 #include <stdio.h>
 #include <stdlib.h>
-#include <unistd.h>
-#include <errno.h>
-#include <sys/types.h>
-#include <sys/param.h>
-#include <sys/stat.h>
-#include <atalk/logger.h>
-#include <netatalk/endian.h>
-#include <dirent.h>
-#include <limits.h>
-#include <atalk/adouble.h>
-#include <atalk/afp.h>
+
 /* STDC check */
 #ifdef STDC_HEADERS
 #include <string.h>
 #else /* STDC_HEADERS */
+
 #ifndef HAVE_STRCHR
 #define strchr index
 #define strrchr index
 #endif /* HAVE_STRCHR */
 char *strchr (), *strrchr ();
+
 #ifndef HAVE_MEMCPY
 #define memcpy(d,s,n) bcopy ((s), (d), (n))
 #define memmove(d,s,n) bcopy ((s), (d), (n))
 #endif /* ! HAVE_MEMCPY */
 #endif /* STDC_HEADERS */
 
-#ifdef HAVE_FCNTL_H
-#include <fcntl.h>
-#endif /* HAVE_FCNTL_H */
+#include <errno.h>
+#include <dirent.h>
+#include <limits.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <atalk/logger.h>
+#include <atalk/adouble.h>
+#include <atalk/afp.h>
+#include <atalk/util.h>
+
 #include "auth.h"
 #include "directory.h"
 #include "volume.h"
@@ -151,16 +150,19 @@ mode_t mode;
      * the "owner" bit set, even tho you can do these things on unix wiht
      * only write permission.  What were the things?
      * 
-     * FIXME and so what ?
+     * FIXME 
+     * ditto seems to care if st_uid is 0 ?
+     * was ma->ma_user & AR_UWRITE
+     * but 0 as owner is a can of worms.
      */
-#if 0
-    if ( ma->ma_user & AR_UWRITE ) {
+    if ( !stat->st_uid ) {
         ma->ma_user |= AR_UOWN;
     }
-#endif    
 }
 
-
+#ifdef accessmode
+#undef accessmode
+#endif
 /*
  * Calculate the mode for a directory using a stat() call to
  * estimate permission.
@@ -168,11 +170,13 @@ mode_t mode;
  * Note: the previous method, using access(), does not work correctly
  * over NFS.
  * FIXME what about ACL?
+ *
+ * dir parameter is used by AFS
  */
 void accessmode( path, ma, dir, st )
 char           *path;
 struct maccess *ma;
-struct dir     *dir;
+struct dir     *dir _U_;
 struct stat     *st;
 
 {
@@ -185,7 +189,6 @@ struct stat     sb;
         st = &sb;
     }
     utommode( st, ma );
-    return;
 }
 
 int gmem( gid )
@@ -238,13 +241,28 @@ struct maccess    *ma;
     return( mode );
 }
 
-/*
+/* ----------------------------- */
+char *fullpathname(const char *name)
+{
+    static char wd[ MAXPATHLEN + 1];
+
+    if ( getcwd( wd , MAXPATHLEN) ) {
+        strlcat(wd, "/", MAXPATHLEN);
+        strlcat(wd, name, MAXPATHLEN);
+    }
+    else {
+        strlcpy(wd, name, MAXPATHLEN);
+    }
+    return wd;
+}
+
+/* -----------------------------
    a dropbox is a folder where w is set but not r eg:
    rwx-wx-wx or rwx-wx-- 
    rwx----wx (is not asked by a Mac with OS >= 8.0 ?)
 */
-static int stickydirmode(name, mode, dropbox)
-char * name;
+int stickydirmode(name, mode, dropbox)
+const char * name;
 const mode_t mode;
 const int dropbox;
 {
@@ -263,10 +281,10 @@ const int dropbox;
                 LOG(log_error, logtype_afpd, "stickydirmode: unable to seteuid root: %s", strerror(errno));
             }
             if ( (retval=chmod( name, ( (DIRBITS | mode | S_ISVTX) & ~default_options.umask) )) < 0) {
-                LOG(log_error, logtype_afpd, "stickydirmode: chmod \"%s\": %s", name, strerror(errno) );
+                LOG(log_error, logtype_afpd, "stickydirmode: chmod \"%s\": %s", fullpathname(name), strerror(errno) );
             } else {
 #ifdef DEBUG
-                LOG(log_info, logtype_afpd, "stickydirmode: (debug) chmod \"%s\": %s", name, strerror(retval) );
+                LOG(log_info, logtype_afpd, "stickydirmode: (debug) chmod \"%s\": %s", fullpathname(name), strerror(retval) );
 #endif /* DEBUG */
             }
             seteuid(uid);
@@ -280,13 +298,21 @@ const int dropbox;
      *  group writable, in which case chmod will fail.
      */
     if ( (chmod( name, (DIRBITS | mode) & ~default_options.umask ) < 0) && errno != EPERM)  {
-        LOG(log_error, logtype_afpd, "stickydirmode: chmod \"%s\": %s",name, strerror(errno) );
+        LOG(log_error, logtype_afpd, "stickydirmode: chmod \"%s\": %s", fullpathname(name), strerror(errno) );
         retval = -1;
     }
 
     return retval;
 }
 
+/* ------------------------- */
+int dir_rx_set(mode_t mode)
+{
+    return (mode & (S_IXUSR | S_IRUSR)) == (S_IXUSR | S_IRUSR);
+}
+
+#define EXEC_MODE (S_IXGRP | S_IXUSR | S_IXOTH)
+
 int setdeskmode( mode )
 const mode_t   mode;
 {
@@ -296,6 +322,10 @@ const mode_t       mode;
     struct dirent      *deskp, *subp;
     DIR                        *desk, *sub;
 
+    if (!dir_rx_set(mode)) {
+        /* want to remove read and search access to owner it will screw the volume */
+        return -1 ;
+    }
     if ( getcwd( wd , MAXPATHLEN) == NULL ) {
         return( -1 );
     }
@@ -328,27 +358,23 @@ const mode_t      mode;
             strcat( modbuf, subp->d_name );
             /* XXX: need to preserve special modes */
             if (stat(modbuf, &st) < 0) {
-                LOG(log_error, logtype_afpd, "setdeskmode: stat %s: %s",
-                    modbuf, strerror(errno) );
+                LOG(log_error, logtype_afpd, "setdeskmode: stat %s: %s",fullpathname(modbuf), strerror(errno) );
                 continue;
             }
 
             if (S_ISDIR(st.st_mode)) {
                 if ( chmod( modbuf,  (DIRBITS | mode) & ~default_options.umask ) < 0 && errno != EPERM ) {
-                    LOG(log_error, logtype_afpd, "setdeskmode: chmod %s: %s",
-                        modbuf, strerror(errno) );
+                     LOG(log_error, logtype_afpd, "setdeskmode: chmod %s: %s",fullpathname(modbuf), strerror(errno) );
                 }
-            } else if ( chmod( modbuf,  mode & ~default_options.umask ) < 0 && errno != EPERM ) {
-                LOG(log_error, logtype_afpd, "setdeskmode: chmod %s: %s",
-                    modbuf, strerror(errno) );
+            } else if ( chmod( modbuf,  mode & ~(default_options.umask | EXEC_MODE) ) < 0 && errno != EPERM ) {
+                LOG(log_error, logtype_afpd, "setdeskmode: chmod %s: %s",fullpathname(modbuf), strerror(errno) );
             }
 
         }
         closedir( sub );
         /* XXX: need to preserve special modes */
         if ( chmod( deskp->d_name,  (DIRBITS | mode) & ~default_options.umask ) < 0 && errno != EPERM ) {
-            LOG(log_error, logtype_afpd, "setdeskmode: chmod %s: %s",
-                deskp->d_name, strerror(errno) );
+            LOG(log_error, logtype_afpd, "setdeskmode: chmod %s: %s",fullpathname(deskp->d_name), strerror(errno) );
         }
     }
     closedir( desk );
@@ -358,13 +384,14 @@ const mode_t      mode;
     }
     /* XXX: need to preserve special modes */
     if ( chmod( ".AppleDesktop",  (DIRBITS | mode) & ~default_options.umask ) < 0 && errno != EPERM ) {
-        LOG(log_error, logtype_afpd, "setdeskmode: chmod .AppleDesktop: %s", strerror(errno) );
+        LOG(log_error, logtype_afpd, "setdeskmode: chmod %s: %s", fullpathname(".AppleDesktop"),strerror(errno) );
     }
     return( 0 );
 }
 
 /* --------------------- */
-int setfilemode (path, mode)
+int setfilunixmode (vol, path, mode)
+const struct vol *vol;
 struct path* path;
 mode_t mode;
 {
@@ -379,12 +406,12 @@ mode_t mode;
     if (setfilmode( path->u_name, mode, &path->st) < 0)
         return -1;
     /* we need to set write perm if read set for resource fork */
-    return setfilmode(ad_path( path->u_name, ADFLAGS_HF ), ad_hf_mode(mode), &path->st);
+    return vol->vfs->rf_setfilmode(vol, path->u_name, mode, &path->st);
 }
 
 /* --------------------- */
 int setfilmode(name, mode, st)
-char * name;
+const char * name;
 mode_t mode;
 struct stat *st;
 {
@@ -405,109 +432,86 @@ mode_t mask = S_IRUSR |S_IWUSR | S_IRGRP | S_IWGRP |S_IROTH | S_IWOTH;
 }
 
 /* --------------------- */
-int setdirunixmode( mode, noadouble, dropbox )
-const mode_t mode;
-const int noadouble;
-const int dropbox;
+int setdirunixmode( vol, name, mode )
+const struct vol *vol;
+const char       *name;
+const mode_t     mode;
 {
-    if ( stickydirmode(".AppleDouble", DIRBITS | mode, dropbox) < 0 && !noadouble)
-        return  -1 ;
 
-    if ( stickydirmode(".", DIRBITS | mode, dropbox) < 0 )
-        return -1;
+    int dropbox = (vol->v_flags & AFPVOL_DROPBOX);
+
+    if (dir_rx_set(mode)) {
+       /* extending right? dir first then .AppleDouble in rf_setdirmode */
+       if ( stickydirmode(name, DIRBITS | mode, dropbox) < 0 )
+               return -1;
+    }
+    if (vol->vfs->rf_setdirunixmode(vol, name, mode, NULL) < 0 && !vol_noadouble(vol)) {
+        return  -1 ;
+    }
+    if (!dir_rx_set(mode)) {
+       if ( stickydirmode(name, DIRBITS | mode, dropbox) < 0 )
+            return -1;
+    }
     return 0;
 }
 
 /* --------------------- */
-int setdirmode( mode, noadouble, dropbox )
+int setdirmode( vol, name, mode )
+const struct vol *vol;
+const char       *name;
 const mode_t mode;
-const int noadouble;
-const int dropbox;
 {
-    char               buf[ MAXPATHLEN + 1];
     struct stat                st;
-    char               *m;
     struct dirent      *dirp;
     DIR                        *dir;
+    int                 osx = vol->v_adouble == AD_VERSION2_OSX;
+    mode_t              hf_mode = ad_hf_mode(mode);
+    int                 dropbox = (vol->v_flags & AFPVOL_DROPBOX);
+    
+    if (dir_rx_set(mode)) {
+       /* extending right? dir first */
+       if ( stickydirmode(name, DIRBITS | mode, dropbox) < 0 )
+               return -1;
+    }
     
-    if (( dir = opendir( "." )) == NULL ) {
-        LOG(log_error, logtype_afpd, "setdirmode: opendir .: %s", strerror(errno) );
+    if (( dir = opendir( name )) == NULL ) {
+        LOG(log_error, logtype_afpd, "setdirmode: opendir: %s", fullpathname(name), strerror(errno) );
         return( -1 );
     }
 
     for ( dirp = readdir( dir ); dirp != NULL; dirp = readdir( dir )) {
-        if ( *dirp->d_name == '.' ) {
+        /* FIXME */
+        if ( *dirp->d_name == '.' && (!osx || dirp->d_name[1] != '_')) {
             continue;
         }
         if ( stat( dirp->d_name, &st ) < 0 ) {
-            LOG(log_error, logtype_afpd, "setdirmode: stat %s: %s",
-                dirp->d_name, strerror(errno) );
+            LOG(log_error, logtype_afpd, "setdirmode: stat %s: %s",dirp->d_name, strerror(errno) );
             continue;
         }
 
         if (!S_ISDIR(st.st_mode)) {
-           if (setfilmode(dirp->d_name, mode, &st) < 0) {
-                LOG(log_error, logtype_afpd, "setdirmode: chmod %s: %s",
-                    dirp->d_name, strerror(errno) );
+           int setmode = (osx && *dirp->d_name == '.')?hf_mode:mode;
+
+           if (setfilmode(dirp->d_name, setmode, &st) < 0) {
+                LOG(log_error, logtype_afpd, "setdirmode: chmod %s: %s",dirp->d_name, strerror(errno) );
                 return -1;
            }
         }
-#if 0
-            /* XXX: need to preserve special modes */
-        else if (S_ISDIR(st.st_mode)) {
-                if (stickydirmode(dirp->d_name, DIRBITS | mode, dropbox) < 0)
-                    return (-1);
-            } else if (stickydirmode(dirp->d_name, mode, dropbox) < 0)
-                return (-1);
-        }
-#endif
     }
     closedir( dir );
-
-    /* change perm of .AppleDouble's files
-    */
-    if (( dir = opendir( ".AppleDouble" )) == NULL ) {
-        if (noadouble)
-            goto setdirmode_noadouble;
-        LOG(log_error, logtype_afpd, "setdirmode: opendir .AppleDouble: %s", strerror(errno) );
-        return( -1 );
+    
+    if (vol->vfs->rf_setdirmode(vol, name, mode, NULL) < 0 && !vol_noadouble(vol)) {
+        return  -1 ;
     }
-    strcpy( buf, ".AppleDouble" );
-    strcat( buf, "/" );
-    m = strchr( buf, '\0' );
-    for ( dirp = readdir( dir ); dirp != NULL; dirp = readdir( dir )) {
-        if ( strcmp( dirp->d_name, "." ) == 0 ||
-                strcmp( dirp->d_name, ".." ) == 0 ) {
-            continue;
-        }
-        *m = '\0';
-        strcat( buf, dirp->d_name );
 
-        if ( stat( buf, &st ) < 0 ) {
-            LOG(log_error, logtype_afpd, "setdirmode: stat %s: %s", buf, strerror(errno) );
-            continue;
-        }
-        if (!S_ISDIR(st.st_mode)) {
-           if (setfilmode(buf, ad_hf_mode(mode), &st) < 0) {
-               /* FIXME what do we do then? */
-           }
-        }
-    } /* end for */
-    closedir( dir );
-
-    /* XXX: use special bits to tag directory permissions */
-
-    /* XXX: need to preserve special modes */
-    if ( stickydirmode(".AppleDouble", DIRBITS | mode, dropbox) < 0 )
-        return( -1 );
-
-setdirmode_noadouble:
-    /* XXX: need to preserve special modes */
-    if ( stickydirmode(".", DIRBITS | mode, dropbox) < 0 )
-        return( -1 );
+    if (!dir_rx_set(mode)) {
+       if ( stickydirmode(name, DIRBITS | mode, dropbox) < 0 )
+               return -1;
+    }
     return( 0 );
 }
 
+/* ----------------------------- */
 int setdeskowner( uid, gid )
 const uid_t    uid;
 const gid_t    gid;
@@ -550,8 +554,7 @@ const gid_t gid;
             strcat( modbuf, subp->d_name );
             /* XXX: add special any uid, ignore group bits */
             if ( chown( modbuf, uid, gid ) < 0 && errno != EPERM ) {
-                LOG(log_error, logtype_afpd, "setdeskown: chown %s: %s",
-                    modbuf, strerror(errno) );
+                LOG(log_error, logtype_afpd, "setdeskown: chown %s: %s", fullpathname(modbuf), strerror(errno) );
             }
         }
         closedir( sub );
@@ -567,94 +570,90 @@ const gid_t       gid;
         return -1;
     }
     if ( chown( ".AppleDesktop", uid, gid ) < 0 && errno != EPERM ) {
-        LOG(log_error, logtype_afpd, "setdeskowner: chown .AppleDesktop: %s",
-            strerror(errno) );
+        LOG(log_error, logtype_afpd, "setdeskowner: chown %s: %s", fullpathname(".AppleDouble"), strerror(errno) );
     }
     return( 0 );
 }
 
+/* ----------------------------- */
+int setfilowner(vol, uid, gid, path)
+const struct vol *vol;
+const uid_t    uid;
+const gid_t    gid;
+struct path* path;
+{
+
+    if (!path->st_valid) {
+        of_stat(path);
+    }
 
-/* uid/gid == 0 need to be handled as special cases. they really mean
+    if (path->st_errno) {
+        return -1;
+    }
+
+    if ( chown( path->u_name, uid, gid ) < 0 && errno != EPERM ) {
+        LOG(log_debug, logtype_afpd, "setfilowner: chown %d/%d %s: %s",
+            uid, gid, path->u_name, strerror(errno) );
+       return -1;
+    }
+
+    if (vol->vfs->rf_chown(vol, path->u_name, uid, gid ) < 0 && errno != EPERM) {
+        LOG(log_debug, logtype_afpd, "setfilowner: rf_chown %d/%d %s: %s",
+            uid, gid, path->u_name, strerror(errno) );
+        return -1;
+    }
+
+    return 0;
+}
+
+/* --------------------------------- 
+ * uid/gid == 0 need to be handled as special cases. they really mean
  * that user/group should inherit from other, but that doesn't fit
  * into the unix permission scheme. we can get around this by
  * co-opting some bits. */
-int setdirowner( uid, gid, noadouble )
+int setdirowner(vol, name, uid, gid )
+const struct vol *vol;
+const char      *name;
 const uid_t    uid;
 const gid_t    gid;
-const int   noadouble;
 {
-    char               buf[ MAXPATHLEN + 1];
     struct stat                st;
-    char               *m;
     struct dirent      *dirp;
     DIR                        *dir;
+    int                 osx = vol->v_adouble == AD_VERSION2_OSX;
 
-    if (( dir = opendir( "." )) == NULL ) {
+    if (( dir = opendir( name )) == NULL ) {
         return( -1 );
     }
     for ( dirp = readdir( dir ); dirp != NULL; dirp = readdir( dir )) {
-        if ( *dirp->d_name == '.' ) {
+        if ( *dirp->d_name == '.' && (!osx || dirp->d_name[1] != '_')) {
             continue;
-        };
+        }
         if ( stat( dirp->d_name, &st ) < 0 ) {
             LOG(log_error, logtype_afpd, "setdirowner: stat %s: %s",
-                dirp->d_name, strerror(errno) );
+                fullpathname(dirp->d_name), strerror(errno) );
             continue;
         }
         if (( st.st_mode & S_IFMT ) == S_IFREG ) {
             if ( chown( dirp->d_name, uid, gid ) < 0 && errno != EPERM ) {
                 LOG(log_debug, logtype_afpd, "setdirowner: chown %s: %s",
-                    dirp->d_name, strerror(errno) );
+                    fullpathname(dirp->d_name), strerror(errno) );
                 /* return ( -1 ); Sometimes this is okay */
             }
         }
     }
     closedir( dir );
-    if (( dir = opendir( ".AppleDouble" )) == NULL ) {
-        if (noadouble)
-            goto setdirowner_noadouble;
-        return( -1 );
-    }
-    strcpy( buf, ".AppleDouble" );
-    strcat( buf, "/" );
-    m = strchr( buf, '\0' );
-    for ( dirp = readdir( dir ); dirp != NULL; dirp = readdir( dir )) {
-        if ( strcmp( dirp->d_name, "." ) == 0 ||
-                strcmp( dirp->d_name, ".." ) == 0 ) {
-            continue;
-        }
-        *m = '\0';
-        strcat( buf, dirp->d_name );
-        if ( chown( buf, uid, gid ) < 0 && errno != EPERM ) {
-            LOG(log_debug, logtype_afpd, "setdirowner: chown %d/%d %s: %s",
-                uid, gid, buf, strerror(errno) );
-            /* return ( -1 ); Sometimes this is okay */
-        }
-    }
-    closedir( dir );
 
-    /*
-     * We cheat: we know that chown doesn't do anything.
-     */
-    if ( stat( ".AppleDouble", &st ) < 0 ) {
-        LOG(log_error, logtype_afpd, "setdirowner: stat .AppleDouble: %s", strerror(errno) );
-        return( -1 );
-    }
-    if ( gid && gid != st.st_gid && chown( ".AppleDouble", uid, gid ) < 0 &&
-            errno != EPERM ) {
-        LOG(log_debug, logtype_afpd, "setdirowner: chown %d/%d .AppleDouble: %s",
-            uid, gid, strerror(errno) );
-        /* return ( -1 ); Sometimes this is okay */
+    if (vol->vfs->rf_setdirowner(vol, name, uid, gid) < 0) {
+        return -1;
     }
-
-setdirowner_noadouble:
+    
     if ( stat( ".", &st ) < 0 ) {
         return( -1 );
     }
-    if ( gid && gid != st.st_gid && chown( ".", uid, gid ) < 0 &&
-            errno != EPERM ) {
-        LOG(log_debug, logtype_afpd, "setdirowner: chown %d/%d .: %s",
-            uid, gid, strerror(errno) );
+    if ( gid && gid != st.st_gid && chown( ".", uid, gid ) < 0 && errno != EPERM ) {
+        LOG(log_debug, logtype_afpd, "setdirowner: chown %d/%d %s: %s",
+            uid, gid, fullpathname("."), strerror(errno) );
     }
 
     return( 0 );
@@ -672,19 +671,19 @@ static int recursive_chown(const char *path, uid_t uid, gid_t gid) {
     newpath[PATH_MAX] = '\0';
     
     if (chown(path, uid, gid) < 0) {
-        LOG(log_error, logtype_afpd, "cannot chown() file [%s] (uid = %d): %s\n", path, uid, strerror(errno));
+        LOG(log_error, logtype_afpd, "cannot chown() file [%s] (uid = %d): %s", path, uid, strerror(errno));
        return -1;
     }
 
     if (stat(path, &sbuf) < 0) {
-       LOG(log_error, logtype_afpd, "cannot chown() file [%s] (uid = %d): %s\n", path, uid, strerror(errno));
+       LOG(log_error, logtype_afpd, "cannot chown() file [%s] (uid = %d): %s", path, uid, strerror(errno));
        return -1;
     }
        
     if (S_ISDIR(sbuf.st_mode)) {
        odir = opendir(path);
        if (odir == NULL) {
-           LOG(log_error, logtype_afpd, "cannot opendir() [%s] (uid = %d): %s\n", path, uid, strerror(errno));
+           LOG(log_error, logtype_afpd, "cannot opendir() [%s] (uid = %d): %s", path, uid, strerror(errno));
            goto recursive_chown_end;
        }
        while (NULL != (entry=readdir(odir)) ) {
@@ -730,7 +729,7 @@ int unix_rename(const char *oldpath, const char *newpath)
         pd_name[i++] = '.'; pd_name[i++] = '\0';
 
         if (stat(pd_name, &pd_stat) < 0) {
-           LOG(log_error, logtype_afpd, "stat() of parent dir failed: pd_name = %s, uid = %d: %s\n",
+           LOG(log_error, logtype_afpd, "stat() of parent dir failed: pd_name = %s, uid = %d: %s",
                pd_name, geteuid(), strerror(errno));
                return 0;
        }
@@ -739,9 +738,9 @@ int unix_rename(const char *oldpath, const char *newpath)
         if ((S_ISGID & pd_stat.st_mode)        != 0) {
             uid = geteuid();
             if (seteuid(0) < 0)
-               LOG(log_error, logtype_afpd, "seteuid() failed: %s\n", strerror(errno));
+               LOG(log_error, logtype_afpd, "seteuid() failed: %s", strerror(errno));
             if (recursive_chown(newpath, uid, pd_stat.st_gid) < 0)
-               LOG(log_error, logtype_afpd, "chown() of parent dir failed: newpath=%s, uid=%d: %s\n",
+               LOG(log_error, logtype_afpd, "chown() of parent dir failed: newpath=%s, uid=%d: %s",
                    pd_name, geteuid(), strerror(errno));
             seteuid(uid);
        }
index b0d377c3d03be95c3cc7f130e4b5f65a358054e3..9e2fec919706e39565832c220b1c6def2bff91f9 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: unix.h,v 1.17 2004-01-14 16:10:29 bfernhomberg Exp $
+ * $Id: unix.h,v 1.18 2005-04-28 20:49:45 bfernhomberg Exp $
  */
 
 #ifndef AFPD_UNIX_H
@@ -9,6 +9,7 @@
 #include <sys/cdefs.h>
 #endif /* HAVE_SYS_CDEFS_H */
 #include <netatalk/endian.h>
+#include "config.h"
 #include "volume.h"
 
 #if defined( sun ) && !defined( __svr4__ )
@@ -30,7 +31,8 @@ typedef int   mode_t;
 #if defined(TRU64)
 #define f_frsize f_fsize
 #else /* TRU64 */
-#if defined(HAVE_SYS_STATVFS_H) || defined(__svr4__)
+/* temp fix, was: defined(HAVE_SYS_STATVFS) || defined(__svr4__) */
+#if defined(__svr4__)
 #include <sys/statvfs.h>
 #define statfs statvfs
 #else /* HAVE_SYS_STATVFS || __svr4__ */
@@ -42,12 +44,12 @@ typedef int mode_t;
 #include <sys/mnttab.h>
 #endif /* __svr4__ || HAVE_SYS_MNTTAB_H */
 
-#ifdef HAVE_SYS_MOUNT_H
-#ifdef HAVE_SYS_PARM_H
-#include <sys/parm.h>
-#endif /* HAVE_SYS_PARM_H */
+
+
+#if defined(HAVE_SYS_MOUNT_H) || defined(BSD4_4) || \
+    defined(linux) || defined(ultrix)
 #include <sys/mount.h>
-#endif /* HAVE_SYS_MOUNT_H */
+#endif /* HAVE_SYS_MOUNT_H || BSD4_4 || linux || ultrix */
 
 #if defined(linux) || defined(HAVE_MNTENT_H)
 #include <mntent.h>
@@ -60,9 +62,18 @@ typedef int  mode_t;
 #define dqb_btimelimit  dqb_btime
 #endif /* ! __svr4__ || HAVE_DQB_BTIMELIMIT */
 
-#if defined(HAVE_SYS_QUOTA_H)
-#include <sys/quota.h>
-#endif /* HAVE_SYS_QUOTA_H */
+#if defined(linux) || defined(ultrix) || defined(HAVE_QUOTA_H)
+#ifndef NEED_QUOTACTL_WRAPPER
+/*#include <sys/quota.h>*/
+/*long quotactl __P((int, const char *, unsigned int, caddr_t)); */
+/* extern long quotactl __P((int, const char *, long, caddr_t)); */
+
+#else /* ! NEED_QUOTACTL_WRAPPER */
+#include <asm/types.h>
+#include <asm/unistd.h>
+#include <linux/quota.h>
+#endif /* ! NEED_QUOTACTL_WRAPPER */
+#endif /* linux || ultrix || HAVE_QUOTA_H */
 
 #ifdef __svr4__ 
 #include <sys/fs/ufs_quota.h>
@@ -76,20 +87,129 @@ typedef int        mode_t;
 #include <ufs/quota.h>
 #endif /* HAVE_UFS_QUOTA_H */
 
+#ifdef _IBMR2
+#include <jfs/quota.h>
+#endif /* _IBMR2 */
+
 #include <unistd.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include "directory.h"
 
-#ifdef HAVE_STRUCT_IF_DQBLK
-#undef dqblk
-#define dqblk if_dqblk
-#endif
 
-extern int getnfsquota __P((const struct vol *, const int, const u_int32_t,
+#if defined (linux)
+
+#define MAXQUOTAS 2
+
+/* definitions from sys/quota.h */
+#define USRQUOTA  0             /* element used for user quotas */
+#define GRPQUOTA  1             /* element used for group quotas */
+
+/*
+ * Command definitions for the 'quotactl' system call.
+ * The commands are broken into a main command defined below
+ * and a subcommand that is used to convey the type of
+ * quota that is being manipulated (see above).
+ */
+#define SUBCMDMASK  0x00ff
+#define SUBCMDSHIFT 8
+#define QCMD(cmd, type)  (((cmd) << SUBCMDSHIFT) | ((type) & SUBCMDMASK))
+
+/* declare an internal version of the quota block struct */
+typedef u_int64_t qsize_t;     /* Type in which we store size limitations */
+typedef u_int32_t qid_t;       /* Type in which we store ids in memory */
+
+struct dqblk {
+  qsize_t bsize;
+  qsize_t dqb_ihardlimit;   /* absolute limit on allocated inodes */
+  qsize_t dqb_isoftlimit;   /* preferred inode limit */
+  qsize_t dqb_curinodes;    /* current # allocated inodes */
+  qsize_t dqb_bhardlimit;   /* absolute limit on disk blks alloc */
+  qsize_t dqb_bsoftlimit;   /* preferred limit on disk blks */
+  qsize_t dqb_curblocks;    /* current block count */
+  time_t  dqb_btime;        /* time limit for excessive disk use */
+  time_t  dqb_itime;        /* time limit for excessive inode use */
+};
+
+/* API v1 command definitions */
+#define Q_V1_GETQUOTA  0x0300
+#define Q_V1_SYNC      0x0600
+#define Q_V1_SETQLIM   0x0700
+#define Q_V1_GETSTATS  0x0800
+/* API v2 command definitions */
+#define Q_V2_SYNC      0x0600
+#define Q_V2_SETQLIM   0x0700
+#define Q_V2_GETQUOTA  0x0D00
+#define Q_V2_GETSTATS  0x1100
+/* proc API command definitions */
+#define Q_V3_SYNC      0x800001
+#define Q_V3_GETQUOTA  0x800007
+#define Q_V3_SETQUOTA  0x800008
+
+/* Interface versions */
+#define IFACE_UNSET 0
+#define IFACE_VFSOLD 1
+#define IFACE_VFSV0 2
+#define IFACE_GENERIC 3
+
+#define DEV_QBSIZE 1024
+
+struct dqblk_v3 {
+  u_int64_t dqb_bhardlimit;
+  u_int64_t dqb_bsoftlimit;
+  u_int64_t dqb_curspace;
+  u_int64_t dqb_ihardlimit;
+  u_int64_t dqb_isoftlimit;
+  u_int64_t dqb_curinodes;
+  u_int64_t dqb_btime;
+  u_int64_t dqb_itime;
+  u_int32_t dqb_valid;
+};
+
+struct dqblk_v2 {
+  unsigned int dqb_ihardlimit;
+  unsigned int dqb_isoftlimit;
+  unsigned int dqb_curinodes;
+  unsigned int dqb_bhardlimit;
+  unsigned int dqb_bsoftlimit;
+  qsize_t dqb_curspace;
+  time_t dqb_btime;
+  time_t dqb_itime;
+};
+
+struct dqstats_v2 {
+  u_int32_t lookups;
+  u_int32_t drops;
+  u_int32_t reads;
+  u_int32_t writes;
+  u_int32_t cache_hits;
+  u_int32_t allocated_dquots;
+  u_int32_t free_dquots;
+  u_int32_t syncs;
+  u_int32_t version;
+};
+
+struct dqblk_v1 {
+  u_int32_t dqb_bhardlimit;
+  u_int32_t dqb_bsoftlimit;
+  u_int32_t dqb_curblocks;
+  u_int32_t dqb_ihardlimit;
+  u_int32_t dqb_isoftlimit;
+  u_int32_t dqb_curinodes;
+  time_t dqb_btime;
+  time_t dqb_itime;
+};
+
+extern long quotactl __P ((unsigned int, const char *, int, caddr_t));
+
+
+
+#endif /* linux */
+
+extern int getnfsquota __P((struct vol *, const int, const u_int32_t,
                                 struct dqblk *));
 
-extern int uquota_getvolspace __P((const struct vol *, VolSpace *, VolSpace *,
+extern int uquota_getvolspace __P((struct vol *, VolSpace *, VolSpace *,
                                        const u_int32_t));
 #endif /* NO_QUOTA_SUPPORT */
 
@@ -97,15 +217,19 @@ extern struct afp_options default_options;
 
 extern int gmem            __P((const gid_t));
 extern int setdeskmode      __P((const mode_t));
-extern int setdirunixmode   __P((const mode_t, const int, const int));
-extern int setdirmode       __P((const mode_t, const int, const int));
+extern int setdirunixmode   __P((const struct vol *, const char *, const mode_t));
+extern int setdirmode       __P((const struct vol *, const char *, const mode_t));
 extern int setdeskowner     __P((const uid_t, const gid_t));
-extern int setdirowner      __P((const uid_t, const gid_t, const int));
-extern int setfilmode       __P((char *, mode_t , struct stat *));
-extern int setfilemode      __P((struct path*, const mode_t));
+extern int setdirowner      __P((const struct vol *, const char *, const uid_t, const gid_t));
+extern int setfilmode       __P((const char *, mode_t , struct stat *));
+extern int setfilunixmode   __P((const struct vol *, struct path*, const mode_t));
+extern int setfilowner      __P((const struct vol *, const uid_t, const gid_t, struct path*));
 extern int unix_rename      __P((const char *oldpath, const char *newpath));
+extern int dir_rx_set       __P((mode_t mode));
+extern int stickydirmode    __P((const char * name, const mode_t mode, const int dropbox));
 
 extern void accessmode      __P((char *, struct maccess *, struct dir *, struct stat *));
+extern char *fullpathname   __P((const char *));
 
 #ifdef AFS     
     #define accessmode afsmode
diff --git a/etc/afpd/vfs_adouble.c b/etc/afpd/vfs_adouble.c
new file mode 100644 (file)
index 0000000..a80ae02
--- /dev/null
@@ -0,0 +1,758 @@
+/*
+    Copyright (c) 2004 Didier Gautheron
+   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 /* HAVE_CONFIG_H */
+
+#ifdef STDC_HEADERS
+#include <string.h>
+#endif
+
+#include <stdio.h>
+    
+#include <atalk/adouble.h>
+#include <atalk/logger.h>
+#include <atalk/util.h>
+
+#include "directory.h"
+#include "volume.h"
+#include "unix.h"
+
+struct perm {
+    uid_t uid;
+    gid_t gid;
+};
+
+typedef int (*rf_loop)(struct dirent *, char *, void *, int );
+
+/* ----------------------------- */
+static int 
+for_each_adouble(const char *from, const char *name, rf_loop fn, void *data, int flag)
+{
+    char            buf[ MAXPATHLEN + 1];
+    char            *m;
+    DIR             *dp;
+    struct dirent   *de;
+    int             ret;
+    
+
+    if (NULL == ( dp = opendir( name)) ) {
+        if (!flag) {
+            LOG(log_error, logtype_afpd, "%s: opendir %s: %s", from, fullpathname(name),strerror(errno) );
+            return -1;
+        }
+        return 0;
+    }
+    strlcpy( buf, name, sizeof(buf));
+    strlcat( buf, "/", sizeof(buf) );
+    m = strchr( buf, '\0' );
+    ret = 0;
+    while ((de = readdir(dp))) {
+        if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) {
+                continue;
+        }
+        
+        strlcat(buf, de->d_name, sizeof(buf));
+        if (fn && (ret = fn(de, buf, data, flag))) {
+           closedir(dp);
+           return ret;
+        }
+        *m = 0;
+    }
+    closedir(dp);
+    return ret;
+}
+
+/* ------------------------------ */
+static int ads_chown_loop(struct dirent *de _U_, char *name, void *data, int flag _U_)
+{
+    struct perm   *owner  = data;
+    
+    if (chown( name , owner->uid, owner->gid ) < 0) {
+        return -1;
+    }
+    return 0;
+}
+
+static int RF_chown_ads(const struct vol *vol, const char *path, uid_t uid, gid_t gid)
+
+{
+    struct        stat st;
+    char          *ad_p;
+    struct perm   owner;
+    
+    owner.uid = uid;
+    owner.gid = gid;
+
+
+    ad_p = ad_dir(vol->vfs->ad_path(path, ADFLAGS_HF ));
+
+    if ( stat( ad_p, &st ) < 0 ) {
+       /* ignore */
+        return 0;
+    }
+    
+    if (chown( ad_p, uid, gid ) < 0) {
+       return -1;
+    }
+    return for_each_adouble("chown_ads", ad_p, ads_chown_loop, &owner, 1);
+}
+
+/* --------------------------------- */
+static int deletecurdir_ads1_loop(struct dirent *de _U_, char *name, void *data _U_, int flag _U_)
+{
+    return netatalk_unlink(name);
+}
+
+static int ads_delete_rf(char *name) 
+{
+    int err;
+
+    if ((err = for_each_adouble("deletecurdir", name, deletecurdir_ads1_loop, NULL, 1))) 
+        return err;
+    /* FIXME 
+     * it's a problem for a nfs mounted folder, there's .nfsxxx around
+     * for linux the following line solve it.
+     * but it could fail if rm .nfsxxx  create a new .nfsyyy :(
+    */
+    if ((err = for_each_adouble("deletecurdir", name, deletecurdir_ads1_loop, NULL, 1))) 
+        return err;
+    return netatalk_rmdir(name);
+}
+
+static int deletecurdir_ads_loop(struct dirent *de, char *name, void *data _U_, int flag _U_)
+{
+    struct stat st;
+    
+    /* bail if the file exists in the current directory.
+     * note: this will not fail with dangling symlinks */
+    
+    if (stat(de->d_name, &st) == 0) {
+        return AFPERR_DIRNEMPT;
+    }
+    return ads_delete_rf(name);
+}
+
+static int RF_deletecurdir_ads(const struct vol *vol _U_)
+{
+    int err;
+    
+    /* delete stray .AppleDouble files. this happens to get .Parent files as well. */
+    if ((err = for_each_adouble("deletecurdir", ".AppleDouble", deletecurdir_ads_loop, NULL, 1))) 
+        return err;
+    return netatalk_rmdir( ".AppleDouble" );
+}
+
+/* ------------------- */
+struct set_mode {
+    mode_t mode;
+    struct stat *st;
+};
+
+static int ads_setfilmode_loop(struct dirent *de _U_, char *name, void *data, int flag _U_)
+{
+    struct set_mode *param = data;
+
+    return setfilmode(name, param->mode, param->st);
+}
+
+static int ads_setfilmode(const char * name, mode_t mode, struct stat *st)
+{
+    mode_t dir_mode = mode;
+    mode_t file_mode = ad_hf_mode(mode);
+    struct set_mode param;
+
+    if ((dir_mode & (S_IRUSR | S_IWUSR )))
+        dir_mode |= S_IXUSR;
+    if ((dir_mode & (S_IRGRP | S_IWGRP )))
+        dir_mode |= S_IXGRP;
+    if ((dir_mode & (S_IROTH | S_IWOTH )))
+        dir_mode |= S_IXOTH;   
+    
+       /* change folder */
+       dir_mode |= DIRBITS;
+    if (dir_rx_set(dir_mode)) {
+        if (chmod( name,  dir_mode ) < 0)
+            return -1;
+    }
+    param.st = st;
+    param.mode = file_mode;
+    if (for_each_adouble("setfilmode_ads", name, ads_setfilmode_loop, &param, 0) < 0)
+        return -1;
+
+    if (!dir_rx_set(dir_mode)) {
+        if (chmod( name,  dir_mode ) < 0)
+            return -1;
+    }
+
+    return 0;
+}
+
+static int RF_setfilmode_ads(const struct vol *vol, const char * name, mode_t mode, struct stat *st)
+{
+    return ads_setfilmode(ad_dir(vol->vfs->ad_path( name, ADFLAGS_HF )), mode, st);
+}
+
+/* ------------------- */
+static int RF_setdirunixmode_ads(const struct vol *vol, const char * name, mode_t mode, struct stat *st)
+{
+    char *adouble = vol->vfs->ad_path( name, ADFLAGS_DIR );
+    char   ad_p[ MAXPATHLEN + 1];
+    int dropbox = (vol->v_flags & AFPVOL_DROPBOX);
+
+    strlcpy(ad_p,ad_dir(adouble), MAXPATHLEN + 1);
+
+    if (dir_rx_set(mode)) {
+
+        /* .AppleDouble */
+        if (stickydirmode(ad_dir(ad_p), DIRBITS | mode, dropbox) < 0 && !vol_noadouble(vol)) 
+            return -1;
+
+        /* .AppleDouble/.Parent */
+        if (stickydirmode(ad_p, DIRBITS | mode, dropbox) < 0 && !vol_noadouble(vol)) 
+            return -1;
+    }
+
+    if (ads_setfilmode(ad_dir(vol->vfs->ad_path( name, ADFLAGS_DIR)), mode, st) < 0)
+        return -1;
+
+    if (!dir_rx_set(mode)) {
+        if (stickydirmode(ad_p, DIRBITS | mode, dropbox) < 0 && !vol_noadouble(vol)) 
+            return  -1 ;
+        if (stickydirmode(ad_dir(ad_p), DIRBITS | mode, dropbox) < 0 && !vol_noadouble(vol)) 
+            return -1;
+    }
+    return 0;
+}
+
+/* ------------------- */
+struct dir_mode {
+    mode_t mode;
+    int    dropbox;
+};
+
+static int setdirmode_ads_loop(struct dirent *de _U_, char *name, void *data, int flag)
+{
+
+    struct dir_mode *param = data;
+    int    ret = 0; /* 0 ignore error, -1 */
+
+    if (dir_rx_set(param->mode)) {
+        if (stickydirmode(name, DIRBITS | param->mode, param->dropbox) < 0) {
+            if (flag) {
+                return 0;
+            }
+            return ret;
+        }
+    }
+    if (ads_setfilmode(name, param->mode, NULL) < 0)
+        return ret;
+
+    if (!dir_rx_set(param->mode)) {
+        if (stickydirmode(name, DIRBITS | param->mode, param->dropbox) < 0) {
+            if (flag) {
+                return 0;
+            }
+            return ret;
+        }
+    }
+    return 0;
+}
+
+static int RF_setdirmode_ads(const struct vol *vol, const char * name, mode_t mode, struct stat *st _U_)
+{
+    char *adouble = vol->vfs->ad_path( name, ADFLAGS_DIR );
+    char   ad_p[ MAXPATHLEN + 1];
+    struct dir_mode param;
+
+    param.mode = mode;
+    param.dropbox = (vol->v_flags & AFPVOL_DROPBOX);
+
+    strlcpy(ad_p,ad_dir(adouble), sizeof(ad_p));
+
+    if (dir_rx_set(mode)) {
+        /* .AppleDouble */
+        if (stickydirmode(ad_dir(ad_p), DIRBITS | mode, param.dropbox) < 0 && !vol_noadouble(vol)) 
+            return -1;
+    }
+
+    if (for_each_adouble("setdirmode_ads", ad_dir(ad_p), setdirmode_ads_loop, &param, vol_noadouble(vol)))
+        return -1;
+
+    if (!dir_rx_set(mode)) {
+        if (stickydirmode(ad_dir(ad_p), DIRBITS | mode, param.dropbox) < 0 && !vol_noadouble(vol)) 
+            return -1;
+    }
+    return 0;
+}
+
+/* ------------------- */
+static int setdirowner_ads1_loop(struct dirent *de _U_, char *name, void *data, int flag _U_)
+{
+    struct perm   *owner  = data;
+
+    if ( chown( name, owner->uid, owner->gid ) < 0 && errno != EPERM ) {
+         LOG(log_debug, logtype_afpd, "setdirowner: chown %d/%d %s: %s",
+                owner->uid, owner->gid, fullpathname(name), strerror(errno) );
+         /* return ( -1 ); Sometimes this is okay */
+    }
+    return 0;
+}
+
+static int setdirowner_ads_loop(struct dirent *de _U_, char *name, void *data, int flag)
+{
+    struct perm   *owner  = data;
+
+    if (for_each_adouble("setdirowner", name, setdirowner_ads1_loop, data, flag) < 0)
+        return -1;
+
+    if ( chown( name, owner->uid, owner->gid ) < 0 && errno != EPERM ) {
+         LOG(log_debug, logtype_afpd, "setdirowner: chown %d/%d %s: %s",
+                owner->uid, owner->gid, fullpathname(name), strerror(errno) );
+         /* return ( -1 ); Sometimes this is okay */
+    }
+    return 0;
+}
+
+static int RF_setdirowner_ads(const struct vol *vol, const char *name, uid_t uid, gid_t gid)
+{
+    int           noadouble = vol_noadouble(vol);
+    char          adouble_p[ MAXPATHLEN + 1];
+    struct stat   st;
+    struct perm   owner;
+    
+    owner.uid = uid;
+    owner.gid = gid;
+
+    strlcpy(adouble_p, ad_dir(vol->vfs->ad_path( name, ADFLAGS_DIR )), sizeof(adouble_p));
+
+    if (for_each_adouble("setdirowner", ad_dir(adouble_p), setdirowner_ads_loop, &owner, noadouble)) 
+        return -1;
+
+    /*
+     * We cheat: we know that chown doesn't do anything.
+     */
+    if ( stat( ".AppleDouble", &st ) < 0) {
+        if (errno == ENOENT && noadouble)
+            return 0;
+        LOG(log_error, logtype_afpd, "setdirowner: stat %s: %s", fullpathname(".AppleDouble"), strerror(errno) );
+        return -1;
+    }
+    if ( gid && gid != st.st_gid && chown( ".AppleDouble", uid, gid ) < 0 && errno != EPERM ) {
+        LOG(log_debug, logtype_afpd, "setdirowner: chown %d/%d %s: %s",
+            uid, gid,fullpathname(".AppleDouble"), strerror(errno) );
+        /* return ( -1 ); Sometimes this is okay */
+    }
+    return 0;
+}
+
+/* ------------------- */
+static int RF_deletefile_ads(const struct vol *vol, const char *file )
+{
+    char *ad_p = ad_dir(vol->vfs->ad_path(file, ADFLAGS_HF ));
+
+    return ads_delete_rf(ad_p);
+}
+
+/* --------------------------- */
+int RF_renamefile_ads(const struct vol *vol, const char *src, const char *dst)
+{
+    char  adsrc[ MAXPATHLEN + 1];
+    int   err = 0;
+
+    strcpy( adsrc, ad_dir(vol->vfs->ad_path( src, 0 )));
+    if (unix_rename( adsrc, ad_dir(vol->vfs->ad_path( dst, 0 ))) < 0) {
+        struct stat st;
+
+        err = errno;
+        if (errno == ENOENT) {
+               struct adouble    ad;
+
+            if (stat(adsrc, &st)) /* source has no ressource fork, */
+                return AFP_OK;
+            
+            /* We are here  because :
+             * -there's no dest folder. 
+             * -there's no .AppleDouble in the dest folder.
+             * if we use the struct adouble passed in parameter it will not
+             * 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.
+             */
+            ad_init(&ad, vol->v_adouble, vol->v_ad_options); 
+            if (!ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, &ad)) {
+               ad_close(&ad, ADFLAGS_HF);
+
+               /* We must delete it */
+               RF_deletefile_ads(vol, dst );
+               if (!unix_rename( adsrc, ad_dir(vol->vfs->ad_path( dst, 0 ))) ) 
+                   err = 0;
+                else 
+                   err = errno;
+            }
+            else { /* it's something else, bail out */
+                   err = errno;
+               }
+           }
+       }
+       if (err) {
+               errno = err;
+               return -1;
+       }
+       return 0;
+}
+
+/* ===================================================
+ classic adouble format 
+*/
+
+static int validupath_adouble(const struct vol *vol, const char *name) 
+{
+    return (vol->v_flags & AFPVOL_USEDOTS) ? strncasecmp(name,".Apple", 6) && strcasecmp(name, ".Parent")
+                                           : name[0] != '.';
+}
+
+/* ----------------- */
+static int RF_chown_adouble(const struct vol *vol, const char *path, uid_t uid, gid_t gid)
+
+{
+    struct stat st;
+    char        *ad_p;
+
+    ad_p = vol->vfs->ad_path(path, ADFLAGS_HF );
+
+    if ( stat( ad_p, &st ) < 0 )
+        return 0; /* ignore */
+
+    return chown( ad_p, uid, gid );
+}
+
+/* ----------------- */
+int RF_renamedir_adouble(const struct vol *vol _U_, const char *oldpath _U_, const char *newpath _U_)
+{
+    return 0;
+}
+
+/* ----------------- */
+static int deletecurdir_adouble_loop(struct dirent *de, char *name, void *data _U_, int flag _U_)
+{
+    struct stat st;
+    int         err;
+    
+    /* bail if the file exists in the current directory.
+     * note: this will not fail with dangling symlinks */
+    
+    if (stat(de->d_name, &st) == 0)
+        return AFPERR_DIRNEMPT;
+
+    if ((err = netatalk_unlink(name)))
+        return err;
+
+    return 0;
+}
+
+static int RF_deletecurdir_adouble(const struct vol *vol _U_)
+{
+    int err;
+
+    /* delete stray .AppleDouble files. this happens to get .Parent files
+       as well. */
+    if ((err = for_each_adouble("deletecurdir", ".AppleDouble", deletecurdir_adouble_loop, NULL, 1))) 
+        return err;
+    return netatalk_rmdir( ".AppleDouble" );
+}
+
+/* ----------------- */
+static int adouble_setfilmode(const char * name, mode_t mode, struct stat *st)
+{
+    return setfilmode(name, ad_hf_mode(mode), st);
+}
+
+static int RF_setfilmode_adouble(const struct vol *vol, const char * name, mode_t mode, struct stat *st)
+{
+    return adouble_setfilmode(vol->vfs->ad_path( name, ADFLAGS_HF ), mode, st);
+}
+
+/* ----------------- */
+static int RF_setdirunixmode_adouble(const struct vol *vol, const char * name, mode_t mode, struct stat *st)
+{
+    char *adouble = vol->vfs->ad_path( name, ADFLAGS_DIR );
+    int  dropbox = (vol->v_flags & AFPVOL_DROPBOX);
+
+    if (dir_rx_set(mode)) {
+        if (stickydirmode(ad_dir(adouble), DIRBITS | mode, dropbox) < 0 && !vol_noadouble(vol)) 
+            return -1;
+    }
+
+    if (adouble_setfilmode(vol->vfs->ad_path( name, ADFLAGS_DIR ), mode, st) < 0) 
+        return -1;
+
+    if (!dir_rx_set(mode)) {
+        if (stickydirmode(ad_dir(adouble), DIRBITS | mode, dropbox) < 0 && !vol_noadouble(vol)) 
+            return  -1 ;
+    }
+    return 0;
+}
+
+/* ----------------- */
+static int setdirmode_adouble_loop(struct dirent *de _U_, char *name, void *data, int flag)
+{
+    mode_t hf_mode = *(mode_t *)data;
+    struct stat st;
+
+    if ( stat( name, &st ) < 0 ) {
+        if (flag)
+            return 0;
+        LOG(log_error, logtype_afpd, "setdirmode: stat %s: %s", name, strerror(errno) );
+    }
+    else if (!S_ISDIR(st.st_mode)) {
+        if (setfilmode(name, hf_mode , &st) < 0) {
+               /* FIXME what do we do then? */
+        }
+    }
+    return 0;
+}
+
+static int RF_setdirmode_adouble(const struct vol *vol, const char * name, mode_t mode, struct stat *st _U_)
+{
+    int   dropbox = (vol->v_flags & AFPVOL_DROPBOX);
+    mode_t hf_mode = ad_hf_mode(mode);
+    char  *adouble = vol->vfs->ad_path( name, ADFLAGS_DIR );
+    char  *adouble_p = ad_dir(adouble);
+
+    if (dir_rx_set(mode)) {
+        if (stickydirmode(ad_dir(adouble), DIRBITS | mode, dropbox) < 0 && !vol_noadouble(vol)) 
+            return -1;
+    }
+
+    if (for_each_adouble("setdirmode", adouble_p, setdirmode_adouble_loop, &hf_mode, vol_noadouble(vol)))
+        return -1;
+
+    if (!dir_rx_set(mode)) {
+        if (stickydirmode(ad_dir(adouble), DIRBITS | mode, dropbox) < 0 && !vol_noadouble(vol)) 
+            return  -1 ;
+    }
+    return 0;
+}
+
+/* ----------------- */
+static int setdirowner_adouble_loop(struct dirent *de _U_, char *name, void *data, int flag _U_)
+{
+    struct perm   *owner  = data;
+
+    if ( chown( name, owner->uid, owner->gid ) < 0 && errno != EPERM ) {
+         LOG(log_debug, logtype_afpd, "setdirowner: chown %d/%d %s: %s",
+                owner->uid, owner->gid, fullpathname(name), strerror(errno) );
+         /* return ( -1 ); Sometimes this is okay */
+    }
+    return 0;
+}
+
+static int RF_setdirowner_adouble(const struct vol *vol, const char *name, uid_t uid, gid_t gid)
+
+{
+    int           noadouble = vol_noadouble(vol);
+    char          *adouble_p;
+    struct stat   st;
+    struct perm   owner;
+    
+    owner.uid = uid;
+    owner.gid = gid;
+
+    adouble_p = ad_dir(vol->vfs->ad_path( name, ADFLAGS_DIR ));
+
+    if (for_each_adouble("setdirowner", adouble_p, setdirowner_adouble_loop, &owner, noadouble)) 
+        return -1;
+
+    /*
+     * We cheat: we know that chown doesn't do anything.
+     */
+    if ( stat( ".AppleDouble", &st ) < 0) {
+        if (errno == ENOENT && noadouble)
+            return 0;
+        LOG(log_error, logtype_afpd, "setdirowner: stat %s: %s", fullpathname(".AppleDouble"), strerror(errno) );
+        return -1;
+    }
+    if ( gid && gid != st.st_gid && chown( ".AppleDouble", uid, gid ) < 0 && errno != EPERM ) {
+        LOG(log_debug, logtype_afpd, "setdirowner: chown %d/%d %s: %s",
+            uid, gid,fullpathname(".AppleDouble"), strerror(errno) );
+        /* return ( -1 ); Sometimes this is okay */
+    }
+    return 0;
+}
+
+/* ----------------- */
+static int RF_deletefile_adouble(const struct vol *vol, const char *file )
+{
+       return netatalk_unlink(vol->vfs->ad_path( file, ADFLAGS_HF));
+}
+
+/* ----------------- */
+int RF_renamefile_adouble(const struct vol *vol, const char *src, const char *dst)
+{
+    char  adsrc[ MAXPATHLEN + 1];
+    int   err = 0;
+
+    strcpy( adsrc, vol->vfs->ad_path( src, 0 ));
+    if (unix_rename( adsrc, vol->vfs->ad_path( dst, 0 )) < 0) {
+        struct stat st;
+
+        err = errno;
+        if (errno == ENOENT) {
+               struct adouble    ad;
+
+            if (stat(adsrc, &st)) /* source has no ressource fork, */
+                return AFP_OK;
+            
+            /* We are here  because :
+             * -there's no dest folder. 
+             * -there's no .AppleDouble in the dest folder.
+             * if we use the struct adouble passed in parameter it will not
+             * 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.
+             */
+            ad_init(&ad, vol->v_adouble, vol->v_ad_options); 
+            if (!ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, &ad)) {
+               ad_close(&ad, ADFLAGS_HF);
+               if (!unix_rename( adsrc, vol->vfs->ad_path( dst, 0 )) ) 
+                   err = 0;
+                else 
+                   err = errno;
+            }
+            else { /* it's something else, bail out */
+                   err = errno;
+               }
+           }
+       }
+       if (err) {
+               errno = err;
+               return -1;
+       }
+       return 0;
+}
+
+struct vfs_ops netatalk_adouble = {
+    /* ad_path:           */ ad_path,
+    /* validupath:        */ validupath_adouble,
+    /* rf_chown:          */ RF_chown_adouble,
+    /* rf_renamedir:      */ RF_renamedir_adouble,
+    /* rf_deletecurdir:   */ RF_deletecurdir_adouble,
+    /* rf_setfilmode:     */ RF_setfilmode_adouble,
+    /* rf_setdirmode:     */ RF_setdirmode_adouble,
+    /* rf_setdirunixmode: */ RF_setdirunixmode_adouble,
+    /* rf_setdirowner:    */ RF_setdirowner_adouble,
+    /* rf_deletefile:     */ RF_deletefile_adouble,
+    /* rf_renamefile:     */ RF_renamefile_adouble,
+};
+
+/* =======================================
+ osx adouble format 
+ */
+static int validupath_osx(const struct vol *vol _U_, const char *name) 
+{
+    return strncasecmp(name,".Apple", 6) && strncasecmp(name,"._", 2);
+}
+
+/* ---------------- */
+int RF_renamedir_osx(const struct vol *vol, const char *oldpath, const char *newpath)
+{
+    /* We simply move the corresponding ad file as well */
+    char   tempbuf[258]="._";
+    return rename(vol->vfs->ad_path(oldpath,0),strcat(tempbuf,newpath));
+}
+
+/* ---------------- */
+int RF_deletecurdir_osx(const struct vol *vol)
+{
+    return netatalk_unlink( vol->vfs->ad_path(".",0) );
+}
+
+/* ---------------- */
+static int RF_setdirunixmode_osx(const struct vol *vol, const char * name, mode_t mode, struct stat *st)
+{
+    return adouble_setfilmode(vol->vfs->ad_path( name, ADFLAGS_DIR ), mode, st);
+}
+
+/* ---------------- */
+static int 
+RF_setdirmode_osx(const struct vol *vol _U_, const char *name _U_, mode_t mode _U_, struct stat *st _U_)
+{
+    return 0;
+}
+
+/* ---------------- */
+static int 
+RF_setdirowner_osx(const struct vol *vol _U_, const char *path _U_, uid_t uid _U_, gid_t gid _U_)
+{
+       return 0;
+}
+
+/* ---------------- */
+int RF_renamefile_osx(const struct vol *vol, const char *src, const char *dst)
+{
+    char  adsrc[ MAXPATHLEN + 1];
+
+    strcpy( adsrc, vol->vfs->ad_path( src, 0 ));
+    return unix_rename( adsrc, vol->vfs->ad_path( dst, 0 ));
+}
+
+struct vfs_ops netatalk_adouble_osx = {
+    /* ad_path:          */ ad_path_osx,
+    /* validupath:       */ validupath_osx,
+    /* rf_chown:         */ RF_chown_adouble,
+    /* rf_renamedir:     */ RF_renamedir_osx,
+    /* rf_deletecurdir:  */ RF_deletecurdir_osx,
+    /* rf_setfilmode:    */ RF_setfilmode_adouble,
+    /* rf_setdirmode:    */ RF_setdirmode_osx,
+    /* rf_setdirunixmode:*/ RF_setdirunixmode_osx,
+    /* rf_setdirowner:   */ RF_setdirowner_osx,
+    /* rf_deletefile:    */ RF_deletefile_adouble,
+    /* rf_renamefile:    */ RF_renamefile_osx,
+};
+
+/* =======================================
+   samba ads format 
+ */
+struct vfs_ops netatalk_adouble_ads = {
+    /* ad_path:          */ ad_path_ads,
+    /* validupath:       */ validupath_adouble,
+    /* rf_chown:         */ RF_chown_ads,
+    /* rf_renamedir:     */ RF_renamedir_adouble,
+    /* rf_deletecurdir:  */ RF_deletecurdir_ads,
+    /* rf_setfilmode:    */ RF_setfilmode_ads,
+    /* rf_setdirmode:    */ RF_setdirmode_ads,
+    /* rf_setdirunixmode:*/ RF_setdirunixmode_ads,
+    /* rf_setdirowner:   */ RF_setdirowner_ads,
+    /* rf_deletefile:    */ RF_deletefile_ads,
+    /* rf_renamefile:    */ RF_renamefile_ads,
+};
+
+/* ---------------- */
+void initvol_vfs(struct vol *vol)
+{
+    if (vol->v_adouble == AD_VERSION2_OSX) {
+        vol->vfs = &netatalk_adouble_osx;
+    }
+    else if (vol->v_adouble == AD_VERSION1_ADS) {
+        vol->vfs = &netatalk_adouble_ads;
+    }
+    else {
+        vol->vfs = &netatalk_adouble;
+    }
+}
+
index 9b7311b25819d723b0db88f979d47a4864982d1f..b86da29ca1954bef5129da1feea1a68c04bbdbed 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: volume.c,v 1.57 2003-09-03 21:25:38 samnoble Exp $
+ * $Id: volume.c,v 1.58 2005-04-28 20:49:45 bfernhomberg Exp $
  *
  * Copyright (c) 1990,1993 Regents of The University of Michigan.
  * All Rights Reserved.  See COPYRIGHT.
@@ -9,31 +9,17 @@
 #include "config.h"
 #endif /* HAVE_CONFIG_H */
 
-#include <sys/time.h>
-#include <atalk/logger.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/param.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <netatalk/endian.h>
-#include <atalk/asp.h>
-#include <atalk/dsi.h>
-#include <atalk/adouble.h>
-#include <atalk/afp.h>
-#include <atalk/util.h>
-#ifdef CNID_DB
-#include <atalk/cnid.h>
-#endif /* CNID_DB*/
-#include <dirent.h>
-#ifdef HAVE_FCNTL_H
-#include <fcntl.h>
-#endif /* HAVE_FCNTL_H */
 #include <stdio.h>
 #include <stdlib.h>
 #include <ctype.h>
-
+#include <dirent.h>
+#include <pwd.h>
+#include <grp.h>
+#include <utime.h>
+#include <errno.h>
+#ifdef HAVE_STRINGS_H
+#include <strings.h>
+#endif
 /* STDC check */
 #if STDC_HEADERS
 #include <string.h>
@@ -48,17 +34,28 @@ char *strchr (), *strrchr ();
 #define memmove(d,s,n) bcopy ((s), (d), (n))
 #endif /* ! HAVE_MEMCPY */
 #endif /* STDC_HEADERS */
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <atalk/asp.h>
+#include <atalk/dsi.h>
+#include <atalk/adouble.h>
+#include <atalk/afp.h>
+#include <atalk/util.h>
+#include <atalk/logger.h>
+#ifdef CNID_DB
+#include <atalk/cnid.h>
+#endif /* CNID_DB*/
 
-#include <pwd.h>
-#include <grp.h>
-#include <utime.h>
-#include <errno.h>
-
+#include "globals.h"
 #include "directory.h"
 #include "file.h"
 #include "volume.h"
-#include "globals.h"
 #include "unix.h"
+#include "fork.h"
+
+extern int afprun(int root, char *cmd, int *outfd);
 
 #ifndef MIN
 #define MIN(a, b) ((a) < (b) ? (a) : (b))
@@ -75,24 +72,23 @@ char *strchr (), *strrchr ();
 #endif /* BYTE_ORDER == BIG_ENDIAN */
 #endif /* ! NO_LARGE_VOL_SUPPORT */
 
-static struct vol *volumes = NULL;
-static int             lastvid = 0;
-#ifndef CNID_DB
+static struct vol *Volumes = NULL;
+static u_int16_t       lastvid = 0;
 static char            *Trash = "\02\024Network Trash Folder";
-#endif /* CNID_DB */
-static struct extmap   *extmap = NULL, *defextmap = NULL;
-static int              extmap_cnt;
+
+static struct extmap   *Extmap = NULL, *Defextmap = NULL;
+static int              Extmap_cnt;
+static void             free_extmap(void);
 
 #define VOLOPT_ALLOW      0  /* user allow list */
 #define VOLOPT_DENY       1  /* user deny list */
 #define VOLOPT_RWLIST     2  /* user rw list */
 #define VOLOPT_ROLIST     3  /* user ro list */
-#define VOLOPT_CODEPAGE   4  /* codepage */
-#define VOLOPT_PASSWORD   5  /* volume password */
-#define VOLOPT_CASEFOLD   6  /* character case mangling */
-#define VOLOPT_FLAGS      7  /* various flags */
-#define VOLOPT_DBPATH     8  /* path to database */
-#define VOLOPT_MAPCHARS   9  /* does mtou and utom mappings. syntax:
+#define VOLOPT_PASSWORD   4  /* volume password */
+#define VOLOPT_CASEFOLD   5  /* character case mangling */
+#define VOLOPT_FLAGS      6  /* various flags */
+#define VOLOPT_DBPATH     7  /* path to database */
+#define VOLOPT_MAPCHARS   8  /* does mtou and utom mappings. syntax:
 m and u can be double-byte hex
 strings if necessary.
 m=u -> map both ways
@@ -102,21 +98,30 @@ m=u -> map both ways
   ~u  -> make u illegal only as the first
   part of a double-byte character.
   */
-#define VOLOPT_VETO      10  /* list of veto filespec */
+#define VOLOPT_VETO          10  /* list of veto filespec */
+#define VOLOPT_PREEXEC       11  /* preexec command */
+#define VOLOPT_ROOTPREEXEC   12  /* root preexec command */
+
+#define VOLOPT_POSTEXEC      13  /* postexec command */
+#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  11  /* force uid for username x */
-#define VOLOPT_FORCEGID  12  /* force gid for group x */
-#define VOLOPT_UMASK     13
-#define VOLOPT_MAX       13
-#else /* normally, there are only 9 possible options */
-#define VOLOPT_UMASK     11
-#define VOLOPT_MAX       11
+#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     19
 #endif /* FORCE_UIDGID */
 
+#define VOLOPT_MAX       (VOLOPT_UMASK +1)
+
 #define VOLOPT_NUM        (VOLOPT_MAX + 1)
 
 #define VOLPASSLEN  8
@@ -127,6 +132,62 @@ m=u -> map both ways
       int i_value;
   };
 
+typedef struct _special_folder {
+        const char *name;
+        int precreate;
+        mode_t mode;
+        int hide;
+} _special_folder;
+
+static const _special_folder special_folders[] = {
+  {"Network Trash Folder",     1,  0777,  1},
+  {"Temporary Items",          1,  0777,  1},
+  {".AppleDesktop",            1,  0777,  0},
+#if 0
+  {"TheFindByContentFolder",   0,     0,  1},
+  {"TheVolumeSettingsFolder",  0,     0,  1},
+#endif
+  {NULL, 0, 0, 0}};
+
+typedef struct _volopt_name {
+       const u_int32_t option;
+       const char      *name;
+} _vol_opt_name;
+
+static const _vol_opt_name vol_opt_names[] = {
+    {AFPVOL_A2VOL,      "PRODOS"},      /* prodos volume */
+    {AFPVOL_CRLF,       "CRLF"},        /* cr/lf translation */
+    {AFPVOL_NOADOUBLE,  "NOADOUBLE"},   /* don't create .AppleDouble by default */
+    {AFPVOL_RO,         "READONLY"},    /* read-only volume */
+    {AFPVOL_MSWINDOWS,  "MSWINDOWS"},   /* deal with ms-windows yuckiness. this is going away. */
+    {AFPVOL_NOHEX,      "NOHEX"},       /* don't do :hex translation */
+    {AFPVOL_USEDOTS,    "USEDOTS"},     /* use real dots */
+    {AFPVOL_LIMITSIZE,  "LIMITSIZE"},   /* limit size for older macs */
+    {AFPVOL_MAPASCII,   "MAPASCII"},    /* map the ascii range as well */
+    {AFPVOL_DROPBOX,    "DROPBOX"},     /* dropkludge dropbox support */
+    {AFPVOL_NOFILEID,   "NOFILEID"},    /* don't advertise createid resolveid and deleteid calls */
+    {AFPVOL_NOSTAT,     "NOSTAT"},      /* advertise the volume even if we can't stat() it
+                                         * maybe because it will be mounted later in preexec */
+    {AFPVOL_UNIX_PRIV,  "UNIXPRIV"},    /* support unix privileges */
+    {AFPVOL_NODEV,      "NODEV"},       /* always use 0 for device number in cnid calls */
+    {AFPVOL_CASEINSEN,  "CASEINSENSITIVE"}, /* volume is case insensitive */
+    {AFPVOL_EILSEQ,     "ILLEGALSEQ"},     /* encode illegal sequence */
+    {AFPVOL_CACHE,      "CACHE ID"},     /* encode illegal sequence */
+    {0, NULL}
+};
+
+static const _vol_opt_name vol_opt_casefold[] = {
+    {AFPVOL_MTOUUPPER, "MTOULOWER"},
+    {AFPVOL_MTOULOWER,  "MTOULOWER"},
+    {AFPVOL_UTOMUPPER,  "UTOMUPPER"},
+    {AFPVOL_UTOMLOWER,  "UTOMLOWER"},
+    {0, NULL}
+};
+
+static void handle_special_folders (const struct vol *);
+static int savevoloptions (const struct vol *);
+static void deletevol(struct vol *vol);
+
 static __inline__ void volfree(struct vol_option *options,
                                const struct vol_option *save)
 {
@@ -147,29 +208,46 @@ static __inline__ void volfree(struct vol_option *options,
 
 
 /* handle variable substitutions. here's what we understand:
+ * $b   -> basename of path
  * $c   -> client ip/appletalk address
+ * $d   -> volume pathname on server
  * $f   -> full name (whatever's in the gecos field)
  * $g   -> group
  * $h   -> hostname 
+ * $i   -> client ip/appletalk address without port
  * $s   -> server name (hostname if it doesn't exist)
  * $u   -> username (guest is usually nobody)
- * $v   -> volume name (ADEID_NAME or basename)
+ * $v   -> volume name or basename if null
  * $z   -> zone (may not exist)
  * $$   -> $
+ *
+ *
  */
 #define is_var(a, b) (strncmp((a), (b), 2) == 0)
-static void volxlate(AFPObj *obj, char *dest, int destlen,
-                     char *src, struct passwd *pwd, char *path)
+
+static char *volxlate(AFPObj *obj, char *dest, size_t destlen,
+                     char *src, struct passwd *pwd, char *path, char *volname)
 {
     char *p, *q;
     int len;
-
-    strncpy(dest, src, destlen);
+    char *ret;
+    
+    if (!src) {
+        return NULL;
+    }
+    if (!dest) {
+        dest = calloc(destlen +1, 1);
+    }
+    ret = dest;
+    if (!ret) {
+        return NULL;
+    }
+    strlcpy(dest, src, destlen +1);
     if ((p = strchr(src, '$')) == NULL) /* nothing to do */
-        return;
+        return ret;
 
     /* first part of the path. just forward to the next variable. */
-    len = MIN(p - src, destlen);
+    len = MIN((size_t)(p - src), destlen);
     if (len > 0) {
         destlen -= len;
         dest += len;
@@ -178,7 +256,14 @@ static void volxlate(AFPObj *obj, char *dest, int destlen,
     while (p && destlen > 0) {
         /* now figure out what the variable is */
         q = NULL;
-        if (is_var(p, "$c")) {
+        if (is_var(p, "$b")) {
+            if (path) {
+                if ((q = strrchr(path, '/')) == NULL)
+                    q = path;
+                else if (*(q + 1) != '\0')
+                    q++;
+            }
+        } else if (is_var(p, "$c")) {
             if (obj->proto == AFPPROTO_ASP) {
                 ASP asp = obj->handle;
 
@@ -195,6 +280,8 @@ static void volxlate(AFPObj *obj, char *dest, int destlen,
                 dest += len;
                 destlen -= len;
             }
+        } else if (is_var(p, "$d")) {
+             q = path;
         } else if (is_var(p, "$f")) {
             if ((q = strchr(pwd->pw_gecos, ',')))
                 *q = '\0';
@@ -205,6 +292,19 @@ static void volxlate(AFPObj *obj, char *dest, int destlen,
                 q = grp->gr_name;
         } else if (is_var(p, "$h")) {
             q = obj->options.hostname;
+        } else if (is_var(p, "$i")) {
+            if (obj->proto == AFPPROTO_ASP) {
+                ASP asp = obj->handle;
+                len = sprintf(dest, "%u", ntohs(asp->asp_sat.sat_addr.s_net));
+                dest += len;
+                destlen -= len;
+            } else if (obj->proto == AFPPROTO_DSI) {
+                DSI *dsi = obj->handle;
+                q = inet_ntoa(dsi->client.sin_addr);
+            }
         } else if (is_var(p, "$s")) {
             if (obj->Obj)
                 q = obj->Obj;
@@ -215,26 +315,14 @@ static void volxlate(AFPObj *obj, char *dest, int destlen,
         } else if (is_var(p, "$u")) {
             q = obj->username;
         } else if (is_var(p, "$v")) {
-            if (path) {
-                struct adouble ad;
-
-                memset(&ad, 0, sizeof(ad));
-                if (ad_open(path, ADFLAGS_HF, O_RDONLY, 0, &ad) < 0)
-                    goto no_volname;
-
-                if ((len = MIN(ad_getentrylen(&ad, ADEID_NAME), destlen)) > 0) {
-                    memcpy(dest, ad_entry(&ad, ADEID_NAME), len);
-                    ad_close(&ad, ADFLAGS_HF);
-                    dest += len;
-                    destlen -= len;
-                } else {
-                    ad_close(&ad, ADFLAGS_HF);
-no_volname: /* simple basename */
-                    if ((q = strrchr(path, '/')) == NULL)
-                        q = path;
-                    else if (*(q + 1) != '\0')
-                        q++;
-                }
+            if (volname) {
+                q = volname;
+            }
+            else if (path) {
+                if ((q = strrchr(path, '/')) == NULL)
+                    q = path;
+                else if (*(q + 1) != '\0')
+                    q++;
             }
         } else if (is_var(p, "$z")) {
             q = obj->Zone;
@@ -255,86 +343,78 @@ no_volname: /* simple basename */
         /* stuff up to next $ */
         src = p + 2;
         p = strchr(src, '$');
-        len = p ? MIN(p - src, destlen) : destlen;
+        len = p ? MIN((size_t)(p - src), destlen) : destlen;
         if (len > 0) {
             strncpy(dest, src, len);
             dest += len;
             destlen -= len;
         }
     }
+    return ret;
 }
 
 /* to make sure that val is valid, make sure to select an opt that
    includes val */
-#define optionok(buf,opt,val) (strstr((buf),(opt)) && ((val)[1] != '\0'))
-
-static __inline__ char *get_codepage_path(const char *path, const char *name)
+static int optionok(const char *buf, const char *opt, const char *val) 
 {
-    char *page;
-    int len;
-
-    if (path) {
-        page = (char *) malloc((len = strlen(path)) + strlen(name) + 2);
-        if (page) {
-            strcpy(page, path);
-            if (path[len - 1] != '/') /* add a / */
-                strcat(page, "/");
-            strcat(page, name);
-        }
-    } else {
-        page = strdup(name);
-    }
+    if (!strstr(buf,opt))
+        return 0;
+    if (!val[1])
+        return 0;
+    return 1;    
+}
 
-    /* debug: show which codepage directory we are using */
-    LOG(log_debug, logtype_afpd, "using codepage directory: %s", page);
 
-    return page;
+/* -------------------- */
+static void setoption(struct vol_option *options, struct vol_option *save, int opt, const char *val)
+{
+    if (options[opt].c_value && (!save || options[opt].c_value != save[opt].c_value))
+        free(options[opt].c_value);
+    options[opt].c_value = strdup(val + 1);
 }
 
-/* handle all the options. tmp can't be NULL. */
-static void volset(struct vol_option *options, char *volname, int vlen,
-                  const char *nlspath, const char *tmp, AFPObj *obj,
-                  struct passwd *pwd)
+/* ------------------------------------------
+   handle all the options. tmp can't be NULL. */
+static void volset(struct vol_option *options, struct vol_option *save, 
+                   char *volname, int vlen,
+                   const char *tmp)
 {
     char *val;
 
-    LOG(log_debug, logtype_afpd, "Parsing volset %s", tmp);
-
     val = strchr(tmp, ':');
     if (!val) {
         /* we'll assume it's a volume name. */
         strncpy(volname, tmp, vlen);
-
-    } else if (optionok(tmp, "allow:", val)) {
-        if (options[VOLOPT_ALLOW].c_value)
-            free(options[VOLOPT_ALLOW].c_value);
-        options[VOLOPT_ALLOW].c_value = strdup(val + 1);
+        volname[vlen] = 0;
+        return;
+    }
+#if 0
+    LOG(log_debug, logtype_afpd, "Parsing volset %s", val);
+#endif
+    if (optionok(tmp, "allow:", val)) {
+        setoption(options, save, VOLOPT_ALLOW, val);
 
     } else if (optionok(tmp, "deny:", val)) {
-        if (options[VOLOPT_DENY].c_value)
-            free(options[VOLOPT_DENY].c_value);
-        options[VOLOPT_DENY].c_value = strdup(val + 1);
+        setoption(options, save, VOLOPT_DENY, val);
 
     } else if (optionok(tmp, "rwlist:", val)) {
-        if (options[VOLOPT_RWLIST].c_value)
-            free(options[VOLOPT_RWLIST].c_value);
-        options[VOLOPT_RWLIST].c_value = strdup(val + 1);
+        setoption(options, save, VOLOPT_RWLIST, val);
 
     } else if (optionok(tmp, "rolist:", val)) {
-        if (options[VOLOPT_ROLIST].c_value)
-            free(options[VOLOPT_ROLIST].c_value);
-        options[VOLOPT_ROLIST].c_value = strdup(val + 1);
+        setoption(options, save, VOLOPT_ROLIST, val);
 
     } else if (optionok(tmp, "codepage:", val)) {
-        if (options[VOLOPT_CODEPAGE].c_value)
-            free(options[VOLOPT_CODEPAGE].c_value);
-        options[VOLOPT_CODEPAGE].c_value = get_codepage_path(nlspath, val + 1);
-
+       LOG (log_error, logtype_afpd, "The old codepage system has been removed. Please make sure to read the documentation !!!!");
+       /* Make sure we don't screw anything */
+       exit (EXITERR_CONF);
+    } 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)) {
-        if (options[VOLOPT_VETO].c_value)
-            free(options[VOLOPT_VETO].c_value);
-        options[VOLOPT_VETO].c_value = strdup(val + 1);
-
+        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;
@@ -344,7 +424,17 @@ static void volset(struct vol_option *options, char *volname, int vlen,
             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;
+        else if (strcasecmp(val + 1, "osx") == 0)
+            options[VOLOPT_ADOUBLE].i_value = AD_VERSION2_OSX;
+        else if (strcasecmp(val + 1, "ads") == 0)
+            options[VOLOPT_ADOUBLE].i_value = AD_VERSION1_ADS;
+#endif
     } else if (optionok(tmp, "options:", val)) {
         char *p;
 
@@ -355,11 +445,7 @@ static void volset(struct vol_option *options, char *volname, int vlen,
             if (strcasecmp(p, "prodos") == 0)
                 options[VOLOPT_FLAGS].i_value |= AFPVOL_A2VOL;
             else if (strcasecmp(p, "mswindows") == 0) {
-                options[VOLOPT_FLAGS].i_value |= (AFPVOL_MSWINDOWS | AFPVOL_USEDOTS);
-                if (!options[VOLOPT_CODEPAGE].c_value)
-                    options[VOLOPT_CODEPAGE].c_value =
-                        get_codepage_path(nlspath, MSWINDOWS_CODEPAGE);
-
+                options[VOLOPT_FLAGS].i_value |= AFPVOL_MSWINDOWS | AFPVOL_USEDOTS;
             } else if (strcasecmp(p, "crlf") == 0)
                 options[VOLOPT_FLAGS].i_value |= AFPVOL_CRLF;
             else if (strcasecmp(p, "noadouble") == 0)
@@ -379,60 +465,88 @@ static void volset(struct vol_option *options, char *volname, int vlen,
                 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)
+               options[VOLOPT_PREEXEC].i_value = 1;
+            else if (strcasecmp(p, "root_preexec_close") == 0)
+               options[VOLOPT_ROOTPREEXEC].i_value = 1;
             else if (strcasecmp(p, "upriv") == 0)
                 options[VOLOPT_FLAGS].i_value |= AFPVOL_UNIX_PRIV;
+            else if (strcasecmp(p, "nodev") == 0)
+                options[VOLOPT_FLAGS].i_value |= AFPVOL_NODEV;
+            else if (strcasecmp(p, "caseinsensitive") == 0)
+                options[VOLOPT_FLAGS].i_value |= AFPVOL_CASEINSEN;
+            else if (strcasecmp(p, "illegalseq") == 0)
+                options[VOLOPT_FLAGS].i_value |= AFPVOL_EILSEQ;
+            else if (strcasecmp(p, "cachecnid") == 0)
+                options[VOLOPT_FLAGS].i_value |= AFPVOL_CACHE;
 
             p = strtok(NULL, ",");
         }
 
-#ifdef CNID_DB
     } else if (optionok(tmp, "dbpath:", val)) {
-       char t[MAXPATHLEN + 1];
-        if (options[VOLOPT_DBPATH].c_value)
-            free(options[VOLOPT_DBPATH].c_value);
+        setoption(options, save, VOLOPT_DBPATH, val);
 
-       volxlate(obj, t, MAXPATHLEN, val, pwd, NULL);
-       options[VOLOPT_DBPATH].c_value = strdup(t + 1);
-#endif /* CNID_DB */
     } else if (optionok(tmp, "umask:", val)) {
-       options[VOLOPT_UMASK].i_value = (int)strtol(val, (char **)NULL, 8);
+       options[VOLOPT_UMASK].i_value = (int)strtol(val +1, (char **)NULL, 8);
     } else if (optionok(tmp, "mapchars:",val)) {
-        if (options[VOLOPT_MAPCHARS].c_value)
-            free(options[VOLOPT_MAPCHARS].c_value);
-        options[VOLOPT_MAPCHARS].c_value = strdup(val + 1);
+        setoption(options, save, VOLOPT_MAPCHARS, val);
 
     } else if (optionok(tmp, "password:", val)) {
-        if (options[VOLOPT_PASSWORD].c_value)
-            free(options[VOLOPT_PASSWORD].c_value);
-        options[VOLOPT_PASSWORD].c_value = strdup(val + 1);
+        setoption(options, save, VOLOPT_PASSWORD, val);
 
 #ifdef FORCE_UIDGID
 
         /* this code allows forced uid/gid per volume settings */
     } else if (optionok(tmp, "forceuid:", val)) {
-        if (options[VOLOPT_FORCEUID].c_value)
-            free(options[VOLOPT_FORCEUID].c_value);
-        options[VOLOPT_FORCEUID].c_value = strdup(val + 1);
+        setoption(options, save, VOLOPT_FORCEUID, val);
     } else if (optionok(tmp, "forcegid:", val)) {
-        if (options[VOLOPT_FORCEGID].c_value)
-            free(options[VOLOPT_FORCEGID].c_value);
-        options[VOLOPT_FORCEGID].c_value = strdup(val + 1);
+        setoption(options, save, VOLOPT_FORCEGID, val);
 
 #endif /* FORCE_UIDGID */
+    } else if (optionok(tmp, "root_preexec:", val)) {
+        setoption(options, save, VOLOPT_ROOTPREEXEC, val);
+
+    } else if (optionok(tmp, "preexec:", val)) {
+        setoption(options, save, VOLOPT_PREEXEC, val);
+
+    } else if (optionok(tmp, "root_postexec:", val)) {
+        setoption(options, save, VOLOPT_ROOTPOSTEXEC, val);
+
+    } else if (optionok(tmp, "postexec:", val)) {
+        setoption(options, save, VOLOPT_POSTEXEC, val);
 
     } else {
         /* ignore unknown options */
         LOG(log_debug, logtype_afpd, "ignoring unknown volume option: %s", tmp);
 
+    } 
+}
+
+/* ----------------- */
+static void showvol(const ucs2_t *name)
+{
+    struct vol *volume;
+    for ( volume = Volumes; volume; volume = volume->v_next ) {
+        if (volume->v_hide && !strcasecmp_w( volume->v_name, name ) ) {
+            volume->v_hide = 0;
+            return;
+        }
     }
 }
 
-static int creatvol(const char *path, char *name, struct vol_option *options)
+/* ------------------------------- */
+static int creatvol(AFPObj *obj, struct passwd *pwd, 
+                    char *path, char *name, 
+                    struct vol_option *options, 
+                    const int user /* user defined volume */
+                    )
 {
     struct vol *volume;
     int                vlen;
+    int         hide = 0;
+    ucs2_t     tmpname[512];
 
     if ( name == NULL || *name == '\0' ) {
         if ((name = strrchr( path, '/' )) == NULL) {
@@ -444,45 +558,52 @@ static int creatvol(const char *path, char *name, struct vol_option *options)
             return -1;
     }
 
-    for ( volume = volumes; volume; volume = volume->v_next ) {
-        if ( strcasecmp( volume->v_name, name ) == 0 ) {
-            return -1; /* Won't be able to access it, anyway... */
-        }
-    }
-
     vlen = strlen( name );
     if ( vlen > AFPVOL_NAMELEN ) {
         vlen = AFPVOL_NAMELEN;
         name[AFPVOL_NAMELEN] = '\0';
     }
 
-    if (( volume =
-                (struct vol *)calloc(1, sizeof( struct vol ))) == NULL ) {
+    /* convert name to UCS2 first */
+    if ( 0 >= ( vlen = convert_string(obj->options.unixcharset, CH_UCS2, name, vlen, tmpname, 512)) )
+        return -1;
+
+    for ( volume = Volumes; volume; volume = volume->v_next ) {
+        if ( strcasecmp_w( volume->v_name, tmpname ) == 0 ) {
+           if (volume->v_deleted) {
+               volume->v_new = hide = 1;
+           }
+           else {
+               return -1;      /* Won't be able to access it, anyway... */
+           }
+        }
+    }
+
+
+    if (!( volume = (struct vol *)calloc(1, sizeof( struct vol ))) ) {
         LOG(log_error, logtype_afpd, "creatvol: malloc: %s", strerror(errno) );
         return -1;
     }
-    if (( volume->v_name =
-                (char *)malloc( vlen + 1 )) == NULL ) {
+    if ( NULL == ( volume->v_name = strdup_w(tmpname))) {
         LOG(log_error, logtype_afpd, "creatvol: malloc: %s", strerror(errno) );
         free(volume);
         return -1;
     }
-    if (( volume->v_path =
-                (char *)malloc( strlen( path ) + 1 )) == NULL ) {
+    if (!( volume->v_path = (char *)malloc( strlen( path ) + 1 )) ) {
         LOG(log_error, logtype_afpd, "creatvol: malloc: %s", strerror(errno) );
         free(volume->v_name);
         free(volume);
         return -1;
     }
-
-    strcpy( volume->v_name, name);
+    volume->v_hide = hide;
     strcpy( volume->v_path, path );
 
 #ifdef __svr4__
     volume->v_qfd = -1;
 #endif /* __svr4__ */
-    volume->v_vid = lastvid++;
-    volume->v_lastdid = 17;
+    /* os X start at 1 and use network order ie. 1 2 3 */
+    volume->v_vid = ++lastvid;
+    volume->v_vid = htons(volume->v_vid);
 
     /* handle options */
     if (options) {
@@ -492,26 +613,40 @@ static int creatvol(const char *path, char *name, struct vol_option *options)
         /* shift in some flags */
         volume->v_flags = options[VOLOPT_FLAGS].i_value;
 
-        /* read in the code pages */
-        if (options[VOLOPT_CODEPAGE].c_value)
-            codepage_read(volume, options[VOLOPT_CODEPAGE].c_value);
-
+        volume->v_ad_options = 0;
+        if ((volume->v_flags & AFPVOL_NODEV))
+            volume->v_ad_options |= ADVOL_NODEV;
+        if ((volume->v_flags & AFPVOL_CACHE))
+            volume->v_ad_options |= ADVOL_CACHE;
+        
         if (options[VOLOPT_PASSWORD].c_value)
             volume->v_password = strdup(options[VOLOPT_PASSWORD].c_value);
 
         if (options[VOLOPT_VETO].c_value)
             volume->v_veto = strdup(options[VOLOPT_VETO].c_value);
 
-#ifdef CNID_DB
+        if (options[VOLOPT_ENCODING].c_value)
+            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 = strdup(options[VOLOPT_DBPATH].c_value);
-#endif /* CNID_DB */
+            volume->v_dbpath = volxlate(obj, NULL, MAXPATHLEN, options[VOLOPT_DBPATH].c_value, pwd, path, name);
+
+       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;
 
-#ifdef FORCE_UIDGID
+       if (options[VOLOPT_ADOUBLE].i_value)
+           volume->v_adouble = options[VOLOPT_ADOUBLE].i_value;
+       else 
+           volume->v_adouble = AD_VERSION;
 
+       initvol_vfs(volume);
+#ifdef FORCE_UIDGID
         if (options[VOLOPT_FORCEUID].c_value) {
             volume->v_forceuid = strdup(options[VOLOPT_FORCEUID].c_value);
         } else {
@@ -523,16 +658,30 @@ static int creatvol(const char *path, char *name, struct vol_option *options)
         } else {
             volume->v_forcegid = NULL; /* set as null so as to return 0 later on */
         }
+#endif
+        if (!user) {
+            if (options[VOLOPT_PREEXEC].c_value)
+                volume->v_preexec = volxlate(obj, NULL, MAXPATHLEN, options[VOLOPT_PREEXEC].c_value, pwd, path, name);
+            volume->v_preexec_close = options[VOLOPT_PREEXEC].i_value;
 
-#endif /* FORCE_UIDGID */
+            if (options[VOLOPT_POSTEXEC].c_value)
+                volume->v_postexec = volxlate(obj, NULL, MAXPATHLEN, options[VOLOPT_POSTEXEC].c_value, pwd, path, name);
+
+            if (options[VOLOPT_ROOTPREEXEC].c_value)
+                volume->v_root_preexec = volxlate(obj, NULL, MAXPATHLEN, options[VOLOPT_ROOTPREEXEC].c_value, pwd, path,  name);
+            volume->v_root_preexec_close = options[VOLOPT_ROOTPREEXEC].i_value;
 
+            if (options[VOLOPT_ROOTPOSTEXEC].c_value)
+                volume->v_root_postexec = volxlate(obj, NULL, MAXPATHLEN, options[VOLOPT_ROOTPOSTEXEC].c_value, pwd, path,  name);
+        }
     }
 
-    volume->v_next = volumes;
-    volumes = volume;
+    volume->v_next = Volumes;
+    Volumes = volume;
     return 0;
 }
 
+/* ---------------- */
 static char *myfgets( buf, size, fp )
 char   *buf;
 int            size;
@@ -571,6 +720,18 @@ FILE       *fp;
  *      0: list exists, but name isn't in it
  *      1: in list
  */
+
+#ifndef NO_REAL_USER_NAME
+/* authentication is case insensitive 
+ * FIXME should we do the same with group name?
+*/
+#define access_strcmp strcasecmp
+
+#else
+#define access_strcmp strcmp
+
+#endif
+
 static int accessvol(args, name)
 const char *args;
 const char *name;
@@ -581,7 +742,7 @@ const char *name;
     if (!args)
         return -1;
 
-    strncpy(buf, args, sizeof(buf));
+    strlcpy(buf, args, sizeof(buf));
     if ((p = strtok(buf, ",")) == NULL) /* nothing, return okay */
         return -1;
 
@@ -589,7 +750,7 @@ const char *name;
         if (*p == '@') { /* it's a group */
             if ((gr = getgrnam(p + 1)) && gmem(gr->gr_gid))
                 return 1;
-        } else if (strcmp(p, name) == 0) /* it's a user name */
+        } else if (access_strcmp(p, name) == 0) /* it's a user name */
             return 1;
         p = strtok(NULL, ",");
     }
@@ -604,26 +765,26 @@ int                       user;
     struct extmap      *em;
     int                 cnt;
 
-    if (extmap == NULL) {
-        if (( extmap = calloc(1, sizeof( struct extmap ))) == NULL ) {
+    if (Extmap == NULL) {
+        if (( Extmap = calloc(1, sizeof( struct extmap ))) == NULL ) {
             LOG(log_error, logtype_afpd, "setextmap: calloc: %s", strerror(errno) );
             return;
         }
     }
     ext++;
-    for ( em = extmap, cnt = 0; em->em_ext; em++, cnt++) {
+    for ( em = Extmap, cnt = 0; em->em_ext; em++, cnt++) {
         if ( (strdiacasecmp( em->em_ext, ext )) == 0 ) {
             break;
         }
     }
 
     if ( em->em_ext == NULL ) {
-        if (!(extmap  = realloc( extmap, sizeof( struct extmap ) * (cnt +2))) ) {
+        if (!(Extmap  = realloc( Extmap, sizeof( struct extmap ) * (cnt +2))) ) {
             LOG(log_error, logtype_afpd, "setextmap: realloc: %s", strerror(errno) );
             return;
         }
-        (extmap +cnt +1)->em_ext = NULL;
-        em = extmap +cnt;
+        (Extmap +cnt +1)->em_ext = NULL;
+        em = Extmap +cnt;
     } else if ( !user ) {
         return;
     }
@@ -659,26 +820,66 @@ static void sortextmap( void)
 {
     struct extmap      *em;
 
-    extmap_cnt = 0;
-    if ((em = extmap) == NULL) {
+    Extmap_cnt = 0;
+    if ((em = Extmap) == NULL) {
         return;
     }
     while (em->em_ext) {
         em++;
-        extmap_cnt++;
+        Extmap_cnt++;
     }
-    if (extmap_cnt) {
-        qsort(extmap, extmap_cnt, sizeof(struct extmap), extmap_cmp);
-        defextmap = extmap;
+    if (Extmap_cnt) {
+        qsort(Extmap, Extmap_cnt, sizeof(struct extmap), extmap_cmp);
+        if (*Extmap->em_ext == 0) {
+            /* the first line is really "." the default entry, 
+             * we remove the leading '.' in setextmap
+            */
+            Defextmap = Extmap;
+        }
     }
 }
 
+/* ----------------------
+*/
+static void free_extmap( void)
+{
+    struct extmap      *em;
 
-/*
+    if (Extmap) {
+        for ( em = Extmap; em->em_ext; em++) {
+             free (em->em_ext);
+        }
+        free(Extmap);
+        Extmap = NULL;
+        Defextmap = Extmap;
+        Extmap_cnt = 0;
+    }
+}
+
+/* ----------------------
+*/
+static int volfile_changed(struct afp_volume_name *p) 
+{
+    struct stat      st;
+    char *name;
+    
+    if (p->full_name) 
+       name = p->full_name;
+    else
+        name = p->name;
+        
+    if (!stat( name, &st) && st.st_mtime > p->mtime) {
+        p->mtime = st.st_mtime;
+        return 1;
+    }
+    return 0;
+}
+
+/* ----------------------
  * Read a volume configuration file and add the volumes contained within to
  * the global volume list.  If p2 is non-NULL, the file that is opened is
  * p1/p2
- *
+ * 
  * Lines that begin with # and blank lines are ignored.
  * Volume lines are of the form:
  *             <unix path> [<volume name>] [allow:<user>,<@group>,...] \
@@ -687,7 +888,8 @@ static void sortextmap( void)
  */
 static int readvolfile(obj, p1, p2, user, pwent)
 AFPObj      *obj;
-char   *p1, *p2;
+struct afp_volume_name         *p1;
+char        *p2;
 int            user;
 struct passwd *pwent;
 {
@@ -699,19 +901,29 @@ struct passwd *pwent;
     struct passwd      *pw;
     struct vol_option   options[VOLOPT_NUM], save_options[VOLOPT_NUM];
     int                 i;
+    struct stat         st;
+    int                 fd;
 
-    if (!p1)
+    if (!p1->name)
         return -1;
-
-    strcpy( path, p1 );
+    p1->mtime = 0;
+    strcpy( path, p1->name );
     if ( p2 != NULL ) {
         strcat( path, "/" );
         strcat( path, p2 );
+        if (p1->full_name) {
+            free(p1->full_name);
+        }
+        p1->full_name = strdup(path);
     }
 
     if (NULL == ( fp = fopen( path, "r" )) ) {
         return( -1 );
     }
+    fd = fileno(fp);
+    if (fd != -1 && !fstat( fd, &st) ) {
+        p1->mtime = st.st_mtime;
+    }
 
     memset(save_options, 0, sizeof(save_options));
     while ( myfgets( buf, sizeof( buf ), fp ) != NULL ) {
@@ -730,9 +942,8 @@ struct passwd *pwent;
                     if (parseline( sizeof( path ) - VOLOPT_DEFAULT_LEN - 1,
                                    path + VOLOPT_DEFAULT_LEN) < 0)
                         break;
-                    volset(save_options, tmp, sizeof(tmp) - 1,
-                          obj->options.nlspath, path + VOLOPT_DEFAULT_LEN,
-                          obj, pwent);
+                    volset(save_options, NULL, tmp, sizeof(tmp) - 1,
+                           path + VOLOPT_DEFAULT_LEN);
                 }
             }
             break;
@@ -766,13 +977,13 @@ struct passwd *pwent;
                 strcpy(tmp, path);
             if (!pwent)
                 pwent = getpwnam(obj->username);
-            volxlate(obj, path, sizeof(path) - 1, tmp, pwent, NULL);
+            volxlate(obj, path, sizeof(path) - 1, tmp, pwent, NULL, NULL);
 
             /* this is sort of braindead. basically, i want to be
              * able to specify things in any order, but i don't want to 
              * re-write everything. 
              *
-             * currently we have 11 options: 
+             * currently we have options: 
              *   volname
              *   codepage:x
              *   casefold:x
@@ -780,21 +991,22 @@ struct passwd *pwent;
              *   deny:x,y,@z
              *   rwlist:x,y,@z
              *   rolist:x,y,@z
-             *   options:prodos,crlf,noadouble,ro
+             *   options:prodos,crlf,noadouble,ro...
              *   dbpath:x
              *   password:x
+             *   preexec:x
+             *
              *   namemask:x,y,!z  (not implemented yet)
              */
             memcpy(options, save_options, sizeof(options));
             *volname = '\0';
 
-            /* read in up to 11 possible options */
+            /* read in up to VOLOP_NUM possible options */
             for (i = 0; i < VOLOPT_NUM; i++) {
                 if (parseline( sizeof( tmp ) - 1, tmp ) < 0)
                     break;
 
-                volset(options, volname, sizeof(volname) - 1,
-                      obj->options.nlspath, tmp, obj, pwent);
+                volset(options, save_options, volname, sizeof(volname) - 1, tmp);
             }
 
             /* check allow/deny lists:
@@ -814,9 +1026,9 @@ struct passwd *pwent;
                                     obj->username)))
                     options[VOLOPT_FLAGS].i_value |= AFPVOL_RO;
 
-                /* do variable substitution */
-                volxlate(obj, tmp, sizeof(tmp) - 1, volname, pwent, path);
-                creatvol(path, tmp, options);
+                /* do variable substitution for volname */
+                volxlate(obj, tmp, sizeof(tmp) - 1, volname, pwent, path, NULL);
+                creatvol(obj, pwent, path, tmp, options, p2 != NULL);
             }
             volfree(options, save_options);
             break;
@@ -836,37 +1048,81 @@ struct passwd *pwent;
     if ( fclose( fp ) != 0 ) {
         LOG(log_error, logtype_afpd, "readvolfile: fclose: %s", strerror(errno) );
     }
+    p1->loaded = 1;
     return( 0 );
 }
 
+/* ------------------------------- */
+static void volume_free(struct vol *vol)
+{
+    free(vol->v_name);
+    vol->v_name = NULL;
+    free(vol->v_path);
+    free(vol->v_password);
+    free(vol->v_veto);
+    free(vol->v_volcodepage);
+    free(vol->v_maccodepage);
+    free(vol->v_cnidscheme);
+    free(vol->v_dbpath);
+    free(vol->v_gvs);
+#ifdef FORCE_UIDGID
+    free(vol->v_forceuid);
+    free(vol->v_forcegid);
+#endif /* FORCE_UIDGID */
+}
 
-static void load_volumes(AFPObj *obj)
+/* ------------------------------- */
+static void free_volumes(void )
 {
-    struct passwd      *pwent = getpwnam(obj->username);
+    struct vol *vol;
+    struct vol  *nvol, *ovol;
 
-    if ( (obj->options.flags & OPTION_USERVOLFIRST) == 0 ) {
-        readvolfile(obj, obj->options.systemvol, NULL, 0, pwent);
+    for ( vol = Volumes; vol; vol = vol->v_next ) {
+        if (( vol->v_flags & AFPVOL_OPEN ) ) {
+            vol->v_deleted = 1;
+            continue;
+        }
+        volume_free(vol);
     }
 
-    if ((*obj->username == '\0') || (obj->options.flags & OPTION_NOUSERVOL)) {
-        readvolfile(obj, obj->options.defaultvol, NULL, 1, pwent);
-    } else if (pwent) {
-        /*
-        * Read user's AppleVolumes or .AppleVolumes file
-        * If neither are readable, read the default volumes file. if
-        * that doesn't work, create a user share.
-        */
-        if ( readvolfile(obj, pwent->pw_dir, "AppleVolumes", 1, pwent) < 0 &&
-                readvolfile(obj, pwent->pw_dir, ".AppleVolumes", 1, pwent) < 0 &&
-                readvolfile(obj, pwent->pw_dir, "applevolumes", 1, pwent) < 0 &&
-                readvolfile(obj, pwent->pw_dir, ".applevolumes", 1, pwent) < 0 &&
-                obj->options.defaultvol != NULL ) {
-            if (readvolfile(obj, obj->options.defaultvol, NULL, 1, pwent) < 0)
-                creatvol(pwent->pw_dir, NULL, NULL);
+    for ( vol = Volumes, ovol = NULL; vol; vol = nvol) {
+        nvol = vol->v_next;
+
+        if (vol->v_name == NULL) {
+           if (Volumes == vol) {
+               Volumes = nvol;
+               ovol = Volumes;
+           }
+           else {
+              ovol->v_next = nvol;
+           }
+           free(vol);
+        }
+        else {
+           ovol = vol;
         }
     }
-    if ( obj->options.flags & OPTION_USERVOLFIRST ) {
-        readvolfile(obj, obj->options.systemvol, NULL, 0, pwent );
+}
+
+/* ------------------------------- */
+static void volume_unlink(struct vol *volume)
+{
+struct vol *vol, *ovol, *nvol;
+
+    if (volume == Volumes) {
+        Volumes = Volumes->v_next;
+        return;
+    }
+    for ( vol = Volumes->v_next, ovol = Volumes; vol; vol = nvol) {
+        nvol = vol->v_next;
+
+        if (vol == volume) {
+            ovol->v_next = nvol;
+            break;
+        }
+        else {
+           ovol = vol;
+        }
     }
 }
 
@@ -879,7 +1135,7 @@ VolSpace    *xbfree, *xbtotal;
     u_int32_t   maxsize;
 #ifndef NO_QUOTA_SUPPORT
     VolSpace   qfree, qtotal;
-#endif /* ! NO_QUOTA_SUPPORT */
+#endif
 
     spaceflag = AFPVOL_GVSMASK & vol->v_flags;
     /* report up to 2GB if afp version is < 2.2 (4GB if not) */
@@ -894,7 +1150,7 @@ VolSpace    *xbfree, *xbtotal;
             goto getvolspace_done;
         }
     }
-#endif /* AFS */
+#endif
 
     if (( rc = ustatfs_getvolspace( vol, xbfree, xbtotal,
                                     bsize)) != AFP_OK ) {
@@ -911,7 +1167,7 @@ VolSpace    *xbfree, *xbtotal;
             goto getvolspace_done;
         }
     }
-#endif /* ! NO_QUOTA_SUPPORT */
+#endif
     vol->v_flags = ( ~AFPVOL_GVSMASK & vol->v_flags ) | AFPVOL_USTATFS;
 
 getvolspace_done:
@@ -920,6 +1176,29 @@ getvolspace_done:
     return( AFP_OK );
 }
 
+/* ----------------------- 
+ * set volume creation date
+ * avoid duplicate, well at least it tries
+*/
+static void vol_setdate(u_int16_t id, struct adouble *adp, time_t date)
+{
+    struct vol *volume;
+    struct vol *vol = Volumes;
+
+    for ( volume = Volumes; volume; volume = volume->v_next ) {
+        if (volume->v_vid == id) {
+            vol = volume;
+        }
+        else if ((time_t)(AD_DATE_FROM_UNIX(date)) == volume->v_ctime) {
+            date = date+1;
+            volume = Volumes; /* restart */
+        }
+    }
+    vol->v_ctime = AD_DATE_FROM_UNIX(date);
+    ad_setdate(adp, AD_DATE_CREATE | AD_DATE_UNIX, date);
+}
+
+/* ----------------------- */
 static int getvolparams( bitmap, vol, st, buf, buflen )
 u_int16_t      bitmap;
 struct vol     *vol;
@@ -940,11 +1219,12 @@ int              *buflen;
      * For MacOS8.x support we need to create the
      * .Parent file here if it doesn't exist. */
 
-    memset(&ad, 0, sizeof(ad));
+    ad_init(&ad, vol->v_adouble, vol->v_ad_options);
     if ( ad_open( vol->v_path, vol_noadouble(vol) |
                   ADFLAGS_HF|ADFLAGS_DIR, O_RDWR | O_CREAT,
                   0666, &ad) < 0 ) {
         isad = 0;
+        vol->v_ctime = AD_DATE_FROM_UNIX(st->st_mtime);
 
     } else if (ad_get_HF_flags( &ad ) & O_CREAT) {
         slash = strrchr( vol->v_path, '/' );
@@ -952,13 +1232,20 @@ int              *buflen;
             slash++;
         else
             slash = vol->v_path;
-
-        ad_setentrylen( &ad, ADEID_NAME, strlen( slash ));
-        memcpy(ad_entry( &ad, ADEID_NAME ), slash,
+        if (ad_getentryoff(&ad, ADEID_NAME)) {
+            ad_setentrylen( &ad, ADEID_NAME, strlen( slash ));
+            memcpy(ad_entry( &ad, ADEID_NAME ), slash,
                ad_getentrylen( &ad, ADEID_NAME ));
-        ad_setdate(&ad, AD_DATE_CREATE | AD_DATE_UNIX, st->st_mtime);
+        }
+        vol_setdate(vol->v_vid, &ad, st->st_mtime);
         ad_flush(&ad, ADFLAGS_HF);
     }
+    else {
+        if (ad_getdate(&ad, AD_DATE_CREATE, &aint) < 0)
+            vol->v_ctime = AD_DATE_FROM_UNIX(st->st_mtime);
+        else 
+            vol->v_ctime = aint;
+    }
 
     if (( bitmap & ( (1<<VOLPBIT_BFREE)|(1<<VOLPBIT_BTOTAL) |
                      (1<<VOLPBIT_XBFREE)|(1<<VOLPBIT_XBTOTAL) |
@@ -982,11 +1269,10 @@ int              *buflen;
         switch ( bit ) {
         case VOLPBIT_ATTR :
             ashort = 0;
-#ifdef CNID_DB
-            if (0 == (vol->v_flags & AFPVOL_NOFILEID) && vol->v_db != NULL) {
+            if (0 == (vol->v_flags & AFPVOL_NOFILEID) && vol->v_cdb != NULL &&
+                           (vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
                 ashort = VOLPBIT_ATTR_FILEID;
             }
-#endif /* CNID_DB */
             /* check for read-only.
              * NOTE: we don't actually set the read-only flag unless
              *       it's passed in that way as it's possible to mount
@@ -1013,19 +1299,16 @@ int             *buflen;
             break;
 
         case VOLPBIT_CDATE :
-            if (!isad || (ad_getdate(&ad, AD_DATE_CREATE, &aint) < 0))
-                aint = AD_DATE_FROM_UNIX(st->st_mtime);
+            aint = vol->v_ctime;
             memcpy(data, &aint, sizeof( aint ));
             data += sizeof( aint );
             break;
 
         case VOLPBIT_MDATE :
-            if ( st->st_mtime > vol->v_time ) {
-                vol->v_time = st->st_mtime;
-                aint = AD_DATE_FROM_UNIX(st->st_mtime);
-            } else {
-                aint = AD_DATE_FROM_UNIX(vol->v_time);
+            if ( st->st_mtime > vol->v_mtime ) {
+                vol->v_mtime = st->st_mtime;
             }
+            aint = AD_DATE_FROM_UNIX(vol->v_mtime);
             memcpy(data, &aint, sizeof( aint ));
             data += sizeof( aint );
             break;
@@ -1099,9 +1382,13 @@ int              *buflen;
     if ( nameoff ) {
         ashort = htons( data - buf );
         memcpy(nameoff, &ashort, sizeof( ashort ));
-        aint = strlen( vol->v_name );
+       aint = ucs2_to_charset( (utf8_encoding()?CH_UTF8_MAC:vol->v_maccharset), vol->v_name, data+1, 255);
+       if ( aint <= 0 ) {
+           *buflen = 0;
+            return AFPERR_MISC;
+        }
+               
         *data++ = aint;
-        memcpy(data, vol->v_name, aint );
         data += aint;
     }
     if ( isad ) {
@@ -1111,33 +1398,135 @@ int            *buflen;
     return( AFP_OK );
 }
 
+/* ------------------------- */
+static int stat_vol(u_int16_t bitmap, struct vol *vol, char *rbuf, int *rbuflen)
+{
+    struct stat        st;
+    int                buflen, ret;
+
+    if ( stat( vol->v_path, &st ) < 0 ) {
+        *rbuflen = 0;
+        return( AFPERR_PARAM );
+    }
+    /* save the volume device number */
+    vol->v_dev = st.st_dev;
+
+    buflen = *rbuflen - sizeof( bitmap );
+    if (( ret = getvolparams( bitmap, vol, &st,
+                              rbuf + sizeof( bitmap ), &buflen )) != AFP_OK ) {
+        *rbuflen = 0;
+        return( ret );
+    }
+    *rbuflen = buflen + sizeof( bitmap );
+    bitmap = htons( bitmap );
+    memcpy(rbuf, &bitmap, sizeof( bitmap ));
+    return( AFP_OK );
+
+}
+
+/* ------------------------------- */
+void load_volumes(AFPObj *obj)
+{
+    struct passwd      *pwent;
+
+    if (Volumes) {
+        int changed = 0;
+        
+        /* check files date */
+        if (obj->options.defaultvol.loaded) {
+            changed = volfile_changed(&obj->options.defaultvol);
+        }
+        if (obj->options.systemvol.loaded) {
+            changed |= volfile_changed(&obj->options.systemvol);
+        }
+        if (obj->options.uservol.loaded) {
+            changed |= volfile_changed(&obj->options.uservol);
+        }
+        if (!changed)
+            return;
+        
+        free_extmap();
+        free_volumes();
+    }
+    
+    pwent = getpwnam(obj->username);
+    if ( (obj->options.flags & OPTION_USERVOLFIRST) == 0 ) {
+        readvolfile(obj, &obj->options.systemvol, NULL, 0, pwent);
+    }
 
+    if ((*obj->username == '\0') || (obj->options.flags & OPTION_NOUSERVOL)) {
+        readvolfile(obj, &obj->options.defaultvol, NULL, 1, pwent);
+    } else if (pwent) {
+        /*
+        * Read user's AppleVolumes or .AppleVolumes file
+        * If neither are readable, read the default volumes file. if
+        * that doesn't work, create a user share.
+        */
+        if (obj->options.uservol.name) {
+            free(obj->options.uservol.name);
+        }
+        obj->options.uservol.name = strdup(pwent->pw_dir);
+        if ( readvolfile(obj, &obj->options.uservol,    "AppleVolumes", 1, pwent) < 0 &&
+                readvolfile(obj, &obj->options.uservol, ".AppleVolumes", 1, pwent) < 0 &&
+                readvolfile(obj, &obj->options.uservol, "applevolumes", 1, pwent) < 0 &&
+                readvolfile(obj, &obj->options.uservol, ".applevolumes", 1, pwent) < 0 &&
+                obj->options.defaultvol.name != NULL ) {
+            if (readvolfile(obj, &obj->options.defaultvol, NULL, 1, pwent) < 0)
+                creatvol(obj, pwent, pwent->pw_dir, NULL, NULL, 1);
+        }
+    }
+    if ( obj->options.flags & OPTION_USERVOLFIRST ) {
+        readvolfile(obj, &obj->options.systemvol, NULL, 0, pwent );
+    }
+    
+    if ( obj->options.closevol ) {
+        struct vol *vol;
+        
+        for ( vol = Volumes; vol; vol = vol->v_next ) {
+            if (vol->v_deleted && !vol->v_new ) {
+                of_closevol(vol);
+                deletevol(vol);
+                vol = Volumes;
+            }
+        }
+    }
+}
 
+/* ------------------------------- */
 int afp_getsrvrparms(obj, ibuf, ibuflen, rbuf, rbuflen )
-AFPObj      *obj;
-char   *ibuf, *rbuf;
-int    ibuflen, *rbuflen;
+AFPObj  *obj;
+char   *ibuf _U_, *rbuf;
+int    ibuflen _U_, *rbuflen;
 {
     struct timeval     tv;
     struct stat                st;
     struct vol         *volume;
     char       *data;
-    int                        vcnt, len;
+    char               *namebuf;
+    int                        vcnt;
+    size_t             len;
 
-
-    if (!volumes)
-        load_volumes(obj);
+    load_volumes(obj);
 
     data = rbuf + 5;
-    for ( vcnt = 0, volume = volumes; volume; volume = volume->v_next ) {
-        if ( stat( volume->v_path, &st ) < 0 ) {
-            LOG(log_info, logtype_afpd, "afp_getsrvrparms: stat %s: %s",
-                volume->v_path, strerror(errno) );
-            continue;          /* can't access directory */
+    for ( vcnt = 0, volume = Volumes; volume; volume = volume->v_next ) {
+        if (!(volume->v_flags & AFPVOL_NOSTAT)) {
+            if ( stat( volume->v_path, &st ) < 0 ) {
+                LOG(log_info, logtype_afpd, "afp_getsrvrparms(%s): stat: %s",
+                        volume->v_path, strerror(errno) );
+                continue;              /* can't access directory */
+            }
+            if (!S_ISDIR(st.st_mode)) {
+                continue;              /* not a dir */
+            }
         }
-        if (!S_ISDIR(st.st_mode)) {
-            continue;          /* not a dir */
+        if (volume->v_hide) {
+            continue;          /* config file changed but the volume was mounted */
         }
+       len = ucs2_to_charset_allocate((utf8_encoding()?CH_UTF8_MAC:obj->options.maccharset),
+                                       &namebuf, volume->v_name);
+       if (len == (size_t)-1)
+               continue;
 
         /* set password bit if there's a volume password */
         *data = (volume->v_password) ? AFPSRVR_PASSWD : 0;
@@ -1150,17 +1539,17 @@ int     ibuflen, *rbuflen;
            off.. <shirsch@ibm.net> */
         *data |= (volume->v_flags & AFPVOL_A2VOL) ? AFPSRVR_CONFIGINFO : 0;
         *data++ |= 0; /* UNIX PRIVS BIT ..., OSX doesn't seem to use it, so we don't either */
-        len = strlen( volume->v_name );
         *data++ = len;
-        memcpy(data, volume->v_name, len );
+        memcpy(data, namebuf, len );
         data += len;
+       free(namebuf);
         vcnt++;
     }
 
     *rbuflen = data - rbuf;
     data = rbuf;
     if ( gettimeofday( &tv, 0 ) < 0 ) {
-        LOG(log_error, logtype_afpd, "afp_getsrvrparms: gettimeofday: %s", strerror(errno) );
+        LOG(log_error, logtype_afpd, "afp_getsrvrparms(%s): gettimeofday: %s", volume->v_path, strerror(errno) );
         *rbuflen = 0;
         return AFPERR_PARAM;
     }
@@ -1171,61 +1560,77 @@ int     ibuflen, *rbuflen;
     return( AFP_OK );
 }
 
+/* ------------------------- 
+ * we are the user here
+*/
 int afp_openvol(obj, ibuf, ibuflen, rbuf, rbuflen )
-AFPObj      *obj;
+AFPObj  *obj;
 char   *ibuf, *rbuf;
-int            ibuflen, *rbuflen;
+int    ibuflen _U_, *rbuflen;
 {
     struct stat        st;
     char       *volname;
-#ifndef CNID_DB
     char        *p;
-#else
-    int         opened = 0;
-#endif /* CNID_DB */
     struct vol *volume;
     struct dir *dir;
-    int                len, ret, buflen;
+    int                len, ret;
+    size_t     namelen;
     u_int16_t  bitmap;
+    char        path[ MAXPATHLEN + 1];
+    char        *vol_uname;
+    char        *vol_mname;
 
     ibuf += 2;
     memcpy(&bitmap, ibuf, sizeof( bitmap ));
     bitmap = ntohs( bitmap );
     ibuf += sizeof( bitmap );
     if (( bitmap & (1<<VOLPBIT_VID)) == 0 ) {
-        ret = AFPERR_BITMAP;
-        goto openvol_err;
+        *rbuflen = 0;
+        return AFPERR_BITMAP;
     }
 
     len = (unsigned char)*ibuf++;
     volname = obj->oldtmp;
-    memcpy(volname, ibuf, len );
-    *(volname +  len) = '\0';
+    namelen = convert_string( (utf8_encoding()?CH_UTF8_MAC:obj->options.maccharset), CH_UCS2,
+                              ibuf, len, volname, sizeof(obj->oldtmp));
+    if ( namelen <= 0){
+        *rbuflen = 0;
+        return AFPERR_PARAM;
+    }
+
     ibuf += len;
     if ((len + 1) & 1) /* pad to an even boundary */
         ibuf++;
 
-    if (!volumes)
-        load_volumes(obj);
+    load_volumes(obj);
 
-    for ( volume = volumes; volume; volume = volume->v_next ) {
-        if ( strcasecmp( volname, volume->v_name ) == 0 ) {
+    for ( volume = Volumes; volume; volume = volume->v_next ) {
+        if ( strcasecmp_w( (ucs2_t*) volname, volume->v_name ) == 0 ) {
             break;
         }
     }
 
     if ( volume == NULL ) {
-        ret = AFPERR_PARAM;
-        goto openvol_err;
+        *rbuflen = 0;
+        return AFPERR_PARAM;
     }
 
     /* check for a volume password */
-    if (volume->v_password &&
-            strncmp(ibuf, volume->v_password, VOLPASSLEN)) {
-        ret = AFPERR_ACCESS;
-        goto openvol_err;
+    if (volume->v_password && strncmp(ibuf, volume->v_password, VOLPASSLEN)) {
+        *rbuflen = 0;
+        return AFPERR_ACCESS;
     }
-    /* FIXME 
+
+    if (( volume->v_flags & AFPVOL_OPEN  ) ) {
+        /* the volume is already open */
+#ifdef FORCE_UIDGID
+        set_uidgid ( volume );
+#endif
+        return stat_vol(bitmap, volume, rbuf, rbuflen);
+    }
+
+    /* initialize volume variables
+     * FIXME file size
     */
     if (afp_version >= 30) {
         volume->max_filename = 255;
@@ -1233,28 +1638,31 @@ int             ibuflen, *rbuflen;
     else {
         volume->max_filename = MACFILELEN;
     }
-    if (( volume->v_flags & AFPVOL_OPEN  ) == 0 ) {
-        /* FIXME unix name != mac name */
-        if ((dir = dirnew(volume->v_name, volume->v_name) ) == NULL) {
-            LOG(log_error, logtype_afpd, "afp_openvol: malloc: %s", strerror(errno) );
+
+    volume->v_dir = volume->v_root = NULL;
+
+    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) {
+            LOG(log_error, logtype_afpd, "afp_openvol(%s): root preexec : %d", volume->v_path, ret );
             ret = AFPERR_MISC;
             goto openvol_err;
-        }
-        dir->d_did = DIRDID_ROOT;
-        dir->d_color = DIRTREE_COLOR_BLACK; /* root node is black */
-        volume->v_dir = volume->v_root = dir;
-        volume->v_flags |= AFPVOL_OPEN;
-#ifdef CNID_DB
-        volume->v_db = NULL;
-        opened = 1;
-#endif
+       }
     }
-    else {
-       /* FIXME */
-    }    
+
 #ifdef FORCE_UIDGID
     set_uidgid ( volume );
-#endif /* FORCE_UIDGID */
+#endif
+
+    if (volume->v_preexec) {
+       if ((ret = afprun(0, volume->v_preexec, NULL)) && volume->v_preexec_close) {
+            LOG(log_error, logtype_afpd, "afp_openvol(%s): preexec : %d", volume->v_path, ret );
+            ret = AFPERR_MISC;
+            goto openvol_err;
+       }
+    }
 
     if ( stat( volume->v_path, &st ) < 0 ) {
         ret = AFPERR_PARAM;
@@ -1265,111 +1673,177 @@ int           ibuflen, *rbuflen;
         ret = AFPERR_PARAM;
         goto openvol_err;
     }
-    curdir = volume->v_dir;
 
-#ifdef CNID_DB
-    if (opened) {
-        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) {
-           /* config option? 
-            * - mount the volume readonly
-            * - return an error
-            * - read/write with other scheme
-            */
-        }
+    len = convert_string_allocate( CH_UCS2, (utf8_encoding()?CH_UTF8_MAC:obj->options.maccharset),
+                                      volume->v_name, namelen, &vol_mname);
+    if ( !vol_mname || len <= 0) {
+        ret = AFPERR_MISC;
+        goto openvol_err;
+    }
+    
+    if ( NULL == getcwd(path, MAXPATHLEN)) {
+        /* shouldn't be fatal but it will fail later */
+        LOG(log_error, logtype_afpd, "afp_openvol(%s): volume pathlen too long", volume->v_path);
+        ret = AFPERR_MISC;
+        goto openvol_err;
+    }        
+    
+    if ((vol_uname = strrchr(path, '/')) == NULL)
+         vol_uname = path;
+    else if (*(vol_uname + 1) != '\0')
+         vol_uname++;
+       
+    if ((dir = dirnew(vol_mname, vol_uname) ) == NULL) {
+       free(vol_mname);
+        LOG(log_error, logtype_afpd, "afp_openvol(%s): malloc: %s", volume->v_path, strerror(errno) );
+        ret = AFPERR_MISC;
+        goto openvol_err;
     }
-#endif /* CNID_DB */
+    free(vol_mname);
 
-    buflen = *rbuflen - sizeof( bitmap );
-    if (( ret = getvolparams( bitmap, volume, &st,
-                              rbuf + sizeof(bitmap), &buflen )) != AFP_OK ) {
+    dir->d_did = DIRDID_ROOT;
+    dir->d_color = DIRTREE_COLOR_BLACK; /* root node is black */
+    dir->d_m_name_ucs2 = strdup_w(volume->v_name);
+    volume->v_dir = volume->v_root = dir;
+
+    curdir = volume->v_dir;
+    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_cdb = cnid_open (volume->v_dbpath, volume->v_umask, volume->v_cnidscheme, (volume->v_flags & AFPVOL_NODEV));
+    else
+        volume->v_cdb = cnid_open (volume->v_path, volume->v_umask, volume->v_cnidscheme, (volume->v_flags & AFPVOL_NODEV));
+    if (volume->v_cdb == NULL) {
+        LOG(log_error, logtype_afpd, "Fatal error: cannot open CNID or invalid CNID backend for %s: %s", 
+           volume->v_path, volume->v_cnidscheme);
+        ret = AFPERR_MISC;
         goto openvol_err;
     }
-#ifdef AFP3x
-    volume->v_utf8toucs2 = (iconv_t)(-1);
-    volume->v_ucs2toutf8 = (iconv_t)(-1);
-    volume->v_mactoutf8  = (iconv_t)(-1);
-    volume->v_ucs2tomac  = (iconv_t)(-1);
-    
-    if (vol_utf8(volume)) {
-        if ((iconv_t)(-1) == (volume->v_utf8toucs2 = iconv_open("UCS-2LE", "UTF-8"))) {
-            LOG(log_error, logtype_afpd, "openvol: no UTF8 to UCS-2LE");
-            goto openvol_err;
-        }
-        if ((iconv_t)(-1) == (volume->v_ucs2toutf8 = iconv_open("UTF-8", "UCS-2LE"))) {
-            LOG(log_error, logtype_afpd, "openvol: no UCS-2LE to UTF-8");
-            goto openvol_err_iconv;
-        }
-        if ((iconv_t)(-1) == (volume->v_mactoutf8 = iconv_open("UTF-8", "MAC"))) {
-            LOG(log_error, logtype_afpd, "openvol: no MAC to UTF-8");
-            goto openvol_err_iconv;
+
+    /* 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) {
+
+        if (!(volume->v_flags & AFPVOL_RO)) {
+            handle_special_folders( volume );
+            savevoloptions( volume);
         }
-        if ((iconv_t)(-1) == (volume->v_ucs2tomac = iconv_open("MAC", "UCS-2LE"))) {
-            LOG(log_error, logtype_afpd, "openvol:  no UCS-2LE to MAC");
-            goto openvol_err_iconv;
+
+        /*
+         * 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)) < 0) {
+               LOG (log_error, logtype_afpd, 
+                     "afp_openvol(%s): Fatal error: Unable to get stamp value from CNID backend",
+                     volume->v_path);
+               ret = AFPERR_MISC;
+               goto openvol_err;
+           }
+       }
+       else {
+            p = Trash;
+            cname( volume, volume->v_dir, &p );
         }
+        return( AFP_OK );
     }
-#endif
-    *rbuflen = buflen + sizeof( bitmap );
-    bitmap = htons( bitmap );
-    memcpy(rbuf, &bitmap, sizeof( bitmap ));
-
-#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.
-     */
-    p = Trash;
-    cname( volume, volume->v_dir, &p );
-#endif /* CNID_DB */
 
-    return( AFP_OK );
-#ifdef AFP3x
-openvol_err_iconv:
-    if (volume->v_utf8toucs2 != (iconv_t)(-1))
-        iconv_close(volume->v_utf8toucs2);
-    if (volume->v_ucs2toutf8 != (iconv_t)(-1))
-        iconv_close(volume->v_ucs2toutf8);
-    if (volume->v_mactoutf8  != (iconv_t)(-1))
-        iconv_close(volume->v_mactoutf8);    
-    if (volume->v_ucs2tomac  != (iconv_t)(-1))
-        iconv_close(volume->v_ucs2tomac);
-#endif        
 openvol_err:
-#ifdef CNID_DB
-    if (opened && volume->v_db != NULL) {
-        cnid_close(volume->v_db);
-        volume->v_db = NULL;
+    if (volume->v_dir) {
+        dirfree( volume->v_dir );
+        volume->v_dir = volume->v_root = NULL;
+    }
+
+    volume->v_flags &= ~AFPVOL_OPEN;
+    if (volume->v_cdb != NULL) {
+        cnid_close(volume->v_cdb);
+        volume->v_cdb = NULL;
     }
-#endif
     *rbuflen = 0;
     return ret;
 }
 
-int afp_closevol(obj, ibuf, ibuflen, rbuf, rbuflen )
-AFPObj      *obj;
-char   *ibuf, *rbuf;
-int            ibuflen, *rbuflen;
+/* ------------------------- */
+static void closevol(struct vol        *vol)
 {
-    struct vol *vol, *ovol;
-    u_int16_t  vid;
+    if (!vol)
+        return;
 
-    *rbuflen = 0;
-    ibuf += 2;
-    memcpy(&vid, ibuf, sizeof( vid ));
-    if (NULL == ( vol = getvolbyvid( vid )) ) {
-        return( AFPERR_PARAM );
+    dirfree( vol->v_root );
+    vol->v_dir = NULL;
+    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 (vol->v_root_postexec) {
+       afprun(1, vol->v_root_postexec, NULL);
+    }
+}
+
+/* ------------------------- */
+void close_all_vol(void)
+{
+    struct vol *ovol;
+    curdir = NULL;
+    for ( ovol = Volumes; ovol; ovol = ovol->v_next ) {
+        if ( (ovol->v_flags & AFPVOL_OPEN) ) {
+            ovol->v_flags &= ~AFPVOL_OPEN;
+            closevol(ovol);
+        }
     }
+}
+
+/* ------------------------- */
+static void deletevol(struct vol *vol)
+{
+    struct vol *ovol;
 
     vol->v_flags &= ~AFPVOL_OPEN;
-    for ( ovol = volumes; ovol; ovol = ovol->v_next ) {
-        if ( ovol->v_flags & AFPVOL_OPEN ) {
+    for ( ovol = Volumes; ovol; ovol = ovol->v_next ) {
+        if ( (ovol->v_flags & AFPVOL_OPEN) ) {
             break;
         }
     }
@@ -1379,20 +1853,43 @@ int             ibuflen, *rbuflen;
             curdir = ovol->v_dir;
         }
     }
-    dirfree( vol->v_root );
-    vol->v_dir = NULL;
-#ifdef CNID_DB
-    cnid_close(vol->v_db);
-    vol->v_db = NULL;
-#endif /* CNID_DB */
+
+    closevol(vol);
+    if (vol->v_deleted) {
+       showvol(vol->v_name);
+       volume_free(vol);
+       volume_unlink(vol);
+       free(vol);
+    }
+}
+
+/* ------------------------- */
+int afp_closevol(obj, ibuf, ibuflen, rbuf, rbuflen )
+AFPObj  *obj _U_;
+char   *ibuf, *rbuf _U_;
+int    ibuflen _U_, *rbuflen;
+{
+    struct vol *vol;
+    u_int16_t  vid;
+
+    *rbuflen = 0;
+    ibuf += 2;
+    memcpy(&vid, ibuf, sizeof( vid ));
+    if (NULL == ( vol = getvolbyvid( vid )) ) {
+        return( AFPERR_PARAM );
+    }
+
+    deletevol(vol);
+
     return( AFP_OK );
 }
 
+/* ------------------------- */
 struct vol *getvolbyvid(const u_int16_t vid )
 {
     struct vol *vol;
 
-    for ( vol = volumes; vol; vol = vol->v_next ) {
+    for ( vol = Volumes; vol; vol = vol->v_next ) {
         if ( vid == vol->v_vid ) {
             break;
         }
@@ -1421,26 +1918,27 @@ struct extmap *getextmap(const char *path)
     struct extmap *em;
 
     if (NULL == ( p = strrchr( path, '.' )) ) {
-        return( defextmap );
+        return( Defextmap );
     }
     p++;
-    if (!*p || !extmap_cnt) {
-        return( defextmap );
+    if (!*p || !Extmap_cnt) {
+        return( Defextmap );
     }
-    em = bsearch(p, extmap, extmap_cnt, sizeof(struct extmap), ext_cmp_key);
+    em = bsearch(p, Extmap, Extmap_cnt, sizeof(struct extmap), ext_cmp_key);
     if (em) {
         return( em );
     } else {
-        return( defextmap );
+        return( Defextmap );
     }
 }
 
+/* ------------------------- */
 struct extmap *getdefextmap(void)
 {
-    return( defextmap );
+    return( Defextmap );
 }
 
-/*
+/* --------------------------
    poll if a volume is changed by other processes.
 */
 int  pollvoltime(obj)
@@ -1456,10 +1954,10 @@ AFPObj *obj;
     if ( gettimeofday( &tv, 0 ) < 0 ) 
          return 0;
 
-    for ( vol = volumes; vol; vol = vol->v_next ) {
-        if ( (vol->v_flags & AFPVOL_OPEN)  && vol->v_time + 30 < tv.tv_sec) {
-            if ( !stat( vol->v_path, &st ) && vol->v_time != st.st_mtime ) {
-                vol->v_time = st.st_mtime;
+    for ( vol = Volumes; vol; vol = vol->v_next ) {
+        if ( (vol->v_flags & AFPVOL_OPEN)  && vol->v_mtime + 30 < tv.tv_sec) {
+            if ( !stat( vol->v_path, &st ) && vol->v_mtime != st.st_mtime ) {
+                vol->v_mtime = st.st_mtime;
                 if (!obj->attention(obj->handle, AFPATTN_NOTIFY | AFPATTN_VOLCHANGED))
                     return -1;
                 return 1;
@@ -1469,20 +1967,21 @@ AFPObj *obj;
     return 0;
 }
 
+/* ------------------------- */
 void setvoltime(obj, vol )
 AFPObj *obj;
 struct vol     *vol;
 {
     struct timeval     tv;
 
-    /* just looking at vol->v_time is broken seriously since updates
+    /* just looking at vol->v_mtime is broken seriously since updates
      * from other users afpd processes never are seen.
      * This is not the most elegant solution (a shared memory between
      * the afpd processes would come closer)
      * [RS] */
 
     if ( gettimeofday( &tv, 0 ) < 0 ) {
-        LOG(log_error, logtype_afpd, "setvoltime: gettimeofday: %s", strerror(errno) );
+        LOG(log_error, logtype_afpd, "setvoltime(%s): gettimeofday: %s", vol->v_path, strerror(errno) );
         return;
     }
     if( utime( vol->v_path, NULL ) < 0 ) {
@@ -1492,22 +1991,22 @@ struct vol      *vol;
     }
 
     /* a little granularity */
-    if (vol->v_time < tv.tv_sec) {
-        vol->v_time = tv.tv_sec;
+    if (vol->v_mtime < tv.tv_sec) {
+        vol->v_mtime = tv.tv_sec;
+        /* or finder doesn't update free space */
         if (afp_version > 21 && obj->options.server_notif) {
             obj->attention(obj->handle, AFPATTN_NOTIFY | AFPATTN_VOLCHANGED);
         }
     }
 }
 
+/* ------------------------- */
 int afp_getvolparams(obj, ibuf, ibuflen, rbuf, rbuflen )
-AFPObj      *obj;
+AFPObj  *obj _U_;
 char   *ibuf, *rbuf;
-int            ibuflen, *rbuflen;
+int    ibuflen _U_, *rbuflen;
 {
-    struct stat        st;
     struct vol *vol;
-    int                buflen, ret;
     u_int16_t  vid, bitmap;
 
     ibuf += 2;
@@ -1521,27 +2020,14 @@ int             ibuflen, *rbuflen;
         return( AFPERR_PARAM );
     }
 
-    if ( stat( vol->v_path, &st ) < 0 ) {
-        *rbuflen = 0;
-        return( AFPERR_PARAM );
-    }
-
-    buflen = *rbuflen - sizeof( bitmap );
-    if (( ret = getvolparams( bitmap, vol, &st,
-                              rbuf + sizeof( bitmap ), &buflen )) != AFP_OK ) {
-        *rbuflen = 0;
-        return( ret );
-    }
-    *rbuflen = buflen + sizeof( bitmap );
-    bitmap = htons( bitmap );
-    memcpy(rbuf, &bitmap, sizeof( bitmap ));
-    return( AFP_OK );
+    return stat_vol(bitmap, vol, rbuf, rbuflen);
 }
 
+/* ------------------------- */
 int afp_setvolparams(obj, ibuf, ibuflen, rbuf, rbuflen )
-AFPObj      *obj;
-char   *ibuf, *rbuf;
-int            ibuflen, *rbuflen;
+AFPObj  *obj _U_;
+char   *ibuf, *rbuf _U_;
+int    ibuflen _U_, *rbuflen;
 {
     struct adouble ad;
     struct vol *vol;
@@ -1561,14 +2047,14 @@ int             ibuflen, *rbuflen;
         return( AFPERR_PARAM );
     }
 
-    if (vol->v_flags & AFPVOL_RO)
+    if ((vol->v_flags & AFPVOL_RO))
         return AFPERR_VLOCK;
 
     /* we can only set the backup date. */
     if (bitmap != (1 << VOLPBIT_BDATE))
         return AFPERR_BITMAP;
 
-    memset(&ad, 0, sizeof(ad));
+    ad_init(&ad, vol->v_adouble, vol->v_ad_options);
     if ( ad_open( vol->v_path, ADFLAGS_HF|ADFLAGS_DIR, O_RDWR,
                   0666, &ad) < 0 ) {
         if (errno == EROFS)
@@ -1584,7 +2070,7 @@ int               ibuflen, *rbuflen;
     return( AFP_OK );
 }
 
-
+/* ------------------------- */
 int wincheck(const struct vol *vol, const char *path)
 {
     int len;
@@ -1611,18 +2097,220 @@ int wincheck(const struct vol *vol, const char *path)
 }
 
 
-void close_vols ()
+/*
+ * precreate a folder 
+ * this is only intended for folders in the volume root 
+ * It will *not* work if the folder name contains extended characters 
+ */
+static int create_special_folder (const struct vol *vol, const struct _special_folder *folder)
 {
-#ifdef CNID_DB
-    struct vol *vol;
+       char            *p,*q,*r;
+       struct adouble  ad;
+       u_int16_t       attr;
+       struct stat     st;
+       int             ret;
+
+
+       p = (char *) malloc ( strlen(vol->v_path)+strlen(folder->name)+2);
+       if ( p == NULL) {
+               LOG(log_error, logtype_afpd,"malloc failed");
+               exit (EXITERR_SYS);
+       }
+
+       q=strdup(folder->name);
+       if ( q == NULL) {
+               LOG(log_error, logtype_afpd,"malloc failed");
+               exit (EXITERR_SYS);
+       }
+
+       strcpy(p, vol->v_path);
+       strcat(p, "/");
+
+       r=q;
+       while (*r) {
+               if ((vol->v_casefold & AFPVOL_MTOUUPPER))
+                       *r=toupper(*r);
+               else if ((vol->v_casefold & AFPVOL_MTOULOWER))
+                       *r=tolower(*r);
+               r++;
+       }
+       strcat(p, q);
+
+       if ( (ret = stat( p, &st )) < 0 ) {
+               if (folder->precreate) {
+                   if (ad_mkdir(p, folder->mode)) {
+                       LOG(log_debug, logtype_afpd,"Creating '%s' failed in %s: %s", p, vol->v_path, strerror(errno));
+                       free(p);
+                       free(q);
+                       return -1;
+                    }
+                   ret = 0;
+               }
+       }
+
+       if ( !ret && folder->hide) {
+               /* Hide it */
+               ad_init(&ad, vol->v_adouble, vol->v_ad_options);
+               if (ad_open( p, vol_noadouble(vol) | ADFLAGS_HF|ADFLAGS_DIR,
+                       O_RDWR|O_CREAT, 0666, &ad) < 0) {
+                       free (p);
+                       free(q);
+                       return (-1);
+               }
+               if ((ad_get_HF_flags( &ad ) & O_CREAT) ) {
+                   if (ad_getentryoff(&ad, ADEID_NAME)) {
+                       ad_setentrylen( &ad, ADEID_NAME, strlen(folder->name));
+                       memcpy(ad_entry( &ad, ADEID_NAME ), folder->name,
+                              ad_getentrylen( &ad, ADEID_NAME ));
+                   }
+               }
+               ad_getattr(&ad, &attr);
+               attr |= htons( ntohs( attr ) | ATTRBIT_INVISIBLE );
+               ad_setattr(&ad, attr);
+#if 0          
+               /* do the same with the finder info */
+               if (ad_entry(&ad, ADEID_FINDERI)) {
+                       memcpy(&attr, ad_entry(&ad, ADEID_FINDERI) + FINDERINFO_FRFLAGOFF, sizeof(attr));
+                       attr   |= htons(FINDERINFO_INVISIBLE);
+                       memcpy(ad_entry(&ad, ADEID_FINDERI) + FINDERINFO_FRFLAGOFF,&attr, sizeof(attr));
+               }
+#endif    
+               ad_flush( &ad, ADFLAGS_HF );
+               ad_close( &ad, ADFLAGS_HF );
+       }
+       free(p);
+       free(q);
+       return 0;
+}
 
-    for ( vol = volumes; vol; vol = vol->v_next ) {
-       if ( (vol->v_flags & AFPVOL_OPEN ) == 0 ) 
-               continue;
-       if ( vol->v_db )
-           cnid_close(vol->v_db);
-       vol->v_db = NULL;
-    }
-#endif
+static void handle_special_folders (const struct vol * vol)
+{
+       const _special_folder *p = &special_folders[0];
+
+       if ((vol->v_flags & AFPVOL_RO))
+               return;
+
+        for (; p->name != NULL; p++) {
+               create_special_folder (vol, p);
+       }
 }
 
+/*
+ * Save the volume options to a file, used by
+ * shell utilities.
+ * Writing the file everytime a volume is opened is
+ * unnecessary, but it shouldn't hurt much.
+ */
+static int savevoloptions (const struct vol *vol)
+{
+    char buf[16348];
+    char item[MAXPATHLEN];
+    int fd;
+    int ret = 0;
+    struct flock lock;
+    const _vol_opt_name *op = &vol_opt_names[0];
+    const _vol_opt_name *cf = &vol_opt_casefold[0];
+
+    strlcpy (item, vol->v_path, sizeof(item));
+    strlcat (item, "/.AppleDesktop/", sizeof(item));
+    strlcat (item, VOLINFOFILE, sizeof(item));
+
+    if ((fd = open( item, O_RDWR | O_CREAT , 0666)) <0 ) {
+        LOG(log_debug, logtype_afpd,"Error opening %s: %s", item, strerror(errno));
+        return (-1);
+    }
+
+    /* try to get a lock */
+    lock.l_start  = 0;
+    lock.l_whence = SEEK_SET;
+    lock.l_len    = 0;
+    lock.l_type   = F_WRLCK;
+
+    if (fcntl(fd, F_SETLK, &lock) < 0) {
+        if (errno == EACCES || errno == EAGAIN) {
+            /* ignore, other process already writing the file */
+            return 0;
+        } else {
+            LOG(log_error, logtype_cnid, "savevoloptions: cannot get lock: %s", strerror(errno));
+            return (-1);
+        }
+    }
+
+    /* write volume options */
+    snprintf(buf, sizeof(buf), "MAC_CHARSET:%s\n", vol->v_maccodepage);
+    snprintf(item, sizeof(item), "VOL_CHARSET:%s\n", vol->v_volcodepage);
+    strlcat(buf, item, sizeof(buf));
+
+    switch (vol->v_adouble) {
+        case AD_VERSION1:
+            strlcat(buf, "ADOUBLE_VER:v1\n", sizeof(buf));
+            break;
+        case AD_VERSION2:
+            strlcat(buf, "ADOUBLE_VER:v2\n", sizeof(buf));
+            break;
+        case AD_VERSION2_OSX:
+            strlcat(buf, "ADOUBLE_VER:osx\n", sizeof(buf));
+            break;
+        case AD_VERSION1_ADS:
+            strlcat(buf, "ADOUBLE_VER:ads\n", sizeof(buf));
+            break;
+    }
+
+    strlcat(buf, "CNIDBACKEND:", sizeof(buf));
+    strlcat(buf, vol->v_cnidscheme, sizeof(buf));
+    strlcat(buf, "\n", sizeof(buf));
+
+    strlcat(buf, "CNIDDBDHOST:", sizeof(buf));
+    strlcat(buf, Cnid_srv, sizeof(buf));
+    strlcat(buf, "\n", sizeof(buf));
+
+    snprintf(item, sizeof(item), "CNIDDBDPORT:%u\n", Cnid_port);
+    strlcat(buf, item, sizeof(buf));
+
+    strcpy(item, "CNID_DBPATH:");
+    if (vol->v_dbpath)
+        strlcat(item, vol->v_dbpath, sizeof(item));
+    else
+        strlcat(item, vol->v_path, sizeof(item));
+    strlcat(item, "\n", sizeof(item));
+    strlcat(buf, item, sizeof(buf));
+
+    /* volume flags */
+    strcpy(item, "VOLUME_OPTS:");
+    for (;op->name; op++) {
+       if ( (vol->v_flags & op->option) ) {
+            strlcat(item, op->name, sizeof(item));
+            strlcat(item, " ", sizeof(item));
+        }
+    }
+    strlcat(item, "\n", sizeof(item));
+    strlcat(buf, item, sizeof(buf));
+
+    /* casefold flags */
+    strcpy(item, "VOLCASEFOLD:");
+    for (;cf->name; cf++) {
+        if ( (vol->v_casefold & cf->option) ) {
+            strlcat(item, cf->name, sizeof(item));
+            strlcat(item, " ", sizeof(item));
+        }
+    }
+    strlcat(item, "\n", sizeof(item));
+    strlcat(buf, item, sizeof(buf));
+
+    if (strlen(buf) >= sizeof(buf)-1)
+        LOG(log_debug, logtype_afpd,"Error writing .volinfo file: buffer too small, %s", buf);
+
+
+   if (write( fd, buf, strlen(buf)) < 0) {
+       LOG(log_debug, logtype_afpd,"Error writing .volinfo file: %s", strerror(errno));
+       goto done;
+   }
+   ftruncate(fd, strlen(buf));
+
+done:
+   lock.l_type = F_UNLCK;
+   fcntl(fd, F_SETLK, &lock);
+   close (fd);
+   return ret;
+}
index 2f29f236cf1630c2aa229a3e03e8687ede85c8d1..f01a80b1b8e868914863a2528faf07811f0b057f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: volume.h,v 1.20 2003-06-05 09:17:12 didg Exp $
+ * $Id: volume.h,v 1.21 2005-04-28 20:49:46 bfernhomberg Exp $
  *
  * Copyright (c) 1990,1994 Regents of The University of Michigan.
  * All Rights Reserved.  See COPYRIGHT.
 #include <sys/types.h>
 #include <netatalk/endian.h>
 
-#ifdef HAVE_USABLE_ICONV
-#include <iconv.h>
-#endif
-
+#include "atalk/unicode.h"
 #include "globals.h"
+#include "afp_vfs.h"
 
 #define AFPVOL_NAMELEN   27
 
-struct codepage_hash {
-    unsigned char *from, *to;
-    struct codepage_hash *next, *prev;
-};
-
-union codepage_val {
-    struct codepage_hash hash; /* hash for multibyte values */
-    unsigned char value; /* single byte value/rule */
-};
-
-struct codepage {
-    union codepage_val *map;
-    int quantum;
-};
-
-#define CP_HASH(a)    (*(a))
+#include <atalk/cnid.h>
 
 struct vol {
     struct vol         *v_next;
-    char               *v_name;
+    ucs2_t             *v_name;
     char               *v_path;
     struct dir         *v_dir, *v_root;
     int                        v_flags;
@@ -47,23 +30,24 @@ struct vol {
     int                        v_qfd;
 #endif /*__svr4__*/
     char               *v_gvs;
-    time_t             v_time;
-    int                        v_lastdid;
+    time_t             v_mtime;
+    time_t             v_ctime;  /* volume creation date, not unix ctime */
+
     u_int16_t          v_vid;
     void                *v_nfsclient;
     int                 v_nfs;
     
     int                 v_casefold;
-    struct codepage     *v_mtoupage, *v_utompage, *v_badumap;
     size_t              max_filename;
     
     char                *v_password;
     char                *v_veto;
 
-#ifdef CNID_DB
-    void                *v_db;
+    char                *v_cnidscheme;
     char                *v_dbpath;
-#endif 
+    dev_t               v_dev;              /* Unix volume device */
+    struct _cnid_db     *v_cdb;
+    char                v_stamp[ADEDLEN_PRIVSYN];
     mode_t             v_umask;
 
 #ifdef FORCE_UIDGID
@@ -71,13 +55,32 @@ struct vol {
     char               *v_forcegid;
 #endif 
 
-#ifdef HAVE_USABLE_ICONV
-    iconv_t             *v_utf8toucs2;
-    iconv_t             *v_ucs2toutf8;
-    iconv_t             *v_mactoutf8;
-    iconv_t             *v_ucs2tomac;
-#endif
+    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 until old volume is closed */
+    int                 v_new;        /* volume deleted but there's a new one with the same name */
+    int                 v_adouble;    /* default adouble format */
+    int                        v_ad_options; /* adouble option NODEV, NOCACHE, etc.. */
+
+    char                *v_root_preexec;
+    char                *v_preexec;
 
+    char                *v_root_postexec;
+    char                *v_postexec;
+
+    int                 v_root_preexec_close;
+    int                 v_preexec_close;
+    
+    /* adouble indirection */
+    struct vfs_ops      *vfs;
+    int                 (*validupath)(const struct vol *, const char *);
+    char                *(*ad_path)(const char *, int);
 };
 
 #ifdef NO_LARGE_VOL_SUPPORT
@@ -108,8 +111,18 @@ this is going away. */
 #define AFPVOL_MAPASCII  (1 << 13)  /* map the ascii range as well */
 #define AFPVOL_DROPBOX   (1 << 14)  /* dropkludge dropbox support */
 #define AFPVOL_NOFILEID  (1 << 15)  /* don't advertise createid resolveid and deleteid calls */
-#define AFPVOL_UTF8      (1 << 16)  /* unix name are in UTF8 */
+#define AFPVOL_NOSTAT    (1 << 16)  /* advertise the volume even if we can't stat() it
+                                     * maybe because it will be mounted later in preexec */
 #define AFPVOL_UNIX_PRIV (1 << 17)  /* support unix privileges */
+#define AFPVOL_NODEV     (1 << 18)  /* always use 0 for device number in cnid calls 
+                                     * help if device number is notconsistent across reboot 
+                                     * NOTE symlink to a different device will return an ACCESS error
+                                     */
+#define AFPVOL_CASEINSEN (1 << 19)  /* volume is case insensitive */
+#define AFPVOL_EILSEQ    (1 << 20)  /* encode illegal sequence 'asis' UCS2, ex "\217-", which is not 
+                                       a valid SHIFT-JIS char, is encoded  as U\217 -*/
+
+#define AFPVOL_CACHE     (1 << 21)  /* Use adouble v2 CNID caching, default don't use it */
 
 /* FPGetSrvrParms options */
 #define AFPSRVR_CONFIGINFO     (1 << 0)
@@ -126,7 +139,6 @@ this is going away. */
 #define AFPVOL_ULOWERMUPPER    (AFPVOL_MTOULOWER | AFPVOL_UTOMUPPER)
 
 #define MSWINDOWS_BADCHARS ":\t\\/<>*?|\""
-#define MSWINDOWS_CODEPAGE "maccode.iso8859-1"
 
 int wincheck(const struct vol *vol, const char *path);
 
@@ -162,26 +174,23 @@ int wincheck(const struct vol *vol, const char *path);
 
 #define vol_noadouble(vol) (((vol)->v_flags & AFPVOL_NOADOUBLE) ? \
                            ADFLAGS_NOADOUBLE : 0)
-
 #ifdef AFP3x
-#define vol_utf8(vol) ((vol)->v_flags & AFPVOL_UTF8)
 #define utf8_encoding() (afp_version >= 30)
 #else
-#define vol_utf8(vol) (0)
 #define utf8_encoding() (0)
 #endif
+
+#define vol_nodev(vol) (((vol)->v_flags & AFPVOL_NODEV) ? 1 : 0)
+
 #define vol_unix_priv(vol) (afp_version >= 30 && ((vol)->v_flags & AFPVOL_UNIX_PRIV))
 
 extern struct vol      *getvolbyvid __P((const u_int16_t));
 extern int              ustatfs_getvolspace __P((const struct vol *,
             VolSpace *, VolSpace *,
             u_int32_t *));
-extern int              codepage_init __P((struct vol *, const int,
-            const int));
-extern int              codepage_read __P((struct vol *, const char *));
-extern union codepage_val codepage_find __P(());
 extern void             setvoltime __P((AFPObj *, struct vol *));
 extern int              pollvoltime __P((AFPObj *));
+extern void             load_volumes __P((AFPObj *obj));
 
 /* FP functions */
 extern int     afp_openvol      __P((AFPObj *, char *, int, char *, int *));
@@ -190,4 +199,7 @@ extern int  afp_setvolparams __P((AFPObj *, char *, int, char *, int *));
 extern int     afp_getsrvrparms __P((AFPObj *, char *, int, char *, int *));
 extern int     afp_closevol     __P((AFPObj *, char *, int, char *, int *));
 
+/* netatalk functions */
+extern void     close_all_vol   __P((void));
+
 #endif
index 5cbd63d299e70c808aa88ecc95f4c29633d904d7..2e0a18d3f447906c83a50acecae72821cf74c365 100644 (file)
@@ -19,5 +19,4 @@ noinst_HEADERS =      \
        rtmp.h          \
        zip.h
 
-INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/sys \
-       -D_PATH_ATALKDCONF=\"$(pkgconfdir)/atalkd.conf\"
+CFLAGS = @CFLAGS@ -D_PATH_ATALKDCONF=\"$(pkgconfdir)/atalkd.conf\"
index e66ccadd96e7eb3843974ec9832656497c34e358..8a1368ffe49d3b6ee729c7350bda8aa12266aa3f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: atserv.h,v 1.2 2001-06-25 20:13:45 rufustfirefly Exp $
+ * $Id: atserv.h,v 1.3 2005-04-28 20:49:46 bfernhomberg Exp $
  *
  * Copyright (c) 1990,1992 Regents of The University of Michigan.
  * All Rights Reserved. See COPYRIGHT.
@@ -19,5 +19,3 @@ struct atport {
     int                        (*ap_packet)();
 };
 
-extern struct atserv   atserv[];
-extern int             atservNATSERV;
index ccf8ff49203b55ac5d660ad19e5e18522ddf1947..4630f7c5ede0559789dc52ae4267877e8074ba5b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: config.c,v 1.13 2003-03-18 23:32:17 srittau Exp $
+ * $Id: config.c,v 1.14 2005-04-28 20:49:46 bfernhomberg Exp $
  *
  * Copyright (c) 1990,1993 Regents of The University of Michigan.
  * All Rights Reserved. See COPYRIGHT.
@@ -55,19 +55,21 @@ char *strchr (), *strrchr ();
 #include <sys/stropts.h>
 #endif /* __svr4__ */
 
+#include <atalk/unicode.h>
 #include "interface.h"
 #include "multicast.h"
 #include "rtmp.h"
 #include "zip.h"
 #include "list.h"
+#include "main.h"
 
 #ifndef IFF_SLAVE /* a little backward compatibility */
 #define IFF_SLAVE 0
 #endif /* IFF_SLAVE */
 
-int    router(), dontroute(), seed(), phase(), net(), addr(), zone();
+int    router(), dontroute(), seed(), phase(), net(), addr(), zone(), noallmulti();
 
-static struct param {
+static const struct param {
     char       *p_name;
     int                (*p_func)();
 } params[] = {
@@ -78,6 +80,7 @@ static struct param {
     { "net",   net },
     { "addr",  addr },
     { "zone",  zone },
+    { "noallmulti", noallmulti }
 };
 
 #define ARGV_CHUNK_SIZE 128
@@ -185,6 +188,8 @@ int writeconf( cf )
     struct interface   *iface;
     struct list                *l;
     int                        mode = 0644, fd;
+    size_t             len;
+    char               *zonename;
 
     if ( cf == NULL ) {
        path = _PATH_ATALKDCONF;
@@ -243,6 +248,11 @@ int writeconf( cf )
            if ( iface->i_flags & IFACE_DONTROUTE) {
                fprintf( newconf, " -dontroute");
            }
+#ifdef linux
+            if ( !(iface->i_flags & IFACE_ALLMULTI)) {
+               fprintf( newconf, " -noallmulti");
+            }
+#endif
 
            fprintf( newconf, " -phase %d",
                    ( iface->i_flags & IFACE_PHASE1 ) ? 1 : 2 );
@@ -254,9 +264,20 @@ int writeconf( cf )
                    ntohs( iface->i_addr.sat_addr.s_net ),
                    iface->i_addr.sat_addr.s_node );
            for ( l = iface->i_rt->rt_zt; l; l = l->l_next ) {
-               fprintf( newconf, " -zone \"%.*s\"",
-                       ((struct ziptab *)l->l_data)->zt_len,
-                       ((struct ziptab *)l->l_data)->zt_name );
+                /* codepage conversion */
+                if ((size_t)(-1) == (len = convert_string_allocate(CH_MAC, CH_UNIX, 
+                                      ((struct ziptab *)l->l_data)->zt_name,
+                                      ((struct ziptab *)l->l_data)->zt_len,
+                                      &zonename)) ) {
+                    if ( NULL == 
+                      (zonename = strdup(((struct ziptab *)l->l_data)->zt_name))) {
+                       LOG(log_error, logtype_atalkd, "malloc: %m" );
+                       return( -1 );
+                    }
+                    len = ((struct ziptab *)l->l_data)->zt_len;
+                } 
+               fprintf( newconf, " -zone \"%.*s\"", (int)len, zonename);
+                free(zonename);
            }
            fprintf( newconf, "\n" );
 
@@ -306,7 +327,8 @@ int readconf( cf )
     struct ifreq       ifr;
     struct interface   *iface, *niface;
     char               line[ MAXLINELEN ], **argv, *p;
-    int                        i, j, s, cc;
+    unsigned int       i, j;
+    int                        s, cc = 0;
     FILE               *conf;
 
     if ( cf == NULL ) {
@@ -336,8 +358,7 @@ int readconf( cf )
         * Check that av[ 0 ] is a valid interface.
         * Not possible under sysV.
         */
-       strncpy( ifr.ifr_name, argv[ 0 ], sizeof(ifr.ifr_name) );
-       ifr.ifr_name[sizeof(ifr.ifr_name) - 1] = '\0';
+       strlcpy( ifr.ifr_name, argv[ 0 ], sizeof(ifr.ifr_name) );
 
        /* for devices that don't support appletalk */
        if ((ioctl(s, SIOCGIFADDR, &ifr) < 0) && (errno == ENODEV)) {
@@ -367,6 +388,7 @@ int readconf( cf )
          fprintf(stderr, "Can't configure multicast.\n");
          goto read_conf_err;
        }
+
 #endif /* __svr4__ */
 
        if (( niface = newiface( argv[ 0 ] )) == NULL ) {
@@ -407,6 +429,15 @@ int readconf( cf )
            goto read_conf_err;
        }
 
+#ifdef linux
+       /* Don't set interface to allmulti if it already is, or -noallmulti was given */
+       if ((ifr.ifr_flags & IFF_ALLMULTI))
+               niface->i_flags |= IFACE_WASALLMULTI; 
+
+       if ((niface->i_flags & IFACE_ALLMULTI) && !(niface->i_flags & IFACE_WASALLMULTI))
+               ifsetallmulti(ifr.ifr_name, 1);
+#endif
+
        if ( interfaces == NULL ) {
            interfaces = niface;
        } else {
@@ -443,10 +474,20 @@ read_conf_err:
     return -1;
 }
 
+int noallmulti( iface, av )
+    struct interface   *iface;
+    char               **av _U_;
+{
+    /* Linux specific, no effect on other platforms */
+    iface->i_flags &= !IFACE_ALLMULTI;
+
+    return (1);
+}
+       
 /*ARGSUSED*/
 int router( iface, av )
     struct interface   *iface;
-    char               **av;
+    char               **av _U_;
 {
     /* make sure "-router" and "-dontroute" aren't both on the same line. */
     if (iface->i_flags & IFACE_DONTROUTE) {
@@ -470,7 +511,7 @@ int router( iface, av )
 /*ARGSUSED*/
 int dontroute( iface, av )
     struct interface   *iface;
-    char               **av;
+    char               **av _U_;
 {
     /* make sure "-router" and "-dontroute" aren't both on the same line. */
     if (iface->i_flags & IFACE_RSEED) {
@@ -485,7 +526,7 @@ int dontroute( iface, av )
 /*ARGSUSED*/
 int seed( iface, av )
     struct interface   *iface;
-    char               **av;
+    char               **av _U_;
 {
     /*
      * Check to be sure "-seed" is before "-zone". we keep the old
@@ -642,11 +683,16 @@ int zone( iface, av )
     struct ziptab      *zt;
     char               *zname;
 
-    if (( zname = av[ 0 ] ) == NULL ) {
+    if ( av[ 0 ]  == NULL ) {
        fprintf( stderr, "No zone.\n" );
        return -1;
     }
 
+    /* codepage conversion */
+    if ((size_t)(-1) == convert_string_allocate(CH_UNIX, CH_MAC, av[0], strlen(av[0]), &zname)) {
+       zname = strdup(av[0]);
+    }
+
     /*
      * Only process "-zone" if this interface has "-seed".  We keep our
      * list of configured zones in the interface structure.  Then we can
@@ -657,6 +703,7 @@ int zone( iface, av )
            fprintf( stderr, "Must specify net-range before zones.\n" );
            return -1;
         }
+
        if (( zt = newzt( strlen( zname ), zname )) == NULL ) {
            perror( "newzt" );
            return -1;
@@ -668,6 +715,8 @@ int zone( iface, av )
            iface->i_czt->zt_next = zt;
        }
     }
+    free(zname);
+
     return( 2 );
 }
 
@@ -689,7 +738,7 @@ int getifconf()
 
     start = list = getifacelist();
     while (list && *list) {
-        strncpy(ifr.ifr_name, *list, sizeof(ifr.ifr_name));
+        strlcpy(ifr.ifr_name, *list, sizeof(ifr.ifr_name));
        list++;
 
        if (ioctl(s, SIOCGIFFLAGS, &ifr) < 0)
@@ -764,7 +813,7 @@ struct interface *newiface( name )
            == NULL ) {
        return( NULL );
     }
-    strncpy( niface->i_name, name, sizeof(niface->i_name));
+    strlcpy( niface->i_name, name, sizeof(niface->i_name));
 #ifdef BSD4_4
     niface->i_addr.sat_len = sizeof( struct sockaddr_at );
 #endif /* BSD4_4 */
@@ -773,6 +822,9 @@ struct interface *newiface( name )
     niface->i_caddr.sat_len = sizeof( struct sockaddr_at );
 #endif /* BSD4_4 */
     niface->i_caddr.sat_family = AF_APPLETALK;
+#ifdef linux
+    niface->i_flags = IFACE_ALLMULTI;
+#endif
     return( niface );
 }
 
index f1e4dd3fe0256a1c183719fc154012c96fee0c3d..4fdd1b5f43483bb4d47ffe31850f22f312cb0146 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: interface.h,v 1.3 2001-07-31 19:50:14 srittau Exp $
+ * $Id: interface.h,v 1.4 2005-04-28 20:49:46 bfernhomberg Exp $
  * Copyright (c) 1990,1992 Regents of The University of Michigan.
  * All Rights Reserved. See COPYRIGHT.
  */
@@ -36,6 +36,8 @@ struct interface {
                                           do routing. */
 #define IFACE_DONTROUTE 0x200           /* don't route this interface */
 #define IFACE_ISROUTER  0x400           /* act as a router. */
+#define IFACE_ALLMULTI  0x800          /* set allmulti on this interface, linux only */
+#define IFACE_WASALLMULTI 0x1000       /* don't unset allmulti on this interface on shutdown, linux only */
 
 #define UNSTABLE       2
 #define STABLE         0
index 95b58925f62fc35a516315d7e070a8204f6d1c61..b53b2e1c328b03769794d278ef6ab40c560f7415 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: main.c,v 1.17 2002-10-05 13:20:13 didg Exp $
+ * $Id: main.c,v 1.18 2005-04-28 20:49:46 bfernhomberg Exp $
  *
  * Copyright (c) 1990,1993 Regents of The University of Michigan.
  * All Rights Reserved. See COPYRIGHT.
@@ -108,13 +108,13 @@ extern int        zip_packet();
 
 int            rtfd;
 
-struct atserv  atserv[] = {
+static struct atserv   atserv[] = {
     { "rtmp",          1,      rtmp_packet },          /* 0 */
     { "nbp",           2,      nbp_packet },           /* 1 */
     { "echo",          4,      aep_packet },           /* 2 */
     { "zip",           6,      zip_packet },           /* 3 */
 };
-int            atservNATSERV = elements( atserv );
+static int             atservNATSERV = elements( atserv );
 
 struct interface       *interfaces = NULL, *ciface = NULL;
 
@@ -156,6 +156,10 @@ static void atalkd_exit(const int i)
              ntohs(iface->i_addr.sat_addr.s_net), 
              iface->i_addr.sat_addr.s_node, strerror(errno));
     }
+#ifdef linux
+    if (!(iface->i_flags & IFACE_WASALLMULTI) && (iface->i_flags & IFACE_ALLMULTI))
+        ifsetallmulti(iface->i_name, 0);
+#endif /* linux */
   }
 #endif /* SOPCDOFADDR */
 
@@ -164,7 +168,7 @@ static void atalkd_exit(const int i)
 }
 
 
-static void as_timer(int sig)
+static void as_timer(int sig _U_)
 {
     struct sockaddr_at sat;
     struct ziphdr      zh;
@@ -179,6 +183,8 @@ static void as_timer(int sig)
     int                        sentzipq = 0;
     int                        n, cc;
 
+    ap=zap=rap=NULL;
+
     memset(&sat, 0, sizeof( struct sockaddr_at ));
     for ( iface = interfaces; iface; iface = iface->i_next ) {
        if ( iface->i_flags & IFACE_LOOPBACK ) {
@@ -689,7 +695,7 @@ consistency()
        for ( lr = zt->zt_rt; lr; lr = lr->l_next ) {
            rtmp = (struct rtmptab *)lr->l_data;
            if ( rtmp->rt_iprev == 0 && rtmp->rt_gate != 0 ) {
-               LOG(log_error, logtype_atalkd, "%.*s has %u-%u (unused)\n",
+               LOG(log_error, logtype_atalkd, "%.*s has %u-%u (unused)",
                        zt->zt_len, zt->zt_name, ntohs( rtmp->rt_firstnet ),
                        ntohs( rtmp->rt_lastnet ));
                atalkd_exit(1);
@@ -700,7 +706,7 @@ consistency()
                }
            }
            if ( lz == 0 ) {
-               LOG(log_error, logtype_atalkd, "no map from %u-%u to %.*s\n", 
+               LOG(log_error, logtype_atalkd, "no map from %u-%u to %.*s", 
                        ntohs( rtmp->rt_firstnet ),
                        ntohs( rtmp->rt_lastnet ),
                        zt->zt_len, zt->zt_name );
@@ -861,14 +867,15 @@ int main( ac, av )
     struct sockaddr_at sat;
     struct sigaction   sv;
     struct itimerval   it;
+    sigset_t            signal_set, old_set;
+    
     struct interface   *iface;
     int                        status;
     struct atport      *ap;
     fd_set             readfds;
-    int                        i, mask, c;
+    int                        i, c;
     SOCKLEN_T          fromlen;
     char               *prog;
-;
 
     while (( c = getopt( ac, av, "12qsdtf:P:v" )) != EOF ) {
        switch ( c ) {
@@ -1023,6 +1030,12 @@ int main( ac, av )
        exit( 1 );
     }
 
+    /*
+     * Set process name for logging
+     */
+
+    set_processname("atalkd");
+
     /* do this here so that we can use ifconfig */
 #ifdef __svr4__
     if ( plumb() < 0 ) {
@@ -1155,6 +1168,14 @@ int main( ac, av )
        atalkd_exit( 1 );
     }
 
+    sigemptyset( &signal_set );
+    sigaddset(&signal_set, SIGALRM);
+#if 0
+    /* don't block SIGTERM */
+    sigaddset(&signal_set, SIGTERM);
+#endif
+    sigaddset(&signal_set, SIGUSR1);
+
     for (;;) {
        readfds = fds;
        if ( select( nfds, &readfds, NULL, NULL, NULL) < 0 ) {
@@ -1177,7 +1198,7 @@ int main( ac, av )
                            LOG(log_error, logtype_atalkd, "recvfrom: %s", strerror(errno) );
                            continue;
                        }
-#ifdef DEBUG
+#ifdef DEBUG1
                        if ( debug ) {
                            printf( "packet from %u.%u on %s (%x) %d (%d)\n",
                                    ntohs( sat.sat_addr.s_net ),
@@ -1185,16 +1206,12 @@ int main( ac, av )
                                    iface->i_flags, ap->ap_port, ap->ap_fd );
                            bprint( Packet, c );
                        }
-#endif /* DEBUG */
-#ifdef __svr4__
-                       if ( sighold( SIGALRM ) || sighold( SIGUSR1 )) {
-                           LOG(log_error, logtype_atalkd, "sighold: %s", strerror(errno) );
+#endif 
+                       if (sigprocmask(SIG_BLOCK, &signal_set, &old_set) < 0) {
+                           LOG(log_error, logtype_atalkd, "sigprocmask: %s", strerror(errno) );
                            atalkd_exit( 1 );
                        }
-#else /* __svr4__ */
-                       mask = sigsetmask( sigmask( SIGALRM ) |
-                               sigmask( SIGUSR1 ));
-#endif /* __svr4__ */
+
                        if (( *ap->ap_packet )( ap, &sat, Packet, c ) < 0) {
                          LOG(log_error, logtype_atalkd, "ap->ap_packet: %s", strerror(errno));
                          atalkd_exit(1);
@@ -1202,15 +1219,12 @@ int main( ac, av )
 
 #ifdef DEBUG
                        consistency();
-#endif /* DEBUG */
-#ifdef __svr4__
-                       if ( sigrelse( SIGUSR1 ) || sigrelse( SIGALRM )) {
-                           LOG(log_error, logtype_atalkd, "sigrelse: %s", strerror(errno) );
+#endif 
+                       if (sigprocmask(SIG_SETMASK, &old_set, NULL) < 0) {
+                           LOG(log_error, logtype_atalkd, "sigprocmask old set: %s", strerror(errno) );
                            atalkd_exit( 1 );
                        }
-#else /* __svr4__ */
-                       sigsetmask( mask );
-#endif /* __svr4__ */
+
                    }
                }
            }
@@ -1340,7 +1354,8 @@ smaller net range.", iface->i_name, ntohs(first), ntohs(last), strerror(errno));
 
     /* open ports */
     i = 1; /* enable broadcasts */
-#ifdef __svr4__ 
+#if 0
+    /* useless message, no? */
     LOG(log_info, logtype_atalkd, "setsockopt incompatible w/ Solaris STREAMS module.");
 #endif /* __svr4__ */
     for ( ap = iface->i_ports; ap; ap = ap->ap_next ) {
@@ -1395,6 +1410,43 @@ smaller net range.", iface->i_name, ntohs(first), ntohs(last), strerror(errno));
     nfds++;
 }
 
+int ifsetallmulti ( iname, set )
+const char             *iname;
+int set;
+{
+    int sock;
+    struct ifreq ifr;
+
+    memset(&ifr, 0, sizeof(ifr));
+
+    if (( sock = socket( AF_APPLETALK, SOCK_DGRAM, 0 )) < 0 ) {
+        return( -1 );
+    }
+
+    /* get interface config */
+    strlcpy(ifr.ifr_name, iname, sizeof(ifr.ifr_name));
+    if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) {
+        close(sock);
+        return (-1);
+    }
+
+    /* should we set or unset IFF_ALLMULTI */
+    if (set)
+           ifr.ifr_flags |= IFF_ALLMULTI;
+    else
+           ifr.ifr_flags &= ~IFF_ALLMULTI;
+
+    /* set interface config */
+    strlcpy(ifr.ifr_name, iname, sizeof(ifr.ifr_name));
+    if (ioctl(sock, SIOCSIFFLAGS, &ifr) < 0) {
+        close(sock);   
+        return -1;
+    }
+
+    close(sock);
+    return (0);
+}
+
 int ifconfig( iname, cmd, sa )
     const char         *iname;
     unsigned long      cmd;
index 21852eb7ee0e720adeab67f81bf2ba4b0cd3f4cf..196a6415013807346116925c78eaced756068298 100644 (file)
@@ -1,11 +1,12 @@
 /*
- * $Id: main.h,v 1.3 2001-06-25 20:13:45 rufustfirefly Exp $
+ * $Id: main.h,v 1.4 2005-04-28 20:49:46 bfernhomberg Exp $
  */
 
 #ifndef ATALKD_MAIN_H
 #define ATALKD_MAIN_H
 
 #include <sys/cdefs.h>
+#include "config.h"
 
 int ifconfig __P(( const char *, unsigned long, struct sockaddr_at * ));
 void setaddr __P(( struct interface *, u_int8_t, u_int16_t,
@@ -13,4 +14,8 @@ void setaddr __P(( struct interface *, u_int8_t, u_int16_t,
 void bootaddr __P(( struct interface * ));
 void dumpconfig __P(( struct interface * ));
 
+#ifdef linux
+int ifsetallmulti __P(( const char *, int));
+#endif
+
 #endif /* ATALKD_MAIN_H */
index 3306c14c45bf5f3a59535a5b24f1fde4d0031bd8..a01521f73dc07f49f8a4b83bacbe01054208e575 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: nbp.c,v 1.10 2002-09-29 23:24:47 sibaz Exp $
+ * $Id: nbp.c,v 1.11 2005-04-28 20:49:46 bfernhomberg Exp $
  *
  * Copyright (c) 1990,1993 Regents of The University of Michigan.
  * All Rights Reserved. See COPYRIGHT.
@@ -79,7 +79,7 @@ int nbp_packet( ap, from, data, len )
     struct nbpnve      nn;
     struct sockaddr_at sat;
     struct nbptab      *ntab;
-    struct ziptab      *zt;
+    struct ziptab      *zt=NULL;
     struct interface   *iface;
     struct list                *l;
     struct rtmptab     *rtmp;
@@ -563,7 +563,7 @@ Can't find route's interface!" );
             * Another tuple won't fit. Send what we've already
             * got, and start the next packet.
             */
-           if ( data + SZ_NBPTUPLE + 3 + ntab->nt_nve.nn_objlen +
+           if ( n > 14 || data + SZ_NBPTUPLE + 3 + ntab->nt_nve.nn_objlen +
                    ntab->nt_nve.nn_typelen + ntab->nt_nve.nn_zonelen > end ) {
                nh.nh_op = NBPOP_LKUPREPLY;
                nh.nh_cnt = n;
index 9f363d5129b7e706280531c480c89d1c6152b6ca..215be5096c31e41f53f06c020ce13c41e37a38b8 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: route.c,v 1.6 2002-01-17 06:10:12 srittau Exp $
+ * $Id: route.c,v 1.7 2005-04-28 20:49:46 bfernhomberg Exp $
  *
  * Copyright (c) 1990,1996 Regents of The University of Michigan.
  * All Rights Reserved. See COPYRIGHT.
@@ -9,13 +9,15 @@
 #include "config.h"
 #endif /* HAVE_CONFIG_H */
 
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
 #include <string.h>
 #include <sys/param.h>
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <net/route.h>
 #include <sys/ioctl.h>
-
 #include <netatalk/at.h>
 
 #include "rtmp.h"
index 7e384e5a8c60b497c9c0ada5c7fd2c15a472db30..acfa4aac487a9386760a0671603532596dc8499d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: rtmp.c,v 1.12 2002-09-29 23:24:47 sibaz Exp $
+ * $Id: rtmp.c,v 1.13 2005-04-28 20:49:46 bfernhomberg Exp $
  *
  * Copyright (c) 1990,1993 Regents of The University of Michigan.
  * All Rights Reserved. See COPYRIGHT.
@@ -800,7 +800,7 @@ int rtmp_packet( ap, from, data, len )
                    from->sat_addr.s_node );
 #endif /* DEBUG */
        } else {
-           LOG(log_info, logtype_atalkd, "rtmp_packet unknown request from %u.%u\n",
+           LOG(log_info, logtype_atalkd, "rtmp_packet unknown request from %u.%u",
                    ntohs( from->sat_addr.s_net ), from->sat_addr.s_node );
        }
        break;
index a547018440d6cd9b2915c014b537f21b6db3a4d8..5efd1c58dd14bc2127b37f4a4297aa511a1d175e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: zip.c,v 1.11 2002-09-29 23:24:47 sibaz Exp $
+ * $Id: zip.c,v 1.12 2005-04-28 20:49:47 bfernhomberg Exp $
  *
  * Copyright (c) 1990,1993 Regents of The University of Michigan.
  * All Rights Reserved. See COPYRIGHT.
@@ -98,7 +98,7 @@ int zip_packet( ap, from, data, len )
     struct atphdr      ah;
     struct interface   *iface;
     struct gate                *gate;
-    struct rtmptab     *rtmp;
+    struct rtmptab     *rtmp = NULL;
     struct list                *l;
     struct ziptab      *zt;
     u_short            firstnet, lastnet, index, nz;
@@ -753,7 +753,7 @@ int zip_packet( ap, from, data, len )
            break;
 
        default :
-           LOG(log_info, logtype_atalkd, "zip_packet bad zip op from %u.%u\n",
+           LOG(log_info, logtype_atalkd, "zip_packet bad zip op from %u.%u",
                    ntohs( from->sat_addr.s_net ), from->sat_addr.s_node );
        }
        break;
@@ -890,7 +890,7 @@ int zip_packet( ap, from, data, len )
        break;
 
     default :
-       LOG(log_info, logtype_atalkd, "zip_packet bad ddp type from %u.%u\n",
+       LOG(log_info, logtype_atalkd, "zip_packet bad ddp type from %u.%u",
                ntohs( from->sat_addr.s_net ), from->sat_addr.s_node );
        return 1;
     }
diff --git a/etc/cnid_dbd/.cvsignore b/etc/cnid_dbd/.cvsignore
new file mode 100644 (file)
index 0000000..33dffa1
--- /dev/null
@@ -0,0 +1,6 @@
+Makefile
+Makefile.in
+cnid_metad
+cnid_dbd
+.deps
+.libs
diff --git a/etc/cnid_dbd/Makefile.am b/etc/cnid_dbd/Makefile.am
new file mode 100644 (file)
index 0000000..7ea9d07
--- /dev/null
@@ -0,0 +1,26 @@
+# Makefile.am for etc/cnid_dbd/
+
+if BUILD_DBD_DAEMON
+sbin_PROGRAMS = cnid_dbd cnid_metad
+else
+sbin_PROGRAMS =
+endif
+
+cnid_dbd_SOURCES = dbif.c pack.c comm.c db_param.c main.c \
+                   dbd_add.c dbd_get.c dbd_resolve.c dbd_lookup.c \
+                   dbd_update.c dbd_delete.c dbd_getstamp.c \
+                   dbd_rebuild_add.c dbd_dbcheck.c
+
+cnid_dbd_LDADD = $(top_builddir)/libatalk/libatalk.la @BDB_LIBS@
+
+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
+
+
+CFLAGS = @CFLAGS@ @BDB_CFLAGS@ \
+         -D_PATH_CNID_DBD=\"$(sbindir)/cnid_dbd\"
diff --git a/etc/cnid_dbd/README b/etc/cnid_dbd/README
new file mode 100644 (file)
index 0000000..f34d4a8
--- /dev/null
@@ -0,0 +1,197 @@
+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 as
+long as necessary (see the idle_timeout option below) 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
+idle_timeout       600
+
+
+"backlog" specifies the maximum number of connection requests that can
+be pending on the unix domain socket cnid_dbd uses. listen(2) has more
+information about this value on your system.
+
+"cachesize" determines the size of the Berkeley DB cache in
+kilobytes. Each cnid_dbd process grabs that much memory on top of its
+normal memory footprint. It can be used to tune database
+performance. The db_stat utility with the "-m" option that comes with
+Berkely DB can help you determine wether you need to change this
+value. The default is pretty conservative so that a large percentage
+of requests should be satisfied from the cache directly. If memory is
+not a bottleneck on your system you might want to leave it at that
+value. The Berkeley DB Tutorial and Reference Guide has a section
+"Selecting a cache size" that gives more detailed information.
+
+"nosync" is only valid if transactional support is enabled. If it is
+set to 1, transactional changes to the database are not synchronously
+written to disk when the transaction completes. This will increase
+performance considerably at the risk of recent changes getting
+lost in case of a crash. The database will still be consistent,
+though. See "Transaction throughput" in the Berkeley DB Tutorial for
+more information.
+
+"flush_frequency" and "flush_interval" control how often changes to
+the database are written to the underlying database files if no
+transactions are used or how often the transaction system is
+checkpointed for transactions. Both of these operations are
+performed if either i) more than flush_frequency requests have been
+received or ii) more than flush_interval seconds have elapsed since
+the last save/checkpoint. If you use transactions with nosync set to
+zero these parameters only influence how long recovery takes after
+a crash, there should never be any lost data. If nosync is 1, changes
+might be lost, but only since the last checkpoint. Be careful to check
+your harddisk configuration for on disk cache settings. Many IDE disks
+just cache writes as the default behaviour, so even flushing database
+files to disk will not have the desired effect.
+
+"usock_file" gives the pathname of the unix domain socket file that
+that instance of cnid_dbd will use for receiving requests. You might
+have to use another value if the total length of the default pathname
+exceeds the limits for unix domain socket files on your system,
+usually this is something like 100 bytes.
+
+"fd_table_size" is the maximum number of connections (filedescriptors)
+that can be open for afpd client processes in cnid_dbd. If this number
+is exceeded, one of the existing connections is closed and reused. The
+affected afpd process will transparently reconnect later, which causes
+slight overhead. On the other hand, setting this parameter too high
+could affect performance in cnid_dbd since all descriptors have to be
+checked in a select() system call, or worse, you might exceed the per
+process limit of open file descriptors on your system. It is safe to
+set the value to 1 on volumes where only one afpd client process
+is expected to run, e.g. home directories.
+
+"idle_timeout" is the number of seconds of inactivity before an idle
+cnid_dbd exits. Set this to 0 to disable the timeout.
+
+Current shortcomings:
+
+- The implementation for cnid_dbd doubles code from libatalk/cnid,
+making it more difficult to keep changes to the library interface and
+the semantics of database requests in sync.  If cnid_dbd takes over
+the world, this problem will eventually disappear, otherwise it should
+be possible to merge things again, if transactional support is
+eliminated from libatalk/cnid. I do not think it can work relieably in
+the current form anyway.
+
+- It would be more flexible to have transaction support as a run time
+option as well.
+
+- mmap for IPC would be nice as an alternative.
+
+- The parameter file parsing of db_param is very simpleminded. It is
+easy to cause buffer overruns and the like.
+Also, there is no support for blanks (or weird characters) in
+filenames for the usock_file parameter.
+
+- There is no protection against a malicious user connecting to the
+cnid_dbd socket and changing the database. I will adress this problem
+soon.
+
+Please feel free to grep the source in etc/cnid_dbd and the file
+libatalk/cnid/dbd/cnid_dbd.c for the string TODO, which indicates
+comments that adress other, less important points.
+
+
+Joerg Lenneis, lenneis@wu-wien.ac.at
diff --git a/etc/cnid_dbd/cnid_metad.c b/etc/cnid_dbd/cnid_metad.c
new file mode 100644 (file)
index 0000000..4702046
--- /dev/null
@@ -0,0 +1,545 @@
+/*
+ * $Id: cnid_metad.c,v 1.2 2005-04-28 20:49:47 bfernhomberg Exp $
+ *
+ * Copyright (C) Joerg Lenneis 2003
+ * All Rights Reserved.  See COPYING.
+ *
+ */
+
+/* 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
+#define __USE_GNU
+#include <unistd.h>
+#undef __USE_GNU
+#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
+#ifdef HAVE_SYS_UIO_H
+#include <sys/uio.h>
+#endif
+#include <sys/un.h>
+#define _XPG4_2 1
+#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>
+
+/* FIXME */
+#ifdef linux
+#ifndef USE_SETRESUID
+#define USE_SETRESUID 1
+#define SWITCH_TO_GID(gid)  ((setresgid(gid,gid,gid) < 0 || setgid(gid) < 0) ? -1 : 0)
+#define SWITCH_TO_UID(uid)  ((setresuid(uid,uid,uid) < 0 || setuid(uid) < 0) ? -1 : 0)
+#endif
+#else
+#ifndef USE_SETEUID
+#define USE_SETEUID 1
+#define SWITCH_TO_GID(gid)  ((setegid(gid) < 0 || setgid(gid) < 0) ? -1 : 0)
+#define SWITCH_TO_UID(uid)  ((setuid(uid) < 0 || seteuid(uid) < 0 || setuid(uid) < 0) ? -1 : 0)
+#endif
+#endif
+
+#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 128
+
+#define MAXSPAWN   3                   /* Max times respawned in.. */
+
+#define DEFAULTHOST  "localhost"
+#define DEFAULTPORT  4700
+#define TESTTIME   22                  /* this much seconds apfd client tries to
+                                        * to reconnect every 5 secondes, catch it
+                                        */
+
+struct server {
+    char  *name;
+    pid_t pid;
+    time_t tm;                    /* When respawned last */
+    int count;                    /* Times respawned in the last TESTTIME secondes */
+    int toofast; 
+    int control_fd;               /* file descriptor to child cnid_dbd process */
+};
+
+static struct server srv[MAXSRV +1];
+
+static struct server *test_usockfn(char *dir, char *fn _U_)
+{
+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;
+   size_t size;
+   int er=0;
+
+   size = CMSG_SPACE(sizeof fd);
+   buf = malloc(size);
+   if (!buf) {
+       LOG(log_error, logtype_cnid, "error in sendmsg: %s", strerror(errno));
+       return -1;
+   }
+
+   memset(&msgh,0,sizeof (msgh));
+   memset(buf,0, size);
+
+   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 = size;
+
+   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));
+       free(buf);
+       return -1;
+   }
+   free(buf);
+   return 0;
+}
+
+/* -------------------- */
+static int maybe_start_dbd(char *dbdpn, char *dbdir, char *usockfn)
+{
+    pid_t pid;
+    struct server *up;
+    int sv[2];
+    int i;
+    time_t t;
+    char buf1[8];
+    char buf2[8];
+
+    up = test_usockfn(dbdir, usockfn);
+    if (up && up->pid) {
+       /* we already have a process, send our fd */
+       if (send_cred(up->control_fd, 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;
+                up->toofast = 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) {
+            if (up->toofast) {
+                /* silently exit */
+                return -1;
+            }
+            up->count++;
+        } else {
+            up->count = 0;
+           up->toofast = 0;
+            up->tm = t;
+        }
+        if (up->count > MAXSPAWN) {
+           up->toofast = 1;
+            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, sv) < 0) {
+       LOG(log_error, logtype_cnid, "error in socketpair: %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) {
+        int ret;
+       /*
+        *  Child. Close descriptors and start the daemon. If it fails
+        *  just log it. The client process will fail connecting
+        *  afterwards anyway.
+        */
+
+       close(srvfd);
+       close(sv[0]);
+       
+       for (i = 1; i <= MAXSRV; i++) {
+            if (srv[i].pid && up != &srv[i]) {
+               close(srv[i].control_fd);
+            }
+        }
+
+       sprintf(buf1, "%i", sv[1]);
+       sprintf(buf2, "%i", rqstfd);
+       
+       if (up->count == MAXSPAWN) {
+           /* there's a pb with the db inform child 
+            * it will run recover, delete the db whatever
+           */
+           LOG(log_error, logtype_cnid, "try with -d %s", up->name);
+           ret = execlp(dbdpn, dbdpn, "-d", dbdir, buf1, buf2, NULL);
+       }
+       else {
+           ret = execlp(dbdpn, dbdpn, dbdir, buf1, buf2, NULL);
+       }
+       if (ret < 0) {
+           LOG(log_error, logtype_cnid, "Fatal error in exec: %s", strerror(errno));
+           exit(0);
+       }
+    }
+    /*
+     *  Parent.
+     */
+    up->pid = pid;
+    close(sv[1]);
+    up->control_fd = sv[0];
+    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 = _PATH_CNID_DBD;
+    char  *host = DEFAULTHOST;
+    u_int16_t   port = DEFAULTPORT;
+    struct db_param *dbp;
+    int    i;
+    int    cc;
+    uid_t  uid = 0;
+    gid_t  gid = 0;
+    int    err = 0;
+    int    debug = 0;
+    int    ret;
+
+    set_processname("cnid_metad");
+    
+    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) {
+        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 (SWITCH_TO_GID(gid) < 0) {
+                LOG(log_info, logtype_cnid, "unable to switch to group %d", gid);
+                exit(1);
+            }
+        }
+        if (uid) {
+            if (SWITCH_TO_UID(uid) < 0) {
+                LOG(log_info, logtype_cnid, "unable to switch to user %d", uid);
+                exit(1);
+            }
+        }
+    }
+
+    signal(SIGPIPE, SIG_IGN);
+
+    while (1) {
+        rqstfd = usockfd_check(srvfd, 10000000);
+       /* 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].control_fd);
+                   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 <= 0)
+            continue;
+        /* TODO: Check out read errors, broken pipe etc. in libatalk. Is
+           SIGIPE ignored there? Answer: Ignored for dsi, but not for asp ... */
+        ret = read(rqstfd, &len, sizeof(int));
+        if (!ret) {
+            /* already close */
+            goto loop_end;
+        }
+        else if (ret < 0) {
+            LOG(log_error, logtype_cnid, "error read: %s", strerror(errno));
+            goto loop_end;
+        }
+        else if (ret != sizeof(int)) {
+            LOG(log_error, logtype_cnid, "short read: got %d", ret);
+            goto loop_end;
+        }
+        /*
+         *  checks for buffer overruns. The client libatalk side does it too 
+         *  before handing the dir path over but who trusts clients?
+         */
+        if (!len || len +DBHOMELEN +2 > MAXPATHLEN) {
+            LOG(log_error, logtype_cnid, "wrong len parameter: %d", len);
+            goto loop_end;
+        }
+        if (read(rqstfd, dbdir, len) != len) {
+            LOG(log_error, logtype_cnid, "error/short read (dir): %s", strerror(errno));
+            goto loop_end;
+        }
+        dbdir[len] = '\0';
+        
+        if (set_dbdir(dbdir, len) < 0) {
+            goto loop_end;
+        }
+        
+        if ((dbp = db_param_read(dbdir)) == NULL) {
+            LOG(log_error, logtype_cnid, "Error reading config file");
+            goto loop_end;
+        }
+       maybe_start_dbd(dbdpn, dbdir, dbp->usock_file);
+
+    loop_end:
+        close(rqstfd);
+    }
+}
diff --git a/etc/cnid_dbd/comm.c b/etc/cnid_dbd/comm.c
new file mode 100644 (file)
index 0000000..e909d63
--- /dev/null
@@ -0,0 +1,329 @@
+/*
+ * $Id: comm.c,v 1.2 2005-04-28 20:49:47 bfernhomberg Exp $
+ *
+ * Copyright (C) Joerg Lenneis 2003
+ * All Rights Reserved.  See COPYING.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif 
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif 
+
+#include <sys/param.h>
+#define _XPG4_2 1
+#include <sys/socket.h>
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif 
+
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif 
+
+#ifdef HAVE_SYS_UIO_H
+#include <sys/uio.h>
+#endif 
+
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+
+
+#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"
+
+/* Length of the space taken up by a padded control message of length len */
+#ifndef CMSG_SPACE
+#define        CMSG_SPACE(len) (__CMSG_ALIGN(sizeof(struct cmsghdr)) + __CMSG_ALIGN(len))
+#endif
+
+
+struct connection {
+    time_t tm;                    /* When respawned last */
+    int    fd;
+};
+
+static int   control_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 == control_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 new descriptor via
+ *  control_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 = control_fd;
+    time_t t;
+    
+    FD_ZERO(&readfds);
+    FD_SET(control_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(control_fd, &readfds)) {
+       int    l = 0;
+       
+        fd = recv_cred(control_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 ctrlfd, int clntfd)
+{
+    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 */
+    control_fd = ctrlfd;
+#if 0
+    int b = 1;
+    /* this one dump core in recvmsg, great */
+    if ( setsockopt(control_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 client fd */
+    fd_table[fds_in_use].fd = clntfd;
+    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;
+}
+
+/* ------------ */
+#define USE_WRITEV
+int comm_snd(struct cnid_dbd_rply *rply)
+{
+#ifdef USE_WRITEV 
+  struct iovec iov[2];
+  size_t towrite;
+#endif
+
+    if (!rply->namelen) {
+        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;
+        }
+        return 1;
+    }
+#ifdef USE_WRITEV 
+
+    iov[0].iov_base = rply;
+    iov[0].iov_len = sizeof(struct cnid_dbd_rply);
+    iov[1].iov_base = rply->name;
+    iov[1].iov_len = rply->namelen;
+    towrite = sizeof(struct cnid_dbd_rply) +rply->namelen;
+
+    if (writev(cur_fd, iov, 2) != towrite) {
+        LOG(log_error, logtype_cnid, "error writing message : %s", strerror(errno));
+        invalidate_fd(cur_fd);
+        return 0;
+    }
+#else
+    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 (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;
+    }
+#endif    
+    return 1;
+}
+
+
diff --git a/etc/cnid_dbd/comm.h b/etc/cnid_dbd/comm.h
new file mode 100644 (file)
index 0000000..beda770
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * $Id: comm.h,v 1.2 2005-04-28 20:49:47 bfernhomberg Exp $
+ *
+ * Copyright (C) Joerg Lenneis 2003
+ * All Rights Reserved.  See COPYING.
+ */
+
+#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 *, int, int));
+extern int      comm_rcv  __P((struct cnid_dbd_rqst *));
+extern int      comm_snd  __P((struct cnid_dbd_rply *));
+extern int      comm_nbe  __P((void));
+
+#endif /* CNID_DBD_COMM_H */
+
diff --git a/etc/cnid_dbd/db_param.c b/etc/cnid_dbd/db_param.c
new file mode 100644 (file)
index 0000000..3020c80
--- /dev/null
@@ -0,0 +1,187 @@
+/*
+ * $Id: db_param.c,v 1.2 2005-04-28 20:49:47 bfernhomberg Exp $
+ *
+ * Copyright (C) Joerg Lenneis 2003
+ * All Rights Reserved.  See COPYING.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#ifdef HAVE_STRINGS_H
+#include <strings.h>
+#endif
+#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_LOGFILE_AUTOREMOVE 0   
+#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
+#define DEFAULT_CHECK              0
+
+static struct db_param params;
+static int parse_err;
+
+static size_t usock_maxlen()
+{
+    struct sockaddr_un addr;
+
+    return sizeof(addr.sun_path) - 1;
+}
+
+static int make_pathname(char *path, char *dir, char *fn, size_t 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->check               = DEFAULT_CHECK;
+    dbp->logfile_autoremove  = DEFAULT_LOGFILE_AUTOREMOVE;
+    dbp->cachesize           = DEFAULT_CACHESIZE;
+    dbp->nosync              = DEFAULT_NOSYNC;
+    dbp->flush_frequency     = DEFAULT_FLUSH_FREQUENCY;
+    dbp->flush_interval      = DEFAULT_FLUSH_INTERVAL;
+    if (make_pathname(dbp->usock_file, dir, DEFAULT_USOCK_FILE, usock_maxlen()) < 0) {
+        /* Not an error yet, it might be set in the config file */
+        dbp->usock_file[0] = '\0';
+    }
+    dbp->fd_table_size       = DEFAULT_FD_TABLE_SIZE;
+    dbp->idle_timeout        = DEFAULT_IDLE_TIMEOUT;
+    return;
+}
+
+static int parse_int(char *val)
+{
+    char *tmp;
+    int   result = 0;
+
+    result = strtol(val, &tmp, 10);
+    if (tmp[0] != '\0') {
+        LOG(log_error, logtype_cnid, "invalid characters in token %s", val);
+        parse_err++;
+    }
+    return result;
+}
+
+
+/* TODO: This configuration file reading routine is neither very robust (%s
+   buffer overflow) nor elegant, we need to add support for whitespace in
+   filenames as well. */
+
+struct db_param *db_param_read(char *dir)
+{
+    FILE *fp;
+    static char key[MAXKEYLEN + 1];
+    static char val[MAXPATHLEN + 1];
+    static char pfn[MAXPATHLEN + 1];
+    int    items;
+    
+    default_params(&params, dir);
+    
+    if (make_pathname(pfn, dir, DB_PARAM_FN, MAXPATHLEN) < 0) {
+        LOG(log_error, logtype_cnid, "Parameter filename too long");
+        return NULL;
+    }
+
+    if ((fp = fopen(pfn, "r")) == NULL) {
+        if (errno == ENOENT) {
+            if (strlen(params.usock_file) == 0) {
+                LOG(log_error, logtype_cnid, "default usock filename too long");
+                return NULL;
+            } else {
+                return &params;
+            }
+        } else {
+            LOG(log_error, logtype_cnid, "error opening %s: %s", pfn, strerror(errno));
+            return NULL;
+        }
+    }
+    parse_err = 0;
+
+    while ((items = fscanf(fp, " %s %s", key, val)) != EOF) {
+        if (items != 2) {
+            LOG(log_error, logtype_cnid, "error parsing config file");
+            parse_err++;
+            break;
+        }
+        
+        if (! strcmp(key, "logfile_autoremove")) 
+            params.logfile_autoremove = 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, "check"))
+            params.check = parse_int(val);
+        else if (! strcmp(key, "flush_frequency"))
+            params.flush_frequency = parse_int(val);
+        else if (! strcmp(key, "flush_interval"))
+            params.flush_interval = parse_int(val);
+        else if (! strcmp(key, "usock_file")) {
+            if (make_pathname(params.usock_file, dir, val, usock_maxlen()) < 0) {
+                LOG(log_error, logtype_cnid, "usock filename %s too long", val);
+                parse_err++;
+            }
+        } else if (! strcmp(key, "fd_table_size"))
+            params.fd_table_size = parse_int(val);
+       else if (! strcmp(key, "idle_timeout"))
+            params.idle_timeout = parse_int(val);
+       else {
+            LOG(log_error, logtype_cnid, "error parsing %s -> %s in config file", key, val);
+            parse_err++;
+        }
+        if(parse_err)
+            break;
+    }
+    
+    if (strlen(params.usock_file) == 0) {
+        LOG(log_error, logtype_cnid, "default usock filename too long");
+        parse_err++;
+    }
+
+    fclose(fp);
+    if (! parse_err)
+        return &params;
+    else
+        return NULL;
+}
+
+
+
diff --git a/etc/cnid_dbd/db_param.h b/etc/cnid_dbd/db_param.h
new file mode 100644 (file)
index 0000000..515ed9a
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * $Id: db_param.h,v 1.2 2005-04-28 20:49:47 bfernhomberg Exp $
+ *
+ * Copyright (C) Joerg Lenneis 2003
+ * All Rights Reserved.  See COPYING.
+ */
+
+#ifndef CNID_DBD_DB_PARAM_H
+#define CNID_DBD_DB_PARAM_H 1
+
+#include <sys/param.h>
+#include <sys/cdefs.h>
+
+
+struct db_param {
+    int check;
+    int logfile_autoremove;
+    int cachesize;
+    int nosync;
+    int flush_frequency;
+    int flush_interval;
+    char usock_file[MAXPATHLEN + 1];    
+    int fd_table_size;
+    int idle_timeout;
+};
+
+extern struct db_param *      db_param_read  __P((char *));
+
+
+#endif /* CNID_DBD_DB_PARAM_H */
+
diff --git a/etc/cnid_dbd/dbd.h b/etc/cnid_dbd/dbd.h
new file mode 100644 (file)
index 0000000..eb944d5
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * $Id: dbd.h,v 1.2 2005-04-28 20:49:47 bfernhomberg Exp $
+ *
+ * Copyright (C) Joerg Lenneis 2003
+ * All Rights Reserved.  See COPYING.
+ */
+
+#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 *));
+extern int      dbd_getstamp  __P((struct cnid_dbd_rqst *, struct cnid_dbd_rply *));
+extern int      dbd_rebuild_add __P((struct cnid_dbd_rqst *, struct cnid_dbd_rply *));
+extern int      dbd_check  __P((char *));
+
+
+#endif /* CNID_DBD_DBD_H */
diff --git a/etc/cnid_dbd/dbd_add.c b/etc/cnid_dbd/dbd_add.c
new file mode 100644 (file)
index 0000000..d2e8477
--- /dev/null
@@ -0,0 +1,206 @@
+/*
+ * $Id: dbd_add.c,v 1.2 2005-04-28 20:49:47 bfernhomberg Exp $
+ *
+ * Copyright (C) Joerg Lenneis 2003
+ * All Rights Reserved.  See COPYING.
+ */
+
+#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>
+#ifdef HAVE_DB4_DB_H
+#include <db4/db.h>
+#else
+#include <db.h>
+#endif
+
+#include "dbif.h"
+#include "pack.h"
+#include "dbd.h"
+
+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:
+           /* FIXME: Should that not be logged for case 1:? */
+            LOG(log_error, logtype_cnid, "add_cnid: duplicate %x %s", rply->cnid
+             , (char *)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;
+    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: dbd_lookup success, cnid %u", 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: Added dev/ino %s did %u name %s cnid %u",
+       stringify_devino(rqst->dev, rqst->ino),
+       ntohl(rqst->did), rqst->name, ntohl(rply->cnid));
+#endif
+    rply->result = CNID_DBD_RES_OK;
+    return 1;
+}
diff --git a/etc/cnid_dbd/dbd_dbcheck.c b/etc/cnid_dbd/dbd_dbcheck.c
new file mode 100644 (file)
index 0000000..4a36dcb
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * $Id: dbd_dbcheck.c,v 1.2 2005-04-28 20:49:48 bfernhomberg Exp $
+ *
+ * Copyright (C) Joerg Lenneis 2003
+ * All Rights Reserved.  See COPYING.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/param.h>
+#include <errno.h>
+#include <netatalk/endian.h>
+#include <atalk/logger.h>
+#include <atalk/cnid_dbd_private.h>
+
+#include "pack.h"
+#include "dbif.h"
+#include "dbd.h"
+
+#ifndef CNID_BACKEND_DBD_TXN
+int dbd_check(char *dbdir)
+{
+    u_int32_t c_didname = 0, c_devino = 0, c_cnid = 0;
+#if 0
+    char dbdir[MAXPATHLEN];
+
+    if (NULL == getcwd(dbdir, sizeof(dbdir)) )
+        return -1;
+#endif
+
+    LOG(log_debug, logtype_cnid, "CNID database at `%s' is being checked (quick)", dbdir);
+
+    if (dbif_count(DBIF_IDX_CNID, &c_cnid)) 
+        return -1;
+
+    if (dbif_count(DBIF_IDX_DEVINO, &c_devino))
+        return -1;
+
+    /* bailout after the first error */
+    if ( c_cnid != c_devino) {
+        LOG(log_error, logtype_cnid, "CNID database at `%s' corrupted (%u/%u)", dbdir, c_cnid, c_devino);
+        return 1;
+    }
+
+    if (dbif_count(DBIF_IDX_DIDNAME, &c_didname)) 
+        return -1;
+    
+    if ( c_cnid != c_didname) {
+        LOG(log_error, logtype_cnid, "CNID database at `%s' corrupted (%u/%u)", dbdir, c_cnid, c_didname);
+        return 1;
+    }
+
+    LOG(log_debug, logtype_cnid, "CNID database at `%s' seems ok, %u entries.", dbdir, c_cnid);
+    return 0;  
+}
+
+#endif
+
diff --git a/etc/cnid_dbd/dbd_delete.c b/etc/cnid_dbd/dbd_delete.c
new file mode 100644 (file)
index 0000000..d54d268
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * $Id: dbd_delete.c,v 1.2 2005-04-28 20:49:48 bfernhomberg Exp $
+ *
+ * Copyright (C) Joerg Lenneis 2003
+ * All Rights Reserved.  See COPYING.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include <string.h>
+#include <errno.h>
+#include <netatalk/endian.h>
+#include <atalk/logger.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;
+    }
+
+    if (rc) {
+#ifdef DEBUG
+        LOG(log_info, logtype_cnid, "cnid_delete: CNID %u deleted", ntohl(rqst->cnid));
+#endif
+        rply->result = CNID_DBD_RES_OK;
+    } else {
+#ifdef DEBUG
+        LOG(log_info, logtype_cnid, "cnid_delete: CNID %u not in database", ntohl(rqst->cnid));
+#endif
+        rply->result = CNID_DBD_RES_NOTFOUND;
+    }
+    return 1;
+}
diff --git a/etc/cnid_dbd/dbd_get.c b/etc/cnid_dbd/dbd_get.c
new file mode 100644 (file)
index 0000000..c71ab71
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * $Id: dbd_get.c,v 1.2 2005-04-28 20:49:48 bfernhomberg Exp $
+ *
+ * Copyright (C) Joerg Lenneis 2003
+ * All Rights Reserved.  See COPYING.
+ */
+
+#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 <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) {
+#ifdef DEBUG
+       LOG(log_info, logtype_cnid, "cnid_get: CNID not found for did %u name %s",
+           ntohl(rqst->did), rqst->name);
+#endif
+        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 did %u name %s as %u",
+        ntohl(rqst->did), rqst->name, ntohl(rply->cnid));
+#endif
+    rply->result = CNID_DBD_RES_OK;
+    return 1;
+}
diff --git a/etc/cnid_dbd/dbd_getstamp.c b/etc/cnid_dbd/dbd_getstamp.c
new file mode 100644 (file)
index 0000000..804878b
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * $Id: dbd_getstamp.c,v 1.2 2005-04-28 20:49:48 bfernhomberg Exp $
+ *
+ * Copyright (C) Joerg Lenneis 2003
+ * All Rights Reserved.  See COPYING.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include <string.h>
+#include <atalk/logger.h>
+#include <errno.h>
+#include <netatalk/endian.h>
+#include <atalk/cnid_dbd_private.h>
+
+#include "dbif.h"
+#include "dbd.h"
+#include "pack.h"
+
+/* Return the unique stamp associated with this database */
+
+int dbd_getstamp(struct cnid_dbd_rqst *rqst _U_, 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 = ROOTINFO_KEY;
+    key.size = ROOTINFO_KEYLEN;
+
+    if ((rc = dbif_get(DBIF_IDX_CNID, &key, &data, 0)) < 0) {
+        LOG(log_error, logtype_cnid, "dbd_getstamp: Error getting rootinfo record");
+        rply->result = CNID_DBD_RES_ERR_DB;
+        return -1;
+    }
+     
+    if (rc == 0) {
+       LOG(log_error, logtype_cnid, "dbd_getstamp: No rootinfo record found");
+        rply->result = CNID_DBD_RES_NOTFOUND;
+        return 1;
+    }
+    
+    rply->namelen = CNID_DEV_LEN;
+    rply->name = (char *)data.data + CNID_DEV_OFS;
+    
+#ifdef DEBUG
+    LOG(log_info, logtype_cnid, "cnid_getstamp: Returning stamp");
+#endif
+    rply->result = CNID_DBD_RES_OK;
+    return 1;
+}
diff --git a/etc/cnid_dbd/dbd_lookup.c b/etc/cnid_dbd/dbd_lookup.c
new file mode 100644 (file)
index 0000000..7ae9c1f
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+ * $Id: dbd_lookup.c,v 1.2 2005-04-28 20:49:48 bfernhomberg Exp $
+ *
+ * Copyright (C) Joerg Lenneis 2003
+ * All Rights Reserved.  See COPYING.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/param.h>
+#include <errno.h>
+#include <netatalk/endian.h>
+#include <atalk/logger.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;
+    char dev[CNID_DEV_LEN];
+    char ino[CNID_INO_LEN];
+    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, CNID_DEV_LEN);
+    /* FIXME: ino is not needed later on, remove? */
+    memcpy(ino, buf + CNID_INO_OFS, CNID_INO_LEN);
+
+    /* 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, (char *)devdata.data +CNID_TYPE_OFS, sizeof(type_devino));
+        type_devino = ntohl(type_devino);
+    }
+    
+    /* FIXME: This second call to pack_cnid_data() is redundant, any reason it is here? */
+    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, (char *)diddata.data +CNID_TYPE_OFS, sizeof(type_didname));
+        type_didname = ntohl(type_didname);
+    }
+    
+    if (!devino && !didname) {  
+        /* not found */
+#ifdef DEBUG
+       LOG(log_info, logtype_cnid, "cnid_lookup: dev/ino %s did %u name %s neither in devino nor didname", 
+           stringify_devino(rqst->dev, rqst->ino), ntohl(rqst->did), rqst->name);
+#endif
+        rply->result = CNID_DBD_RES_NOTFOUND;
+        return 1;
+    }
+
+    if (devino && didname && id_devino == id_didname && type_devino == rqst->type) {
+        /* the same */
+#ifdef DEBUG
+       LOG(log_info, logtype_cnid, "cnid_lookup: Looked up dev/ino %s did %u name %s as %u", 
+           stringify_devino(rqst->dev, rqst->ino), ntohl(rqst->did), rqst->name, ntohl(id_didname));
+#endif
+        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, CNID_DEV_LEN) ||
+                   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 dev/ino %s did %u name %s as %u (needed update)", 
+       stringify_devino(rqst->dev, rqst->ino), ntohl(rqst->did), rqst->name, ntohl(rply->cnid));
+#endif
+    return rc;
+}
diff --git a/etc/cnid_dbd/dbd_rebuild_add.c b/etc/cnid_dbd/dbd_rebuild_add.c
new file mode 100644 (file)
index 0000000..3b2a26e
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * $Id: dbd_rebuild_add.c,v 1.2 2005-04-28 20:49:48 bfernhomberg Exp $
+ *
+ * Copyright (C) Joerg Lenneis 2005
+ * All Rights Reserved.  See COPYING.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include <stdio.h>
+#include <string.h>
+#include <atalk/logger.h>
+#include <netatalk/endian.h>
+#include <atalk/cnid_dbd_private.h>
+
+
+#include "pack.h"
+#include "dbif.h"
+#include "dbd.h"
+
+
+/* rebuild_add: Enter all fields (including the CNID) into the database and
+   update the current cnid, for emergency repairs. */
+
+int dbd_rebuild_add(struct cnid_dbd_rqst *rqst, struct cnid_dbd_rply *rply)
+{
+    DBT key, data;
+    cnid_t cur, tmp, id;
+    
+    memset(&key, 0, sizeof(key));
+    memset(&data, 0, sizeof(data));
+
+    rply->namelen = 0;
+
+    key.data = &rqst->cnid;
+    key.size = sizeof(cnid_t);
+
+    data.data = pack_cnid_data(rqst);
+    data.size = CNID_HEADER_LEN + rqst->namelen + 1;
+    memcpy(data.data, &rqst->cnid, sizeof(cnid_t));
+
+    /* FIXME: In cnid_cdb.c Bjoern does a lookup here and returns the CNID found if sucessful. Why? */
+
+    if (dbif_put(DBIF_IDX_CNID, &key, &data, 0) < 0) {
+       rply->result = CNID_DBD_RES_ERR_DB;
+       return -1;
+    }
+
+    key.data = ROOTINFO_KEY;   
+    key.size = ROOTINFO_KEYLEN;
+    
+    if (dbif_get(DBIF_IDX_CNID, &key, &data, 0) <= 0) {
+       /* FIXME: If we cannot find ROOTINFO_KEY, should this be considered
+           fatal or should we just return 0 and roll back? */
+       rply->result = CNID_DBD_RES_ERR_DB;
+       return -1;
+    }
+    
+    memcpy(&tmp, (char *) data.data + CNID_TYPE_OFS, sizeof(cnid_t));    
+    cur = ntohl(tmp);
+    id  = ntohl(rqst->cnid);
+
+    if (id > cur) {
+       data.size = ROOTINFO_DATALEN;
+       memcpy((char *) data.data + CNID_TYPE_OFS, &rqst->cnid, sizeof(cnid_t));
+       if (dbif_put(DBIF_IDX_CNID, &key, &data, 0) < 0) {
+           rply->result = CNID_DBD_RES_ERR_DB;
+           return -1;
+       }
+    }
+    
+    rply->cnid = rqst->cnid;
+    rply->result = CNID_DBD_RES_OK;
+    return 1;
+}
+
+
diff --git a/etc/cnid_dbd/dbd_resolve.c b/etc/cnid_dbd/dbd_resolve.c
new file mode 100644 (file)
index 0000000..4be2343
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * $Id: dbd_resolve.c,v 1.2 2005-04-28 20:49:48 bfernhomberg Exp $
+ *
+ * Copyright (C) Joerg Lenneis 2003
+ * All Rights Reserved.  See COPYING.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include <string.h>
+#include <atalk/logger.h>
+#include <errno.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: DB Error resolving CNID %u", ntohl(rqst->cnid));
+        rply->result = CNID_DBD_RES_ERR_DB;
+        return -1;
+    }
+     
+    if (rc == 0) {
+#ifdef DEBUG
+       LOG(log_info, logtype_cnid, "dbd_resolve: Could not resolve CNID %u",
+           ntohl(rqst->cnid));
+#endif
+        rply->result = CNID_DBD_RES_NOTFOUND;
+        return 1;
+    }
+
+    memcpy(&rply->did, (char *) data.data + CNID_DID_OFS, sizeof(cnid_t));
+
+    rply->namelen = data.size - CNID_NAME_OFS;
+    rply->name = (char *)data.data + CNID_NAME_OFS;
+
+#ifdef DEBUG
+    LOG(log_info, logtype_cnid, "dbd_resolve: Resolving CNID %u to did %u name %s",
+        ntohl(rqst->cnid), ntohl(rply->did), rply->name);
+#endif
+    rply->result = CNID_DBD_RES_OK;
+    return 1;
+}
diff --git a/etc/cnid_dbd/dbd_update.c b/etc/cnid_dbd/dbd_update.c
new file mode 100644 (file)
index 0000000..816c1f6
--- /dev/null
@@ -0,0 +1,130 @@
+/*
+ * $Id: dbd_update.c,v 1.2 2005-04-28 20:49:48 bfernhomberg Exp $
+ *
+ * Copyright (C) Joerg Lenneis 2003
+ * All Rights Reserved.  See COPYING.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include <string.h>
+#include <errno.h>
+#include <atalk/logger.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. */
+
+/* FIXME: This calls pack_cnid_data(rqst) three times without modifying rqst */
+/* FIXME: (Only tested with DB 4.1.25):
+
+      dbif_pget on the secondary index followed by dbif_del with the CNID on the
+      main cnid db could be replaced by a single dbif_del on the secondary index. That 
+      deletes the secondary, the corresponding entry from the main cnid db as well as the 
+      other secondary index.
+*/   
+   
+int dbd_update(struct cnid_dbd_rqst *rqst, struct cnid_dbd_rply *rply)
+{
+    DBT key,pkey, data;
+    int rc;
+    char *buf;                            
+    int notfound = 0;
+    char getbuf[CNID_HEADER_LEN + MAXPATHLEN +1];
+#ifdef DEBUG
+    cnid_t tmpcnid;
+#endif
+
+    memset(&key, 0, sizeof(key));
+    memset(&pkey, 0, sizeof(pkey));
+    memset(&data, 0, sizeof(data));
+
+    rply->namelen = 0;
+
+    buf = pack_cnid_data(rqst);
+    key.data = buf +CNID_DEVINO_OFS;
+    key.size = CNID_DEVINO_LEN;
+
+    data.data = getbuf;
+    data.size = CNID_HEADER_LEN + MAXPATHLEN + 1;
+    if ((rc = dbif_pget(DBIF_IDX_DEVINO, &key, &pkey, &data, 0)) < 0 ) {
+        goto err_db;
+    }
+    else if  (rc > 0) {
+#ifdef DEBUG
+       memcpy(&tmpcnid, pkey.data, sizeof(cnid_t));
+       LOG(log_info, logtype_cnid, "dbd_update: Deleting %u corresponding to dev/ino %s from cnid2.db",
+           ntohl(tmpcnid), stringify_devino(rqst->dev, rqst->ino));
+#endif
+        if ((rc = dbif_del(DBIF_IDX_CNID, &pkey, 0)) < 0 ) {
+            goto err_db;
+        }
+        else if (!rc) {
+               LOG(log_error, logtype_cnid, "dbd_update: delete DEVINO %u %s", ntohl(rqst->cnid), db_strerror(errno));
+        }
+    }
+    if (!rc) {
+       notfound = 1;
+    }
+
+    buf = pack_cnid_data(rqst);
+    key.data = buf + CNID_DID_OFS;
+    key.size = CNID_DID_LEN + rqst->namelen +1;
+    memset(&pkey, 0, sizeof(pkey));
+
+    if ((rc = dbif_pget(DBIF_IDX_DIDNAME, &key, &pkey, &data, 0)) < 0) {
+        goto err_db;
+    }
+    else if  (rc > 0) {
+#ifdef DEBUG
+       memcpy(&tmpcnid, pkey.data, sizeof(cnid_t));
+       LOG(log_info, logtype_cnid, "dbd_update: Deleting %u corresponding to did %u name %s from cnid2.db",
+           ntohl(tmpcnid), ntohl(rqst->did), rqst->name);
+#endif
+        if ((rc = dbif_del(DBIF_IDX_CNID, &pkey, 0)) < 0) {
+            goto err_db;
+        }
+        else if (!rc) {
+               LOG(log_error, logtype_cnid, "dbd_update: delete DIDNAME %u %s", ntohl(rqst->cnid), db_strerror(errno));
+        }
+    }
+    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;
+#ifdef DEBUG
+    LOG(log_info, logtype_cnid, "dbd_update: Updated cnid2.db with dev/ino %s did %u name %s cnid %u",
+       stringify_devino(rqst->dev, rqst->ino),
+       ntohl(rqst->did), rqst->name, ntohl(rqst->cnid));
+#endif
+    rply->result = CNID_DBD_RES_OK;
+    return 1;
+
+err_db:
+#ifdef DEBUG
+    LOG(log_error, logtype_cnid, "dbd_update: Unable to update CNID %u dev/ino %s, DID %x:%s",
+        ntohl(rqst->cnid), stringify_devino(rqst->ino, rqst->did), rqst->name);
+#endif
+    rply->result = CNID_DBD_RES_ERR_DB;
+    return -1;
+}
diff --git a/etc/cnid_dbd/dbif.c b/etc/cnid_dbd/dbif.c
new file mode 100644 (file)
index 0000000..15f2f7d
--- /dev/null
@@ -0,0 +1,530 @@
+/*
+ * $Id: dbif.c,v 1.2 2005-04-28 20:49:48 bfernhomberg Exp $
+ *
+ * Copyright (C) Joerg Lenneis 2003
+ * All Rights Reserved.  See COPYING.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif /* HAVE_SYS_TYPES_H */
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/cdefs.h>
+#include <unistd.h>
+#include <atalk/logger.h>
+#include <db.h>
+#include "db_param.h"
+#include "dbif.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 | DB_PRIVATE) 
+#endif
+
+static struct db_table {
+     char            *name;
+     DB              *db;
+     u_int32_t       general_flags;
+     DBTYPE          type;
+} db_table[] =
+{
+     { "cnid2.db",       NULL,      0, DB_BTREE},
+     { "devino.db",      NULL,      0, DB_BTREE},
+     { "didname.db",     NULL,      0, DB_BTREE},
+};
+
+static char *old_dbfiles[] = {"cnid.db", NULL};
+
+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  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, db_txn, s, callback, flags);
+#else
+#if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR == 0)
+    return p->associate(p,       s, callback, flags);
+#else
+    return 0;
+#endif
+#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)
+    ret = db->open(db, db_txn, file, name, type, DB_CREATE, mode); 
+#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;
+    }
+}
+
+/* --------------- */
+static int upgrade_required()
+{
+    int i;
+    int found = 0;
+    struct stat st;
+    
+    for (i = 0; old_dbfiles[i] != NULL; i++) {
+       if ( !(stat(old_dbfiles[i], &st) < 0) ) {
+           found++;
+           continue;
+       }
+       if (errno != ENOENT) {
+           LOG(log_error, logtype_cnid, "cnid_open: Checking %s gave %s", old_dbfiles[i], strerror(errno));
+           found++;
+       }
+    }
+    return found;
+}
+
+/* --------------- */
+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;
+}
+
+/* --------------- */
+/*
+ *  We assume our current directory is already the BDB homedir. Otherwise
+ *  opening the databases will not work as expected. If we use transactions,
+ *  dbif_env_init(), dbif_close() and dbif_stamp() are the only interface
+ *  functions that can be called without a valid transaction handle in db_txn.
+ */
+int dbif_env_init(struct db_param *dbp)
+{
+    int ret;
+#ifdef CNID_BACKEND_DBD_TXN
+    char **logfiles = NULL;
+    char **file;
+#endif
+
+    /* Refuse to do anything if this is an old version of the CNID database */
+    if (upgrade_required()) {
+       LOG(log_error, logtype_cnid, "Found version 1 of the CNID database. Please upgrade to version 2");
+       return -1;
+    }
+
+    if ((db_errlog = fopen(DB_ERRLOGFILE, "a")) == NULL)
+        LOG(log_warning, logtype_cnid, "error creating/opening DB errlogfile: %s", strerror(errno));
+
+#ifdef CNID_BACKEND_DBD_TXN
+    if ((ret = db_env_create(&db_env, 0))) {
+        LOG(log_error, logtype_cnid, "error creating DB environment: %s", 
+            db_strerror(ret));
+        db_env = NULL;
+        return -1;
+    }    
+    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, ".", DBOPTIONS | DB_PRIVATE | DB_RECOVER, 0))) {
+        LOG(log_error, logtype_cnid, "error opening DB environment: %s", 
+            db_strerror(ret));
+        db_env->close(db_env, 0);
+        db_env = NULL;
+        return -1;
+    }
+
+    if (db_errlog != NULL)
+        fflush(db_errlog);
+
+    if ((ret = db_env->close(db_env, 0))) {
+        LOG(log_error, logtype_cnid, "error closing DB environment after recovery: %s", 
+            db_strerror(ret));
+        db_env = NULL;
+        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));
+        db_env = NULL;
+        return -1;
+    }
+    if ((ret = db_env->set_cachesize(db_env, 0, 1024 * dbp->cachesize, 0))) {
+        LOG(log_error, logtype_cnid, "error setting DB environment cachesize to %i: %s",
+            dbp->cachesize, db_strerror(ret));
+        db_env->close(db_env, 0);
+        db_env = NULL;
+        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);
+        db_env = NULL;
+        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);
+        db_env = NULL;
+        return -1;
+    }
+    if (dbp->logfile_autoremove && db_env->log_archive(db_env, &logfiles, 0)) {
+       LOG(log_error, logtype_cnid, "error getting list of stale logfiles: %s",
+            db_strerror(ret));
+        db_env->close(db_env, 0);
+        db_env = NULL;
+        return -1;
+    }
+    if (logfiles != NULL) {
+       for (file = logfiles; *file != NULL; file++) {
+           if (unlink(*file) < 0)
+               LOG(log_warning, logtype_cnid, "Error removing stale logfile %s: %s", *file, strerror(errno));
+       }
+       free(logfiles);
+    }
+#endif
+    return 0;
+}
+
+/* --------------- */
+int dbif_open(struct db_param *dbp _U_, int do_truncate)
+{
+    int ret;
+    int i;
+    u_int32_t count;
+
+    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);
+
+        if (do_truncate && i > 0) {
+           if ((ret = db_table[i].db->truncate(db_table[i].db, db_txn, &count, 0))) {
+                LOG(log_error, logtype_cnid, "error truncating database %s: %s", 
+                    db_table[i].name, db_strerror(ret));
+                return -1;
+            }
+        }
+    }
+
+    /* 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, (do_truncate)?DB_CREATE: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, (do_truncate)?DB_CREATE:0)) != 0) {
+        LOG(log_error, logtype_cnid, "Failed to associate devino database: %s",db_strerror(ret));
+       return -1;
+    }
+
+    return 0;
+}
+
+/* ------------------------ */
+int dbif_closedb()
+{
+    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 (err)
+        return -1;
+    return 0;
+}
+
+/* ------------------------ */
+int dbif_close()
+{
+    int ret;
+    int err = 0;
+    
+    if (dbif_closedb()) 
+       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;
+    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;
+}
+
+/* search by secondary return primary */
+int dbif_pget(const int dbi, DBT *key, DBT *pkey, DBT *val, u_int32_t flags)
+{
+    int ret;
+    DB *db = db_table[dbi].db;
+
+    ret = db->pget(db, db_txn, key, pkey, val, flags);
+
+#if DB_VERSION_MAJOR >= 4
+    if (ret == DB_NOTFOUND || ret == DB_SECONDARY_BAD) {
+#else
+    if (ret == DB_NOTFOUND) {
+#endif     
+        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 DB_VERSION_MAJOR > 3
+    if (ret == DB_NOTFOUND || ret == DB_SECONDARY_BAD)
+#else
+    if (ret == DB_NOTFOUND)
+#endif
+        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;
+}
+
+
+int dbif_count(const int dbi, u_int32_t *count) 
+{
+    int ret;
+    DB_BTREE_STAT *sp;
+    DB *db = db_table[dbi].db;
+
+    ret = db->stat(db, &sp, 0);
+
+    if (ret) {
+        LOG(log_error, logtype_cnid, "error getting stat infotmation on database: %s", db_strerror(errno));
+        return -1;
+    }
+
+    *count = sp->bt_ndata;
+    free(sp);
+
+    return 0;
+}
+#endif /* CNID_BACKEND_DBD_TXN */
+
diff --git a/etc/cnid_dbd/dbif.h b/etc/cnid_dbd/dbif.h
new file mode 100644 (file)
index 0000000..a8b5998
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * $Id: dbif.h,v 1.2 2005-04-28 20:49:48 bfernhomberg Exp $
+ *
+ * Copyright (C) Joerg Lenneis 2003
+ * All Rights Reserved.  See COPYING.
+ */
+
+#ifndef CNID_DBD_DBIF_H
+#define CNID_DBD_DBIF_H 1
+
+#include <sys/cdefs.h>
+#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_env_init  __P((struct db_param *));
+extern int        dbif_open  __P((struct db_param *, int));
+extern int        dbif_close __P((void));
+extern int        dbif_closedb __P((void));
+extern int        dbif_get __P((const int, DBT *, DBT *, u_int32_t));
+extern int        dbif_pget __P((const int, DBT *, 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));
+
+extern int        dbif_count __P((const int, u_int32_t *));
+
+
+#ifdef CNID_BACKEND_DBD_TXN
+extern int        dbif_txn_begin  __P((void));
+extern int        dbif_txn_commit  __P((void));
+extern int        dbif_txn_abort  __P((void));
+extern int        dbif_txn_checkpoint  __P((u_int32_t, u_int32_t, u_int32_t));
+#else
+extern int        dbif_sync  __P((void));
+#endif /* CNID_BACKEND_DBD_TXN */
+
+#endif
diff --git a/etc/cnid_dbd/main.c b/etc/cnid_dbd/main.c
new file mode 100644 (file)
index 0000000..41e23bf
--- /dev/null
@@ -0,0 +1,393 @@
+/*
+ * $Id: main.c,v 1.2 2005-04-28 20:49:48 bfernhomberg Exp $
+ *
+ * Copyright (C) Joerg Lenneis 2003
+ * All Rights Reserved.  See COPYING.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif /* HAVE_FCNTL_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 <sys/file.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;
+}
+
+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;
+}
+
+/* 
+   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 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;
+        case CNID_DBD_OP_GETSTAMP:
+            ret = dbd_getstamp(&rqst, &rply);
+            break;
+        case CNID_DBD_OP_REBUILD_ADD:
+            ret = dbd_rebuild_add(&rqst, &rply);
+            break;
+        default:
+            LOG(log_error, logtype_cnid, "loop: unknown op %d", rqst.op);
+            ret = -1;
+            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 */
+    }
+}
+
+/* ------------------------ */
+static void switch_to_user(char *dir)
+{
+    struct stat st;
+
+    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 (!getuid()) {
+        LOG(log_info, logtype_cnid, "Setting uid/gid to %i/%i", st.st_uid, st.st_gid);
+        if (setgid(st.st_gid) < 0 || setuid(st.st_uid) < 0) {
+            LOG(log_error, logtype_cnid, "uid/gid: %s", strerror(errno));
+            exit(1);
+        }
+    }
+}
+
+/* ------------------------ */
+int get_lock(void)
+{
+    int lockfd;
+    struct flock lock;
+
+    if ((lockfd = open(LOCKFILENAME, O_RDWR | O_CREAT, 0644)) < 0) {
+       LOG(log_error, logtype_cnid, "main: error opening lockfile: %s", strerror(errno));
+       exit(1);
+    }
+    
+    lock.l_start  = 0;
+    lock.l_whence = SEEK_SET;
+    lock.l_len    = 0;
+    lock.l_type   = F_WRLCK;
+
+    if (fcntl(lockfd, F_SETLK, &lock) < 0) {
+       if (errno == EACCES || errno == EAGAIN) {
+           exit(0);
+       } else {
+           LOG(log_error, logtype_cnid, "main: fcntl F_WRLCK lockfile: %s", strerror(errno));
+           exit(1);
+       }
+    }
+    
+    return lockfd;
+}
+
+/* ----------------------- */
+void set_signal(void)
+{
+    struct sigaction sv;
+
+    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);
+    }
+}
+
+/* ----------------------- */
+void free_lock(int lockfd)
+{
+    struct flock lock;
+
+    lock.l_start  = 0;
+    lock.l_whence = SEEK_SET;
+    lock.l_len    = 0;
+    lock.l_type = F_UNLCK;
+    fcntl(lockfd, F_SETLK, &lock);
+    close(lockfd);
+}
+
+/* ------------------------ */
+int main(int argc, char *argv[])
+{
+    struct db_param *dbp;
+    int err = 0;
+    int ret;
+    int lockfd, ctrlfd, clntfd;
+    char *dir;
+       
+    set_processname("cnid_dbd");
+    syslog_setup(log_debug, logtype_default, logoption_ndelay | logoption_pid, logfacility_daemon);
+    
+    if (argc  != 4) {
+        LOG(log_error, logtype_cnid, "main: not enough arguments");
+        exit(1);
+    }
+
+    dir = argv[1];
+    ctrlfd = atoi(argv[2]);
+    clntfd = atoi(argv[3]);
+
+    switch_to_user(dir);
+    
+    /* Before we do anything else, check if there is an instance of cnid_dbd
+       running already and silently exit if yes. */
+    lockfd = get_lock();
+    
+    LOG(log_info, logtype_cnid, "Startup, DB dir %s", dir);
+    
+    set_signal();
+    
+    /* 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_env_init(dbp) < 0)
+        exit(2); /* FIXME: same exit code as failure for dbif_open() */  
+    
+#ifdef CNID_BACKEND_DBD_TXN
+    if (dbif_txn_begin() < 0)
+       exit(6);
+#endif
+    
+    if (dbif_open(dbp, 0) < 0) {
+#ifdef CNID_BACKEND_DBD_TXN
+       dbif_txn_abort();
+#endif
+        dbif_close();
+        exit(2);
+    }
+
+#ifndef CNID_BACKEND_DBD_TXN
+    if (dbp->check && (ret = dbd_check(dir))) {
+        if (ret < 0) {
+            dbif_close();
+            exit(2);
+        }
+        dbif_closedb();
+       LOG(log_info, logtype_cnid, "main: re-opening, secondaries will be rebuilt. This may take some time");
+        if (dbif_open(dbp, 1) < 0) {
+           LOG(log_info, logtype_cnid, "main: re-opening databases failed");
+            dbif_close();
+            exit(2);
+        }
+       LOG(log_info, logtype_cnid, "main: rebuilt done");
+    }
+#endif
+
+    if (dbd_stamp() < 0) {
+#ifdef CNID_BACKEND_DBD_TXN
+       dbif_txn_abort();
+#endif
+        dbif_close();
+        exit(5);
+    }
+#ifdef CNID_BACKEND_DBD_TXN
+    if (dbif_txn_commit() < 0)
+       exit(6);
+#endif
+
+    if (comm_init(dbp, ctrlfd, clntfd) < 0) {
+        dbif_close();
+        exit(3);
+    }
+
+    if (loop(dbp) < 0)
+        err++;
+
+#ifndef CNID_BACKEND_DBD_TXN
+    /* FIXME: Do we really need to sync before closing the DB? Just closing it
+       should be enough. */
+    if (dbif_sync() < 0)
+        err++;
+#endif
+
+    if (dbif_close() < 0)
+        err++;
+        
+    free_lock(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");
+    
+    return 0;
+}
diff --git a/etc/cnid_dbd/pack.c b/etc/cnid_dbd/pack.c
new file mode 100644 (file)
index 0000000..13b7e73
--- /dev/null
@@ -0,0 +1,153 @@
+/*
+ * $Id: pack.c,v 1.2 2005-04-28 20:49:48 bfernhomberg Exp $
+ *
+ * Copyright (C) Joerg Lenneis 2003
+ * All Rights Reserved.  See COPYING.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include <netatalk/endian.h>
+
+#include <string.h>
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif /* HAVE_SYS_TYPES_H */
+#include <sys/param.h>
+#include <sys/cdefs.h>
+#include <db.h>
+
+#include <atalk/cnid_dbd_private.h>
+#include "pack.h"
+
+#ifdef DEBUG
+/*
+ *  Auxiliary stuff for stringify_devino. See comments below.
+ */
+static char hexchars[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
+#endif
+
+/* --------------- */
+/*
+ *  This implementation is portable, but could probably be faster by using htonl
+ *  where appropriate. Also, this again doubles code from the cdb backend.
+ */
+static void pack_devino(unsigned char *buf, dev_t dev, ino_t ino)
+{
+    buf[CNID_DEV_LEN - 1] = dev; dev >>= 8;
+    buf[CNID_DEV_LEN - 2] = dev; dev >>= 8;
+    buf[CNID_DEV_LEN - 3] = dev; dev >>= 8;
+    buf[CNID_DEV_LEN - 4] = dev; dev >>= 8;
+    buf[CNID_DEV_LEN - 5] = dev; dev >>= 8;
+    buf[CNID_DEV_LEN - 6] = dev; dev >>= 8;
+    buf[CNID_DEV_LEN - 7] = dev; dev >>= 8;
+    buf[CNID_DEV_LEN - 8] = dev;
+
+    buf[CNID_DEV_LEN + CNID_INO_LEN - 1] = ino; ino >>= 8;
+    buf[CNID_DEV_LEN + CNID_INO_LEN - 2] = ino; ino >>= 8;
+    buf[CNID_DEV_LEN + CNID_INO_LEN - 3] = ino; ino >>= 8;
+    buf[CNID_DEV_LEN + CNID_INO_LEN - 4] = ino; ino >>= 8;
+    buf[CNID_DEV_LEN + CNID_INO_LEN - 5] = ino; ino >>= 8;
+    buf[CNID_DEV_LEN + CNID_INO_LEN - 6] = ino; ino >>= 8;
+    buf[CNID_DEV_LEN + CNID_INO_LEN - 7] = ino; ino >>= 8;
+    buf[CNID_DEV_LEN + CNID_INO_LEN - 8] = ino;    
+}
+
+/* --------------- */
+int didname(dbp, pkey, pdata, skey)
+DB *dbp _U_;
+const DBT *pkey _U_, *pdata;
+DBT *skey;
+{
+int len;
+    memset(skey, 0, sizeof(DBT));
+    skey->data = (char *)pdata->data + CNID_DID_OFS;
+    /* FIXME: At least DB 4.0.14 and 4.1.25 pass in the correct length of
+       pdata.size. strlen is therefore not needed. Also, skey should be zeroed
+       out already. */
+    len = strlen((char *)skey->data + CNID_DID_LEN);
+    skey->size = CNID_DID_LEN + len + 1;
+    return (0);
+}
+/* --------------- */
+int devino(dbp, pkey, pdata, skey)
+DB *dbp _U_;
+const DBT *pkey _U_, *pdata;
+DBT *skey;
+{
+    memset(skey, 0, sizeof(DBT));
+    skey->data = (char *)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;
+
+    pack_devino(buf, rqst->dev, rqst->ino);
+    buf += CNID_DEVINO_LEN;
+
+    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;
+}
+
+#ifdef DEBUG
+
+/*
+ *  Whack 4 or 8 byte dev/ino numbers into something printable for DEBUG
+ *  logging. This function must not be used more that once per printf() style
+ *  invocation. This (or something improved) should probably migrate to
+ *  libatalk logging. Checking for printf() %ll support would be an alternative.
+ */
+
+char *stringify_devino(dev_t dev, ino_t ino)
+{
+    static char rbuf[CNID_DEV_LEN * 2 + 1 + CNID_INO_LEN * 2 + 1] = {0};
+    char buf[CNID_DEV_LEN + CNID_INO_LEN];
+    char *c1;
+    char *c2;
+    char *middle;
+    char *end;
+    int   ci;
+
+    pack_devino(buf, dev, ino);
+    
+    middle = buf + CNID_DEV_LEN;
+    end = buf + CNID_DEV_LEN + CNID_INO_LEN;
+    c1  = buf;
+    c2  = rbuf;  
+    
+    while (c1 < end) {
+       if (c1 == middle) {
+           *c2 = '/';
+           c2++;
+       }    
+       ci = *c1;
+       c2[0] = hexchars[(ci & 0xf0) >> 4];
+       c2[1] = hexchars[ci & 0x0f];
+       c1++;
+       c2 += 2;
+    }
+    return rbuf;
+}
+#endif
diff --git a/etc/cnid_dbd/pack.h b/etc/cnid_dbd/pack.h
new file mode 100644 (file)
index 0000000..90add9d
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * $Id: pack.h,v 1.2 2005-04-28 20:49:49 bfernhomberg Exp $
+ *
+ * Copyright (C) Joerg Lenneis 2003
+ * All Rights Reserved.  See COPYING.
+ */
+
+#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 *));
+
+#ifdef DEBUG
+extern char      *stringify_devino  __P((dev_t dev, ino_t ino));
+#endif
+
+#endif /* CNID_DBD_PACK_H */
diff --git a/etc/cnid_dbd/usockfd.c b/etc/cnid_dbd/usockfd.c
new file mode 100644 (file)
index 0000000..8fba605
--- /dev/null
@@ -0,0 +1,174 @@
+/*
+ * $Id: usockfd.c,v 1.2 2005-04-28 20:49:49 bfernhomberg Exp $
+ *
+ * Copyright (C) Joerg Lenneis 2003
+ * All Rights Reserved.  See COPYING.
+ */
+
+#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>
+#include <netdb.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 *host, u_int16_t ipport, int backlog)
+{
+    int sockfd;
+    struct sockaddr_in server;
+    struct hostent     *hp;  
+    int                port;
+    
+    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) {
+            LOG(log_error, logtype_cnid, "gethostbyaddr %s: %s", host, strerror(errno));
+            return -1;
+        }
+    }
+    memcpy((char*)&server.sin_addr,(char*)hp->h_addr,sizeof(server.sin_addr));    
+
+    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);
+    
+    server.sin_family = AF_INET;
+    server.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 *)&server, sizeof(server)) < 0) {
+        LOG(log_error, logtype_cnid, "error binding to socket for %s: %s",
+            host, strerror(errno));
+        return -1;
+    }
+
+    if (listen(sockfd, backlog) < 0) {
+        LOG(log_error, logtype_cnid, "error in listen for %s: %s",
+            host, strerror(errno));
+        return -1;
+    }
+
+    return sockfd;
+}
+
+/* --------------------- */
+int usockfd_check(int sockfd, unsigned long ndelay)
+{
+    int fd;
+    int size;
+    fd_set readfds;
+    struct timeval tv;
+    int ret;
+     
+    FD_ZERO(&readfds);
+    FD_SET(sockfd, &readfds);
+
+    tv.tv_usec = ndelay % 1000000;
+    tv.tv_sec  = ndelay / 1000000;
+    if ((ret = select(sockfd + 1, &readfds, NULL, NULL, &tv)) < 0) {
+        if (errno == EINTR)
+            return 0;
+        LOG(log_error, logtype_cnid, "error in select: %s",
+            strerror(errno));
+        return -1;
+    }
+
+    if (ret) {
+        size = 0;
+        if ((fd = accept(sockfd, NULL, &size)) < 0) {
+            if (errno == EINTR)
+                return 0;
+            LOG(log_error, logtype_cnid, "error in accept: %s", 
+                strerror(errno));
+            return -1;
+        }
+        return fd;
+    } else
+        return 0;
+}
diff --git a/etc/cnid_dbd/usockfd.h b/etc/cnid_dbd/usockfd.h
new file mode 100644 (file)
index 0000000..12de313
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * $Id: usockfd.h,v 1.2 2005-04-28 20:49:49 bfernhomberg Exp $
+ *
+ * Copyright (C) Joerg Lenneis 2003
+ * All Rights Reserved.  See COPYING.
+ */
+
+#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 *, u_int16_t, int));
+extern int      usockfd_check   __P((int, unsigned long));
+
+#ifndef OSSH_ALIGNBYTES
+#define OSSH_ALIGNBYTES (sizeof(int) - 1)
+#endif
+#ifndef __CMSG_ALIGN
+#ifndef u_int
+#define u_int unsigned int
+#endif
+#define __CMSG_ALIGN(p) (((u_int)(p) + OSSH_ALIGNBYTES) &~ OSSH_ALIGNBYTES)
+#endif
+
+/* Length of the contents of a control message of length len */
+#ifndef CMSG_LEN
+#define CMSG_LEN(len)   (__CMSG_ALIGN(sizeof(struct cmsghdr)) + (len))
+#endif
+
+/* Length of the space taken up by a padded control message of length len */
+#ifndef CMSG_SPACE
+#define CMSG_SPACE(len) (__CMSG_ALIGN(sizeof(struct cmsghdr)) + __CMSG_ALIGN(len))
+#endif
+
+
+
+#endif /* CNID_DBD_USOCKFD_H */
index a625c60e03a140cbe5f5a4009e831d67458155ff..dda2bffb2f6003daeb8c518892b01dc0e2e07ee8 100644 (file)
@@ -1,5 +1,6 @@
 Makefile
 Makefile.in
 papd
+showppd
 .deps
 .libs
index c878a6ffd8cb74945db6aa7cb6a5881174a3e68e..66929b0d2eaa8b0792a75924240e6eae3d11ca99 100644 (file)
@@ -1,17 +1,20 @@
 # Makefile.am for etc/papd/
 
 pkgconfdir = @PKGCONFDIR@
+spooldir = @SPOOLDIR@
 
 sbin_PROGRAMS = papd
-#bin_PROGRAMS = showppd
+bin_PROGRAMS = showppd
 
 papd_SOURCES = main.c printcap.c session.c file.c comment.c lp.c ppd.c \
-       magics.c headers.c queries.c auth.c uam.c
-papd_LDADD = @PAM_LIBS@ $(top_builddir)/libatalk/libatalk.la
-papd_LDFLAGS = -export-dynamic
+              magics.c headers.c queries.c auth.c uam.c print_cups.c
 
-#showppd_SOURCES = showppd.c ppd.c
-#showppd_LDADD = $(top_builddir)/libatalk/libatalk.la
+papd_LDADD = $(top_builddir)/libatalk/libatalk.la @PAM_LIBS@ @CUPS_LIBS@ @LIBADD_DL@
+papd_LDFLAGS = -export-dynamic @CUPS_LDFLAGS@
+
+showppd_SOURCES = showppd.c ppd.c
+showppd_CFLAGS = @CFLAGS@ -DSHOWPPD
+showppd_LDADD = $(top_builddir)/libatalk/libatalk.la
 
 noinst_HEADERS =       \
        comment.h       \
@@ -21,9 +24,23 @@ noinst_HEADERS =     \
        printcap.h      \
        printer.h       \
        session.h       \
+       print_cups.h    \
        uam_auth.h
 
-INCLUDES = \
+CFLAGS = \
        -I$(top_srcdir)/include -I$(top_srcdir)/sys \
+       @CFLAGS@ @CUPS_CFLAGS@\
        -D_PATH_PAPDCONF=\"$(pkgconfdir)/papd.conf\" \
-       -D_PATH_PAPDUAMPATH=\"$(UAMS_PATH)/\"
+       -D_PATH_PAPDUAMPATH=\"$(UAMS_PATH)/\" \
+       -DSPOOLDIR=\"$(spooldir)/\"
+
+if USE_SPOOLDIR
+install-exec-hook:
+       echo "Creating SPOOLDIR $(DESTDIR)$(spooldir)..."
+       $(mkinstalldirs) $(DESTDIR)$(spooldir)
+       chmod 0777 $(DESTDIR)$(spooldir)
+
+else
+install-exec-hook:
+
+endif
index 124a083fed8c4085d8ba315644745996abfc57ef..9ce22acc09109b6c229d1beef0c99752d61eb65b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: auth.c,v 1.6 2002-09-29 23:29:13 sibaz Exp $
+ * $Id: auth.c,v 1.7 2005-04-28 20:49:49 bfernhomberg Exp $
  *
  * Copyright (c) 1990,1993 Regents of The University of Michigan.
  * All Rights Reserved.  See COPYRIGHT.
 #include "uam_auth.h"
 
 static struct uam_mod uam_modules = {NULL, NULL, &uam_modules, &uam_modules};
-static struct uam_obj uam_login = {"", "", 0, {{NULL}}, &uam_login,
+static struct uam_obj uam_login = {"", "", 0, {{NULL, NULL, NULL}}, &uam_login,
                                   &uam_login};
-static struct uam_obj uam_changepw = {"", "", 0, {{NULL}}, &uam_changepw, 
+static struct uam_obj uam_changepw = {"", "", 0, {{NULL, NULL, NULL}}, &uam_changepw, 
                                      &uam_changepw};
-static struct uam_obj uam_printer = {"", "", 0, {{NULL}}, &uam_printer,
+static struct uam_obj uam_printer = {"", "", 0, {{NULL, NULL, NULL}}, &uam_printer,
                                        &uam_printer};
 
 
@@ -87,7 +87,7 @@ int auth_register(const int type, struct uam_obj *uam)
     return -1;
 
   if (!(start = UAM_LIST(type)))
-    return 0; /* silently fail */
+    return 1; 
 
   uam_attach(start, uam);
   return 0;
@@ -104,7 +104,7 @@ int auth_load(const char *path, const char *list)
   if (!path || !list || (len = strlen(path)) > sizeof(name) - 2)
     return -1;
 
-  strncpy(buf, list, sizeof(buf));
+  strlcpy(buf, list, sizeof(buf));
   if ((p = strtok(buf, ",")) == NULL)
     return -1;
 
@@ -115,7 +115,7 @@ int auth_load(const char *path, const char *list)
   }
 
   while (p) {
-    strncpy(name + len, p, sizeof(name) - len);
+    strlcpy(name + len, p, sizeof(name) - len);
     if ((stat(name, &st) == 0) && (mod = uam_load(name, p))) {
       uam_attach(&uam_modules, mod);
       LOG(log_info, logtype_papd, "uam: %s loaded", p);
index c5fb435c3e43c337b2be80ce10c8c6a4e137e5d2..a1e2c060dc406161c78dbeb06eb539ea64777e42 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: file.h,v 1.6 2001-06-25 20:13:45 rufustfirefly Exp $
+ * $Id: file.h,v 1.7 2005-04-28 20:49:49 bfernhomberg Exp $
  *
  * Copyright (c) 1990,1991 Regents of The University of Michigan.
  * All Rights Reserved.  See COPYRIGHT.
@@ -17,11 +17,14 @@ struct papfile {
     int                        pf_datalen;
     char               *pf_buf;
     char               *pf_data;
+    int                origin;
 };
 
 #define PF_BOT         (1<<0)
 #define PF_EOF         (1<<1)
 #define PF_QUERY       (1<<2)
+#define PF_STW         (1<<3)
+#define PF_TRANSLATE   (1<<4)
 
 #define CONSUME( pf, len )  {   (pf)->pf_data += (len); \
                                (pf)->pf_datalen -= (len); \
index e6ac1ec022906039e18f5933312530fabfcd8528..2aa3d9ea5acbf556c4ec6e777e287fccacfc56b7 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: headers.c,v 1.9 2002-01-04 04:45:47 sibaz Exp $
+ * $Id: headers.c,v 1.10 2005-04-28 20:49:49 bfernhomberg Exp $
  *
  * Copyright (c) 1990,1994 Regents of The University of Michigan.
  * All Rights Reserved.  See COPYRIGHT.
@@ -9,20 +9,72 @@
 #include "config.h" 
 #endif /* HAVE_CONFIG_H */
 
-#include <atalk/logger.h>
 #include <sys/param.h>
+#include <string.h>
 #include <stdio.h>
 
 #include <netatalk/at.h>
+#include <atalk/logger.h>
 
 #include "file.h"
 #include "comment.h"
 #include "lp.h"
 
 int ch_title( struct papfile *, struct papfile * );
+int ch_for( struct papfile *, struct papfile * );
+
+
+int ch_for( in, out )
+       struct papfile  *in, *out _U_;
+{
+    char                *start, *stop, *p, *q, c;
+    int                 linelength, crlflength;
+
+    switch ( markline( in, &start, &linelength, &crlflength )) {
+    case 0 :
+        return( 0 );
+
+    case -1 :
+        return( CH_MORE );
+    }
+
+    stop = start + linelength;
+    for ( p = start; p < stop; p++ ) {
+        if ( *p == ':' ) {
+            break;
+        }
+    }
+
+    for ( ; p < stop; p++ ) {
+        if ( *p == '(' ) {
+            break;
+        }
+    }
+
+    for ( q = p; q < stop; q++ ) {
+        if ( *q == ')' ) {
+            break;
+        }
+    }
+
+    if ( q < stop && p < stop ) {
+        p++;
+        c = *q;
+        *q = '\0';
+       lp_for ( p );
+        *q = c;
+    }
+
+    in->pf_state |= PF_TRANSLATE;
+    lp_write( in, start, linelength + crlflength );
+    in->pf_state &= ~PF_TRANSLATE;
+    compop();
+    CONSUME( in, linelength + crlflength );
+    return( CH_DONE );
+}
 
 int ch_title( in, out )
-    struct papfile     *in, *out;
+    struct papfile     *in, *out _U_;
 {
     char               *start, *stop, *p, *q, c;
     int                        linelength, crlflength;
@@ -35,6 +87,10 @@ int ch_title( in, out )
        return( CH_MORE );
     }
 
+#ifdef DEBUG
+    LOG(log_debug, logtype_papd, "Parsing %%Title");
+#endif
+
     stop = start + linelength;
     for ( p = start; p < stop; p++ ) {
        if ( *p == ':' ) {
@@ -62,16 +118,203 @@ int ch_title( in, out )
        *q = c;
     }
 
-    lp_write( start, linelength + crlflength );
+    in->pf_state |= PF_TRANSLATE;
+    lp_write( in, start, linelength + crlflength );
+    in->pf_state &= ~PF_TRANSLATE;
     compop();
     CONSUME( in, linelength + crlflength );
     return( CH_DONE );
 }
 
+static int guess_creator ( char *creator )
+{
+       if (strstr(creator, "LaserWriter"))
+               return 1;
+       if (strstr(creator, "cgpdftops"))
+               return 2;
+
+       return 0;
+}
+
+
+int ch_creator( in, out )
+    struct papfile     *in, *out _U_;
+{
+    char               *start, *stop, *p, *q, c;
+    int                        linelength, crlflength;
+
+    switch ( markline( in, &start, &linelength, &crlflength )) {
+    case 0 :
+       return( 0 );
+
+    case -1 :
+       return( CH_MORE );
+    }
+
+    stop = start + linelength;
+    for ( p = start; p < stop; p++ ) {
+       if ( *p == ':' ) {
+           break;
+       }
+    }
+
+    for ( ; p < stop; p++ ) {
+       if ( *p == '(' ) {
+           break;
+       }
+    }
+
+    for ( q = p; q < stop; q++ ) {
+       if ( *q == ')' ) {
+           break;
+       }
+    }
+
+    if ( q < stop && p < stop ) {
+       p++;
+       c = *q;
+       *q = '\0';
+       in->origin = guess_creator ( p );
+       lp_origin(in->origin);
+       *q = c;
+    }
+
+    in->pf_state |= PF_TRANSLATE;
+    lp_write( in, start, linelength + crlflength );
+    in->pf_state &= ~PF_TRANSLATE;
+    compop();
+    CONSUME( in, linelength + crlflength );
+    return( CH_DONE );
+}
+
+int ch_endcomm( in, out )
+    struct papfile     *in, *out _U_;
+{
+    char                *start;
+    int                 linelength, crlflength;
+
+#ifdef DEBUG
+    LOG(log_debug, logtype_papd, "End Comment");
+#endif
+    in->pf_state |= PF_STW;
+
+    switch ( markline( in, &start, &linelength, &crlflength )) {
+    case 0 :
+       return( 0 );
+
+    case -1 :
+       return( CH_MORE );
+    }
+
+    in->pf_state |= PF_TRANSLATE;
+    lp_write( in, start, linelength + crlflength );
+    in->pf_state &= ~PF_TRANSLATE;
+    compop();
+    CONSUME( in, linelength + crlflength );
+    return ( CH_DONE);
+}
+
+int ch_starttranslate(in,out)
+    struct papfile      *in, *out _U_;
+{
+    char                *start;
+    int                 linelength, crlflength;
+
+#ifdef DEBUG
+    LOG(log_debug, logtype_papd, "Start translate");
+#endif
+
+    switch ( markline( in, &start, &linelength, &crlflength )) {
+    case 0 :
+        return( 0 );
+
+    case -1 :
+        return( CH_MORE );
+    }
+
+    in->pf_state |= PF_TRANSLATE;
+    lp_write( in, start, linelength + crlflength );
+    compop();
+    CONSUME( in, linelength + crlflength );
+    return ( CH_DONE);
+}
+
+int ch_endtranslate(in,out)
+    struct papfile      *in, *out _U_;
+{
+    char                *start;
+    int                 linelength, crlflength;
+
+#ifdef DEBUG
+    LOG(log_debug, logtype_papd, "EndTranslate");
+#endif
+
+    switch ( markline( in, &start, &linelength, &crlflength )) {
+    case 0 :
+        return( 0 );
+
+    case -1 :
+        return( CH_MORE );
+    }
+
+    lp_write( in, start, linelength + crlflength );
+    in->pf_state &= ~PF_TRANSLATE;
+    compop();
+    CONSUME( in, linelength + crlflength );
+    return ( CH_DONE);
+}
+
+int ch_translateone(in,out)
+    struct papfile      *in, *out _U_;
+{
+    char                *start;
+    int                 linelength, crlflength;
+
+#ifdef DEBUG
+    LOG(log_debug, logtype_papd, "TranslateOne");
+#endif
+
+    switch ( markline( in, &start, &linelength, &crlflength )) {
+    case 0 :
+        return( 0 );
+
+    case -1 :
+        return( CH_MORE );
+    }
+
+    in->pf_state |= PF_TRANSLATE;
+    lp_write( in, start, linelength + crlflength );
+    in->pf_state &= ~PF_TRANSLATE;
+    compop();
+    CONSUME( in, linelength + crlflength );
+    return ( CH_DONE);
+}
+
+
+
+
 /*
  * "Header" comments.
  */
 struct papd_comment    headers[] = {
-    { "%%Title:",                      0,              ch_title,       0 },
-    { 0 },
+    { "%%Title:",                      NULL,           ch_title,       0 },
+    { "%%For:",                                NULL,           ch_for,         0 },
+    { "%%Creator:",                    NULL,           ch_creator,     0 },
+    { "%%EndComments",                 NULL,           ch_endcomm,     0 },
+    { "%%BeginFeature",                        NULL,           ch_starttranslate,  0 },
+    { "%%EndFeature",                  NULL,           ch_endtranslate,  0 },
+    { "%%BeginPageSetup",              NULL,           ch_starttranslate, 0 },
+    { "%%EndPageSetup",                        NULL,           ch_endtranslate, 0 },
+#if 0
+    { "%%BeginSetup",                  NULL,           ch_translateone,  0 },
+    { "%%EndSetup",                    NULL,           ch_translateone,  0 },
+    { "%%BeginProlog",                 NULL,           ch_translateone,  0 },
+    { "%%EndProlog",                   NULL,           ch_translateone,  0 },
+    { "%%Page:",                       NULL,           ch_translateone, 0 },
+    { "%%PageTrailer",                 NULL,           ch_translateone, 0 },
+    { "%%Trailer",                     NULL,           ch_translateone, 0 },
+    { "%%EOF",                         NULL,           ch_translateone, 0 },
+#endif
+    { "%%",                            NULL,           ch_translateone, 0 },
+    { NULL,                            NULL,           NULL,           0 },
 };
index 1cf9ff9c7e730d05ea84e29e4ffcaa4c9956fd23..35f2ee46fe46960c0f115cf053527af0940d1089 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: lp.c,v 1.14 2002-09-29 23:29:13 sibaz Exp $
+ * $Id: lp.c,v 1.15 2005-04-28 20:49:49 bfernhomberg Exp $
  *
  * Copyright (c) 1990,1994 Regents of The University of Michigan.
  * All Rights Reserved.  See COPYRIGHT.
@@ -46,7 +46,6 @@
 #endif /* HAVE_CONFIG_H */
 
 #include <sys/param.h>
-#include <atalk/logger.h>
 #include <sys/time.h>
 #include <sys/socket.h>
 #include <sys/stat.h>
 #include <sys/un.h>
 #include <netinet/in.h>
 #undef s_net
-#include <netatalk/at.h>
-#include <atalk/atp.h>
-#include <atalk/paths.h>
 
 #ifdef ABS_PRINT
 #include <math.h>
 #endif /* ABS_PRINT */
-
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #endif /* HAVE_FCNTL_H */
 #include <pwd.h>
 
+#include <atalk/logger.h>
+#include <netatalk/at.h>
+#include <atalk/atp.h>
+#include <atalk/paths.h>
+#include <atalk/unicode.h>
+
 #include "printer.h"
 #include "file.h"
 #include "lp.h"
 
+#ifdef HAVE_CUPS
+#include  "print_cups.h"
+#endif
+
+
 /* These functions aren't used outside of lp.c */
 int lp_conn_inet();
 int lp_disconn_inet( int );
@@ -98,16 +104,173 @@ struct lp {
     int                        lp_flags;
     FILE               *lp_stream;
     int                        lp_seq;
+    int                lp_origin;
     char               lp_letter;
     char               *lp_person;
+    char               *lp_created_for; /* Holds the content of the Postscript %%For Comment if available */
     char               *lp_host;
     char               *lp_job;
+    char               *lp_spoolfile;
 } lp;
 #define LP_INIT                (1<<0)
 #define LP_OPEN                (1<<1)
 #define LP_PIPE                (1<<2)
 #define LP_CONNECT     (1<<3)
 #define LP_QUEUE       (1<<4)
+#define LP_JOBPENDING  (1<<5)
+
+void lp_origin (int origin)
+{
+    lp.lp_origin = origin;
+}
+
+/* the converted string should always be shorter, but ... FIXME! */
+static void convert_octal (char *string, charset_t dest)
+{
+    unsigned char *p, *q;
+    char temp[4];
+    long int ch;
+
+    q=p=string;
+    while ( *p != '\0' ) {
+        ch = 0;
+        if ( *p == '\\' ) {
+            p++;
+            if (dest && isdigit(*p) && isdigit(*(p+1)) && isdigit(*(p+2)) ) {
+                temp[0] = *p;
+                temp[1] = *(p+1);
+                temp[2] = *(p+2);
+                temp[3] = 0;
+                ch = strtol( temp, NULL, 8);
+                if ( ch && ch < 0xff)
+                    *q = ch;
+               else
+                    *q = '.';
+                p += 2;
+            }
+                   else 
+                *q = '.';
+       }
+       else {
+           *q = *p;
+       }
+           p++;
+           q++;
+    }
+    *q = 0;
+}
+
+
+static void translate(charset_t from, charset_t dest, char **option)
+{
+    char *translated;
+
+    if (*option != NULL) {
+        convert_octal(*option, from);
+        if (from) {
+             if ((size_t) -1 != (convert_string_allocate(from, dest, *option, strlen(*option), &translated)) ) {
+                 free (*option);
+                 *option = translated;
+             }
+        }
+    }
+}
+
+
+static void lp_setup_comments (charset_t dest)
+{
+    charset_t from=0;
+
+    switch (lp.lp_origin) {
+       case 1:
+               from=CH_MAC;
+               break;
+       case 2:
+               from=CH_UTF8_MAC;
+               break;
+    }
+
+    if (lp.lp_job) {
+#ifdef DEBUG1
+        LOG(log_debug, logtype_papd, "job: %s", lp.lp_job );
+#endif
+        translate(from, dest, &lp.lp_job);
+    }
+    if (lp.lp_created_for) {
+#ifdef DEBUG1
+        LOG(log_debug, logtype_papd, "for: %s", lp.lp_created_for );
+#endif
+        translate(from, dest, &lp.lp_created_for);
+    }
+    if (lp.lp_person) {
+#ifdef DEBUG1
+       LOG(log_debug, logtype_papd, "person: %s", lp.lp_person );
+#endif
+       translate(from, dest, &lp.lp_person);
+    }
+}
+
+#define is_var(a, b) (strncmp((a), (b), 2) == 0)
+
+static char* pipexlate(char *src)
+{
+    char *p, *q, *dest; 
+    static char destbuf[MAXPATHLEN];
+    size_t destlen = MAXPATHLEN;
+    int len = 0;
+   
+    dest = destbuf; 
+
+    if (!src)
+       return NULL;
+
+    strncpy(dest, src, MAXPATHLEN);
+    if ((p = strchr(src, '%')) == NULL) /* nothing to do */
+        return destbuf;
+
+    /* first part of the path. just forward to the next variable. */
+    len = MIN((size_t)(p - src), destlen);
+    if (len > 0) {
+        destlen -= len;
+        dest += len;
+    }
+
+    while (p && destlen > 0) {
+        /* now figure out what the variable is */
+        q = NULL;
+        if (is_var(p, "%U")) {
+           q = lp.lp_person;
+        } else if (is_var(p, "%C") || is_var(p, "%J") ) {
+            q = lp.lp_job;
+        } else if (is_var(p, "%F")) {
+            q =  lp.lp_created_for;
+        } else if (is_var(p, "%%")) {
+            q = "%";
+        } else
+            q = p;
+
+        /* copy the stuff over. if we don't understand something that we
+         * should, just skip it over. */
+        if (q) {
+            len = MIN(p == q ? 2 : strlen(q), destlen);
+            strncpy(dest, q, len);
+            dest += len;
+            destlen -= len;
+        }
+
+        /* stuff up to next $ */
+        src = p + 2;
+        p = strchr(src, '$');
+        len = p ? MIN((size_t)(p - src), destlen) : destlen;
+        if (len > 0) {
+            strncpy(dest, src, len);
+            dest += len;
+            destlen -= len;
+        }
+    }
+    return destbuf;
+}
+
 
 void lp_person( person )
     char       *person;
@@ -151,38 +314,49 @@ void lp_host( host )
        exit( 1 );
     }
     strcpy( lp.lp_host, host );
+    LOG(log_debug, logtype_papd, "host: %s", lp.lp_host );
 }
 
+/* Currently lp_job and lp_for will not handle the
+ * conversion of macroman chars > 0x7f correctly
+ * This should be added.
+ */
+
 void lp_job( job )
     char       *job;
 {
-    char       *p, *q;
-
     if ( lp.lp_job != NULL ) {
        free( lp.lp_job );
     }
-    if (( lp.lp_job = (char *)malloc( strlen( job ) + 1 )) == NULL ) {
-       LOG(log_error, logtype_papd, "malloc: %m" );
-       exit( 1 );
-    }
-    for ( p = job, q = lp.lp_job; *p != '\0'; p++, q++ ) {
-       if ( !isascii( *p ) || !isprint( *p ) || *p == '\\' ) {
-           *q = '.';
-       } else {
-           *q = *p;
-       }
+
+    lp.lp_job = strdup(job);
+#ifdef DEBUG
+    LOG(log_debug, logtype_papd, "job: %s", lp.lp_job );
+#endif
+    
+}
+
+void lp_for ( lpfor )
+       char    *lpfor;
+{
+    if ( lp.lp_created_for != NULL ) {
+       free( lp.lp_created_for );
     }
-    *q = '\0';
+
+    lp.lp_created_for = strdup(lpfor);
 }
 
+
 int lp_init( out, sat )
     struct papfile     *out;
     struct sockaddr_at *sat;
 {
+    int                authenticated = 0;
+#ifndef HAVE_CUPS
     int                fd, n, len;
     char       *cp, buf[ BUFSIZ ];
     struct stat        st;
-    int                authenticated = 0;
+#endif /* HAVE_CUPS */
 #ifdef ABS_PRINT
     char       cost[ 22 ];
     char       balance[ 22 ];
@@ -270,6 +444,8 @@ int lp_init( out, sat )
     lp.lp_letter = 'A';
 
     if ( printer->p_flags & P_SPOOLED ) {
+
+#ifndef HAVE_CUPS
        /* check if queuing is enabled: mode & 010 on lock file */
        if ( stat( printer->p_lock, &st ) < 0 ) {
            LOG(log_error, logtype_papd, "lp_init: %s: %m", printer->p_lock );
@@ -288,11 +464,13 @@ int lp_init( out, sat )
            return( -1 );
        }
 
+#ifndef SOLARIS /* flock is unsupported, I doubt this stuff works anyway with newer solaris so ignore for now */
        if ( flock( fd, LOCK_EX ) < 0 ) {
            LOG(log_error, logtype_papd, "lp_init: can't lock .seq" );
            spoolerror( out, NULL );
            return( -1 );
        }
+#endif
 
        n = 0;
        if (( len = read( fd, buf, sizeof( buf ))) < 0 ) {
@@ -315,6 +493,16 @@ int lp_init( out, sat )
        lseek( fd, 0L, 0 );
        write( fd, buf, strlen( buf ));
        close( fd );
+#else
+
+       if (cups_get_printer_status ( printer ) == 0)
+       {
+           spoolerror( out, "Queuing is disabled." );
+           return( -1 );
+       }
+
+       lp.lp_seq = getpid();
+#endif /* HAVE CUPS */
     } else {
        lp.lp_flags |= LP_PIPE;
        lp.lp_seq = getpid();
@@ -332,15 +520,25 @@ int lp_open( out, sat )
     int                fd;
     struct passwd      *pwent;
 
+#ifdef DEBUG
+    LOG (log_debug, logtype_papd, "lp_open");
+#endif
+
+    if ( lp.lp_flags & LP_JOBPENDING ) {
+       lp_print();
+    }
+
     if (( lp.lp_flags & LP_INIT ) == 0 && lp_init( out, sat ) != 0 ) {
        return( -1 );
     }
     if ( lp.lp_flags & LP_OPEN ) {
-       LOG(log_error, logtype_papd, "lp_open already open" );
-       abort();
+       /* LOG(log_error, logtype_papd, "lp_open already open" ); */
+       /* abort(); */
+       return (-1);
     }
 
     if ( lp.lp_flags & LP_PIPE ) {
+
        /* go right to program */
        if (lp.lp_person != NULL) {
            if((pwent = getpwnam(lp.lp_person)) != NULL) {
@@ -351,11 +549,14 @@ int lp_open( out, sat )
                LOG(log_info, logtype_papd, "Error getting username (%s)", lp.lp_person);
            }
        }
-       if (( lp.lp_stream = popen( printer->p_printer, "w" )) == NULL ) {
+
+       lp_setup_comments(CH_UNIX);
+       if (( lp.lp_stream = popen( pipexlate(printer->p_printer), "w" )) == NULL ) {
            LOG(log_error, logtype_papd, "lp_open popen %s: %m", printer->p_printer );
            spoolerror( out, NULL );
            return( -1 );
        }
+        LOG(log_debug, logtype_papd, "lp_open: opened %s",  pipexlate(printer->p_printer) );
     } else {
        sprintf( name, "df%c%03d%s", lp.lp_letter++, lp.lp_seq, hostname );
 
@@ -365,6 +566,12 @@ int lp_open( out, sat )
            return( -1 );
        }
 
+       if ( NULL == (lp.lp_spoolfile = (char *) malloc (strlen (name) +1)) ) {
+           LOG(log_error, logtype_papd, "malloc: %m");
+           exit(1);
+       }
+       strcpy ( lp.lp_spoolfile, name);        
+
        if (lp.lp_person != NULL) {
            if ((pwent = getpwnam(lp.lp_person)) == NULL) {
                LOG(log_error, logtype_papd, "getpwnam %s: no such user", lp.lp_person);
@@ -390,9 +597,11 @@ int lp_open( out, sat )
            spoolerror( out, NULL );
            return( -1 );
        }
+#ifdef DEBUG        
+        LOG(log_debug, logtype_papd, "lp_open: opened %s", name );
+#endif 
     }
     lp.lp_flags |= LP_OPEN;
-
     return( 0 );
 }
 
@@ -404,18 +613,92 @@ int lp_close()
     fclose( lp.lp_stream );
     lp.lp_stream = NULL;
     lp.lp_flags &= ~LP_OPEN;
+    lp.lp_flags |= LP_JOBPENDING;
     return 0;
 }
 
-int lp_write( buf, len )
+
+
+int lp_write(in, buf, len )
+    struct papfile *in;
     char       *buf;
-    int                len;
+    size_t     len;
 {
+#define BUFSIZE 32768
+    static char tempbuf[BUFSIZE];
+    static char tempbuf2[BUFSIZE];
+    static size_t bufpos = 0;
+    static int last_line_translated = 1; /* if 0, append a \n a the start */
+    char *tbuf = buf;
+
+    /* Before we write out anything check for a pending job, e.g. cover page */
+    if (lp.lp_flags & LP_JOBPENDING)
+       lp_print();
+
+    /* foomatic doesn't handle mac line endings, so we convert them for 
+     * the Postscript headers
+     * REALLY ugly hack, remove ASAP again */
+    if ((printer->p_flags & P_FOOMATIC_HACK) && (in->pf_state & PF_TRANSLATE) && 
+        (buf[len-1] != '\n') ) {
+        if (len <= BUFSIZE) {
+           if (!last_line_translated) {
+               tempbuf2[0] = '\n';
+               memcpy(tempbuf2+1, buf, len++);
+           }
+           else
+               memcpy(tempbuf2, buf, len);
+               
+            if (tempbuf2[len-1] == '\r')
+               tempbuf2[len-1] = '\n';
+            tempbuf2[len] = 0;
+            tbuf = tempbuf2;
+            last_line_translated = 1;
+#ifdef DEBUG
+            LOG(log_debug, logtype_papd, "lp_write: %s", tbuf );
+#endif
+        }
+        else {
+            LOG(log_error, logtype_papd, "lp_write: conversion buffer too small" );
+            abort();
+        }
+    }
+    else {
+        if (printer->p_flags & P_FOOMATIC_HACK && buf[len-1] == '\n') {
+            last_line_translated = 1;
+       }
+        else
+           last_line_translated = 0;
+    }
+
+    /* To be able to do commandline substitutions on piped printers
+     * we store the start of the print job in a buffer.
+     * %%EndComment triggers writing to file */
     if (( lp.lp_flags & LP_OPEN ) == 0 ) {
-       return( -1 );
+#ifdef DEBUG
+        LOG(log_debug, logtype_papd, "lp_write: writing to temporary buffer" );
+#endif
+       if ((bufpos+len) > BUFSIZE) {
+            LOG(log_error, logtype_papd, "lp_write: temporary buffer too small" );
+            /* FIXME: call lp_open here? abort isn't nice... */
+            abort();
+        }
+       else {
+            memcpy(tempbuf + bufpos, tbuf, len);
+            bufpos += len;
+            if (bufpos > BUFSIZE/2)
+                in->pf_state |= PF_STW; /* we used half of the buffer, start writing */
+            return(0);
+       }
+    }
+    else if ( bufpos) {
+        if ( fwrite( tempbuf, 1, bufpos, lp.lp_stream ) != bufpos ) {
+            LOG(log_error, logtype_papd, "lp_write: %m" );
+            abort();
+        }
+        bufpos=0;
     }
 
-    if ( fwrite( buf, 1, len, lp.lp_stream ) != len ) {
+    if ( fwrite( tbuf, 1, len, lp.lp_stream ) != len ) {
        LOG(log_error, logtype_papd, "lp_write: %m" );
        abort();
     }
@@ -453,19 +736,23 @@ int lp_cancel()
  */
 int lp_print()
 {
+#ifndef HAVE_CUPS
     char               buf[ MAXPATHLEN ];
     char               tfname[ MAXPATHLEN ];
     char               cfname[ MAXPATHLEN ];
     char               letter;
     int                        fd, n, s;
     FILE               *cfile;
+#endif /* HAVE_CUPS */
 
     if (( lp.lp_flags & LP_INIT ) == 0 || lp.lp_letter == 'A' ) {
        return 0;
     }
     lp_close();
+    lp.lp_flags &= ~LP_JOBPENDING;
 
     if ( printer->p_flags & P_SPOOLED ) {
+#ifndef HAVE_CUPS
        sprintf( tfname, "tfA%03d%s", lp.lp_seq, hostname );
        if (( fd = open( tfname, O_WRONLY|O_EXCL|O_CREAT, 0660 )) < 0 ) {
            LOG(log_error, logtype_papd, "lp_print %s: %m", tfname );
@@ -541,11 +828,31 @@ int lp_print()
            LOG(log_error, logtype_papd, "lp_print lpd said %c: %m", buf[ 0 ] );
            return 0;
        }
+#else
+        if ( ! (lp.lp_job && *lp.lp_job) ) {
+            lp.lp_job = strdup("Mac Job");
+        }
+
+        lp_setup_comments(add_charset(cups_get_language ()));
+
+        if (lp.lp_person != NULL) {
+           cups_print_job ( printer->p_printer, lp.lp_spoolfile, lp.lp_job, lp.lp_person, printer->p_cupsoptions);
+        } else if (lp.lp_created_for != NULL) {
+            cups_print_job ( printer->p_printer, lp.lp_spoolfile, lp.lp_job, lp.lp_created_for, printer->p_cupsoptions);
+        } else {
+            cups_print_job ( printer->p_printer, lp.lp_spoolfile, lp.lp_job, printer->p_operator, printer->p_cupsoptions);
+        }
+
+       /*LOG(log_info, logtype_papd, "lp_print unlink %s", lp.lp_spoolfile );*/
+        unlink ( lp.lp_spoolfile );
+       return 0;
+#endif /* HAVE_CUPS*/
     }
     LOG(log_info, logtype_papd, "lp_print queued" );
     return 0;
 }
 
+#ifndef HAVE_CUPS
 int lp_disconn_unix( fd )
 {
     return( close( fd ));
@@ -586,7 +893,7 @@ int lp_conn_inet()
     struct hostent     *hp;
 
     if (( sp = getservbyname( "printer", "tcp" )) == NULL ) {
-       LOG(log_error, logtype_papd, "printer/tcp: unknown service\n" );
+       LOG(log_error, logtype_papd, "printer/tcp: unknown service" );
        return( -1 );
     }
 
@@ -596,7 +903,7 @@ int lp_conn_inet()
     }
 
     if (( hp = gethostbyname( hostname )) == NULL ) {
-       LOG(log_error, logtype_papd, "%s: unknown host\n", hostname );
+       LOG(log_error, logtype_papd, "%s: unknown host", hostname );
        return( -1 );
     }
 
@@ -812,3 +1119,4 @@ int lp_queue( out )
        }
     }
 }
+#endif /* HAVE_CUPS */
index 4d74f2a0aff84db1bebc8c2fd5120dcf83fc2e37..30a53074a2b6addd154537b647517f919447672f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: lp.h,v 1.3 2001-06-25 20:13:45 rufustfirefly Exp $
+ * $Id: lp.h,v 1.4 2005-04-28 20:49:49 bfernhomberg Exp $
  */
 
 #ifndef PAPD_LP_H
@@ -13,6 +13,8 @@ void lp_person __P(( char * ));
 int lp_pagecost __P(( void ));
 void lp_host __P(( char * ));
 void lp_job __P(( char * ));
+void lp_for __P(( char * ));
+void lp_origin __P(( int ));
 int lp_rmjob __P(( int ));
 int lp_queue __P(( struct papfile * ));
 
@@ -25,7 +27,7 @@ int lp_print __P(( void ));
 /* open a file for spooling */
 int lp_open __P(( struct papfile *, struct sockaddr_at * ));
 /* open a buffer to the current open file */
-int lp_write __P(( char *, int ));
+int lp_write __P(( struct papfile *,char *, size_t ));
 /* close current spooling file */
 int lp_close __P(( void ));
 
index 800c1854271097d95de6be8e03969d3f2a8766a8..6dc1d5ac1e1362ffa6d49f614d990b4a065ff5e8 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: magics.c,v 1.11 2003-02-17 01:34:35 srittau Exp $
+ * $Id: magics.c,v 1.12 2005-04-28 20:49:49 bfernhomberg Exp $
  *
  * Copyright (c) 1990,1994 Regents of The University of Michigan.
  * All Rights Reserved.  See COPYRIGHT.
@@ -21,6 +21,8 @@
 #include "comment.h"
 #include "lp.h"
 
+static int state=0;
+
 int ps( infile, outfile, sat )
     struct papfile     *infile, *outfile;
     struct sockaddr_at *sat;
@@ -30,6 +32,15 @@ int ps( infile, outfile, sat )
     struct papd_comment                *comment;
 
     for (;;) {
+        if ( infile->pf_state & PF_STW ) {
+               infile->pf_state &= ~PF_STW;
+               /* set up spool file */
+               if ( lp_open( outfile, sat ) < 0 && !state) {
+                   LOG(log_error, logtype_papd, "lp_open failed" );
+                   spoolerror( outfile, "Ignoring job." );
+               }
+               state = 1;
+       }       
        if ( (comment = compeek()) ) {
            switch( (*comment->c_handler)( infile, outfile, sat )) {
            case CH_DONE :
@@ -41,7 +52,6 @@ int ps( infile, outfile, sat )
            default :
                return( CH_ERROR );
            }
-
        } else {
            switch ( markline( infile, &start, &linelength, &crlflength )) {
            case 0 :
@@ -59,6 +69,7 @@ int ps( infile, outfile, sat )
                    compush( comment );
                    continue;   /* top of for (;;) */
                }
+#if 0
                infile->pf_state &= ~PF_BOT;
 
                /* set up spool file */
@@ -66,10 +77,11 @@ int ps( infile, outfile, sat )
                    LOG(log_error, logtype_papd, "lp_open failed" );
                    spoolerror( outfile, "Ignoring job." );
                }
+#endif
            }
 
            /* write to file */
-           lp_write( start, linelength + crlflength );
+           lp_write( infile, start, linelength + crlflength );
            CONSUME( infile, linelength + crlflength );
        }
     }
@@ -77,7 +89,7 @@ int ps( infile, outfile, sat )
 
 int cm_psquery( in, out, sat )
     struct papfile     *in, *out;
-    struct sockaddr_at *sat;
+    struct sockaddr_at *sat _U_;
 {
     struct papd_comment        *comment;
     char               *start;
@@ -110,7 +122,7 @@ int cm_psquery( in, out, sat )
 
 int cm_psadobe( in, out, sat )
     struct papfile     *in, *out;
-    struct sockaddr_at *sat;
+    struct sockaddr_at *sat _U_;
 {
     char               *start;
     int                        linelength, crlflength;
@@ -127,13 +139,14 @@ int cm_psadobe( in, out, sat )
        case -1 :
            return( CH_MORE );
        }
-
        if ( in->pf_state & PF_BOT ) {
            in->pf_state &= ~PF_BOT;
+#if 0
            if ( lp_open( out, sat ) < 0 ) {
                LOG(log_error, logtype_papd, "lp_open failed" );
                spoolerror( out, "Ignoring job." );
            }
+#endif
        } else {
            if (( comment = commatch( start, start + linelength, headers )) != NULL ) {
                compush( comment );
@@ -141,7 +154,7 @@ int cm_psadobe( in, out, sat )
            }
        }
 
-       lp_write( start, linelength + crlflength );
+       lp_write( in, start, linelength + crlflength );
        CONSUME( in, linelength + crlflength );
     }
 }
@@ -150,7 +163,7 @@ char        *Query = "Query";
 
 int cm_psswitch( in, out, sat )
     struct papfile     *in, *out;
-    struct sockaddr_at *sat;
+    struct sockaddr_at *sat _U_;
 {
     char               *start, *stop, *p;
     int                        linelength, crlflength;
@@ -193,9 +206,10 @@ int cm_psswitch( in, out, sat )
     return( CH_DONE );
 }
 
+
 struct papd_comment    magics[] = {
-    { "%!PS-Adobe-3.0 Query",  0,                      cm_psquery, C_FULL },
-    { "%!PS-Adobe-3.0",                0,                      cm_psadobe, C_FULL },
-    { "%!PS-Adobe-",           0,                      cm_psswitch,    0 },
-    { 0 },
+    { "%!PS-Adobe-3.0 Query",  NULL,                   cm_psquery, C_FULL },
+    { "%!PS-Adobe-3.0",                NULL,                   cm_psadobe, C_FULL },
+    { "%!PS-Adobe-",           NULL,                   cm_psswitch,    0 },
+    { NULL,                    NULL,                   NULL,           0 },
 };
index 4f83c7a5f7ccb7508f50d2e03e4347d2a31ca7e4..48723df01f031f16c812f6d616cfa2087394c028 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: main.c,v 1.18 2003-02-17 01:31:51 srittau Exp $
+ * $Id: main.c,v 1.19 2005-04-28 20:49:49 bfernhomberg Exp $
  *
  * Copyright (c) 1990,1995 Regents of The University of Michigan.
  * All Rights Reserved.  See COPYRIGHT.
@@ -68,11 +68,13 @@ char *strchr (), *strrchr ();
 #include <atalk/paths.h>
 #include <atalk/util.h>
 #include <atalk/nbp.h>
+#include <atalk/unicode.h>
 
 #include "printer.h"
 #include "printcap.h"
 #include "session.h"
 #include "uam_auth.h"
+#include "print_cups.h"
 
 #define _PATH_PAPDPPDFILE      ".ppd"
 
@@ -121,13 +123,20 @@ die( n )
     for ( pr = printers; pr; pr = pr->p_next ) {
        if ( pr->p_flags & P_REGISTERED ) {
            if ( nbp_unrgstr( pr->p_name, pr->p_type, pr->p_zone, &addr ) < 0 ) {
-               LOG(log_error, logtype_papd, "can't unregister %s:%s@%s\n", pr->p_name,
+               LOG(log_error, logtype_papd, "can't unregister %s:%s@%s", pr->p_name,
                        pr->p_type, pr->p_zone );
                papd_exit( n + 1 );
            }
-           LOG(log_error, logtype_papd, "unregister %s:%s@%s\n", pr->p_name, pr->p_type,
+           LOG(log_info, logtype_papd, "unregister %s:%s@%s", pr->p_name, pr->p_type,
                    pr->p_zone );
        }
+#ifdef HAVE_CUPS
+       if ( pr->p_flags & P_SPOOLED && pr->p_flags & P_CUPS_PPD ) {
+               LOG(log_info, logtype_papd, "Deleting CUPS temp PPD file for %s (%s)", pr->p_name, pr->p_ppdfile);
+               unlink (pr->p_ppdfile);
+       }
+#endif /* HAVE_CUPS */
+
     }
     papd_exit( n );
 }
@@ -178,6 +187,7 @@ int main( ac, av )
     char               *p, hostname[ MAXHOSTNAMELEN ];
     char               cbuf[ 8 ];
     int                        c;
+    char               *atname;
 
     if ( gethostname( hostname, sizeof( hostname )) < 0 ) {
        perror( "gethostname" );
@@ -247,7 +257,6 @@ int main( ac, av )
        }
     }
 
-    getprinters( conffile );
 
     switch (server_lock("papd", pidfile, debug)) {
     case 0: /* open a couple things again in the child */
@@ -262,6 +271,10 @@ int main( ac, av )
       exit(0);
     }      
 
+#ifdef DEBUG1
+    fault_setup(NULL);
+#endif
+
     /*
      * Start logging.
      */
@@ -278,28 +291,41 @@ int main( ac, av )
 #endif /* ultrix */
 
     LOG(log_info, logtype_papd, "restart (%s)", version );
+#ifdef HAVE_CUPS
+    LOG(log_info, logtype_papd, "CUPS support enabled (%s)", CUPS_API_VERSION );
+#endif
+
+    getprinters( conffile );
 
     for ( pr = printers; pr; pr = pr->p_next ) {
        if (( pr->p_flags & P_SPOOLED ) && rprintcap( pr ) < 0 ) {
            LOG(log_error, logtype_papd, "printcap problem: %s", pr->p_printer );
        }
+
+       if (!(pr->p_flags & P_CUPS)) {
+               if ((size_t)-1 != convert_string_allocate(CH_UNIX, CH_MAC, pr->p_name, strlen(pr->p_name), &atname)) {
+                       pr->p_u_name = pr->p_name;
+                       pr->p_name = atname;
+               }
+       }
+                       
        if (( pr->p_atp = atp_open( ATADDR_ANYPORT, &pr->p_addr )) == NULL ) {
            LOG(log_error, logtype_papd, "atp_open: %m" );
            papd_exit( 1 );
        }
        if ( nbp_rgstr( atp_sockaddr( pr->p_atp ), pr->p_name, pr->p_type,
                pr->p_zone ) < 0 ) {
-           LOG(log_error, logtype_papd, "can't register %s:%s@%s", pr->p_name, pr->p_type,
+           LOG(log_error, logtype_papd, "can't register %s:%s@%s", pr->p_u_name, pr->p_type,
                    pr->p_zone );
            die( 1 );
        }
        if ( pr->p_flags & P_AUTH ) {
-               LOG(log_info, logtype_papd, "Authentication enabled: %s", pr->p_name );
+               LOG(log_info, logtype_papd, "Authentication enabled: %s", pr->p_u_name );
        }
        else {
-               LOG(log_info, logtype_papd, "Authentication disabled: %s", pr->p_name );
+               LOG(log_info, logtype_papd, "Authentication disabled: %s", pr->p_u_name );
        }
-       LOG(log_info, logtype_papd, "register %s:%s@%s", pr->p_name, pr->p_type,
+       LOG(log_info, logtype_papd, "register %s:%s@%s", pr->p_u_name, pr->p_type,
                pr->p_zone );
        pr->p_flags |= P_REGISTERED;
     }
@@ -384,6 +410,23 @@ int main( ac, av )
                        err = 1;
                    }
 
+#ifdef HAVE_CUPS
+                  /*
+                   * If cups is not accepting jobs, we return
+                   * 0xffff to indicate we're busy
+                   */
+#ifdef DEBUG
+                    LOG(log_debug, logtype_papd, "CUPS: PAP_OPEN");
+#endif
+                   if ( (pr->p_flags & P_SPOOLED) && (cups_get_printer_status ( pr ) == 0)) {
+                        LOG(log_error, logtype_papd, "CUPS_PAP_OPEN: %s is not accepting jobs",
+                                pr->p_printer );
+                        rbuf[ 2 ] = rbuf[ 3 ] = 0xff;
+                        err = 1;
+                    }
+#endif /* HAVE_CUPS */
+
+
                    /*
                     * If this fails, we've run out of sockets. Rather than
                     * just die(), let's try to continue. Maybe some sockets
@@ -423,11 +466,20 @@ int main( ac, av )
                    case 0 : /* child */
                        printer = pr;
 
+                       #ifndef HAVE_CUPS
                        if (( printer->p_flags & P_SPOOLED ) &&
                                chdir( printer->p_spool ) < 0 ) {
                            LOG(log_error, logtype_papd, "chdir %s: %m", printer->p_spool );
                            exit( 1 );
                        }
+                       #else
+                       if (( printer->p_flags & P_SPOOLED ) &&
+                               chdir( SPOOLDIR ) < 0 ) {
+                           LOG(log_error, logtype_papd, "chdir %s: %m", SPOOLDIR );
+                           exit( 1 );
+                       }
+
+                       #endif
 
                        sv.sa_handler = SIG_DFL;
                        sigemptyset( &sv.sa_mask );
@@ -513,6 +565,20 @@ int getstatus( pr, buf )
     struct printer     *pr;
     char               *buf;
 {
+
+#ifdef HAVE_CUPS
+    if ( pr->p_flags & P_PIPED ) {
+       *buf = strlen( cannedstatus );
+       strncpy( &buf[ 1 ], cannedstatus, *buf );
+       return( *buf + 1 );
+    } else {
+       cups_get_printer_status( pr );
+       *buf = strlen ( pr->p_status );
+       strncpy ( &buf[1], pr->p_status, *buf);
+       return ( *buf + 1);
+    }
+#else
+
     char               path[ MAXPATHLEN ];
     int                        fd = -1, rc;
 
@@ -537,6 +603,7 @@ int getstatus( pr, buf )
        *buf = rc;
        return( rc + 1 );
     }
+#endif /* HAVE_CUPS */
 }
 
 char   *pgetstr();
@@ -689,8 +756,42 @@ static void getprinters( cf )
        else 
            atalk_aton(p, &pr->p_addr);
 
-       pr->p_next = printers;
-       printers = pr;
+#ifdef HAVE_CUPS
+       if ((p = pgetstr("co", &a)) != NULL ) {
+            pr->p_cupsoptions = strdup(p);
+            LOG (log_error, logtype_papd, "enabling cups-options for %s: %s", pr->p_name, pr->p_cupsoptions);
+       }
+#endif
+
+       /* convert line endings for setup sections.
+           real ugly work around for foomatic deficiencies,
+          need to get rid of this */
+       if ( pgetflag("fo") == 1 ) {
+            pr->p_flags |= P_FOOMATIC_HACK;
+            LOG (log_error, logtype_papd, "enabling foomatic hack for %s", pr->p_name);
+       }
+
+       if (strncasecmp (pr->p_name, "cupsautoadd", 11) == 0)
+       {
+#ifdef HAVE_CUPS
+               pr = cups_autoadd_printers (pr, printers);
+               printers = pr;
+#else
+               LOG (log_error, logtype_papd, "cupsautoadd: Cups support not compiled in");
+#endif /* HAVE_CUPS */
+       }
+       else {
+#ifdef HAVE_CUPS
+               if ( cups_check_printer ( pr, printers, 1) == 0)
+               {
+                       pr->p_next = printers;
+                       printers = pr;
+               }
+#else
+               pr->p_next = printers;
+               printers = pr;
+#endif /* HAVE_CUPS */
+       }
     }
     if ( c == 0 ) {
        endprent();
@@ -702,6 +803,37 @@ static void getprinters( cf )
 int rprintcap( pr )
     struct printer     *pr;
 {
+
+#ifdef HAVE_CUPS
+
+    char               *p;
+
+    if ( pr->p_flags & P_SPOOLED && !(pr->p_flags & P_CUPS_AUTOADDED) ) { /* Skip check if autoadded */
+       if ( cups_printername_ok ( pr->p_printer ) != 1) {
+           LOG(log_error, logtype_papd, "No such CUPS printer: '%s'", pr->p_printer );
+           return( -1 );
+       }
+    }
+
+    /*
+     * Check for ppd file, moved here because of cups_autoadd we cannot check at the usual location
+     */
+
+    if ( pr->p_ppdfile == defprinter.p_ppdfile ) {
+       if ( (p = (char *) cups_get_printer_ppd ( pr->p_printer )) != NULL ) {
+           if (( pr->p_ppdfile = (char *)malloc( strlen( p ) + 1 )) == NULL ) {
+               LOG(log_error, logtype_papd, "malloc: %m" );
+               exit( 1 );
+           }
+           strcpy( pr->p_ppdfile, p );
+           pr->p_flags |= P_CUPS_PPD;
+           /*LOG(log_info, logtype_papd, "PPD File for %s set to %s", pr->p_printer, pr->p_ppdfile );*/
+       }
+    }
+
+
+#else
+
     char               buf[ 1024 ], area[ 1024 ], *a, *p;
     int                        c;
 
@@ -819,6 +951,7 @@ int rprintcap( pr )
 
        endprent();
     }
+#endif /* HAVE_CUPS */
 
     return( 0 );
 }
index dcaea66fc91f8bc8b25868cb1959dd9741b194a4..5710d9473acefa8dc13881db06dc13c7e46073f9 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: ppd.c,v 1.9 2002-09-29 23:29:14 sibaz Exp $
+ * $Id: ppd.c,v 1.10 2005-04-28 20:49:49 bfernhomberg Exp $
  *
  * Copyright (c) 1995 Regents of The University of Michigan.
  * All Rights Reserved.  See COPYRIGHT.
@@ -27,7 +27,11 @@ struct ppd_font              *ppd_fonts = NULL;
 struct ppd_feature     ppd_features[] = {
     { "*LanguageLevel",        0 },
     { "*PSVersion",    0 },
+#ifdef HAVE_CUPS
+    { "*FreeVM",       "33554432" },
+#else
     { "*FreeVM",       0 },
+#endif
     { "*Product",      0 },
     { "*PCFileName",   0 },
     { "*ModelName",    0 },
@@ -59,6 +63,35 @@ int ppd_init()
 }
 #endif /* SHOWPPD */
 
+
+/* quick and ugly hack to be able to read
+   ppd files with Mac line ending */
+static char* my_fgets(buf, bufsize, stream) 
+    char   *buf;
+    size_t bufsize;
+    FILE   *stream;
+{
+    int p;           /* uninitialized, OK 310105 */
+    size_t count = 0;
+    while (count < bufsize && EOF != (p=fgetc(stream))) {
+        buf[count] = p;
+        count++;
+        if ( p == '\r' || p == '\n')
+           break;
+    }
+
+    if (p == EOF && count == 0)
+        return NULL;
+
+    /* translate line endings */
+    if ( buf[count - 1] == '\r')
+        buf[count - 1] = '\n';
+
+    buf[count] = 0;
+    return buf;
+}
+
 struct ppdent *getppdent( stream )
     FILE       *stream;
 {
@@ -69,11 +102,11 @@ struct ppdent *getppdent( stream )
     ppdent.pe_main = ppdent.pe_option = ppdent.pe_translation =
            ppdent.pe_value = NULL;
 
-    while (( p = fgets( buf, sizeof( buf ), stream )) != NULL ) {
+    while (( p = my_fgets( buf, sizeof( buf ), stream )) != NULL ) {
        if ( *p != '*' ) {      /* main key word */
            continue;
        }
-       if ( p[ strlen( p ) - 1 ] != '\n' ) {
+       if ( p[ strlen( p ) - 1 ] != '\n' && p[ strlen( p ) - 1 ] != '\r') {
            LOG(log_error, logtype_papd, "getppdent: line too long" );
            continue;
        }
@@ -204,7 +237,7 @@ int read_ppd( file, fcnt )
                break;
            }
        }
-       if ( pfe->pd_name && (pfe->pd_value == NULL) ) {
+       if ( pfe->pd_name ) { /*&& (pfe->pd_value == NULL) ) { */
            if (( pfe->pd_value =
                    (char *)malloc( strlen( pe->pe_value ) + 1 )) == NULL ) {
                LOG(log_error, logtype_papd, "malloc: %m" );
diff --git a/etc/papd/print_cups.c b/etc/papd/print_cups.c
new file mode 100644 (file)
index 0000000..e4f9b3e
--- /dev/null
@@ -0,0 +1,646 @@
+/*
+ * $Id: print_cups.c,v 1.2 2005-04-28 20:49:49 bfernhomberg Exp $
+ *
+ * Copyright 2004 Bjoern Fernhomberg.
+ *
+ * Some code copied or adapted from print_cups.c for samba
+ * Copyright 1999-2003 by Michael R Sweet.
+ *
+ * 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 /* HAVE_CONFIG_H */
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#include <sys/types.h>
+#include <sys/param.h>
+#include <errno.h>
+
+
+#ifdef HAVE_CUPS
+
+#include <cups/cups.h>
+#include <cups/language.h>
+#include <atalk/unicode.h>
+#include <atalk/logger.h>
+#include <atalk/atp.h>
+#include <atalk/pap.h>
+#include <atalk/util.h>
+
+#include "printer.h"
+#include "print_cups.h"
+
+#define MAXCHOOSERLEN 31
+#define HTTP_MAX_URI 1024
+
+static const char* cups_status_msg[] = {
+        "status: busy; info: \"%s\" is rejecting jobs; ",
+        "status: idle; info: \"%s\" is stopped, accepting jobs ;",
+        "status: idle; info: \"%s\" is ready ; ",
+};
+
+/* Local functions */
+static int     convert_to_mac_name ( char *encoding, char * inptr, char * outptr, size_t outlen);
+static size_t  to_ascii ( char *inbuf, char **outbuf);
+static int     cups_mangle_printer_name ( struct printer *pr, struct printer *printers);
+static void     cups_free_printer ( struct printer *pr);
+
+
+char * cups_get_language ()
+{
+        cups_lang_t *language;
+
+        language = cupsLangDefault();           /* needed for conversion */
+        return cupsLangEncoding(language);
+}
+
+/*
+ * 'cups_passwd_cb()' - The CUPS password callback...
+ */
+
+static const char *                            /* O - Password or NULL */
+cups_passwd_cb(const char *prompt _U_)      /* I - Prompt */
+{
+ /*
+  * Always return NULL to indicate that no password is available...
+  */
+  return (NULL);
+}
+
+
+/*
+ * 'cups_printername_ok()' - Verify supplied printer name is a valid cups printer
+ */
+
+int                                     /* O - 1 if printer name OK */
+cups_printername_ok(char *name)         /* I - Name of printer */
+{
+        http_t          *http;          /* HTTP connection to server */
+        ipp_t           *request,       /* IPP Request */
+                        *response;      /* IPP Response */
+        cups_lang_t     *language;      /* Default language */
+        char            uri[HTTP_MAX_URI]; /* printer-uri attribute */
+
+       /*
+        * Make sure we don't ask for passwords...
+        */
+
+        cupsSetPasswordCB(cups_passwd_cb);
+
+       /*
+        * Try to connect to the server...
+        */
+
+        if ((http = httpConnect(cupsServer(), ippPort())) == NULL)
+        {
+               LOG(log_error, logtype_papd, "Unable to connect to CUPS server %s - %s",
+                         cupsServer(), strerror(errno));
+                return (0);
+        }
+
+
+       /*
+        * Build an IPP_GET_PRINTER_ATTRS request, which requires the following
+        * attributes:
+        *
+        *    attributes-charset
+        *    attributes-natural-language
+        *    requested-attributes
+        *    printer-uri
+        */
+
+        request = ippNew();
+
+        request->request.op.operation_id = IPP_GET_PRINTER_ATTRIBUTES;
+        request->request.op.request_id   = 1;
+
+        language = cupsLangDefault();
+
+        ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
+                     "attributes-charset", NULL, cupsLangEncoding(language));
+
+        ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
+                     "attributes-natural-language", NULL, language->language);
+
+        ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
+                     "requested-attributes", NULL, "printer-uri");
+
+        sprintf(uri, "ipp://localhost/printers/%s", name);
+
+        ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
+                     "printer-uri", NULL, uri);
+
+       /*
+        * Do the request and get back a response...
+        */
+
+        if ((response = cupsDoRequest(http, request, "/")) == NULL)
+        {
+               LOG(log_error, logtype_papd, "Unable to get printer status for %s - %s", name,
+                         ippErrorString(cupsLastError()));
+                httpClose(http);
+                return (0);
+        }
+
+        httpClose(http);
+
+        if (response->request.status.status_code >= IPP_OK_CONFLICT)
+        {
+               LOG(log_error, logtype_papd, "Unable to get printer status for %s - %s", name,
+                         ippErrorString(response->request.status.status_code));
+                ippDelete(response);
+                return (0);
+        }
+        else
+        {
+                ippDelete(response);
+                return (1);
+        }
+
+       return (0);
+}
+
+const char * 
+cups_get_printer_ppd ( char * name)
+{
+       cupsSetPasswordCB(cups_passwd_cb);
+       return cupsGetPPD( name );
+}
+
+int
+cups_get_printer_status (struct printer *pr)
+{
+
+        http_t          *http;          /* HTTP connection to server */
+        ipp_t           *request,       /* IPP Request */
+                        *response;      /* IPP Response */
+        ipp_attribute_t *attr;          /* Current attribute */
+        cups_lang_t     *language;      /* Default language */
+        char            uri[HTTP_MAX_URI]; /* printer-uri attribute */
+       int             status = -1;
+
+        static const char *pattrs[] =   /* Requested printer attributes */
+                        {
+                          "printer-state",
+                          "printer-state-message",
+                         "printer-is-accepting-jobs"
+                        };
+
+       /*
+        * Make sure we don't ask for passwords...
+        */
+
+        cupsSetPasswordCB(cups_passwd_cb);
+
+       /*
+        * Try to connect to the server...
+        */
+
+        if ((http = httpConnect(cupsServer(), ippPort())) == NULL)
+        {
+               LOG(log_error, logtype_papd, "Unable to connect to CUPS server %s - %s",
+                         cupsServer(), strerror(errno));
+                return (0);
+        }
+
+       /*
+        * Generate the printer URI...
+        */
+
+        sprintf(uri, "ipp://localhost/printers/%s", pr->p_printer);
+
+
+
+       /*
+        * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the
+        * following attributes:
+        *
+        *    attributes-charset
+        *    attributes-natural-language
+        *    requested-attributes
+        *    printer-uri
+        */
+
+        request = ippNew();
+
+        request->request.op.operation_id = IPP_GET_PRINTER_ATTRIBUTES;
+        request->request.op.request_id   = 1;
+
+        language = cupsLangDefault();
+
+        ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
+                     "attributes-charset", NULL, cupsLangEncoding(language));
+
+        ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
+                     "attributes-natural-language", NULL, language->language);
+
+        ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
+                      "requested-attributes",
+                      (sizeof(pattrs) / sizeof(pattrs[0])),
+                      NULL, pattrs);
+
+        ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
+                     "printer-uri", NULL, uri);
+
+       /*
+        * Do the request and get back a response...
+        */
+
+        if ((response = cupsDoRequest(http, request, "/")) == NULL)
+        {
+               LOG(log_error, logtype_papd, "Unable to get printer status for %s - %s", pr->p_printer,
+                         ippErrorString(cupsLastError()));
+                httpClose(http);
+                return (0);
+        }
+
+        if (response->request.status.status_code >= IPP_OK_CONFLICT)
+        {
+               LOG(log_error, logtype_papd, "Unable to get printer status for %s - %s", pr->p_printer,
+                         ippErrorString(response->request.status.status_code));
+                ippDelete(response);
+                httpClose(http);
+                return (0);
+        }
+
+       /*
+        * Get the current printer status and convert it to the status values.
+        */
+
+       memset ( pr->p_status, 0 ,sizeof(pr->p_status));
+
+        if ((attr = ippFindAttribute(response, "printer-state", IPP_TAG_ENUM)) != NULL)
+        {
+                if (attr->values[0].integer == IPP_PRINTER_STOPPED)
+                       status = 1;
+                else if (attr->values[0].integer == IPP_NOT_ACCEPTING)
+                       status = 0;
+               else
+                       status = 2;
+        }
+
+       if ((attr = ippFindAttribute(response, "printer-is-accepting-jobs", IPP_TAG_BOOLEAN)) != NULL)
+       {
+               if ( attr->values[0].integer == 0 ) 
+                       status = 0;
+       }
+               
+       snprintf ( pr->p_status, 255, cups_status_msg[status], pr->p_printer );
+
+        if ((attr = ippFindAttribute(response, "printer-state-message", IPP_TAG_TEXT)) != NULL)
+               strncat ( pr->p_status, attr->values[0].string.text, 255-strlen(pr->p_status));
+
+        ippDelete(response);
+
+       /*
+        * Return the print status ...
+        */
+
+        httpClose(http);
+
+       return (status);
+}
+
+
+/*------------------------------------------------------------------------*/
+
+/* pass the job to cups */
+
+int cups_print_job ( char * name, char *filename, char *job, char *username, char * cupsoptions )
+{
+       int             jobid;
+       char            filepath[MAXPATHLEN];
+       int             num_options;
+       cups_option_t   *options;
+
+       /* Initialize the options array */
+       num_options = 0;
+       options     = (cups_option_t *)0;
+
+        cupsSetPasswordCB(cups_passwd_cb);
+
+       if ( username != NULL )
+       {
+               /* Add options using cupsAddOption() */
+               num_options = cupsAddOption("job-originating-user-name", username, num_options, &options);
+               num_options = cupsAddOption("originating-user-name", username, num_options, &options);
+               cupsSetUser ( username );
+       }
+
+       if (cupsoptions != NULL)
+       {
+              num_options = cupsParseOptions(cupsoptions, num_options, &options);
+       }
+       
+       strlcpy ( filepath, SPOOLDIR, sizeof(filepath));
+       strlcat ( filepath , "/", sizeof(filepath));
+       strlcat ( filepath , filename, sizeof(filepath));
+       
+       if ((jobid = cupsPrintFile( name, filepath, job, 0, options)) == 0)
+               LOG(log_error, logtype_papd, "Unable to print job '%s' (%s) to printer '%s' for user '%s' - CUPS error : '%s'", job, filepath, name, username, ippErrorString(cupsLastError()));
+       else 
+               LOG(log_info, logtype_papd, "Job '%s' queued to printer '%s' with id '%d'", job, name, jobid);
+
+       cupsFreeOptions(num_options, options);
+       return (jobid);
+}
+
+
+/*------------------------------------------------------------------------*/
+
+struct printer *
+cups_autoadd_printers ( struct printer *defprinter, struct printer *printers)
+{
+       struct printer  *pr;
+        int            num_dests,i;
+       int             ret;
+        cups_dest_t    *dests;
+        cups_lang_t    *language;
+       char            name[MAXCHOOSERLEN+1], *p;
+
+        language  = cupsLangDefault();         /* needed for conversion */
+        num_dests = cupsGetDests(&dests);      /* get the available destination from CUPS */
+
+        for  (i=0; i< num_dests; i++)
+        {
+               if (( pr = (struct printer *)malloc( sizeof( struct printer ))) == NULL ) {
+                       LOG(log_error, logtype_papd, "malloc: %m" );
+                       exit( 1 );
+               }
+       
+               memcpy( pr, defprinter, sizeof( struct printer ) );
+
+               /* convert from CUPS to local encoding */
+                convert_string_allocate( add_charset(cupsLangEncoding(language)), CH_UNIX, 
+                                         dests[i].name, strlen(dests[i].name), &pr->p_u_name);
+
+               /* convert CUPS name to Mac charset */
+               if ( convert_to_mac_name ( cupsLangEncoding(language), dests[i].name, name, sizeof(name)) <= 0)
+               {
+                       LOG (log_error, logtype_papd, "Conversion from CUPS to MAC name failed for %s", dests[i].name);
+                       free (pr);
+                       continue;
+               }
+
+               if (( pr->p_name = (char *)malloc( strlen( name ) + 1 )) == NULL ) {
+                       LOG(log_error, logtype_papd, "malloc: %m" );
+                       exit( 1 );
+               }
+               strcpy( pr->p_name, name );
+
+               /* set printer flags */
+               pr->p_flags &= ~P_PIPED;
+               pr->p_flags |= P_SPOOLED;
+               pr->p_flags |= P_CUPS;
+               pr->p_flags |= P_CUPS_AUTOADDED;
+                       
+               if (( pr->p_printer = (char *)malloc( strlen( dests[i].name ) + 1 )) == NULL ) {
+                       LOG(log_error, logtype_papd, "malloc: %m" );
+                               exit( 1 );
+               }
+               strcpy( pr->p_printer, dests[i].name );                 
+
+               if ( (p = (char *) cups_get_printer_ppd ( pr->p_printer )) != NULL ) {
+                       if (( pr->p_ppdfile = (char *)malloc( strlen( p ) + 1 )) == NULL ) {
+                               LOG(log_error, logtype_papd, "malloc: %m" );
+                                       exit( 1 );
+                       }
+                       strcpy( pr->p_ppdfile, p );
+                       pr->p_flags |= P_CUPS_PPD;
+               }
+
+               if ( (ret = cups_check_printer ( pr, printers, 0)) == -1) 
+                       ret = cups_mangle_printer_name ( pr, printers );
+
+               if (ret) {
+                       cups_free_printer (pr);
+                       LOG(log_info, logtype_papd, "Printer %s not added: reason %d", name, ret);
+               }
+               else {
+                       pr->p_next = printers;
+                       printers = pr;
+               }
+       }
+        cupsFreeDests(num_dests, dests);
+        cupsLangFree(language);
+
+       return printers;
+}
+
+
+/*------------------------------------------------------------------------*/
+
+/* cups_mangle_printer_name
+ *    Mangles the printer name if two CUPS printer provide the same Chooser Name
+ *    Append '#nn' to the chooser name, if it is longer than 28 char we overwrite the last three chars
+ * Returns: 0 on Success, 2 on Error
+ */
+
+static int cups_mangle_printer_name ( struct printer *pr, struct printer *printers)
+{
+       size_t  count, name_len;
+       char    name[MAXCHOOSERLEN];
+
+       count = 1;
+       name_len = strlen (pr->p_name);
+       strncpy ( name, pr->p_name, MAXCHOOSERLEN-3);
+       
+       /* Reallocate necessary space */
+       (name_len >= MAXCHOOSERLEN-3) ? (name_len = MAXCHOOSERLEN+1) : (name_len = name_len + 4);
+       pr->p_name = (char *) realloc (pr->p_name, name_len );
+               
+       while ( ( cups_check_printer ( pr, printers, 0 )) && count < 100)
+       {
+               memset ( pr->p_name, 0, name_len);
+               strncpy ( pr->p_name, name, MAXCHOOSERLEN-3);
+               sprintf ( pr->p_name, "%s#%2.2u", pr->p_name, count++);
+       }
+
+       if ( count > 99) 
+               return (2);
+       
+       return (0);
+}      
+
+/*------------------------------------------------------------------------*/
+
+/* fallback ASCII conversion */
+
+static size_t
+to_ascii ( char  *inptr, char **outptr)
+{
+       char *out, *osav;
+
+       if ( NULL == (out = (char*) malloc ( strlen ( inptr) + 1 )) ) {
+               LOG(log_error, logtype_papd, "malloc: %m" );
+               exit (1);
+       }
+
+       osav = out;
+
+       while ( *inptr != '\0' ) {
+               if ( *inptr & 0x80 ) {
+                       *out = '_';
+                       out++;
+                       inptr++;
+               }
+               else
+                       *out++ = *inptr++;
+       }
+       *out = '\0';
+       *outptr = osav;
+       return ( strlen (osav) );
+}
+
+
+/*------------------------------------------------------------------------*/
+
+/* convert_to_mac_name
+ *     1) Convert from encoding to MacRoman
+ *     2) Shorten to MAXCHOOSERLEN (31)
+ *      3) Replace @ and _ as they are illegal
+ * Returns: -1 on failure, length of name on success; outpr contains name in MacRoman
+ */
+
+static int convert_to_mac_name ( char * encoding, char * inptr, char * outptr, size_t outlen)
+{
+       char    *outbuf;
+       char    *soptr;
+       size_t  name_len = 0;
+       size_t  i;
+       charset_t chCups;
+
+       /* Change the encoding */
+       if ((charset_t)-1 != (chCups = add_charset(encoding))) {
+               name_len = convert_string_allocate( chCups, CH_MAC, inptr, strlen(inptr), &outbuf);
+       }
+
+       if (name_len == 0 || name_len == (size_t)-1) {
+               /* charset conversion failed, use ascii fallback */
+               name_len = to_ascii ( inptr, &outbuf );
+       }
+       
+       soptr = outptr;
+
+       for ( i=0; i< name_len && i < outlen-1 ; i++)
+       {
+               if ( outbuf[i] == '_' ) 
+                       *soptr = ' '; /* Replace '_' with a space (just for the looks) */
+               else if ( outbuf[i] == '@' || outbuf[i] == ':' ) 
+                       *soptr = '_'; /* Replace @ and : with '_' as they are illegal chars */
+               else
+                       *soptr = outbuf[i];
+               soptr++;
+       }
+       *soptr = '\0';
+       free (outbuf);
+       return (i);
+}
+
+
+/*------------------------------------------------------------------------*/
+
+/*
+ * cups_check_printer:
+ * check if a printer with this name already exists.
+ * if yes, and replace = 1 the existing printer is replaced with
+ * the new one. This allows to overwrite printer settings
+ * created by cupsautoadd. It also used by cups_mangle_printer.
+ */
+
+int cups_check_printer ( struct printer *pr, struct printer *printers, int replace)
+{
+       struct printer *listptr, *listprev;
+
+       listptr = printers;
+       listprev = NULL;
+
+       while ( listptr != NULL) {
+               if ( strcasecmp (pr->p_name, listptr->p_name) == 0) {
+                       if ( pr->p_flags & P_CUPS_AUTOADDED ) {  /* Check if printer has been autoadded */
+                               if ( listptr->p_flags & P_CUPS_AUTOADDED )
+                                       return (-1);             /* Conflicting Cups Auto Printer (mangling issue?) */
+                               else
+                                       return (1);              /* Never replace a hand edited printer with auto one */
+                       }
+
+                       if ( replace ) {
+                               /* Replace printer */
+                               if ( listprev != NULL) {
+                                       pr->p_next = listptr->p_next;
+                                       listprev->p_next = pr;
+                                       cups_free_printer (listptr);
+                               }
+                               else {
+                                       printers = pr;
+                                       printers->p_next = listptr->p_next;
+                                       cups_free_printer (listptr);
+                               }
+                       }
+                       return (1);  /* Conflicting Printers */
+               }
+               listprev = listptr;
+               listptr = listptr->p_next;
+       }       
+       return (0);     /* No conflict */
+}
+
+
+/*------------------------------------------------------------------------*/
+
+
+void
+cups_free_printer ( struct printer *pr)
+{
+       if ( pr->p_name != NULL)
+               free (pr->p_name);
+       if ( pr->p_printer != NULL)
+               free (pr->p_printer);
+       if ( pr->p_ppdfile != NULL)
+               free (pr->p_ppdfile);
+       
+       /* CUPS autoadded printers share the other informations
+        * so if the printer is autoadded we won't free them.
+        * We might leak some bytes here though.
+        */
+       if ( pr->p_flags & P_CUPS_AUTOADDED ) {
+               free (pr);
+               return;
+       }
+
+       if ( pr->p_operator != NULL )
+               free (pr->p_operator);
+       if ( pr->p_zone != NULL )
+               free (pr->p_zone);
+       if ( pr->p_type != NULL )
+               free (pr->p_type);
+       if ( pr->p_authprintdir != NULL )
+               free (pr->p_authprintdir);
+       
+       free ( pr );
+       return;
+       
+}
+       
+#endif /* HAVE_CUPS*/
diff --git a/etc/papd/print_cups.h b/etc/papd/print_cups.h
new file mode 100644 (file)
index 0000000..2811a84
--- /dev/null
@@ -0,0 +1,21 @@
+\r
+#ifndef PAPD_CUPS_H\r
+#define PAPD_CUPS_H 1\r
+\r
+#ifdef HAVE_CUPS\r
+#include <sys/cdefs.h>\r
+\r
+struct cups_status {\r
+       int     pr_status;\r
+       char *  status_message;\r
+};\r
+\r
+int            cups_printername_ok __P((char * ));\r
+const char *   cups_get_printer_ppd __P(( char * ));\r
+int            cups_get_printer_status __P((struct printer *pr));\r
+int            cups_print_job __P(( char *, char *, char *, char *, char *));\r
+struct printer * cups_autoadd_printers __P(( struct printer *, struct printer *));\r
+int            cups_check_printer __P(( struct printer *, struct printer *, int));\r
+char           *cups_get_language __P(());\r
+#endif /* HAVE_CUPS */\r
+#endif /* PAPD_CUPS_H */\r
index 9bc00446d95507b799e21202a5c4c26c8e0fae9b..19ed788331cc8351de1a76774a9fe532b0930f33 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: printcap.c,v 1.9 2003-02-17 01:33:01 srittau Exp $
+ * $Id: printcap.c,v 1.10 2005-04-28 20:49:49 bfernhomberg Exp $
  *
  * Copyright (c) 1990,1994 Regents of The University of Michigan.
  * All Rights Reserved.  See COPYRIGHT.
@@ -118,6 +118,10 @@ int getprent( cap, bp, bufsize )
        for (;;) {
                switch (c = getc(pfp)) {
                case EOF:
+                        if (bp != tbuf) {
+                               *bp = '\0';
+                               return(1);
+                       }
                        fclose(pfp);
                        pfp = NULL;
                        return(0);
@@ -347,7 +351,7 @@ tskip(bp)
 
        while (*bp && *bp != ':')
                bp++;
-       if (*bp == ':')
+       while (*bp && *bp == ':')
                bp++;
        return (bp);
 }
index 49ed104b9c245887f6693e665b65e47f99fd1a5f..7c562734913d74c998aac470046a89181ced2f52 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: printer.h,v 1.5 2001-06-25 20:13:45 rufustfirefly Exp $
+ * $Id: printer.h,v 1.6 2005-04-28 20:49:49 bfernhomberg Exp $
  *
  * Copyright (c) 1990,1995 Regents of The University of Michigan.
  * All Rights Reserved.  See COPYRIGHT.
@@ -9,11 +9,13 @@ struct printer {
     char               *p_name;
     char               *p_type;
     char               *p_zone;
+    char               *p_u_name;
 #ifdef notdef
     char               *p_fonts;
     char               *p_psetdir;
 #endif /* notdef */
     char               *p_ppdfile;
+    char               p_status[255];
     char               *p_authprintdir;
     int                        p_flags;
     struct at_addr      p_addr;
@@ -34,6 +36,9 @@ struct printer {
        char            *pu_cmd;
     } p_un;
     ATP                        p_atp;
+#ifdef HAVE_CUPS
+    char               *p_cupsoptions;
+#endif
     struct printer     *p_next;
 };
 #define p_cmd          p_un.pu_cmd
@@ -57,5 +62,9 @@ struct printer {
 #define P_AUTH         (1<<5)
 #define P_AUTH_PSSP    (1<<6)
 #define P_AUTH_CAP     (1<<7)
+#define P_CUPS         (1<<8)
+#define P_CUPS_PPD     (1<<9)
+#define P_CUPS_AUTOADDED (1<<10)
+#define P_FOOMATIC_HACK (1<<11)
 
 extern struct printer  *printer;
index ab1d745e37a88364d59b2edf563bb014030d6cad..4c41b6344e2d47d01f188c7bfd778cc447d12efb 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: queries.c,v 1.17 2003-05-14 15:13:50 didg Exp $
+ * $Id: queries.c,v 1.18 2005-04-28 20:49:49 bfernhomberg Exp $
  *
  * Copyright (c) 1990,1994 Regents of The University of Michigan.
  * All Rights Reserved.  See COPYRIGHT.
@@ -50,8 +50,10 @@ int cq_font( struct papfile *, struct papfile * );
 int cq_feature( struct papfile *, struct papfile * );
 int cq_printer( struct papfile *, struct papfile * );
 int cq_rmjob( struct papfile *, struct papfile * );
+#ifndef HAVE_CUPS
 int cq_listq( struct papfile *, struct papfile * );
 int cq_rbilogin( struct papfile *, struct papfile * );
+#endif  /* HAVE_CUPS */
 
 
 
@@ -305,7 +307,7 @@ struct genquery {
     { "ADOIsBinaryOK?", gq_true },
     { "UMICHListQueue", gq_true },
     { "UMICHDeleteJob", gq_true },
-    { NULL },
+    { NULL, NULL },
 };
 
 int cq_query( in, out )
@@ -600,6 +602,8 @@ int cq_printer( in, out )
     }
 }
 
+#ifndef HAVE_CUPS
+
 static const char      *rmjobfailed = "Failed\n";
 static const char      *rmjobok = "Ok\n";
 
@@ -666,6 +670,7 @@ int cq_listq( in, out )
     CONSUME( in, linelength + crlflength );
     return( CH_DONE );
 }
+#endif /* HAVE_CUPS */
 
 
 /*
@@ -744,16 +749,18 @@ int cq_rbilogin( in, out )
  */
 struct papd_comment    queries[] = {
 #ifdef KRB
-    { "%%Login: UMICHKerberosIV", 0,                   cq_k4login,     0 },
-    { "%%?BeginUAMethodsQuery",        "%%?EndUAMethodsQuery:", cq_uameth, C_FULL },
+    { "%%Login: UMICHKerberosIV", NULL,                        cq_k4login,     0 },
+    { "%%?BeginUAMethodsQuery",        "%%?EndUAMethodsQuery:", cq_uameth,C_FULL },
 #endif /* KRB */
-    { "%UMICHListQueue", 0,                            cq_listq, C_FULL },
-    { "%UMICHDeleteJob", 0,                            cq_rmjob,       0 },
+#ifndef HAVE_CUPS
+    { "%UMICHListQueue",       NULL,                   cq_listq,  C_FULL },
+    { "%UMICHDeleteJob",       NULL,                   cq_rmjob,       0 },
+#endif /* HAVE_CUPS */
     { "%%?BeginQuery: RBILogin ", "%%?EndQuery",       cq_rbilogin,    0 },
     { "%%?BeginQuery",         "%%?EndQuery",          cq_query,       0 },
     { "%%?BeginFeatureQuery",  "%%?EndFeatureQuery",   cq_feature,     0 },
     { "%%?BeginFontQuery",     "%%?EndFontQuery",      cq_font,        0 },
-    { "%%?BeginPrinterQuery",  "%%?EndPrinterQuery",   cq_printer, C_FULL },
+    { "%%?BeginPrinterQuery",  "%%?EndPrinterQuery",   cq_printer,C_FULL },
     { "%%?Begin",              "%%?End",               cq_default,     0 },
-    { 0 },
+    { NULL,                    NULL,                   NULL,           0 },
 };
index 62b21a8e893390824ade86ee3d32e3db0241bccf..6e1cfd783a15538f70387ccea3cdb0f0c4fd1fa7 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: session.c,v 1.14 2002-09-29 23:29:14 sibaz Exp $
+ * $Id: session.c,v 1.15 2005-04-28 20:49:49 bfernhomberg Exp $
  *
  * Copyright (c) 1990,1994 Regents of The University of Michigan.
  * All Rights Reserved.  See COPYRIGHT.
@@ -74,7 +74,7 @@ int session( atp, sat )
     char               cbuf[ 578 ];
     int                        i, cc, timeout = 0, readpending = 0;
     u_int16_t          seq = 0, rseq = 1, netseq;
-    u_char             readport;
+    u_char             readport; /* uninitialized, OK 310105 */
 
     infile.pf_state = PF_BOT;
     infile.pf_bufsize = 0;
@@ -243,7 +243,7 @@ int session( atp, sat )
 
            for ( i = 0; i < atpb.atp_rresiovcnt; i++ ) {
                append( &infile,
-                       niov[ i ].iov_base + 4, niov[ i ].iov_len - 4 );
+                       (char *)niov[ i ].iov_base + 4, niov[ i ].iov_len - 4 );
                if (( infile.pf_state & PF_EOF ) == 0 &&
                        ((char *)niov[ 0 ].iov_base)[ 2 ] ) {
                    infile.pf_state |= PF_EOF;
@@ -304,7 +304,7 @@ int session( atp, sat )
                }
 
                niov[ i ].iov_len = 4 + cc;
-               memcpy( niov[ i ].iov_base + 4, outfile.pf_data, cc );
+               memcpy( (char *)niov[ i ].iov_base + 4, outfile.pf_data, cc );
                CONSUME( &outfile, cc );
                if ( outfile.pf_datalen == 0 ) {
                    i++;
index 968f48362e9d65f7924dbf2e64f58584b02e47b7..3485df7be0676d650292581f62dcb841c75b1bfb 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: showppd.c,v 1.5 2002-01-04 04:45:48 sibaz Exp $
+ * $Id: showppd.c,v 1.6 2005-04-28 20:49:49 bfernhomberg Exp $
  *
  * Copyright (c) 1995 Regents of The University of Michigan.
  * All Rights Reserved.  See COPYRIGHT.
@@ -26,7 +26,7 @@ extern struct ppd_font                *ppd_fonts;
 extern struct ppd_feature      ppd_features[];
 
 
-main( ac, av )
+int main( ac, av )
     int                ac;
     char       **av;
 {
@@ -43,8 +43,8 @@ main( ac, av )
        printf( "Font: %s\n", pfo->pd_font );
     }
     for ( pfe = ppd_features; pfe->pd_name; pfe++ ) {
-       printf( "Feature: %s %s\n", pfe->pd_name, pfe->pd_value );
+       printf( "Feature: %s %s\n", pfe->pd_name, (pfe->pd_value)?pfe->pd_value:"NULL" );
     }
 
-    exit( 0 );
+    exit ( 0 );
 }
index 0e5b9a4e706823a899c8be479a8a4a9fd494e4c0..c406b1b4745d2b90bd0126536f8edf9f8cd7fc94 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: uam.c,v 1.9 2003-02-17 01:35:57 srittau Exp $
+ * $Id: uam.c,v 1.10 2005-04-28 20:49:49 bfernhomberg Exp $
  *
  * Copyright (c) 1999 Adrian Sun (asun@zoology.washington.edu)
  * All Rights Reserved.  See COPYRIGHT.
@@ -55,8 +55,7 @@ struct uam_mod *uam_load(const char *path, const char *name)
   void *module;
 
   if ((module = mod_open(path)) == NULL) {
-    LOG(log_error, logtype_papd, "uam_load(%s): failed to load.", name);
-    LOG(log_error, logtype_papd, dlerror());
+    LOG(log_error, logtype_papd, "uam_load(%s): failed to load: %s", name, mod_error());
     return NULL;
   }
 
@@ -65,7 +64,7 @@ struct uam_mod *uam_load(const char *path, const char *name)
     goto uam_load_fail;
   }
 
-  strncpy(buf, name, sizeof(buf));
+  strlcpy(buf, name, sizeof(buf));
   if ((p = strchr(buf, '.')))
     *p = '\0';
   if ((mod->uam_fcn = mod_symbol(module, buf)) == NULL) {
@@ -114,6 +113,7 @@ int uam_register(const int type, const char *path, const char *name, ...)
 {
   va_list ap;
   struct uam_obj *uam;
+  int ret;
 
   if (!name)
     return -1;
@@ -157,13 +157,13 @@ int uam_register(const int type, const char *path, const char *name, ...)
   va_end(ap);
 
   /* attach to other uams */
-  if (auth_register(type, uam) < 0) {
+  ret = auth_register(type, uam);
+  if (ret) {
     free(uam->uam_path);
     free(uam);
-    return -1;
   }
 
-  return 0;
+  return ret;
 }
 
 void uam_unregister(const int type, const char *name)
@@ -183,15 +183,15 @@ void uam_unregister(const int type, const char *name)
 }
 
 /* Crap to support uams which call this afpd function */
-int uam_afpserver_option(void *private, const int what, void *option,
-                         int *len)
+int uam_afpserver_option(void *private _U_, const int what _U_, void *option _U_,
+                         int *len _U_)
 {
        return(0);
 }
 
 /* --- helper functions for plugin uams --- */
 
-struct passwd *uam_getname(char *name, const int len)
+struct passwd *uam_getname(void *dummy _U_, char *name, const int len)
 {
   struct passwd *pwent;
   char *user;
index 5cd8387315e2140ec045fdb5115e27177173934f..0ac9be4496141b668d2297ff93c7dce5bb510df0 100644 (file)
@@ -1,6 +1,5 @@
 Makefile
 Makefile.in
-etc2ps.sh
 psf
 psa
 .deps
index f02aa4fb449b2bf9ba2eb96acfafc17121ca15a1..0769919bd26ffed26ade0b0a6052e9b738cc88be 100644 (file)
@@ -8,8 +8,7 @@ pkgdata_DATA = pagecount.ps
 psf_SOURCES = psf.c
 psa_SOURCES = psa.c
 
-INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/sys \
-       -DZEROWIDTH \
+CFLAGS = @CFLAGS@ -DZEROWIDTH \
        -D_PATH_PAP=\"$(bindir)/pap\" \
        -D_PATH_PSORDER=\"$(bindir)/psorder\" \
        -D_PATH_PSA=\"$(libexecdir)/psa\" \
@@ -34,6 +33,15 @@ install-exec-hook:
                (cd $(DESTDIR)$(libexecdir) && $(LN_S) psf $$l);  \
        done
 
+#
+# uninstall sections for links
+#
+
+uninstall-hook:
+       @list='$(psf_LINKS)'; for l in $$list; do \
+               rm -f $(DESTDIR)$(libexecdir)/$$l; \
+       done
+
 #
 # cleanup
 #
diff --git a/etc/psf/etc2ps.sh b/etc/psf/etc2ps.sh
new file mode 100644 (file)
index 0000000..3f1637b
--- /dev/null
@@ -0,0 +1,57 @@
+#!/bin/sh
+#
+# This filter is called by psf to convert "other" formats to PostScript.
+# psf handles text and PostScript native.  "Other" formats, e.g. DVI, C/A/T,
+# need to be converted before the page reverser and the printer can use
+# them.
+#
+# $0 begins with the filter name, e.g. df, tf.  Each format is a separate
+# tag in the case.
+#
+
+DVIPSPATH=/usr/local/tex/bin
+DVIPS=/usr/local/tex/bin/dvips
+DVIPSARGS="-f -q"
+
+TROFF2PS=/usr/local/psroff/troff2/troff2ps
+TROFF2PSARGS="-Z -O-.10"
+
+PATH=/usr/bin:$DVIPSPATH; export PATH
+
+case $1 in
+
+#
+# Use "dvips" by Radical Eye Software to convert TeX DVI files to PostScript.
+# Note that you *must* have METAFONT, etc, in your path.
+#
+df*)
+    if [ -x "$DVIPS" ]; then
+       TEMPFILE=`mktemp -t psfilter.XXXXXX` || exit 1
+       cat > $TEMPFILE
+       $DVIPS $DVIPSARGS < $TEMPFILE
+       rm -f $TEMPFILE
+    else
+       echo "$0: filter dvips uninstalled" 1>&2
+       exit 2
+    fi
+    ;;
+
+#
+# troff2ps is from psroff by Chris Lewis.
+#
+tf*)
+    if [ -x "$TROFF2PS" ]; then
+       exec $TROFF2PS $TROFF2PSARGS
+    else
+       echo "$0: filter troff2ps uninstalled" 1>&2
+       exit 2
+    fi
+    ;;
+
+*)
+    echo "$0: filter $1 unavailable" 1>&2
+    exit 2
+    ;;
+esac
+
+exit 0
diff --git a/etc/psf/etc2ps.sh.in b/etc/psf/etc2ps.sh.in
deleted file mode 100644 (file)
index cdfa385..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-#!/bin/sh
-#
-# This filter is called by psf to convert "other" formats to PostScript.
-# psf handles text and PostScript native.  "Other" formats, e.g. DVI, C/A/T,
-# need to be converted before the page reverser and the printer can use
-# them.
-#
-# $0 begins with the filter name, e.g. df, tf.  Each format is a separate
-# tag in the case.
-#
-
-DVIPS=@DVIPS@
-DVIPSARGS="-f -q"
-
-TROFF2PS=@TROFF2PS@
-TROFF2PSARGS="-Z -O-.10"
-
-case $1 in
-
-#
-# Use "dvips" by Radical Eye Software to convert TeX DVI files to PostScript.
-# Note that you *must* have METAFONT, etc, in your path.
-#
-df*)
-    if [ -x "$DVIPS" ]; then
-       cat > /tmp/psfilter.$$
-       $DVIPS $DVIPSARGS < /tmp/psfilter.$$
-       rm -f /tmp/psfilter.$$
-    else
-       echo "$0: filter dvips uninstalled" 1>&2
-       exit 2
-    fi
-    ;;
-
-#
-# troff2ps is from psroff by Chris Lewis.
-#
-tf*)
-    if [ -x "$TROFF2PS" ]; then
-       exec $TROFF2PS $TROFF2PSARGS
-    else
-       echo "$0: filter troff2ps uninstalled" 1>&2
-       exit 2
-    fi
-    ;;
-
-*)
-    echo "$0: filter $1 unavailable" 1>&2
-    exit 2
-    ;;
-esac
-
-exit 0
index 9d7c2e30e04cc97ee7025da80cee284a8f27bb5a..c4db9b9988d1e4be0dfc554deeca9eb483061c40 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: psf.c,v 1.8 2002-05-23 15:58:55 rufustfirefly Exp $
+ * $Id: psf.c,v 1.9 2005-04-28 20:49:49 bfernhomberg Exp $
  *
  * Copyright (c) 1990,1995 Regents of The University of Michigan.
  * All Rights Reserved. See COPYRIGHT.
@@ -97,7 +97,7 @@ int main( ac, av )
 {
     int                        c, rc, children = 0;
 #ifdef FUCKED
-    int                        psafileno, multiconn = 0, waitidle = 0, waitidle2 = 0;
+    int                        psafileno = 0, multiconn = 0, waitidle = 0, waitidle2 = 0;
 #endif /* FUCKED */
     int                        status;
     extern char                *optarg;
@@ -485,7 +485,8 @@ char                pspro[] = "\
 int textps()
 {
     struct papersize   papersize;
-    int                        state = 0, line = 0, col = 0, npages = 0, rc, i;
+    int                        state = 0, line = 0, col = 0, npages = 0, rc;
+    unsigned int       i;
     char               *p, *end;
 
 #define elements(x)    (sizeof(x)/sizeof((x)[0]))
index 336f3821b6cb56603ad95beabbf9378f1e939e39..55cba1af64619987bafe0742654072be9f2ec32d 100644 (file)
@@ -6,14 +6,14 @@ SUBDIRS = uams_krb4
 # conditionally build some modules
 #
 
-if USE_GSSAPI
-UAMS_GENERIC = uams_guest.la uams_passwd.la uams_gss.la
-else
 UAMS_GENERIC = uams_guest.la uams_passwd.la
-endif
 
 if USE_DHX
-UAMS_DHX_GENERIC = uams_randnum.la uams_pgp.la uams_dhx_passwd.la
+UAMS_DHX_GENERIC = uams_randnum.la uams_dhx_passwd.la
+endif
+
+if USE_PGP
+UAMS_PGP = uams_pgp.la
 endif
 
 if BUILD_PAM
@@ -23,6 +23,10 @@ UAMS_DHX_PAM = uams_dhx_pam.la
 endif
 endif
 
+if USE_GSSAPI
+UAMS_GSSAPI = uams_gss.la
+endif
+
 # links
 if USE_PAM_SO
 UAMS_CLRTXT_LINK = uams_pam.so
@@ -32,54 +36,43 @@ UAMS_CLRTXT_LINK = uams_passwd.so
 UAMS_DHX_LINK    = uams_dhx_passwd.so
 endif
 
-#
-# SSL and crypto flag setup
-#
-
-if HAVE_GCRYPT
-CRYPT_CFLAGS = $(GCRYPT_CFLAGS)
-CRYPT_LIBS = $(GCRYPT_LIBS)
-else
-CRYPT_CFLAGS = $(SSL_CFLAGS)
-CRYPT_LIBS = $(SSL_LIBS)
-endif
-
 #
 # source files
 #
 
 uams_guest_la_SOURCES      = uams_guest.c
-uams_randnum_la_SOURCES    = uams_randnum.c crypt.c crypt.h
+uams_randnum_la_SOURCES    = uams_randnum.c
 uams_passwd_la_SOURCES     = uams_passwd.c
 uams_pam_la_SOURCES        = uams_pam.c
 uams_pgp_la_SOURCES        = uams_pgp.c
-uams_dhx_passwd_la_SOURCES = uams_dhx_passwd.c crypt.c crypt.h
-uams_dhx_pam_la_SOURCES    = uams_dhx_pam.c crypt.c crypt.h
-uams_gss_la_SOURCES       = uams_gss.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
 #
 
-INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/sys @SSL_CFLAGS@
+# do that on behalf of the brokeness of automake 1.4
+CFLAGS = @CFLAGS@ @SSL_CFLAGS@
 
 uams_guest_la_CFLAGS      = @CFLAGS@
-uams_randnum_la_CFLAGS    = @CFLAGS@ $(CRYPT_CFLAGS)
+uams_randnum_la_CFLAGS    = @CFLAGS@ @SSL_CFLAGS@
 uams_passwd_la_CFLAGS     = @CFLAGS@
-uams_pam_la_CFLAGS        = @CFLAGS@
-uams_pgp_la_CFLAGS        = @CFLAGS@ $(CRYPT_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_gss_la_CFLAGS       = @CFLAGS@ @GSSAPI_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 $(CRYPT_LIBS)
-uams_passwd_la_LDFLAGS     = -module -avoid-version
-uams_pam_la_LDFLAGS        = -module -avoid-version -lpam
-uams_pgp_la_LDFLAGS        = -module -avoid-version $(CRYPT_LIBS)
-uams_dhx_passwd_la_LDFLAGS = -module -avoid-version @SSL_LIBS@
-uams_dhx_pam_la_LDFLAGS    = -module -avoid-version @SSL_LIBS@ -lpam
-uams_gss_la_LDFLAGS       = -module -avoid-version @GSSAPI_LIBS@
+uams_randnum_la_LDFLAGS    = -module -avoid-version @SSL_LIBS@
+uams_passwd_la_LDFLAGS     = -module -avoid-version @CRYPT_LIBS@
+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 @CRYPT_LIBS@ @SSL_LIBS@
+uams_dhx_pam_la_LDFLAGS    = -module -avoid-version @SSL_LIBS@ @PAM_LIBS@
+uams_gss_la_LDFLAGS       = -module -avoid-version @GSSAPI_LIBS@ 
 
 #
 # module compilation
@@ -88,9 +81,11 @@ uams_gss_la_LDFLAGS     = -module -avoid-version @GSSAPI_LIBS@
 uamsdir = @UAMS_PATH@
 uams_LTLIBRARIES =             \
        $(UAMS_GENERIC)         \
+       $(UAMS_PGP)             \
        $(UAMS_PAM)             \
        $(UAMS_DHX_GENERIC)     \
-       $(UAMS_DHX_PAM)
+       $(UAMS_DHX_PAM)         \
+       $(UAMS_GSSAPI)
 
 #
 # link creation
@@ -105,10 +100,20 @@ install-exec-hook:
                $(LN_S) $(UAMS_CLRTXT_LINK) uams_clrtxt.so              && \
                $(LN_S) $(UAMS_DHX_LINK) uams_dhx.so                       \
        )
+
+uninstall-hook:
+       (cd $(DESTDIR)$(uamsdir)                                        && \
+               rm -f uams_clrtxt.so uams_dhx.so                           \
+       )
 else
 install-exec-hook:
        (cd $(DESTDIR)$(uamsdir)                                        && \
                rm -f uams_clrtxt.so                                    && \
                $(LN_S) $(UAMS_CLRTXT_LINK) uams_clrtxt.so                 \
        )
+
+uninstall-hook:
+       (cd $(DESTDIR)$(uamsdir)                                        && \
+               rm -f uams_clrtxt.so                                       \
+       )
 endif
diff --git a/etc/uams/crypt.c b/etc/uams/crypt.c
deleted file mode 100644 (file)
index 484ae26..0000000
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * $Id: crypt.c,v 1.3 2003-06-11 07:49:52 srittau Exp $
- *
- * Copyright (c) 1990,1993 Regents of The University of Michigan.
- * Copyright (c) 1999 Adrian Sun (asun@u.washington.edu)
- * Copyright (C) 2003 Sebastian Rittau (srittau@debian.org)
- * All Rights Reserved.  See COPYRIGHT.
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <assert.h>
-#include <ctype.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-
-#ifdef HAVE_GCRYPT
-#include <gcrypt.h>
-#define DES_KEY_SZ 8
-#else /* HAVE_GCRYPT */
-#include <des.h>
-#endif /* HAVE_GCRYPT */
-
-#include <atalk/afp.h>
-
-#include "crypt.h"
-
-/* Cannot perform in-place operation. dstlen must be at least srclen*2. */
-void atalk_hexify(u_int8_t *dst, size_t dstlen, const u_int8_t *src, size_t srclen)
-{
-       static const unsigned char hextable[] = "0123456789ABCDEF";
-
-       assert(dstlen >= srclen * 2);
-
-       for (; srclen > 0; dst += 2, src++, dstlen -= 2, srclen--) {
-               dst[0] = hextable[(*src & 0xF0) >> 4];
-               dst[1] = hextable[(*src & 0x0F)];
-       }
-
-       memset(dst, 0, dstlen);
-}
-
-/* Can perform in-place operation. dstlen must be at least srclen/2. */
-#define unhex(x)  (isdigit(x) ? (x) - '0' : toupper(x) + 10 - 'A')
-void atalk_unhexify(u_int8_t *dst, size_t dstlen, const u_int8_t *src, size_t srclen)
-{
-       assert(srclen % 2 == 0);
-       assert(dstlen >= srclen / 2);
-
-       for (; srclen > 0; dst++, src += 2, dstlen--, srclen -= 2)
-               *dst = (unhex(src[0]) << 4) | unhex(src[1]);
-
-       memset(dst, 0, dstlen);
-}
-
-int atalk_encrypt_start(CryptHandle *handle, u_int8_t *key)
-{
-#ifdef HAVE_GCRYPT
-       GcryCipherHd hd;
-
-       hd = gcry_cipher_open(GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0);
-       if (!hd)
-               return AFPERR_PARAM;
-       gcry_cipher_setkey(hd, key, DES_KEY_SZ);
-
-       *handle = hd;
-
-       return AFP_OK;
-#else /* HAVE_GCRYPT */
-       DES_key_schedule *sched = malloc(sizeof(DES_key_schedule));
-       DES_set_key_unchecked((DES_cblock *) key, sched);
-
-       *handle = sched;
-
-       return AFP_OK;
-#endif /* HAVE_GCRYPT */
-}
-
-int atalk_encrypt_do(CryptHandle handle, u_int8_t *dst, u_int8_t *src)
-{
-#ifdef HAVE_GCRYPT
-       int ret;
-
-       ret = gcry_cipher_encrypt(*(GcryCipherHd *) handle,
-                                 dst, DES_KEY_SZ, src, DES_KEY_SZ);
-
-       return ret == 0 ? AFP_OK : AFPERR_PARAM;
-#else /* HAVE_GCRYPT */
-       DES_ecb_encrypt((DES_cblock *) src, (DES_cblock *) dst,
-                       (DES_key_schedule *) handle, DES_ENCRYPT);
-
-       return AFP_OK;
-#endif /* HAVE_GCRYPT */
-}
-
-void atalk_encrypt_end(CryptHandle handle)
-{
-#ifdef HAVE_GCRYPT
-       gcry_cipher_close(*(GcryCipherHd *) handle);
-#else /* HAVE_GCRYPT */
-       memset(handle, 0, sizeof(DES_key_schedule));
-       free(handle);
-#endif /* HAVE_GCRYPT */
-}
-
-int atalk_encrypt(u_int8_t *key, u_int8_t *dst, u_int8_t *src)
-{
-#ifdef HAVE_GCRYPT
-       GcryCipherHd hd;
-       int ret;
-                                                                                
-       hd = gcry_cipher_open(GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0);
-       if (!hd)
-               return AFPERR_PARAM;
-       gcry_cipher_setkey(hd, key, DES_KEY_SZ);
-
-       ret = gcry_cipher_encrypt(hd, dst, DES_KEY_SZ, src, DES_KEY_SZ);
-
-       gcry_cipher_close(hd);
-
-       return ret == 0 ? AFP_OK : AFPERR_PARAM;
-#else /* HAVE_GCRYPT */
-       DES_key_schedule sched;
-
-       DES_set_key_unchecked((DES_cblock *) key, &sched);
-       DES_ecb_encrypt((DES_cblock *) src, (DES_cblock *) dst,
-                       &sched, DES_ENCRYPT);
-
-       memset(&sched, 0, sizeof(sched));
-
-       return AFP_OK;
-#endif /* HAVE_GCRYPT */
-}
-
-int atalk_decrypt(u_int8_t *key, u_int8_t *dst, u_int8_t *src)
-{
-#ifdef HAVE_GCRYPT
-       GcryCipherHd hd;
-       int ret;
-
-       hd = gcry_cipher_open(GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0);
-       if (!hd)
-               return AFPERR_PARAM;
-       gcry_cipher_setkey(hd, key, DES_KEY_SZ);
-
-       ret = gcry_cipher_encrypt(hd, dst, DES_KEY_SZ, src, DES_KEY_SZ);
-
-       gcry_cipher_close(hd);
-
-       return ret == 0 ? AFP_OK : AFPERR_PARAM;
-#else /* HAVE_GCRYPT */
-       DES_key_schedule sched;
-
-       DES_set_key_unchecked((DES_cblock *) key, &sched);
-       DES_ecb_encrypt((DES_cblock *) src, (DES_cblock *) dst,
-                       &sched, DES_ENCRYPT);
-
-       memset(&sched, 0, sizeof(sched));
-
-       return AFP_OK;
-#endif /* HAVE_GCRYPT */
-}
diff --git a/etc/uams/crypt.h b/etc/uams/crypt.h
deleted file mode 100644 (file)
index 7906c23..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-#ifndef __UAMS_CRYPT_H
-#define __UAMS_CRYPT_H
-
-/*
- * $Id: crypt.h,v 1.2 2003-06-11 07:14:12 srittau Exp $
- *
- * Copyright (c) 1990,1993 Regents of The University of Michigan.
- * Copyright (c) 1999 Adrian Sun (asun@u.washington.edu)
- * All Rights Reserved.  See COPYRIGHT.
- */
-
-#include <sys/types.h>
-
-typedef void *CryptHandle;
-
-void atalk_hexify(u_int8_t *dst, size_t dstlen, const u_int8_t *src, size_t srclen);
-void atalk_unhexify(u_int8_t *dst, size_t dstlen, const u_int8_t *src, size_t srclen);
-
-int atalk_encrypt_start(CryptHandle *handle, u_int8_t *key);
-int atalk_encrypt_do(CryptHandle handle, u_int8_t *dst, u_int8_t *src);
-void atalk_encrypt_end(CryptHandle handle);
-
-int atalk_encrypt(u_int8_t *key, u_int8_t *dst, u_int8_t *src);
-int atalk_decrypt(u_int8_t *key, u_int8_t *dst, u_int8_t *src);
-
-#endif /* __UAMS_CRYPT_H */
index 0e7eed434e790de3a225816bcc35006b73a6cfc8..6af1705024c7631cd64aef9c66d27cbf42d43bdd 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: uams_dhx_pam.c,v 1.24 2003-01-08 22:16:24 didg Exp $
+ * $Id: uams_dhx_pam.c,v 1.25 2005-04-28 20:49:50 bfernhomberg Exp $
  *
  * Copyright (c) 1990,1993 Regents of The University of Michigan.
  * Copyright (c) 1999 Adrian Sun (asun@u.washington.edu) 
 #include <unistd.h>
 #endif /* HAVE_UNISTD_H */
 #include <errno.h>
-
+#ifdef HAVE_SECURITY_PAM_APPL_H
 #include <security/pam_appl.h>
+#endif
+#ifdef HAVE_PAM_PAM_APPL_H
+#include <pam/pam_appl.h>
+#endif
+
 
 #if defined(GNUTLS_DHX)
 #include <gnutls/openssl.h>
@@ -29,6 +34,9 @@
 #include <openssl/bn.h>
 #include <openssl/dh.h>
 #include <openssl/cast.h>
+#ifdef sun
+#include <openssl/rand.h>
+#endif
 #else /* OPENSSL_DHX */
 #include <bn.h>
 #include <dh.h>
@@ -75,7 +83,7 @@ static char *PAM_password;
 static int PAM_conv (int num_msg,
                      const struct pam_message **msg,
                      struct pam_response **resp,
-                     void *appdata_ptr) {
+                     void *appdata_ptr _U_) {
   int count = 0;
   struct pam_response *reply;
   
@@ -177,7 +185,7 @@ static struct pam_conv PAM_conversation = {
 };
 
 
-static int dhx_setup(void *obj, char *ibuf, int ibuflen, 
+static int dhx_setup(void *obj, char *ibuf, int ibuflen _U_
                     char *rbuf, int *rbuflen)
 {
     u_int16_t sessid;
@@ -308,11 +316,11 @@ pam_fail:
 }
 
 /* -------------------------------- */
-static int login(void *obj, char *username, int ulen,  struct passwd **uam_pwd,
+static int login(void *obj, char *username, int ulen,  struct passwd **uam_pwd _U_,
                     char *ibuf, int ibuflen,
                     char *rbuf, int *rbuflen)
 {
-    if (( dhxpwd = uam_getname(username, ulen)) == NULL ) {
+    if (( dhxpwd = uam_getname(obj, username, ulen)) == NULL ) {
         LOG(log_info, logtype_uams, "uams_dhx_pam.c: unknown username");
        return AFPERR_PARAM;
     }
@@ -396,7 +404,7 @@ static int pam_login_ext(void *obj, char *uname, struct passwd **uam_pwd,
 /* -------------------------------- */
 
 static int pam_logincont(void *obj, struct passwd **uam_pwd,
-                        char *ibuf, int ibuflen, 
+                        char *ibuf, int ibuflen _U_
                         char *rbuf, int *rbuflen)
 {
     char *hostname;
@@ -490,18 +498,19 @@ static int pam_logincont(void *obj, struct passwd **uam_pwd,
     }      
 
     PAM_error = pam_acct_mgmt(pamh, 0);
-    if (PAM_error != PAM_SUCCESS) {
-      if (PAM_error == PAM_ACCT_EXPIRED)
+    if (PAM_error != PAM_SUCCESS ) {
+      /* Log Entry */
+      LOG(log_info, logtype_uams, "uams_dhx_pam.c :PAM: PAM_Error: %s",
+         pam_strerror(pamh, PAM_error));
+      /* Log Entry */
+      if (PAM_error == PAM_NEW_AUTHTOK_REQD)   /* password expired */
        err = AFPERR_PWDEXPR;
 #ifdef PAM_AUTHTOKEN_REQD
       else if (PAM_error == PAM_AUTHTOKEN_REQD) 
        err = AFPERR_PWDCHNG;
 #endif
-    /* Log Entry */
-           LOG(log_info, logtype_uams, "uams_dhx_pam.c :PAM: PAM_Error: %s",
-                 pam_strerror(pamh, PAM_error));
-    /* Log Entry */
-      goto logincont_err;
+      else
+        goto logincont_err;
     }
 
 #ifndef PAM_CRED_ESTABLISH
@@ -530,6 +539,8 @@ static int pam_logincont(void *obj, struct passwd **uam_pwd,
     /* Log Entry */
            LOG(log_info, logtype_uams, "uams_dhx_pam.c :PAM: PAM Auth OK!");
     /* Log Entry */
+    if ( err == AFPERR_PWDEXPR)
+       return err;
     return AFP_OK;
 
 logincont_err:
@@ -550,7 +561,7 @@ static void pam_logout() {
 /* change pw for dhx needs a couple passes to get everything all
  * right. basically, it's like the login/logincont sequence */
 static int pam_changepw(void *obj, char *username,
-                       struct passwd *pwd, char *ibuf, int ibuflen,
+                       struct passwd *pwd _U_, char *ibuf, int ibuflen,
                        char *rbuf, int *rbuflen)
 {
     BIGNUM *bn1, *bn2, *bn3;
index 6442cf597d98f358402dfda3dbc2e2521f249132..c8e890ecf4432e544c8304d63ce148c7440b409f 100644 (file)
@@ -1,33 +1,54 @@
 /*
- * $Id: uams_dhx_passwd.c,v 1.22 2003-06-14 16:40:54 srittau Exp $
+ * $Id: uams_dhx_passwd.c,v 1.23 2005-04-28 20:49:50 bfernhomberg Exp $
  *
  * Copyright (c) 1990,1993 Regents of The University of Michigan.
  * Copyright (c) 1999 Adrian Sun (asun@u.washington.edu) 
  * All Rights Reserved.  See COPYRIGHT.
  */
 
-#define _XOPEN_SOURCE /* for crypt() */
-
 #ifdef HAVE_CONFIG_H
-#include <config.h>
+#include "config.h"
 #endif /* HAVE_CONFIG_H */
 
+#ifdef NETBSD
+#define _XOPEN_SOURCE 500 /* for crypt() */
+#endif
+#ifdef FREEBSD
+#define _XOPEN_SOURCE /* for crypt() */
+#endif
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #ifdef HAVE_UNISTD_H
 #include <unistd.h>
 #endif /* HAVE_UNISTD_H */
-#ifndef NO_CRYPT_H
+#ifdef HAVE_CRYPT_H
 #include <crypt.h>
-#endif /* ! NO_CRYPT_H */
+#endif /* ! HAVE_CRYPT_H */
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#ifdef HAVE_TIME_H
+#include <time.h>
+#endif
 #include <pwd.h>
-#include <atalk/logger.h>
-
 #ifdef SHADOWPW
 #include <shadow.h>
 #endif /* SHADOWPW */
+#if defined(GNUTLS_DHX)
+#include <gnutls/openssl.h>
+#elif defined(OPENSSL_DHX)
+#include <openssl/bn.h>
+#include <openssl/dh.h>
+#include <openssl/cast.h>
+#else /* OPENSSL_DHX */
+#include <bn.h>
+#include <dh.h>
+#include <cast.h>
+#endif /* OPENSSL_DHX */
 
+#include <atalk/logger.h>
 #include <atalk/afp.h>
 #include <atalk/uam.h>
 
@@ -41,6 +62,7 @@
                     (unsigned long) (a)) & 0xffff)
 
 /* the secret key */
+static CAST_KEY castkey;
 static struct passwd *dhxpwd;
 static u_int8_t randbuf[16];
 
@@ -51,11 +73,9 @@ static u_int8_t randbuf[16];
 static char *clientname;
 #endif /* TRU64 */
 
-#include "crypt.h"
-
 /* dhx passwd */
-static int pwd_login(void *obj, char *username, int ulen, struct passwd **uam_pwd,
-                       char *ibuf, int ibuflen,
+static int pwd_login(void *obj, char *username, int ulen, struct passwd **uam_pwd _U_,
+                       char *ibuf, int ibuflen _U_,
                        char *rbuf, int *rbuflen)
 {
     unsigned char iv[] = "CJalbert";
@@ -65,19 +85,17 @@ static int pwd_login(void *obj, char *username, int ulen, struct passwd **uam_pw
 #ifdef SHADOWPW
     struct spwd *sp;
 #endif /* SHADOWPW */
-    CastKey castkey;
+    BIGNUM *bn, *gbn, *pbn;
     u_int16_t sessid;
     int i;
-#if 0
-    char *name;
-#endif
+    DH *dh;
 
-#if defined(TRU64) && !defined(HAVE_GCRYPT)
+#ifdef TRU64
     int rnd_seed[256];
     for (i = 0; i < 256; i++)
         rnd_seed[i] = random();
     RAND_seed(rnd_seed, sizeof(rnd_seed));
-#endif /* defined(TRU64) && !defined(HAVE_GCRYPT) */
+#endif /* TRU64 */
 
     *rbuflen = 0;
 
@@ -87,7 +105,7 @@ static int pwd_login(void *obj, char *username, int ulen, struct passwd **uam_pw
         return AFPERR_PARAM;
 #endif /* TRU64 */
 
-    if (( dhxpwd = uam_getname(username, ulen)) == NULL ) {
+    if (( dhxpwd = uam_getname(obj, username, ulen)) == NULL ) {
        return AFPERR_PARAM;
     }
     
@@ -106,10 +124,44 @@ static int pwd_login(void *obj, char *username, int ulen, struct passwd **uam_pw
     if (!dhxpwd->pw_passwd)
       return AFPERR_NOTAUTH;
 
-    castkey = atalk_cast_key(ibuf, KEYSIZE);
-    if (!castkey)
+    /* get the client's public key */
+    if (!(bn = BN_bin2bn(ibuf, KEYSIZE, NULL))) {
       return AFPERR_PARAM;
+    }
+
+    /* get our primes */
+    if (!(gbn = BN_bin2bn(&g, sizeof(g), NULL))) {
+      BN_free(bn);
+      return AFPERR_PARAM;
+    }
 
+    if (!(pbn = BN_bin2bn(p, sizeof(p), NULL))) {
+      BN_free(gbn);
+      BN_free(bn);
+      return AFPERR_PARAM;
+    }
+
+    /* okay, we're ready */
+    if (!(dh = DH_new())) {
+      BN_free(pbn);
+      BN_free(gbn);
+      BN_free(bn);
+      return AFPERR_PARAM;
+    }
+
+    /* generate key and make sure we have enough space */
+    dh->p = pbn;
+    dh->g = gbn;
+    if (!DH_generate_key(dh) || (BN_num_bytes(dh->pub_key) > KEYSIZE)) {
+      goto passwd_fail;
+    }
+
+    /* figure out the key. use rbuf as a temporary buffer. */
+    i = DH_compute_key(rbuf, bn, dh);
+    
+    /* set the key */
+    CAST_set_key(&castkey, i, rbuf);
+    
     /* session id. it's just a hashed version of the object pointer. */
     sessid = dhxhash(obj);
     memcpy(rbuf, &sessid, sizeof(sessid));
@@ -195,7 +247,7 @@ static int passwd_login(void *obj, struct passwd **uam_pwd,
  * uname format :
     byte      3
     2 bytes   len (network order)
-    len bytes unicode name
+    len bytes utf8 name
 */
 static int passwd_login_ext(void *obj, char *uname, struct passwd **uam_pwd,
                        char *ibuf, int ibuflen,
@@ -225,13 +277,17 @@ static int passwd_login_ext(void *obj, char *uname, struct passwd **uam_pwd,
 }
                        
 static int passwd_logincont(void *obj, struct passwd **uam_pwd,
-                           char *ibuf, int ibuflen, 
+                           char *ibuf, int ibuflen _U_
                            char *rbuf, int *rbuflen)
 {
+#ifdef SHADOWPW
+    struct spwd *sp;
+#endif /* SHADOWPW */
     unsigned char iv[] = "LWallace";
     BIGNUM *bn1, *bn2, *bn3;
     u_int16_t sessid;
     char *p;
+    int err = AFPERR_NOTAUTH;
 
     *rbuflen = 0;
 
@@ -300,8 +356,25 @@ static int passwd_logincont(void *obj, struct passwd **uam_pwd,
     memset(rbuf, 0, PASSWDLEN);
     if ( strcmp( p, dhxpwd->pw_passwd ) == 0 ) {
       *uam_pwd = dhxpwd;
-      return AFP_OK;
+      err = AFP_OK;
+    }
+#ifdef SHADOWPW
+    if (( sp = getspnam( dhxpwd->pw_name )) == NULL ) {
+       LOG(log_info, logtype_uams, "no shadow passwd entry for %s", dhxpwd->pw_name);
+       return (AFPERR_NOTAUTH);
     }
+
+    /* check for expired password */
+    if (sp && sp->sp_max != -1 && sp->sp_lstchg) {
+        time_t now = time(NULL) / (60*60*24);
+        int32_t expire_days = sp->sp_lstchg - now + sp->sp_max;
+        if ( expire_days < 0 ) {
+                LOG(log_info, logtype_uams, "password for user %s expired", dhxpwd->pw_name);
+               err = AFPERR_PWDEXPR;
+        }
+    }
+#endif /* SHADOWPW */
+    return err;
 #endif /* TRU64 */
 
     return AFPERR_NOTAUTH;
index 8b99a95343d03d7a84e8d59bd38564894c4a64ed..ae2cc3e330fe23b726f381080047abd6104420f8 100644 (file)
@@ -1,9 +1,10 @@
 /*
- * $Id: uams_gss.c,v 1.2 2003-09-03 18:27:14 samnoble Exp $
+ * $Id: uams_gss.c,v 1.3 2005-04-28 20:49:50 bfernhomberg Exp $
  *
  * Copyright (c) 1990,1993 Regents of The University of Michigan.
  * Copyright (c) 1999 Adrian Sun (asun@u.washington.edu) 
  * Copyright (c) 2003 The Reed Institute
+ * Copyright (c) 2004 Bjoern Fernhomberg
  * All Rights Reserved.  See COPYRIGHT.
  */
 
@@ -33,42 +34,42 @@ char *strchr (), *strrchr ();
 #endif /* ! HAVE_MEMCPY */
 #endif /* STDC_HEADERS */
 
+#include <errno.h>
 #include <atalk/logger.h>
 #include <atalk/afp.h>
 #include <atalk/uam.h>
+#include <atalk/util.h>
 
-#include <errno.h>
+/* Kerberos includes */
 
 #if HAVE_GSSAPI_H
 #include <gssapi.h>
-#endif /* HAVE_GSSAPI_H */
+#endif
 
 #if HAVE_GSSAPI_GSSAPI_H
 #include <gssapi/gssapi.h>
-#endif /* HAVE_GSSAPI_GSSAPI_H */
+#endif
 
 #if HAVE_GSSAPI_GSSAPI_GENERIC_H
 #include <gssapi/gssapi_generic.h>
-#endif /* HAVE_GSSAPI_GSSAPI_GENERIC_H */
+#endif
 
 #if HAVE_GSSAPI_GSSAPI_KRB5_H
 #include <gssapi/gssapi_krb5.h>
-#endif /* HAVE_GSSAPI_GSSAPI_KRB5_H */
+#endif
 
 #if HAVE_COM_ERR_H
 #include <com_err.h>
-#endif /* HAVE_COM_ERR_H */
+#endif
 
-/* This is a Heimdal/MIT compatibiility fix */
-#ifndef GSS_C_NT_HOSTBASED_SERVICE
+/* We work around something I don't entirely understand... */
+/* BF: This is a Heimdal/MIT compatibility fix */
+#ifndef HAVE_GSS_C_NT_HOSTBASED_SERVICE
 #define GSS_C_NT_HOSTBASED_SERVICE gss_nt_service_name
 #endif
 
 #define MIN(a, b) ((a > b) ? b : a)
 
-/* The following routine is derived from code found in some GSS
- * documentation from SUN.
- */
 static void log_status( char *s, OM_uint32 major_status, 
                        OM_uint32 minor_status )
 {
@@ -101,8 +102,9 @@ static void log_status( char *s, OM_uint32 major_status,
 }
 
 
-void log_ctx_flags( OM_uint32 flags )
+static void log_ctx_flags( OM_uint32 flags )
 {
+#ifdef DEBUG1
     if (flags & GSS_C_DELEG_FLAG)
         LOG(log_debug, logtype_uams, "uams_gss.c :context flag: GSS_C_DELEG_FLAG" );
     if (flags & GSS_C_MUTUAL_FLAG)
@@ -115,112 +117,327 @@ void log_ctx_flags( OM_uint32 flags )
         LOG(log_debug, logtype_uams, "uams_gss.c :context flag: GSS_C_CONF_FLAG" );
     if (flags & GSS_C_INTEG_FLAG)
         LOG(log_debug, logtype_uams, "uams_gss.c :context flag: GSS_C_INTEG_FLAG" );
+#endif
 }
 
-/* return 0 on success */
-static int do_gss_auth( char *service, char *ibuf, int ticket_len,
-                char *rbuf, int *rbuflen, char *username, int ulen ) 
+static void log_principal(gss_name_t server_name)
 {
+#ifdef DEBUG1
     OM_uint32 major_status = 0, minor_status = 0;
-    gss_name_t server_name;
-    gss_cred_id_t server_creds;
-    gss_ctx_id_t context_handle = GSS_C_NO_CONTEXT;
-    gss_buffer_desc ticket_buffer, authenticator_buff;
-    gss_name_t client_name;
-    OM_uint32  ret_flags;
-    int ret = 0;
+    gss_buffer_desc exported_name;
+
+    /* Only for debugging purposes, check the gssapi internal representation */
+    major_status = gss_export_name(&minor_status, server_name, &exported_name);
+    LOG(log_debug, logtype_uams, "log_principal: exported server name is %s", (char*) exported_name.value);
+    gss_release_buffer( &minor_status, &exported_name );
+#endif
+}
+
+/* get the principal from afpd and import it into server_name */
+static int get_afpd_principal(void *obj, gss_name_t *server_name)
+{
+    OM_uint32 major_status = 0, minor_status = 0;
+    char *realm, *fqdn, *service, *principal, *p;
+    int realmlen=0, fqdnlen=0, servicelen=0;
+    size_t principal_length;
     gss_buffer_desc s_princ_buffer;
 
-    s_princ_buffer.value = service;
-    s_princ_buffer.length = strlen( service ) + 1;
-    
-    LOG(log_debug, logtype_uams, "uams_gss.c :do_gss_auth: importing name" );
-    major_status = gss_import_name( &minor_status, 
-                   &s_princ_buffer, 
-                   GSS_C_NT_HOSTBASED_SERVICE,
-                   &server_name );
+    /* get all the required information from afpd */
+    if (uam_afpserver_option(obj, UAM_OPTION_KRB5REALM, (void*) &realm, &realmlen) < 0) 
+       return 1;
+    if (uam_afpserver_option(obj, UAM_OPTION_FQDN, (void*) &fqdn, &fqdnlen) < 0) 
+       return 1;
+    if (uam_afpserver_option(obj, UAM_OPTION_KRB5SERVICE, (void *)&service, &servicelen) < 0)
+        return 1;
+
+    /* we need all the info, log error and return if one's missing */
+    if (!service || !servicelen || !fqdn || !fqdnlen || !realm || !realmlen) {
+        LOG(log_error, logtype_uams, 
+            "get_afpd_principal: could not retrieve required information from afpd.");
+        return 1;
+    }
+
+    /* allocate memory to hold the temporary principal string */
+    principal_length = servicelen + 1 + fqdnlen + 1 + realmlen + 1;
+    if ( NULL == (principal = (char*) malloc( principal_length)) ) {
+        LOG(log_error, logtype_uams,
+            "get_afpd_principal: out of memory allocating %u bytes", 
+            principal_length);
+        return 1;
+    }
+
+    /*
+     * Build the principal string.
+     * Format: 'service/fqdn@realm'
+     */
+    strlcpy( principal, service, principal_length);
+    strlcat( principal, "/", principal_length);
+
+    /* 
+     * The fqdn we get from afpd may contain a port.
+     * We need to strip the port from fqdn for principal.
+     */
+    p = strchr(fqdn, ':');
+    if (p)
+       *p = '\0';
+    strlcat( principal, fqdn, principal_length);
+    if (p)
+       *p = ':';
+    strlcat( principal, "@", principal_length);
+    strlcat( principal, realm, principal_length);
+
+    /*
+     * Import our principal into the gssapi internal representation
+     * stored in server_name.
+     */
+    s_princ_buffer.value = principal;
+    s_princ_buffer.length = strlen( principal ) + 1;
+
+    LOG(log_debug, logtype_uams, "get_afpd_principal: importing principal `%s'", principal);
+    major_status = gss_import_name( &minor_status,
+                    &s_princ_buffer,
+                    GSS_C_NO_OID,
+                    server_name );
+
+    /* 
+     * Get rid of malloc'ed memmory.
+     * Don't release the s_princ_buffer, we free principal instead.
+     */
+    free(principal);
+
     if (major_status != GSS_S_COMPLETE) {
-       log_status( "import_name", major_status, minor_status );
-       ret = 1;
-       goto cleanup_vars;
+        /* Importing our service principal failed, bail out. */
+        log_status( "import_principal", major_status, minor_status );
+        return 1;
+    }
+    return 0;
+}
+
+
+/* get the username */
+static int get_client_username(char *username, int ulen, gss_name_t *client_name)
+{
+    OM_uint32 major_status = 0, minor_status = 0;
+    gss_buffer_desc client_name_buffer;
+    char *p;
+    int namelen, ret=0;
+
+    /* 
+     * To extract the unix username, use gss_display_name on client_name.
+     * We do rely on gss_display_name returning a zero terminated string.
+     * The username returned contains the realm and possibly an instance.
+     * We only want the username for afpd, so we have to strip those from
+     * the username before copying it to afpd's buffer.
+     */
+
+    major_status = gss_display_name( &minor_status, *client_name,
+                                     &client_name_buffer, (gss_OID *)NULL );
+    if (major_status != GSS_S_COMPLETE) {
+        log_status( "display_name", major_status, minor_status );
+        return 1;
+    }
+
+    LOG(log_debug, logtype_uams, "get_client_username: user is `%s'", client_name_buffer.value);
+
+    /* chop off realm */
+    p = strchr( client_name_buffer.value, '@' );
+    if (p)
+        *p = 0;
+    /* FIXME: chop off instance? */
+    p = strchr( client_name_buffer.value, '/' );
+    if (p)
+        *p = 0;
+
+    /* check if this username fits into afpd's username buffer */
+    namelen = strlen(client_name_buffer.value);
+    if ( namelen >= ulen ) {
+        /* The username is too long for afpd's buffer, bail out */
+        LOG(log_error, logtype_uams,
+            "get_client_username: username `%s' too long", client_name_buffer.value);
+        ret = 1;
+    }
+    else {
+        /* copy stripped username to afpd's buffer */
+        strlcpy(username, client_name_buffer.value, ulen);
+    }
+
+    /* we're done with client_name_buffer, release it */
+    gss_release_buffer(&minor_status, &client_name_buffer );
+
+    return ret;
+}
+
+/* wrap afpd's sessionkey */
+static int wrap_sessionkey(gss_ctx_id_t context, struct session_info *sinfo)
+{
+    OM_uint32 status = 0;
+    int ret=0;
+    gss_buffer_desc sesskey_buff, wrap_buff;
+
+    /* 
+     * gss_wrap afpd's session_key.
+     * This is needed fo OS X 10.3 clients. They request this information
+     * with type 8 (kGetKerberosSessionKey) on FPGetSession.
+     * See AFP 3.1 specs, page 77.
+     */
+
+    sesskey_buff.value = sinfo->sessionkey;
+    sesskey_buff.length = sinfo->sessionkey_len;
+
+    /* gss_wrap the session key with the default machanism. 
+       Require both confidentiality and integrity services */
+    gss_wrap (&status, context, 1, GSS_C_QOP_DEFAULT, &sesskey_buff, NULL, &wrap_buff);
+
+    if ( status != GSS_S_COMPLETE) {
+        LOG(log_error, logtype_uams, "wrap_sessionkey: failed to gss_wrap sessionkey");
+       log_status( "GSS wrap", 0, status );
+        return 1;
+    }
+
+    /* store the wrapped session key in afpd's session_info struct */
+    if ( NULL == (sinfo->cryptedkey = malloc ( wrap_buff.length )) ) {
+        LOG(log_error, logtype_uams, 
+            "wrap_sessionkey: out of memory tyring to allocate %u bytes", 
+            wrap_buff.length);
+        ret = 1;
+    } else {
+        /* cryptedkey is binary data */
+        memcpy (sinfo->cryptedkey, wrap_buff.value, wrap_buff.length);
+        sinfo->cryptedkey_len = wrap_buff.length;
     }
 
-    LOG(log_debug, logtype_uams, 
-       "uams_gss.c :do_gss_auth: acquiring credentials (uid = %d, keytab = %s)",
+    /* we're done with buffer, release */
+    gss_release_buffer( &status, &wrap_buff );
+
+    return ret;
+}
+
+/*-------------*/
+static int acquire_credentials (gss_name_t *server_name, gss_cred_id_t *server_creds)
+{
+    OM_uint32 major_status = 0, minor_status = 0;
+
+    LOG(log_debug, logtype_uams,
+        "acquire credentials: acquiring credentials (uid = %d, keytab = %s)",
         (int)geteuid(), getenv( "KRB5_KTNAME") );
-    major_status = gss_acquire_cred( &minor_status, server_name, 
-                       GSS_C_INDEFINITE, GSS_C_NO_OID_SET, GSS_C_ACCEPT,
-                       &server_creds, NULL, NULL );    
+   /*
+    * Acquire credentials usable for accepting context negotiations.
+    * Credentials are for server_name, have an indefinite lifetime,
+    * have no specific mechanisms, are to be used for accepting context 
+    * negotiations and are to be placed in server_creds. 
+    * We don't care about the mechanisms or about the time for which they are valid.
+    */
+    major_status = gss_acquire_cred( &minor_status, *server_name,
+                        GSS_C_INDEFINITE, GSS_C_NO_OID_SET, GSS_C_ACCEPT,
+                        server_creds, NULL, NULL );
+
     if (major_status != GSS_S_COMPLETE) {
-       log_status( "acquire_cred", major_status, minor_status );
-       ret = 1;
-       goto cleanup_vars;
+        log_status( "acquire_cred", major_status, minor_status );
+        return 1;
+    }
+   
+    return 0;
+}
+
+/*-------------*/
+static int accept_sec_context (gss_ctx_id_t *context, gss_cred_id_t server_creds, 
+                           gss_buffer_desc *ticket_buffer, gss_name_t *client_name,
+                           gss_buffer_desc *authenticator_buff)
+{
+    OM_uint32 major_status = 0, minor_status = 0, ret_flags;
+
+    /* Initialize autheticator buffer. */
+    authenticator_buff->length = 0;
+    authenticator_buff->value = NULL;
+
+    LOG(log_debug, logtype_uams, "accept_context: accepting context (ticketlen: %u)", 
+        ticket_buffer->length);
+
+    /* 
+     * Try to accept the secondary context using the tocken in ticket_buffer.
+     * We don't care about the mechanisms used, nor for the time. 
+     * We don't act as a proxy either.
+     */
+    major_status = gss_accept_sec_context( &minor_status, context,
+                        server_creds, ticket_buffer, GSS_C_NO_CHANNEL_BINDINGS,
+                        client_name, NULL, authenticator_buff,
+                        &ret_flags, NULL, NULL );
+
+    if (major_status != GSS_S_COMPLETE) {
+        log_status( "accept_sec_context", major_status, minor_status );
+        return 1;
     }
+    log_ctx_flags( ret_flags );
+    return 0;
+}
     
-    /* The GSSAPI docs say that this should be done in a big "do" loop,
-     * but Apple's implementation doesn't seem to support this behavior.
+
+/* return 0 on success */
+static int do_gss_auth(void *obj, char *ibuf, int ticket_len,
+                char *rbuf, int *rbuflen, char *username, int ulen,
+                struct session_info *sinfo ) 
+{
+    OM_uint32 status = 0;
+    gss_name_t server_name, client_name;
+    gss_cred_id_t server_creds;
+    gss_ctx_id_t context_handle = GSS_C_NO_CONTEXT;
+    gss_buffer_desc ticket_buffer, authenticator_buff;
+    int ret = 0;
+
+    /* import our principal name from afpd */
+    if (get_afpd_principal(obj, &server_name) != 0) {
+        return 1;
+    }
+    log_principal(server_name);
+  
+    /* Now we have to acquire our credentials */
+    if ((ret = acquire_credentials (&server_name, &server_creds)))
+       goto cleanup_vars;
+
+    /* 
+     * Try to accept the secondary context, using the ticket/token the 
+     * client sent us. Ticket is stored at current ibuf position. 
+     * Don't try to release ticket_buffer later, it points into ibuf! 
      */
     ticket_buffer.length = ticket_len;
     ticket_buffer.value = ibuf;
-    authenticator_buff.length = 0;
-    authenticator_buff.value = NULL;
-    LOG(log_debug, logtype_uams, 
-       "uams_gss.c :do_gss_auth: accepting context (ticketlen: %u, value: %X)",
-        ticket_buffer.length, ticket_buffer.value );
-    major_status = gss_accept_sec_context( &minor_status, &context_handle,
-                       server_creds, &ticket_buffer, GSS_C_NO_CHANNEL_BINDINGS,
-                       &client_name, NULL, &authenticator_buff,
-                       &ret_flags, NULL, NULL );
-
-    if (major_status == GSS_S_COMPLETE) {
-       gss_buffer_desc client_name_buffer;
-
-       log_ctx_flags( ret_flags );
-       /* use gss_display_name on client_name */
-       major_status = gss_display_name( &minor_status, client_name,
-                               &client_name_buffer, (gss_OID *)NULL );
-       if (major_status == GSS_S_COMPLETE) {
-           u_int16_t auth_len = htons( authenticator_buff.length );
-           /* save the username... note that doing it this way is
-            * not the best idea: if a principal is truncated, a user could be
-            * impersonated
-            */
-           memcpy( username, client_name_buffer.value, 
-               MIN(client_name_buffer.length, ulen - 1));
-           username[MIN(client_name_buffer.length, ulen - 1)] = 0;
-       
-            LOG(log_debug, logtype_uams, "uams_gss.c :do_gss_auth: user is %s!", username );
-           /* copy the authenticator length into the reply buffer */
-           memcpy( rbuf, &auth_len, sizeof(auth_len) );
-           *rbuflen += sizeof(auth_len), rbuf += sizeof(auth_len);
-
-           /* copy the authenticator value into the reply buffer */
-           memcpy( rbuf, authenticator_buff.value, authenticator_buff.length );
-           *rbuflen += authenticator_buff.length;
-
-           gss_release_buffer( &minor_status, &client_name_buffer );
-       } else {
-           log_status( "display_name", major_status, minor_status );
-           ret = 1;
-       }
 
+    ret = accept_sec_context (&context_handle, server_creds, &ticket_buffer, 
+                          &client_name, &authenticator_buff);
 
-       /* Clean up after ourselves */
-        gss_release_name( &minor_status, &client_name );
+    if (!ret) {
+        /* We succesfully acquired the secondary context, now get the 
+           username for afpd and gss_wrap the sessionkey */
+        if ( 0 == (ret = get_client_username(username, ulen, &client_name)) ) {
+            ret = wrap_sessionkey(context_handle, sinfo);
+        }
 
-       if (authenticator_buff.value)
-            gss_release_buffer( &minor_status, &authenticator_buff );
+        if (!ret) {
+            /* FIXME: Is copying the authenticator really necessary? 
+               Where is this documented? */
+            u_int16_t auth_len = htons( authenticator_buff.length );
 
-        gss_delete_sec_context( &minor_status, 
-                       &context_handle, NULL );
-    } else {
-       log_status( "accept_sec_context", major_status, minor_status );
-        ret = 1;
-    }
-    gss_release_cred( &minor_status, &server_creds );
+            /* copy the authenticator length into the reply buffer */
+            memcpy( rbuf, &auth_len, sizeof(auth_len) );
+            *rbuflen += sizeof(auth_len);
+            rbuf += sizeof(auth_len);
+
+            /* copy the authenticator value into the reply buffer */
+            memcpy( rbuf, authenticator_buff.value, authenticator_buff.length );
+            *rbuflen += authenticator_buff.length;
+        }
+
+       /* Clean up after ourselves */
+        gss_release_name( &status, &client_name );
+       if ( authenticator_buff.value)
+           gss_release_buffer( &status, &authenticator_buff );
+
+        gss_delete_sec_context( &status, &context_handle, NULL );
+    } 
+    gss_release_cred( &status, &server_creds );
 
 cleanup_vars:
-    gss_release_name( &minor_status, &server_name );
+    gss_release_name( &status, &server_name );
     
     return ret;
 }
@@ -254,8 +471,8 @@ static int gss_logincont(void *obj, struct passwd **uam_pwd,
     u_int16_t ticket_len;
     char *p;
     int rblen;
-    char *service;
-    int userlen, servicelen;
+    int userlen;
+    struct session_info *sinfo;
 
     /* Apple's AFP 3.1 documentation specifies that this command
      * takes the following format:
@@ -283,6 +500,10 @@ static int gss_logincont(void *obj, struct passwd **uam_pwd,
 
     rblen = *rbuflen = 0;
 
+    if (ibuflen < 3) {
+        LOG(log_info, logtype_uams, "uams_gss.c :LoginCont: received incomplete packet");
+       return AFPERR_PARAM;
+    }
     ibuf++, ibuflen--; /* ?? */
 
     /* 2 byte ID from LoginExt -- always '00 01' in this implementation */
@@ -290,20 +511,25 @@ static int gss_logincont(void *obj, struct passwd **uam_pwd,
     ibuf += sizeof(login_id), ibuflen -= sizeof(login_id);
     login_id = ntohs( login_id );
 
+    /* get the username buffer from apfd */
     if (uam_afpserver_option(obj, UAM_OPTION_USERNAME, (void *) &username, &userlen) < 0)
         return AFPERR_MISC;
 
-    if (uam_afpserver_option(obj, UAM_OPTION_KRB5SERVICE, (void *)&service, &servicelen) < 0)
+    /* get the session_info structure from afpd. We need the session key */
+    if (uam_afpserver_option(obj, UAM_OPTION_SESSIONINFO, (void *)&sinfo, NULL) < 0)
        return AFPERR_MISC;
 
-    if (service == NULL) 
-       return AFPERR_MISC;
+    if (sinfo->sessionkey == NULL || sinfo->sessionkey_len == 0) {
+        /* Should never happen. Most likely way too old afpd version */
+        LOG(log_info, logtype_uams, "internal error: afpd's sessionkey not set");
+        return AFPERR_MISC;
+    }
 
     /* We skip past the 'username' parameter because all that matters is the ticket */
     p = ibuf;
     while( *ibuf && ibuflen ) { ibuf++, ibuflen--; }
     if (ibuflen < 4) {
-        LOG(log_debug, logtype_uams, "uams_gss.c :LoginCont: user is %s, no ticket", p);
+        LOG(log_info, logtype_uams, "uams_gss.c :LoginCont: user is %s, no ticket", p);
        return AFPERR_PARAM;
     }
 
@@ -311,24 +537,27 @@ static int gss_logincont(void *obj, struct passwd **uam_pwd,
 
     if ((ibuf - p + 1) % 2) ibuf++, ibuflen--; /* deal with potential padding */
 
-    LOG(log_debug, logtype_uams, "uams_gss.c :LoginCont: client thinks user is %s", p);
+    LOG(log_info, logtype_uams, "uams_gss.c :LoginCont: client thinks user is %s", p);
 
+    /* get the length of the ticket the client sends us */
     memcpy(&ticket_len, ibuf, sizeof(ticket_len));
     ibuf += sizeof(ticket_len); ibuflen -= sizeof(ticket_len);
     ticket_len = ntohs( ticket_len );
 
+    /* a little bounds checking */
     if (ticket_len > ibuflen) {
-        LOG(log_info, logtype_uams, "uams_gss.c :LoginCont: invalid ticket length");
+        LOG(log_info, logtype_uams,
+            "uams_gss.c :LoginCont: invalid ticket length (%u > %u)", ticket_len, ibuflen);
        return AFPERR_PARAM;
     }
 
-    if (!do_gss_auth(service, ibuf, ticket_len, rbuf, &rblen, username, userlen)) {
-       char *at = strchr( username, '@' );
-
-       // Chop off the realm name
-       if (at)
-           *at = '\0';
-       if((pwd = uam_getname( username, userlen )) == NULL) {
+    /* now try to authenticate */
+    if (!do_gss_auth(obj, ibuf, ticket_len, rbuf, &rblen, username, userlen, sinfo)) {
+        /* We use the username we got back from the gssapi client_name.
+           Should we compare this to the username the client sent in the clear?
+           We know the character encoding of the cleartext username (UTF8), what
+           encoding is the gssapi name in? */
+       if((pwd = uam_getname( obj, username, userlen )) == NULL) {
            LOG(log_info, logtype_uams, "uam_getname() failed for %s", username);
            return AFPERR_PARAM;
        }
@@ -372,15 +601,15 @@ static int gss_login_ext(void *obj, char *uname, struct passwd **uam_pwd,
 static void gss_logout() {
 }
 
-static int uam_setup(const char *path)
+int uam_setup(const char *path)
 {
     if (uam_register(UAM_SERVER_LOGIN_EXT, path, "Client Krb v2", 
                   gss_login, gss_logincont, gss_logout, gss_login_ext) < 0)
-       if (uam_register( UAM_SERVER_LOGIN, path, "Client Krb v2",
-               gss_login, gss_logincont, gss_logout ) < 0)
-            return -1;
+    if (uam_register(UAM_SERVER_LOGIN, path, "Client Krb v2", 
+                  gss_login, gss_logincont, gss_logout) < 0)
+        return -1;
 
-    return 0;
+  return 0;
 }
 
 static void uam_cleanup(void)
index 2b7697456eff3525c7aea3754269bddff904dab3..42a2bc371ccc49807ce2ac87b44ad3ba89a36037 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: uams_guest.c,v 1.12 2003-03-12 15:07:03 didg Exp $
+ * $Id: uams_guest.c,v 1.13 2005-04-28 20:49:50 bfernhomberg Exp $
  *
  * (c) 2001 (see COPYING)
  */
@@ -33,11 +33,18 @@ char *strchr (), *strrchr ();
 
 #include <atalk/afp.h>
 #include <atalk/uam.h>
+#include <atalk/util.h>
+
+#ifndef MIN
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+#endif /* MIN */
+
+extern void append(void *, const char *, int);
 
 /* login and login_ext are almost the same */
 static int noauth_login(void *obj, struct passwd **uam_pwd,
-                       char *ibuf, int ibuflen
-                       char *rbuf, int *rbuflen)
+                       char *ibuf _U_, int ibuflen _U_
+                       char *rbuf _U_, int *rbuflen)
 {
     struct passwd *pwent;
     char *guest, *username;
@@ -71,7 +78,7 @@ static int noauth_login(void *obj, struct passwd **uam_pwd,
     return( AFP_OK );
 }
 
-static int noauth_login_ext(void *obj, char *uname, struct passwd **uam_pwd,
+static int noauth_login_ext(void *obj, char *uname _U_, struct passwd **uam_pwd,
                      char *ibuf, int ibuflen,
                      char *rbuf, int *rbuflen)
 {
@@ -88,7 +95,12 @@ int noauth_printer(start, stop, username, out)
     static const char *loginok = "0\r";
 
     data = (char *)malloc(stop - start + 1);
-    strncpy(data, start, stop - start + 1);
+    if (!data) {
+       LOG(log_info, logtype_uams,"Bad Login NoAuthUAM: malloc");
+       return(-1);
+    }
+
+    strlcpy(data, start, stop - start + 1);
 
     /* We are looking for the following format in data:
      * (username)
@@ -102,12 +114,12 @@ int noauth_printer(start, stop, username, out)
        return(-1);
     }
     p++;
-    if ((q = strchr(data, ')' )) == NULL) {
+    if ((q = strchr(p, ')' )) == NULL) {
        LOG(log_info, logtype_uams,"Bad Login NoAuthUAM: username not found in string");
        free(data);
        return(-1);
     }
-    strncpy(username, p, q - p);
+    memcpy(username, p,  MIN( UAM_USERNAMELEN, q - p ));
 
     /* Done copying username, clean up */
     free(data);
index 59d58efc37feaf898848d6f1db4757efcc070b4d..205b57b809b1686cfd8e6724f5a3eafad46f959e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: uams_krb4.c,v 1.6 2002-01-04 04:45:48 sibaz Exp $
+ * $Id: uams_krb4.c,v 1.7 2005-04-28 20:49:50 bfernhomberg Exp $
  *
  * Copyright (c) 1990,1993 Regents of The University of Michigan.
  * All Rights Reserved.  See COPYRIGHT.
@@ -190,7 +190,7 @@ static int krb4_login(void *obj, struct passwd **uam_pwd,
            *p = KRB4RPL_DONE;  /* XXX */
            *rbuflen = 1;
 
-           if (( pwd = uam_getname( ad.pname, strlen(ad.pname) )) == NULL ) {
+           if (( pwd = uam_getname( obj, ad.pname, strlen(ad.pname) )) == NULL ) {
                return AFPERR_PARAM;
            }
 /*
@@ -337,7 +337,7 @@ static int krb4_logincont(void *obj, struct passwd **uam_pwd,
            *p = KRB4RPL_DONE;  /* XXX */
            *rbuflen = 1;
 
-           if (( pwd = uam_getname( username, strlen(username) ) ) == NULL ) {
+           if (( pwd = uam_getname( obj, username, strlen(username) ) ) == NULL ) {
                return( AFPERR_NOTAUTH );
            }
 /*
@@ -385,7 +385,7 @@ static int krb4_logincont(void *obj, struct passwd **uam_pwd,
                    *p = KRB4RPL_DONE;  /* XXX */
                    *rbuflen = 1;
 
-                   if (( pwd = uam_getname( ad.pname, strlen(ad.pname) )) 
+                   if (( pwd = uam_getname( obj, ad.pname, strlen(ad.pname) )) 
                        == NULL ) {
                        return( AFPERR_PARAM );
                    }
@@ -454,7 +454,7 @@ static int krb4_logincont(void *obj, struct passwd **uam_pwd,
                    *p = KRB4RPL_DONE;  /* XXX */
                    *rbuflen = 1;
 
-                   if (( pwd = uam_getname( ad.pname, strlen(ad.pname) )) 
+                   if (( pwd = uam_getname( obj, ad.pname, strlen(ad.pname) )) 
                        == NULL ) {
                        return( AFPERR_PARAM );
                    }
@@ -746,7 +746,7 @@ static int afskrb_logincont(void *obj, struct passwd *uam_pwd,
        return ( AFPERR_BADUAM );
     }
 
-    if (( pwd = uam_getname( username )) == NULL ) {
+    if (( pwd = uam_getname( obj, username, strlen(username) )) == NULL ) {
        return ( AFPERR_PARAM );
     }
 
index bf47ea8a024b536b54b28523689f84094d5abc6d..0870968cb4f34e1dfe3c011b5c40722f5e5e8114 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: uams_pam.c,v 1.16 2003-05-14 15:13:50 didg Exp $
+ * $Id: uams_pam.c,v 1.17 2005-04-28 20:49:50 bfernhomberg Exp $
  *
  * Copyright (c) 1990,1993 Regents of The University of Michigan.
  * Copyright (c) 1999 Adrian Sun (asun@u.washington.edu) 
@@ -34,10 +34,16 @@ char *strchr (), *strrchr ();
 
 #include <atalk/logger.h>
 
+#ifdef HAVE_SECURITY_PAM_APPL_H
 #include <security/pam_appl.h>
+#endif
+#ifdef HAVE_PAM_PAM_APPL_H
+#include <pam/pam_appl.h>
+#endif
 
 #include <atalk/afp.h>
 #include <atalk/uam.h>
+#include <atalk/util.h>
 
 #define PASSWDLEN 8
 
@@ -54,6 +60,8 @@ static char *hostname;
 static char *PAM_username;
 static char *PAM_password;
 
+extern void append(void *, const char *, int);
+
 /* PAM conversation function
  * Here we assume (for now, at least) that echo on means login name, and
  * echo off means password.
@@ -61,7 +69,7 @@ static char *PAM_password;
 static int PAM_conv (int num_msg,
                      const struct pam_message **msg,
                      struct pam_response **resp,
-                     void *appdata_ptr) 
+                     void *appdata_ptr _U_
 {
   struct pam_response *reply;
   int count;
@@ -131,8 +139,8 @@ static struct pam_conv PAM_conversation = {
 };
 
 static int login(void *obj, char *username, int ulen,  struct passwd **uam_pwd,
-                    char *ibuf, int ibuflen,
-                    char *rbuf, int *rbuflen)
+                    char *ibuf, int ibuflen _U_,
+                    char *rbuf _U_, int *rbuflen _U_)
 {
     struct passwd *pwd;
     int err, PAM_error;
@@ -146,7 +154,7 @@ static int login(void *obj, char *username, int ulen,  struct passwd **uam_pwd,
     
     ibuf[ PASSWDLEN ] = '\0';
 
-    if (( pwd = uam_getname(username, ulen)) == NULL ) {
+    if (( pwd = uam_getname(obj, username, ulen)) == NULL ) {
        return AFPERR_PARAM;
     }
 
@@ -172,13 +180,14 @@ static int login(void *obj, char *username, int ulen,  struct passwd **uam_pwd,
 
     PAM_error = pam_acct_mgmt(pamh, 0);
     if (PAM_error != PAM_SUCCESS) {
-      if (PAM_error == PAM_ACCT_EXPIRED)
+      if (PAM_error == PAM_NEW_AUTHTOK_REQD) /* Password change required */
        err = AFPERR_PWDEXPR;
 #ifdef PAM_AUTHTOKEN_REQD
       else if (PAM_error == PAM_AUTHTOKEN_REQD) 
        err = AFPERR_PWDCHNG;
 #endif /* PAM_AUTHTOKEN_REQD */
-      goto login_err;
+      else
+        goto login_err;
     }
 
 #ifndef PAM_CRED_ESTABLISH
@@ -193,6 +202,10 @@ static int login(void *obj, char *username, int ulen,  struct passwd **uam_pwd,
       goto login_err;
 
     *uam_pwd = pwd;
+
+    if (err == AFPERR_PWDEXPR)
+       return err;
+
     return AFP_OK;
 
 login_err:
@@ -226,6 +239,7 @@ static int pam_login(void *obj, struct passwd **uam_pwd,
     ibuf += len;
 
     username[ len ] = '\0';
+
     if ((unsigned long) ibuf & 1)  /* pad character */
       ++ibuf;
     return (login(obj, username, ulen, uam_pwd, ibuf, ibuflen, rbuf, rbuflen));
@@ -256,7 +270,7 @@ static int pam_login_ext(void *obj, char *uname, struct passwd **uam_pwd,
     }
     memcpy(username, uname +2, len );
     username[ len ] = '\0';
-
+    
     return (login(obj, username, ulen, uam_pwd, ibuf, ibuflen, rbuf, rbuflen));
 }
 
@@ -268,9 +282,9 @@ static void pam_logout() {
 }
 
 /* change passwd */
-static int pam_changepw(void *obj, char *username,
-                       struct passwd *pwd, char *ibuf, int ibuflen,
-                       char *rbuf, int *rbuflen)
+static int pam_changepw(void *obj _U_, char *username,
+                       struct passwd *pwd _U_, char *ibuf, int ibuflen _U_,
+                       char *rbuf _U_, int *rbuflen _U_)
 {
     char pw[PASSWDLEN + 1];
     pam_handle_t *lpamh;
@@ -338,14 +352,13 @@ int pam_printer(start, stop, username, out)
     static const char *loginok = "0\r";
     struct passwd *pwd;
 
-    data = (char *)malloc(stop - start + 2);
+    data = (char *)malloc(stop - start + 1);
     if (!data) {
        LOG(log_info, logtype_uams,"Bad Login ClearTxtUAM: malloc");
        return(-1);
     }
 
-    strncpy(data, start, stop - start + 1);
-    data[stop - start + 2] = 0;
+    strlcpy(data, start, stop - start + 1);
 
     /* We are looking for the following format in data:
      * (username) (password)
@@ -365,8 +378,7 @@ int pam_printer(start, stop, username, out)
        free(data);
        return(-1);
     }
-    strncpy(username, p, MIN(UAM_USERNAMELEN, q - p) );
-    username[ UAM_USERNAMELEN +1] = '\0';
+    memcpy(username, p, MIN(UAM_USERNAMELEN, q - p) );
 
     /* Parse input for password in next () */
     p = q + 3;
@@ -375,13 +387,12 @@ int pam_printer(start, stop, username, out)
        free(data);
        return(-1);
     }
-    strncpy(password, p, MIN(PASSWDLEN, (q - p)) );
-    password[ PASSWDLEN + 1] = '\0';
+    memcpy(password, p, MIN(PASSWDLEN, (q - p)) );
 
     /* Done copying username and password, clean up */
     free(data);
 
-    if (( pwd = uam_getname(username, strlen(username))) == NULL ) {
+    if (( pwd = uam_getname(NULL, username, strlen(username))) == NULL ) {
         LOG(log_info, logtype_uams, "Bad Login ClearTxtUAM: ( %s ) not found ",
             username);
         return(-1);
index 49b4e72ea2408e2d04c361d5e4881f312f09b923..e94539c83c6dc99ff09aa408d05d00c264125f95 100644 (file)
@@ -1,20 +1,26 @@
 /*
- * $Id: uams_passwd.c,v 1.22 2004-01-14 16:10:29 bfernhomberg Exp $
+ * $Id: uams_passwd.c,v 1.23 2005-04-28 20:49:50 bfernhomberg Exp $
  *
  * Copyright (c) 1990,1993 Regents of The University of Michigan.
  * Copyright (c) 1999 Adrian Sun (asun@u.washington.edu) 
  * All Rights Reserved.  See COPYRIGHT.
  */
 
-#define _XOPEN_SOURCE /* for crypt() */
-
 #ifdef HAVE_CONFIG_H
 #include <config.h>
 #endif /* HAVE_CONFIG_H */
 
+#include <sys/types.h>
+/* crypt needs _XOPEN_SOURCE (500) at least on BSD, but that breaks Solaris compile */
+#ifdef NETBSD
+#define _XOPEN_SOURCE 500 /* for crypt() */
+#endif
+#ifdef FREEBSD
+#define _XOPEN_SOURCE /* for crypt() */
+#endif
+
 #include <stdio.h>
 #include <stdlib.h>
-
 /* STDC check */
 #if STDC_HEADERS
 #include <string.h>
@@ -29,26 +35,27 @@ char *strchr (), *strrchr ();
 #define memmove(d,s,n) bcopy ((s), (d), (n))
 #endif /* ! HAVE_MEMCPY */
 #endif /* STDC_HEADERS */
-
 #ifdef HAVE_UNISTD_H
 #include <unistd.h>
 #endif /* HAVE_UNISTD_H */
 #ifdef HAVE_CRYPT_H
 #include <crypt.h>
-#endif /* HAVE_CRYPT_H */
+#endif /* HAVE_CRYPT_H */
 #include <pwd.h>
-#include <atalk/logger.h>
-
-#ifdef SOLARIS
-#define SHADOWPW
-#endif /* SOLARIS */
-
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#ifdef HAVE_TIME_H
+#include <time.h>
+#endif
 #ifdef SHADOWPW
 #include <shadow.h>
 #endif /* SHADOWPW */
 
 #include <atalk/afp.h>
+#include <atalk/logger.h>
 #include <atalk/uam.h>
+#include <atalk/util.h>
 
 #define PASSWDLEN 8
 
@@ -64,12 +71,15 @@ char *strchr (), *strrchr ();
 static char *clientname;
 #endif /* TRU64 */
 
+extern void append(void *, const char *, int);
+
 static int pwd_login(void *obj, char *username, int ulen, struct passwd **uam_pwd,
                         char *ibuf, int ibuflen,
-                        char *rbuf, int *rbuflen)
+                        char *rbuf _U_, int *rbuflen _U_)
 {
     char  *p;
     struct passwd *pwd;
+    int err = AFP_OK;
 #ifdef SHADOWPW
     struct spwd *sp;
 #endif /* SHADOWPW */
@@ -85,7 +95,7 @@ static int pwd_login(void *obj, char *username, int ulen, struct passwd **uam_pw
     }
     ibuf[ PASSWDLEN ] = '\0';
 
-    if (( pwd = uam_getname(username, ulen)) == NULL ) {
+    if (( pwd = uam_getname(obj, username, ulen)) == NULL ) {
         return AFPERR_PARAM;
     }
 
@@ -102,6 +112,15 @@ static int pwd_login(void *obj, char *username, int ulen, struct passwd **uam_pw
         return AFPERR_NOTAUTH;
     }
     pwd->pw_passwd = sp->sp_pwdp;
+
+    if (sp && sp->sp_max != -1 && sp->sp_lstchg) {
+        time_t now = time(NULL) / (60*60*24);
+        int32_t expire_days = sp->sp_lstchg - now + sp->sp_max;
+        if ( expire_days < 0 ) {
+                LOG(log_info, logtype_uams, "Password for user %s expired", username);
+               err = AFPERR_PWDEXPR;
+        }
+    }
 #endif /* SHADOWPW */
 
     if (!pwd->pw_passwd) {
@@ -123,12 +142,12 @@ static int pwd_login(void *obj, char *username, int ulen, struct passwd **uam_pw
                                    NULL, FALSE, NULL, ibuf ) != SIASUCCESS )
             return AFPERR_NOTAUTH;
 
-        return AFP_OK;
+        return err;
     }
 #else /* TRU64 */
     p = crypt( ibuf, pwd->pw_passwd );
     if ( strcmp( p, pwd->pw_passwd ) == 0 )
-        return AFP_OK;
+        return err;
 #endif /* TRU64 */
 
     return AFPERR_NOTAUTH;
@@ -265,13 +284,12 @@ struct papfile    *out;
     static const char *loginok = "0\r";
     int ulen;
 
-    data = (char *)malloc(stop - start + 2);
+    data = (char *)malloc(stop - start + 1);
     if (!data) {
        LOG(log_info, logtype_uams,"Bad Login ClearTxtUAM: malloc");
        return(-1);
     }
-    strncpy(data, start, stop - start + 1);
-    data[stop - start + 2] = 0;
+    strlcpy(data, start, stop - start + 1);
 
     /* We are looking for the following format in data:
      * (username) (password)
@@ -286,32 +304,28 @@ struct papfile    *out;
         return(-1);
     }
     p++;
-    if ((q = strstr(data, ") (" )) == NULL) {
+    if ((q = strstr(p, ") (" )) == NULL) {
         LOG(log_info, logtype_uams,"Bad Login ClearTxtUAM: username not found in string");
         free(data);
         return(-1);
     }
-    strncpy(username, p, MIN( UAM_USERNAMELEN, (q - p)) );
-    username[ UAM_USERNAMELEN+1] = '\0';
-
+    memcpy(username, p,  MIN( UAM_USERNAMELEN, q - p ));
 
     /* Parse input for password in next () */
     p = q + 3;
-    if ((q = strrchr(data, ')' )) == NULL) {
+    if ((q = strrchr(, ')' )) == NULL) {
         LOG(log_info, logtype_uams,"Bad Login ClearTxtUAM: password not found in string");
         free(data);
         return(-1);
     }
-    strncpy(password, p, MIN(PASSWDLEN, q - p) );
-    password[ PASSWDLEN+1] = '\0';
-
+    memcpy(password, p, MIN(PASSWDLEN, q - p) );
 
     /* Done copying username and password, clean up */
     free(data);
 
     ulen = strlen(username);
 
-    if (( pwd = uam_getname(username, ulen)) == NULL ) {
+    if (( pwd = uam_getname(NULL, username, ulen)) == NULL ) {
         LOG(log_info, logtype_uams, "Bad Login ClearTxtUAM: ( %s ) not found ",
             username);
         return(-1);
@@ -329,6 +343,16 @@ struct papfile     *out;
         return(-1);
     }
     pwd->pw_passwd = sp->sp_pwdp;
+
+    if (sp && sp->sp_max != -1 && sp->sp_lstchg) {
+        time_t now = time(NULL) / (60*60*24);
+        int32_t expire_days = sp->sp_lstchg - now + sp->sp_max;
+        if ( expire_days < 0 ) {
+                LOG(log_info, logtype_uams, "Password for user %s expired", username);
+               return (-1);
+        }
+    }
+
 #endif /* SHADOWPW */
 
     if (!pwd->pw_passwd) {
index 3fc8ee4e94f5ff29072e97e041514a10e1d908ae..03670c298de948f0d0cb291704d42248c4369b4a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: uams_pgp.c,v 1.10 2003-06-11 07:26:50 srittau Exp $
+ * $Id: uams_pgp.c,v 1.11 2005-04-28 20:49:50 bfernhomberg Exp $
  *
  * Copyright (c) 1990,1993 Regents of The University of Michigan.
  * Copyright (c) 1999 Adrian Sun (asun@u.washington.edu) 
@@ -7,7 +7,7 @@
  */
 
 #ifdef HAVE_CONFIG_H
-#include <config.h>
+#include "config.h"
 #endif /* HAVE_CONFIG_H */
 
 #ifdef UAM_PGP
@@ -20,6 +20,9 @@
 #ifdef HAVE_UNISTD_H
 #include <unistd.h>
 #endif /* HAVE_UNISTD_H */
+#ifdef HAVE_CRYPT_H
+#include <crypt.h>
+#endif /* HAVE_CRYPT_H */
 #include <pwd.h>
 #include <atalk/logger.h>
 
@@ -57,8 +60,6 @@ static int pgp_login(void *obj, struct passwd **uam_pwd,
                     char *ibuf, int ibuflen,
                     char *rbuf, int *rbuflen)
 {
-    BIGNUM *bn, *gbn, *pbn;
-    u_int16_t sessid;
     int len, i;
     char *name;
 
@@ -78,7 +79,7 @@ static int pgp_login(void *obj, struct passwd **uam_pwd,
     if ((unsigned long) ibuf & 1) /* padding */
       ++ibuf;
 
-    if (( pgppwd = uam_getname(name, i)) == NULL ) {
+    if (( pgppwd = uam_getname(obj, name, i)) == NULL ) {
       return AFPERR_PARAM;
     }
 
@@ -106,12 +107,8 @@ static int pgp_logincont(void *obj, struct passwd **uam_pwd,
                         char *ibuf, int ibuflen, 
                         char *rbuf, int *rbuflen)
 {
-    unsigned char iv[] = "RJscorat";
-#ifdef HAVE_GCRYPT
-    GcryMPI *bn1, *bn2, *bn3;
-#else /* HAVE_GCRYPT */
+       unsigned char iv[] = "RJscorat";
     BIGNUM *bn1, *bn2, *bn3;
-#endif
     u_int16_t sessid;
     char *p;
 
@@ -122,51 +119,11 @@ static int pgp_logincont(void *obj, struct passwd **uam_pwd,
     if (sessid != pgphash(obj))
       return AFPERR_PARAM;
     ibuf += sizeof(sessid);
-
-#ifdef HAVE_GCRYPT
-    {
-      GcryCipherHd handle;
-
-      handle = gcry_cipher_open(GCRY_CIPHER_CAST5,
-                                     GCRY_CIPHER_MODE_CBC, 0);
-      if (!handle)
-        return AFPERR_PARAM;
-
-      if (gcry_cipher_setkey(handle, &castkey, ) != 0) {
-        gcry_cipher_close(handle);
-        return AFPERR_PARAM;
-      }
-
-      if (gcry_cipher_setiv(handle, iv, sizeof(iv)) != 0) {
-        gcry_cipher_close(handle);
-        return AFPERR_PARAM;
-      }
-
-      if (gcry_cipher_decrypt(handle, rbuf, CRYPT2BUFLEN, ibuf, CRYPT2BUFLEN) != 0) {
-        gcry_cipher_close(handle);
-        return AFPERR_PARAM;
-      }
-
-      gcry_cipher_close(handle);
-    }
-#else /* HAVE_GCRYPT */
+   
     /* use rbuf as scratch space */
     CAST_cbc_encrypt(ibuf, rbuf, CRYPT2BUFLEN, &castkey,
                     iv, CAST_DECRYPT);
-#endif /* HAVE_GCRYPT */
-
-#ifdef HAVE_GCRYPT
-    {
-      size_t sz;
-
-      bn1 = gcry_mpi_snew(KEYSIZE * 8);
-      sz = KEYSIZE;
-      gcry_mpi_scan(bn1, GCRYMPI_FMT_STD, rbuf, &sz);
-      bn2 = gcry_mpi_snew(sizeof(randbuf) * 8);
-      sz = sizeof(randbuf);
-      gcry_mpi_scan(bn1, GCRYMPI_FMT_STD, randbuf. &sz);
-    }
-#else /* HAVE_GCRYPT */
+    
     /* check to make sure that the random number is the same. we
      * get sent back an incremented random number. */
     if (!(bn1 = BN_bin2bn(rbuf, KEYSIZE, NULL)))
@@ -176,25 +133,12 @@ static int pgp_logincont(void *obj, struct passwd **uam_pwd,
       BN_free(bn1);
       return AFPERR_PARAM;
     }
-#endif /* HAVE_GCRYPT */
-
+      
     /* zero out the random number */
     memset(rbuf, 0, sizeof(randbuf));
     memset(randbuf, 0, sizeof(randbuf));
     rbuf += KEYSIZE;
 
-#ifdef HAVE_GCRYPT
-    bn3 = gcry_mpi_snew(0);
-    gcry_mpi_sub(bn3, bn1, bn2);
-    gcry_mpi_release(bn2);
-    gcry_mpi_release(bn1);
-
-    if (gcry_mpi_cmp_ui(bn3, 1UL) != 0) {
-      gcry_mpi_release(bn3);
-      return AFPERR_PARAM;
-    }
-    gcry_mpi_release(bn3);
-#else /* HAVE_GCRYPT */
     if (!(bn3 = BN_new())) {
       BN_free(bn2);
       BN_free(bn1);
@@ -211,7 +155,6 @@ static int pgp_logincont(void *obj, struct passwd **uam_pwd,
       return AFPERR_PARAM;
     }
     BN_free(bn3);
-#endif /* HAVE_GCRYPT */
 
 #ifdef AFS
     if ( kcheckuser(*uam_pwd, rbuf) == 0) {
index 7ec4b3854788e5864f7ef6be45d8f106ac3adb62..7d8d78b6f7408ada92f347978e9f152b96e527c7 100644 (file)
@@ -1,5 +1,5 @@
 /* 
- * $Id: uams_randnum.c,v 1.15 2003-06-11 07:23:24 srittau Exp $
+ * $Id: uams_randnum.c,v 1.16 2005-04-28 20:49:50 bfernhomberg Exp $
  *
  * Copyright (c) 1990,1993 Regents of The University of Michigan.
  * Copyright (c) 1999 Adrian Sun (asun@u.washington.edu) 
@@ -7,7 +7,7 @@
  */
 
 #ifdef HAVE_CONFIG_H
-#include <config.h>
+#include "config.h"
 #endif /* HAVE_CONFIG_H */
 
 #include <stdio.h>
@@ -47,25 +47,22 @@ char *strchr (), *strrchr ();
 #include <atalk/uam.h>
 
 
+#include <des.h>
+
 #ifdef USE_CRACKLIB
 #include <crack.h>
 #endif /* USE_CRACKLIB */
 
-#include "crypt.h"
-
 #ifndef __inline__
 #define __inline__
 #endif /* __inline__ */
 
 #define PASSWDLEN 8
 
-#ifndef DES_KEY_SZ
-#define DES_KEY_SZ 8
-#endif
-
-static u_int8_t                 seskey[DES_KEY_SZ];
+static C_Block         seskey;
+static Key_schedule    seskeysched;
 static struct passwd   *randpwd;
-static u_int8_t          randbuf[8];
+static u_int8_t         randbuf[8];
 
 /* hash to a 16-bit number. this will generate completely harmless 
  * warnings on 64-bit machines. */
@@ -75,7 +72,7 @@ static u_int8_t          randbuf[8];
 
 /* handle ~/.passwd. courtesy of shirsch@ibm.net. */
 static  __inline__ int home_passwd(const struct passwd *pwd, 
-                                  const char *path, const int pathlen, 
+                                  const char *path, const int pathlen _U_
                                   char *passwd, const int len,
                                   const int set)
 {
@@ -145,6 +142,7 @@ home_passwd_fail:
  * key file: 
  * key (in hex) */
 #define PASSWD_ILLEGAL '*'
+#define unhex(x)  (isdigit(x) ? (x) - '0' : toupper(x) + 10 - 'A')
 static int afppasswd(const struct passwd *pwd, 
                     const char *path, const int pathlen, 
                     char *passwd, int len, 
@@ -152,7 +150,9 @@ static int afppasswd(const struct passwd *pwd,
 {
   u_int8_t key[DES_KEY_SZ*2];
   char buf[MAXPATHLEN + 1], *p;
+  Key_schedule schedule;
   FILE *fp;
+  unsigned int i, j;
   int keyfd = -1, err = 0;
   off_t pos;
   
@@ -163,7 +163,7 @@ static int afppasswd(const struct passwd *pwd,
   
   /* open the key file if it exists */
   strcpy(buf, path);
-  if (pathlen < sizeof(buf) - 5) {
+  if (pathlen < (int) sizeof(buf) - 5) {
     strcat(buf, ".key");
     keyfd = open(buf, O_RDONLY);
   } 
@@ -172,7 +172,8 @@ static int afppasswd(const struct passwd *pwd,
   memset(buf, 0, sizeof(buf));
   while (fgets(buf, sizeof(buf), fp)) {
     if ((p = strchr(buf, ':'))) {
-      if (strncmp(buf, pwd->pw_name, p - buf) == 0) {
+      if ( strlen(pwd->pw_name) == (p - buf) &&
+           strncmp(buf, pwd->pw_name, p - buf) == 0) {
        p++;
        if (*p == PASSWD_ILLEGAL) {
          LOG(log_info, logtype_uams, "invalid password entry for %s", pwd->pw_name);
@@ -189,38 +190,48 @@ static int afppasswd(const struct passwd *pwd,
   goto afppasswd_done;
 
 afppasswd_found:
-  if (!set)
-    atalk_unhexify(p, sizeof(key), p, sizeof(key));
+  if (!set) {
+    /* convert to binary. */
+    for (i = j = 0; i < sizeof(key); i += 2, j++)
+      p[j] = (unhex(p[i]) << 4) | unhex(p[i + 1]);
+    if (j <= DES_KEY_SZ)
+      memset(p + j, 0, sizeof(key) - j);
+  }
 
   if (keyfd > -1) {
-      size_t len;
-
       /* read in the hex representation of an 8-byte key */
       read(keyfd, key, sizeof(key));
 
       /* convert to binary key */
-      len = strlen((char *) key);
-      atalk_unhexify(key, len, key, len);
+      for (i = j = 0; i < strlen((char *) key); i += 2, j++)
+       key[j] = (unhex(key[i]) << 4) | unhex(key[i + 1]);
+      if (j <= DES_KEY_SZ)
+       memset(key + j, 0, sizeof(key) - j);
+      key_sched((C_Block *) key, schedule);
+      memset(key, 0, sizeof(key));
 
       if (set) {
        /* NOTE: this takes advantage of the fact that passwd doesn't
         *       get used after this call if it's being set. */
-       err = atalk_encrypt(key, passwd, passwd);
+       ecb_encrypt((C_Block *) passwd, (C_Block *) passwd, schedule,
+                   DES_ENCRYPT);
       } else {
-       err = atalk_decrypt(key, p, p);
+       /* decrypt the password */
+       ecb_encrypt((C_Block *) p, (C_Block *) p, schedule, DES_DECRYPT);
       }
-      memset(key, 0, sizeof(key));
-
-      if (err)
-       goto afppasswd_done;
+      memset(&schedule, 0, sizeof(schedule));
   }
 
   if (set) {
+    const unsigned char hextable[] = "0123456789ABCDEF";
     struct flock lock;
     int fd = fileno(fp);
 
     /* convert to hex password */
-    atalk_hexify(key, sizeof(key), passwd, DES_KEY_SZ);
+    for (i = j = 0; i < DES_KEY_SZ; i++, j += 2) {
+      key[j] = hextable[(passwd[i] & 0xF0) >> 4];
+      key[j + 1] = hextable[passwd[i] & 0x0F];
+    }
     memcpy(p, key, sizeof(key));
 
     /* get exclusive access to the user's password entry. we don't
@@ -290,45 +301,29 @@ static int randpass(const struct passwd *pwd, const char *file,
   return i;
 }
 
-  
 /* randnum sends an 8-byte number and uses the user's password to
  * check against the encrypted reply. */
-static int randnum_login(void *obj, struct passwd **uam_pwd,
-                        char *ibuf, int ibuflen,
-                        char *rbuf, int *rbuflen)
+static int rand_login(void *obj, char *username, int ulen, struct passwd **uam_pwd _U_,
+                        char *ibuf _U_, int ibuflen _U_,
+                        char *rbuf, int *rbuflen)
 {
-  char *username, *passwdfile;
-  u_int16_t sessid;
-  int len, ulen, err;
-  
-  *rbuflen = 0;
-  
-  if (uam_afpserver_option(obj, UAM_OPTION_USERNAME, 
-                          (void *) &username, &ulen) < 0)
-    return AFPERR_PARAM;
 
-  len = UAM_PASSWD_FILENAME;
-  if (uam_afpserver_option(obj, UAM_OPTION_PASSWDOPT, 
-                            (void *) &passwdfile, &len) < 0)
-    return AFPERR_PARAM;
-
-  len = (unsigned char) *ibuf++;
-  if ( len > ulen ) {
-       return AFPERR_PARAM;
-  }
-  memcpy(username, ibuf, len );
-  ibuf += len;
-  username[ len ] = '\0';
-  if ((unsigned long) ibuf & 1) /* padding */
-    ++ibuf;
-  
-  if (( randpwd = uam_getname(username, ulen)) == NULL )
+  char *passwdfile;
+  u_int16_t sessid;
+  int len, err;
+  if (( randpwd = uam_getname(obj, username, ulen)) == NULL )
     return AFPERR_PARAM; /* unknown user */
   
   LOG(log_info, logtype_uams, "randnum/rand2num login: %s", username);
   if (uam_checkuser(randpwd) < 0)
     return AFPERR_NOTAUTH;
 
+  len = UAM_PASSWD_FILENAME;
+  if (uam_afpserver_option(obj, UAM_OPTION_PASSWDOPT,
+                             (void *) &passwdfile, &len) < 0)
+    return AFPERR_PARAM;
+
   if ((err = randpass(randpwd, passwdfile, seskey,
                      sizeof(seskey), 0)) != AFP_OK)
     return err;
@@ -355,10 +350,9 @@ static int randnum_login(void *obj, struct passwd **uam_pwd,
 /* check encrypted reply. we actually setup the encryption stuff
  * here as the first part of randnum and rand2num are identical. */
 static int randnum_logincont(void *obj, struct passwd **uam_pwd,
-                            char *ibuf, int ibuflen, 
-                            char *rbuf, int *rbuflen)
+                            char *ibuf, int ibuflen _U_
+                            char *rbuf _U_, int *rbuflen)
 {
-  int err = AFP_OK;
   u_int16_t sessid;
 
   *rbuflen = 0;
@@ -369,10 +363,13 @@ static int randnum_logincont(void *obj, struct passwd **uam_pwd,
 
   ibuf += sizeof(sessid);
 
-  err = atalk_encrypt(seskey, randbuf, randbuf);
+  /* encrypt. this saves a little space by using the fact that
+   * des can encrypt in-place without side-effects. */
+  key_sched((C_Block *) seskey, seskeysched);
   memset(seskey, 0, sizeof(seskey));
-  if (err)
-    return err;
+  ecb_encrypt((C_Block *) randbuf, (C_Block *) randbuf,
+              seskeysched, DES_ENCRYPT);
+  memset(&seskeysched, 0, sizeof(seskeysched));
 
   /* test against what the client sent */
   if (memcmp( randbuf, ibuf, sizeof(randbuf) )) { /* != */
@@ -382,7 +379,7 @@ static int randnum_logincont(void *obj, struct passwd **uam_pwd,
 
   memset(randbuf, 0, sizeof(randbuf));
   *uam_pwd = randpwd;
-  return err;
+  return AFP_OK;
 }
 
 
@@ -392,13 +389,11 @@ static int randnum_logincont(void *obj, struct passwd **uam_pwd,
  *    and sends it back as part of the reply.
  */
 static int rand2num_logincont(void *obj, struct passwd **uam_pwd,
-                             char *ibuf, int ibuflen, 
+                             char *ibuf, int ibuflen _U_
                              char *rbuf, int *rbuflen)
 {
-  int err = AFP_OK;
-  CryptHandle crypt_handle;
   u_int16_t sessid;
-  int i;
+  unsigned int i;
 
   *rbuflen = 0;
 
@@ -414,22 +409,24 @@ static int rand2num_logincont(void *obj, struct passwd **uam_pwd,
     seskey[i] <<= 1;
 
   /* encrypt randbuf */
-  err = atalk_encrypt_start(&crypt_handle, seskey);
-  atalk_encrypt_do(crypt_handle, randbuf, randbuf);
+  key_sched((C_Block *) seskey, seskeysched);
+  memset(seskey, 0, sizeof(seskey));
+  ecb_encrypt( (C_Block *) randbuf, (C_Block *) randbuf,
+              seskeysched, DES_ENCRYPT);
 
   /* test against client's reply */
   if (memcmp(randbuf, ibuf, sizeof(randbuf))) { /* != */
     memset(randbuf, 0, sizeof(randbuf));
+    memset(&seskeysched, 0, sizeof(seskeysched));
     return AFPERR_NOTAUTH;
   }
   ibuf += sizeof(randbuf);
   memset(randbuf, 0, sizeof(randbuf));
 
   /* encrypt client's challenge and send back */
-  atalk_encrypt_do(crypt_handle, rbuf, ibuf);
-  atalk_encrypt_end(crypt_handle);
-  memset(seskey, 0, sizeof(seskey));
-
+  ecb_encrypt( (C_Block *) ibuf, (C_Block *) rbuf,
+              seskeysched, DES_ENCRYPT);
+  memset(&seskeysched, 0, sizeof(seskeysched));
   *rbuflen = sizeof(randbuf);
   
   *uam_pwd = randpwd;
@@ -440,9 +437,9 @@ static int rand2num_logincont(void *obj, struct passwd **uam_pwd,
  * NOTE: an FPLogin must already have completed successfully for this
  *       to work. 
  */
-static int randnum_changepw(void *obj, const char *username, 
+static int randnum_changepw(void *obj, const char *username _U_
                            struct passwd *pwd, char *ibuf,
-                           int ibuflen, char *rbuf, int *rbuflen)
+                           int ibuflen _U_, char *rbuf _U_, int *rbuflen _U_)
 {
     char *passwdfile;
     int err, len;
@@ -462,17 +459,15 @@ static int randnum_changepw(void *obj, const char *username,
       return err;
 
     /* use old passwd to decrypt new passwd */
+    key_sched((C_Block *) seskey, seskeysched);
     ibuf += PASSWDLEN; /* new passwd */
     ibuf[PASSWDLEN] = '\0';
-    err = atalk_decrypt(seskey, ibuf, ibuf);
-    if (err)
-      return err;
+    ecb_encrypt( (C_Block *) ibuf, (C_Block *) ibuf, seskeysched, DES_DECRYPT);
 
     /* now use new passwd to decrypt old passwd */
+    key_sched((C_Block *) ibuf, seskeysched);
     ibuf -= PASSWDLEN; /* old passwd */
-    err = atalk_decrypt(ibuf, ibuf, ibuf);
-    if (err)
-      return err;
+    ecb_encrypt((C_Block *) ibuf, (C_Block *) ibuf, seskeysched, DES_DECRYPT);
     if (memcmp(seskey, ibuf, sizeof(seskey))) 
        err = AFPERR_NOTAUTH;
     else if (memcmp(seskey, ibuf + PASSWDLEN, sizeof(seskey)) == 0)
@@ -486,6 +481,7 @@ static int randnum_changepw(void *obj, const char *username,
       err = randpass(pwd, passwdfile, ibuf + PASSWDLEN, sizeof(seskey), 1);
 
     /* zero out some fields */
+    memset(&seskeysched, 0, sizeof(seskeysched));
     memset(seskey, 0, sizeof(seskey));
     memset(ibuf, 0, sizeof(seskey)); /* old passwd */
     memset(ibuf + PASSWDLEN, 0, sizeof(seskey)); /* new passwd */
@@ -496,17 +492,81 @@ static int randnum_changepw(void *obj, const char *username,
   return( AFP_OK );
 }
 
+/* randnum login */
+static int randnum_login(void *obj, struct passwd **uam_pwd,
+                        char *ibuf, int ibuflen,
+                        char *rbuf, int *rbuflen)
+{
+    char *username;
+    int len, ulen;
+
+    *rbuflen = 0;
+
+    if (uam_afpserver_option(obj, UAM_OPTION_USERNAME,
+                             (void *) &username, &ulen) < 0)
+        return AFPERR_MISC;
+
+    if (ibuflen <= 1) {
+        return( AFPERR_PARAM );
+    }
+
+    len = (unsigned char) *ibuf++;
+    ibuflen--;
+    if (!len || len > ibuflen || len > ulen ) {
+        return( AFPERR_PARAM );
+    }
+    memcpy(username, ibuf, len );
+    ibuf += len;
+    ibuflen -=len;
+    username[ len ] = '\0';
+
+    if ((unsigned long) ibuf & 1) { /* pad character */
+        ++ibuf;
+        ibuflen--;
+    }
+    return (rand_login(obj, username, ulen, uam_pwd, ibuf, ibuflen, rbuf, rbuflen));
+}
+
+/* randnum login ext */
+static int randnum_login_ext(void *obj, char *uname, struct passwd **uam_pwd,
+                        char *ibuf, int ibuflen,
+                        char *rbuf, int *rbuflen)
+{
+    char       *username;
+    int        len, ulen;
+    u_int16_t  temp16;
+
+    *rbuflen = 0;
+
+    if (uam_afpserver_option(obj, UAM_OPTION_USERNAME,
+                             (void *) &username, &ulen) < 0)
+        return AFPERR_MISC;
+
+    if (*uname != 3)
+        return AFPERR_PARAM;
+    uname++;
+    memcpy(&temp16, uname, sizeof(temp16));
+    len = ntohs(temp16);
+    if (!len || len > ulen ) {
+        return( AFPERR_PARAM );
+    }
+    memcpy(username, uname +2, len );
+    username[ len ] = '\0';
+    return (rand_login(obj, username, ulen, uam_pwd, ibuf, ibuflen, rbuf, rbuflen));
+}
+
 static int uam_setup(const char *path)
 {
-  if (uam_register(UAM_SERVER_LOGIN, path, "Randnum exchange", 
-                  randnum_login, randnum_logincont, NULL) < 0)
+  if (uam_register(UAM_SERVER_LOGIN_EXT, path, "Randnum exchange", 
+                  randnum_login, randnum_logincont, NULL, randnum_login_ext) < 0)
     return -1;
-  if (uam_register(UAM_SERVER_LOGIN, path, "2-Way Randnum exchange",
-                  randnum_login, rand2num_logincont, NULL) < 0) {
+
+  if (uam_register(UAM_SERVER_LOGIN_EXT, path, "2-Way Randnum exchange",
+                  randnum_login, rand2num_logincont, NULL, randnum_login_ext) < 0) {
     uam_unregister(UAM_SERVER_LOGIN, "Randnum exchange");
     return -1;
   }
-    
+
   if (uam_register(UAM_SERVER_CHANGEPW, path, "Randnum Exchange", 
                   randnum_changepw) < 0) {
     uam_unregister(UAM_SERVER_LOGIN, "Randnum exchange");
index dfd48306b80a77b8e38fe37477d58be900e58fe7..71f170505cdbd2cf64fc12a0ab041be08dea6424 100644 (file)
@@ -1,4 +1,8 @@
 # Makefile.am for include/atalk/
 
 atalkincludedir = $(includedir)/atalk
-atalkinclude_HEADERS = adouble.h aep.h afp.h asp.h atp.h boolean.h cnid.h compat.h ddp.h dsi.h logger.h nbp.h netddp.h pap.h paths.h rtmp.h server_child.h uam.h util.h zip.h
+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 unicode.h
+     
+noinst_HEADERS = cnid_dbd_private.h
index 62eafdf6f69e71a70b079f6263d343847c239b7d..94cda95518d8e9c01c468b6a6ebb3001a4cee711 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: adouble.h,v 1.23 2003-06-06 20:46:39 srittau Exp $
+ * $Id: adouble.h,v 1.24 2005-04-28 20:49:51 bfernhomberg Exp $
  * Copyright (c) 1990,1991 Regents of The University of Michigan.
  * All Rights Reserved.
  *
 #endif
 
 #ifdef HAVE_PWRITE
-
 #ifndef HAVE_PREAD
 #undef HAVE_PWRITE
 #endif
-
 #endif
 
-#ifdef  HAVE_PREAD
+/*
+   Still have to figure out which platforms really
+   need _XOPEN_SOURCE defined for pread.
+ */  
+#if defined(HAVE_PREAD) && !defined(SOLARIS) && !defined(__OpenBSD__) && !defined(__NetBSD__) && !defined(__FreeBSD__) && !defined(TRU64)
+#ifdef _XOPEN_SOURCE
+#undef _XOPEN_SOURCE
+#endif
 #define _XOPEN_SOURCE 500
 #endif
 
+#include <sys/types.h>
+#include <sys/stat.h>
+
 #ifdef HAVE_UNISTD_H
 #undef __USE_MISC
 #define __USE_MISC
 #include <unistd.h>
 #endif 
 
+#include <sys/cdefs.h>
+
 #ifdef HAVE_FCNTL_H  
 #include <fcntl.h>
 #endif
 
-#include <sys/cdefs.h>
-#include <sys/types.h>
-#include <sys/stat.h>
 #include <sys/mman.h>
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
 #include <netatalk/endian.h>
 
-/* FIXME: this is the wrong place to put this. 
- * NOTE: as of 2.2.1, linux can't do a sendfile from a socket. 
- * and it doesn't have 64 bits sendfile
- */
-#ifdef SENDFILE_FLAVOR_LINUX
-
-#if _FILE_OFFSET_BITS == 64 
-
-#undef SENDFILE_FLAVOR_LINUX
-
-#else /* _FILE_OFFSET_BITS != 64 */
-
-#define HAVE_SENDFILE_READ
-#define HAVE_SENDFILE_WRITE
-#include <asm/unistd.h>
-
-#ifdef __NR_sendfile
-
-extern long int syscall (long int __sysno, ...) __THROW;
-#if _FILE_OFFSET_BITS == 64
-#  error sendfile
-#  define sendfile(fdout, fdin, off, count) \
-       syscall(__NR_sendfile64, (fdout), (fdin), (off), (count))
-#else /* _FILE_OFFSET_BITS == 64 */
-#  define sendfile(fdout, fdin, off, count) \
-       syscall(__NR_sendfile, (fdout), (fdin), (off), (count))
-#endif /* _FILE_OFFSET_BITS == 64 */
-
-#else /* !__NR_sendfile */
-#include <sys/sendfile.h>
-#endif /* __NR_sendfile */
-#endif /* _FILE_OFFSET_BITS */
-#endif /* SENDFILE_FLAVOR_LINUX */
-
-#ifdef SENDFILE_FLAVOR_BSD
-#define HAVE_SENDFILE_READ
-#endif
+/* version info */
+#define AD_VERSION1    0x00010000
+#define AD_VERSION2    0x00020000
+#define AD_VERSION2_OSX        0x00020001
+#define AD_VERSION1_ADS        0x00010002
+#define AD_VERSION     AD_VERSION2
 
 /*
  * AppleDouble entry IDs. 
@@ -125,17 +104,27 @@ extern long int syscall (long int __sysno, ...) __THROW;
 #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 ADEID_PRIVID            19
+
+#define AD_DEV                  0x80444556
+#define AD_INO                  0x80494E4F
+#define AD_SYN                  0x8053594E
+#define AD_ID                   0x8053567E
+#define ADEID_MAX              20
+#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
@@ -143,6 +132,7 @@ extern long int syscall (long int __sysno, ...) __THROW;
 #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 */
@@ -161,10 +151,32 @@ extern long int syscall (long int __sysno, ...) __THROW;
 #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 ADEDLEN_PRIVID          4
+
+#define ADEID_NUM_V1         5
+#define ADEID_NUM_V2         13
+
+/* 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+ ADEDLEN_PRIVID)
+
+/* 725 */
+#define AD_DATASZ2      (AD_DATASZ1 + AD_NEWSZ2 + (ADEID_NUM_V2 -ADEID_NUM_V1)*AD_ENTRY_LEN)
+
+#if AD_DATASZ2 != 741
+#error bad size for AD_DATASZ2
+#endif
 
-#define AD_DATASZ1      589  
-#define AD_DATASZ2      665  /* v1 + 4 new entries (entry desc. + entry) */
 #define AD_DATASZ_MAX   1024
 #if AD_VERSION == AD_VERSION1
 #define AD_DATASZ      AD_DATASZ1 /* hold enough for the entries */
@@ -236,10 +248,14 @@ struct adouble {
     struct ad_entry    ad_eid[ ADEID_MAX ];
     struct ad_fd       ad_df, ad_hf;
     int                 ad_flags, ad_inited;
+    int                 ad_options;
     int                 ad_refcount; /* used in afpd/ofork.c */
     off_t               ad_rlen;     /* ressource fork len with AFP 3.0
                                         the header parameter size is too small.
                                      */
+    char                *(*ad_path)(const char *, int);
+    int                 (*ad_mkrf)(char *);
+                           
 #ifdef USE_MMAPPED_HEADERS
     char                *ad_data;
 #else
@@ -253,6 +269,11 @@ struct adouble {
 #define ADFLAGS_NOADOUBLE (1<<3)
 #define ADFLAGS_V1COMPAT  (1<<4)
 #define ADFLAGS_NOHF      (1<<5)  /* not an error if no ressource fork */
+#define ADFLAGS_RDONLY    (1<<6)  /* don't try readwrite */
+
+/* adouble v2 cnid cache */
+#define ADVOL_NODEV      (1 << 0)   
+#define ADVOL_CACHE      (1 << 1)
 
 /* lock flags */
 #define ADLOCK_CLR      (0)
@@ -279,8 +300,13 @@ struct adouble {
 #if _FILE_OFFSET_BITS == 64   
 #define BYTELOCK_MAX (0x7FFFFFFFFFFFFFFFULL)
 #else
+/* Tru64 is an always-64-bit OS; version 4.0 does not set _FILE_OFFSET_BITS */
+#if defined(TRU64)
+#define BYTELOCK_MAX (0x7FFFFFFFFFFFFFFFULL)
+#else
 #define BYTELOCK_MAX (0x7FFFFFFFU)
 #endif
+#endif
 
 #define AD_FILELOCK_OPEN_WR        (AD_FILELOCK_BASE + 0)
 #define AD_FILELOCK_OPEN_RD       (AD_FILELOCK_BASE + 1)
@@ -300,6 +326,29 @@ struct adouble {
 #define AD_DATE_DELTA         946684800
 #define AD_DATE_FROM_UNIX(x)  htonl((x) - AD_DATE_DELTA)
 #define AD_DATE_TO_UNIX(x)    (ntohl(x) + AD_DATE_DELTA)
+
+/* various finder offset and info bits */
+#define FINDERINFO_FRTYPEOFF   0
+#define FINDERINFO_FRCREATOFF  4
+
+#define FINDERINFO_FRFLAGOFF   8
+/* finderinfo flags */
+#define FINDERINFO_ISONDESK      (1)
+#define FINDERINFO_COLOR         (0x0e)
+#define FINDERINFO_ISHARED       (1<<6)
+#define FINDERINFO_HASNOINITS    (1<<7)
+#define FINDERINFO_HASBEENINITED (1<<8)
+#define FINDERINFO_HASCUSTOMICON (1<<10)
+#define FINDERINFO_ISSTATIONNERY (1<<11)
+#define FINDERINFO_NAMELOCKED    (1<<12)
+#define FINDERINFO_HASBUNDLE     (1<<13)
+#define FINDERINFO_INVISIBLE     (1<<14)
+#define FINDERINFO_ISALIAS       (1<<15)
+
+#define FINDERINFO_FRVIEWOFF  14 
+#define FINDERINFO_CUSTOMICON 0x4
+#define FINDERINFO_CLOSEDVIEW 0x100   
+
  
 /* private AFPFileInfo bits */
 #define AD_AFPFILEI_OWNER       (1 << 0) /* any owner */
@@ -344,19 +393,59 @@ extern int ad_excl_lock     __P((struct adouble * /*adp*/, const u_int32_t /*eid
 #define ad_unlock ad_fcntl_unlock
 
 /* ad_open.c */
-extern int ad_setfuid __P((const uid_t ));
-extern uid_t ad_getfuid __P((void ));
+extern int ad_setfuid     __P((const uid_t ));
+extern uid_t ad_getfuid   __P((void ));
+
+extern char *ad_dir       __P((const char *));
+extern char *ad_path      __P((const char *, int));
+extern char *ad_path_osx  __P((const char *, int));
+extern char *ad_path_ads  __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, int ));
 
-extern char *ad_dir   __P((const char *));
-extern char *ad_path  __P((const char *, int));
-extern int ad_mode    __P((const char *, int));
-extern int ad_mkdir   __P((const char *, int));
-extern int ad_open    __P((const char *, int, int, int, struct adouble *)); 
-extern int ad_refresh __P((struct adouble *));
+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 *));
+extern int ad_metadata    __P((const char *, int, struct adouble *));
+
+#if 0
+#define ad_metadata(name, flags, adp)  ad_open(name, ADFLAGS_HF|(flags), O_RDONLY, 0666, adp)
+#endif
 
 /* extend header to RW if R or W (W if R for locking),
  */ 
+#ifndef ATACC
+#ifndef __inline__
+#define __inline__
+#endif
+static __inline__ mode_t ad_hf_mode (mode_t mode)
+{
+#if 0
+    mode |= S_IRUSR;
+#endif    
+    /* fnctl lock need write access */
+    if ((mode & S_IRUSR))
+        mode |= S_IWUSR;
+    if ((mode & S_IRGRP))
+        mode |= S_IWGRP;
+    if ((mode & S_IROTH))
+        mode |= S_IWOTH;
+
+    /* if write mode set add read mode */
+    if ((mode & S_IWUSR))
+        mode |= S_IRUSR;
+    if ((mode & S_IWGRP))
+        mode |= S_IRGRP;
+    if ((mode & S_IWOTH))
+        mode |= S_IROTH;
+
+    return mode;
+}
+#else
 extern mode_t ad_hf_mode __P((mode_t ));
+#endif
 
 /* ad_read.c/ad_write.c */
 extern ssize_t ad_read __P((struct adouble *, const u_int32_t, 
@@ -390,7 +479,15 @@ extern int ad_getdate __P((const struct adouble *, unsigned int, u_int32_t *));
 extern int ad_setattr __P((const struct adouble *, const u_int16_t));
 extern int ad_getattr __P((const struct adouble *, u_int16_t *));
 
-#ifdef HAVE_SENDFILE_READ
+extern int ad_setname __P((struct adouble *, const char *));
+#if AD_VERSION == AD_VERSION2
+extern int ad_setid __P((struct adouble *, const dev_t dev,const ino_t ino, const u_int32_t, const u_int32_t, const void *));
+extern u_int32_t ad_getid __P((struct adouble *, const dev_t, const ino_t, const cnid_t, const void *));
+#else
+#define ad_setid(a, b, c)
+#endif
+
+#ifdef WITH_SENDFILE
 extern ssize_t ad_readfile __P((const struct adouble *, const int, 
                                const int, off_t, const size_t));
 #endif
index d147deb15b11c9e17164a6734438b80982c5ddc3..4db53a40a9f60dac7111b8ebf5161c635e264e49 100644 (file)
@@ -59,7 +59,7 @@ typedef struct ASP {
     char               child, inited, *commands;
     char                cmdbuf[ASP_CMDMAXSIZ];
     char                data[ASP_DATAMAXSIZ];  
-    unsigned int        cmdlen, datalen;
+    size_t             cmdlen, datalen;
     size_t             read_count, write_count;
 } *ASP;
 
@@ -99,5 +99,6 @@ extern int asp_wrtcont      __P((ASP, char *, int *));
 #define asp_wrtreply(a,b)   asp_cmdreply((a), (b))
 extern void asp_kill        __P((int));
 extern int asp_tickle      __P((ASP, const u_int8_t, struct sockaddr_at *));
+extern void asp_stop_tickle __P((void));
 
 #endif
index f7e676c05554e374369b0909de20f713e0cec2ad..4aad7e0de7ef9a3923182d733c4579c4c66a80d1 100644 (file)
@@ -1,17 +1,37 @@
 /* 
- * interface for database access to cnids. i do it this way to abstract
- * things a bit in case we want to change the underlying implementation.
+ * $Id: cnid.h,v 1.10 2005-04-28 20:49:51 bfernhomberg 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.
+ */
 
-#include <sys/cdefs.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <string.h>
+#ifndef _ATALK_CNID__H
+#define _ATALK_CNID__H 1
 
-#include <netatalk/endian.h>
+#include <atalk/adouble.h>
+#include <atalk/list.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_FLAG_NODEV        0x10      /* don't use device number only inode */
 
 #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 */
+
+       cnid_t (*cnid_add)(struct _cnid_db *cdb, const struct stat *st, const cnid_t did, 
+                       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, char *name,
+                       const int len);
+       cnid_t (*cnid_lookup)(struct _cnid_db *cdb, const struct stat *st, const cnid_t did,
+                       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, char *name, const int len);   
+       void (*cnid_close)(struct _cnid_db *cdb);
+       int  (*cnid_getstamp)(struct _cnid_db *cdb, void *buffer, const int len);
+        cnid_t (*cnid_rebuild_add)(struct _cnid_db *, const struct stat *, const cnid_t,
+                        const char *, const int, cnid_t);
+};
+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;
 
-/* cnid_close.c */
-extern void cnid_close __P((void *));
+/* Inititalize the CNID backends */
+void cnid_init();
 
-/* cnid_add.c */
-extern cnid_t cnid_add __P((void *, const struct stat *, const cnid_t,
-                           const char *, const int, cnid_t));
+/* Registers new CNID backend module */
+void cnid_register(struct _cnid_module *module);
 
-/* 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));
+/* This function opens a CNID database for selected volume. */
+struct _cnid_db *cnid_open(const char *volpath, mode_t mask, char *type, int flags);
 
-/* cnid_update.c */
-extern int cnid_update __P((void *, const cnid_t, const struct stat *,
-                           const cnid_t, const char *, int));
+cnid_t cnid_add(struct _cnid_db *cdb, const struct stat *st, const cnid_t did, 
+                       char *name, const int len, cnid_t hint);
 
-/* cnid_delete.c */
-extern int cnid_delete __P((void *, const cnid_t));
+int    cnid_delete(struct _cnid_db *cdb, cnid_t id);
 
-/* cnid_nextid.c */
-extern cnid_t cnid_nextid __P((void *));
+cnid_t cnid_get   (struct _cnid_db *cdb, const cnid_t did, char *name,const int len);
 
-/* cnid_mangle_* */
-extern int cnid_mangle_add __P((void *, char *, char *));
-extern char *cnid_mangle_get __P((void *, char *));
+int    cnid_getstamp(struct _cnid_db *cdb, void *buffer, const int len);
 
-extern int cnid_lock   __P((void *));
-extern int cnid_unlock __P((void *));
+cnid_t cnid_lookup(struct _cnid_db *cdb, const struct stat *st, const cnid_t did,
+                       char *name, const int len);
+
+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, char *name, const int len);
+
+cnid_t cnid_rebuild_add(struct _cnid_db *cdb, const struct stat *st, const cnid_t did,
+                        const char *name, const int len, cnid_t hint);
+
+
+/* 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.10  2005-04-28 20:49:51  bfernhomberg
+ *
+ * - merge branch-netatalk-afp-3x-dev, HEAD was tagged before
+ *
+ * Revision 1.9.6.8  2005/04/25 22:33:24  lenneis
+ * Add a new interface to the cdb and dbd backends: cnid_rebuild_add. It
+ * takes dev, ino, did, name and cnid and writes these values unconditionally
+ * into the cnid database. To be used in a recovery tool that writes cnids
+ * cached in AppleDouble files back into the database. Not used yet by
+ * any daemons or command line utilities.
+ *
+ * Revision 1.9.6.7  2005/02/08 11:46:59  didg
+ *
+ * warnings fixes from 2.0 branch
+ *
+ * Revision 1.9.6.6  2004/02/22 18:36:37  didg
+ *
+ * small clean up
+ *
+ * Revision 1.9.6.5  2004/01/14 23:15:19  lenneis
+ * Check if we can get a DB stamp sucessfully in afs_openvol and fail
+ * the open if not.
+ *
+ * Revision 1.9.6.4  2004/01/10 07:19:31  bfernhomberg
+ * add cnid_init prototype
+ *
+ * Revision 1.9.6.3  2004/01/03 22:42:55  didg
+ *
+ * better errors handling in afpd for dbd cnid.
+ *
+ * Revision 1.9.6.2  2004/01/03 22:21:09  didg
+ *
+ * add nodev volume option (always use 0 for device number).
+ *
+ * Revision 1.9.6.1  2003/09/09 16:42:20  didg
+ *
+ * big merge for db frontend and unicode.
+ *
+ * Revision 1.9.4.2  2003/06/11 15:29:11  rlewczuk
+ * Removed obsolete parameter from cnid_add. Spotted by Didier.
+ *
+ * Revision 1.9.4.1  2003/05/29 07:53:19  rlewczuk
+ * Selectable CNIDs. Some refactoring. Propably needs more of refactoring, mainly
+ * a well designed API (current API is just an old cnid_* API enclosed in VMT).
+ *
+ */
 
-#endif /* include/atalk/cnid.h */
diff --git a/include/atalk/cnid_dbd_private.h b/include/atalk/cnid_dbd_private.h
new file mode 100644 (file)
index 0000000..930a87c
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ *  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_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_OP_GETSTAMP    0x0b
+#define CNID_DBD_OP_REBUILD_ADD 0x0c
+
+#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)
+
+/* special key/data pair we use to store current cnid and database stamp in cnid2.db */
+
+#define ROOTINFO_KEY    "\0\0\0\0"
+#define ROOTINFO_KEYLEN 4
+
+/*                         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)
+
+
+
+
+struct cnid_dbd_rqst {
+    int     op;
+    cnid_t  cnid;
+    dev_t   dev;
+    ino_t   ino;
+    u_int32_t type;
+    cnid_t  did;
+    char   *name;
+    size_t  namelen;
+};
+
+struct cnid_dbd_rply {
+    int     result;    
+    cnid_t  cnid;
+    cnid_t  did;
+    char   *name;
+    size_t  namelen;
+};
+
+typedef struct CNID_private {
+    u_int32_t magic;
+    char      db_dir[MAXPATHLEN + 1]; /* Database directory without /.AppleDB appended */
+    int       fd;              /* File descriptor to cnid_dbd */
+    char      stamp[ADEDLEN_PRIVSYN]; /* db timestamp */
+    int       notfirst;   /* already open before */
+    int       changed;  /* stamp differ */
+} CNID_private;
+
+
+#endif /* include/atalk/cnid_dbd.h */
index dba461481f6155f5f464ee677f9bc2a6a6d5c670..7bd9983d62fb85380bb07e1ca075223a93a83f0a 100644 (file)
@@ -6,8 +6,6 @@
  * are checks for EINTR everywhere. 
  */
 
-#include <config.h>
-
 #include <sys/cdefs.h>
 #include <signal.h>
 
index 8bb49345ae860859c2b5dc9663e7b995221d64f5..2c4566d56340ffc911a49f8a06002dfbc15dde4c 100644 (file)
@@ -49,7 +49,7 @@ struct dsi_block {
   u_int32_t dsi_reserved;   /* reserved field */
 };
 
-#define DSI_CMDSIZ        800
+#define DSI_CMDSIZ        8192 
 #define DSI_DATASIZ       8192
 /* child and parent processes might interpret a couple of these
  * differently. */
@@ -57,13 +57,16 @@ typedef struct DSI {
   dsi_proto protocol;
   struct dsi_block header;
   struct sockaddr_in server, client;
-  sigset_t sigblockset;
+  
+  sigset_t sigblockset, oldset;
+  int      sigblocked;
   struct itimerval timer, savetimer;
+  
   u_int32_t attn_quantum, datasize, server_quantum;
   u_int16_t serverID, clientID;
   u_int8_t *status, commands[DSI_CMDSIZ], data[DSI_DATASIZ];
   int statuslen;
-  unsigned int datalen, cmdlen;
+  size_t datalen, cmdlen;
   size_t read_count, write_count;
   int asleep; /* client won't reply AFP 0x7a ? */
   /* inited = initialized?, child = a child?, noreply = send reply? */
@@ -76,6 +79,20 @@ typedef struct DSI {
    * write/read just write/read data */
   pid_t  (*proto_open)(struct DSI *);
   void   (*proto_close)(struct DSI *);
+
+  /* url registered with slpd */
+#ifdef USE_SRVLOC
+  char srvloc_url[512];
+#endif 
+
+  /* buffer for OSX deadlock */
+  int noblocking;
+  char *buffer;
+  char *start;
+  char *eof;
+  char *end;
+  int  maxsize;
+
 } DSI;
   
 /* DSI flags */
@@ -112,9 +129,9 @@ typedef struct DSI {
 
 /* server and client quanta */
 #define DSI_DEFQUANT        2           /* default attention quantum size */
-#define DSI_SERVQUANT_MAX   0xffffffffL /* server quantum */
-#define DSI_SERVQUANT_MIN   0x0004A2E0L /* minimum server quantum */
-#define DSI_SERVQUANT_DEF   DSI_SERVQUANT_MIN /* default server quantum */
+#define DSI_SERVQUANT_MAX   0xffffffff  /* server quantum */
+#define DSI_SERVQUANT_MIN   32000       /* minimum server quantum */
+#define DSI_SERVQUANT_DEF   0x0004A2E0L /* default server quantum */
 
 /* default port number */
 #define DSI_AFPOVERTCP_PORT 548
@@ -141,8 +158,11 @@ extern void dsi_getstatus __P((DSI *));
 extern void dsi_close __P((DSI *));
 extern void dsi_sleep __P((DSI *, const int ));
 
+/* set, unset socket blocking mode */
+extern int dsi_block __P((DSI *, const int));
+
 /* low-level stream commands -- in dsi_stream.c */
-extern size_t dsi_stream_write __P((DSI *, void *, const size_t));
+extern size_t dsi_stream_write __P((DSI *, void *, const size_t, const int mode));
 extern size_t dsi_stream_read __P((DSI *, void *, const size_t));
 extern int dsi_stream_send __P((DSI *, void *, size_t));
 extern int dsi_stream_receive __P((DSI *, void *, const size_t, size_t *));
diff --git a/include/atalk/list.h b/include/atalk/list.h
new file mode 100644 (file)
index 0000000..82518eb
--- /dev/null
@@ -0,0 +1,170 @@
+/* This code has been stolen from Linux kernel :) */
+/* distributed under GNU GPL version 2. */
+
+#ifndef _ATALK_LIST_H
+#define _ATALK_LIST_H
+
+/* test for inline */
+#ifndef __inline__
+#define __inline__
+#endif
+
+/*
+ * 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 ATALK_LIST_HEAD_INIT(name) { &(name), &(name) }
+
+#define ATALK_LIST_HEAD(name) \
+    struct list_head name = ATALK_LIST_HEAD_INIT(name)
+
+#define ATALK_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);
+    ATALK_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
index 7112e06964ffbd6633f16000443d35ba0bd43725..aeee9439bc33469ad77f140f759b5910e8dc38b3 100644 (file)
@@ -30,11 +30,12 @@ extern int server_child_remove __P((server_child *, const int, const pid_t));
 extern void server_child_free __P((server_child *));
 
 extern void server_child_kill __P((server_child *, const int, const int));
-extern void server_child_kill_one __P((server_child *children, const int forkid, const pid_t pid));
-extern void server_child_kill_one_by_id __P((server_child *children, const int forkid, const pid_t pid, 
+extern void server_child_kill_one __P((server_child *children, const int forkid, const pid_t, const uid_t));
+extern void server_child_kill_one_by_id __P((server_child *children, const int forkid, const pid_t pid, const uid_t,
                                                const u_int32_t len, char *id, u_int32_t boottime));
 
 extern void server_child_setup __P((server_child *, const int, void (*)()));
 extern void server_child_handler __P((server_child *));
+extern void server_reset_signal __P((void));
 
 #endif
index b462c6f971687e7c82a586ac5e04f6a9896a96ca..eb899f8c891564cb7fe2a509c9a0531eba6d8475 100644 (file)
@@ -8,7 +8,7 @@ void *server_ipc_create(void);
 int server_ipc_child(void *obj);
 int server_ipc_parent(void *obj);
 int server_ipc_read(server_child *children);
-int server_ipc_write(uint16_t command, int len, void *token);
+int server_ipc_write(u_int16_t command, int len, void *token);
 
 
 
diff --git a/include/atalk/tdb.h b/include/atalk/tdb.h
new file mode 100644 (file)
index 0000000..6f3b1ff
--- /dev/null
@@ -0,0 +1,144 @@
+#ifndef __TDB_H__
+#define __TDB_H__
+
+/* 
+   Unix SMB/CIFS implementation.
+   Samba database functions
+   Copyright (C) Andrew Tridgell 1999
+   
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+
+/* flags to tdb_store() */
+#define TDB_REPLACE 1
+#define TDB_INSERT 2
+#define TDB_MODIFY 3
+
+/* flags for tdb_open() */
+#define TDB_DEFAULT 0 /* just a readability place holder */
+#define TDB_CLEAR_IF_FIRST 1
+#define TDB_INTERNAL 2 /* don't store on disk */
+#define TDB_NOLOCK   4 /* don't do any locking */
+#define TDB_NOMMAP   8 /* don't use mmap */
+#define TDB_CONVERT 16 /* convert endian (internal use) */
+#define TDB_BIGENDIAN 32 /* header is big-endian (internal use) */
+
+#define TDB_ERRCODE(code, ret) ((tdb->ecode = (code)), ret)
+
+/* error codes */
+enum TDB_ERROR {TDB_SUCCESS=0, TDB_ERR_CORRUPT, TDB_ERR_IO, TDB_ERR_LOCK, 
+               TDB_ERR_OOM, TDB_ERR_EXISTS, TDB_ERR_NOEXIST, TDB_ERR_NOLOCK, TDB_ERR_LOCK_TIMEOUT };
+
+#ifndef u32
+#define u32 unsigned
+#endif
+
+typedef struct {
+       char *dptr;
+       size_t dsize;
+} TDB_DATA;
+
+typedef u32 tdb_len;
+typedef u32 tdb_off;
+
+/* this is stored at the front of every database */
+struct tdb_header {
+       char magic_food[32]; /* for /etc/magic */
+       u32 version; /* version of the code */
+       u32 hash_size; /* number of hash entries */
+       tdb_off rwlocks;
+       tdb_off reserved[31];
+};
+
+struct tdb_lock_type {
+       u32 count;
+       u32 ltype;
+};
+
+struct tdb_traverse_lock {
+       struct tdb_traverse_lock *next;
+       u32 off;
+       u32 hash;
+};
+
+/* this is the context structure that is returned from a db open */
+typedef struct tdb_context {
+       char *name; /* the name of the database */
+       void *map_ptr; /* where it is currently mapped */
+       int fd; /* open file descriptor for the database */
+       tdb_len map_size; /* how much space has been mapped */
+       int read_only; /* opened read-only */
+       struct tdb_lock_type *locked; /* array of chain locks */
+       enum TDB_ERROR ecode; /* error code for last tdb error */
+       struct tdb_header header; /* a cached copy of the header */
+       u32 flags; /* the flags passed to tdb_open */
+       u32 *lockedkeys; /* array of locked keys: first is #keys */
+       struct tdb_traverse_lock travlocks; /* current traversal locks */
+       struct tdb_context *next; /* all tdbs to avoid multiple opens */
+       dev_t device;   /* uniquely identifies this tdb */
+       ino_t inode;    /* uniquely identifies this tdb */
+       void (*log_fn)(struct tdb_context *tdb, int level, const char *, ...); /* logging function */
+       int open_flags; /* flags used in the open - needed by reopen */
+} TDB_CONTEXT;
+
+typedef int (*tdb_traverse_func)(TDB_CONTEXT *, TDB_DATA, TDB_DATA, void *);
+typedef void (*tdb_log_func)(TDB_CONTEXT *, int , const char *, ...);
+
+TDB_CONTEXT *tdb_open(const char *name, int hash_size, int tdb_flags,
+                     int open_flags, mode_t mode);
+TDB_CONTEXT *tdb_open_ex(const char *name, int hash_size, int tdb_flags,
+                        int open_flags, mode_t mode,
+                        tdb_log_func log_fn);
+
+int tdb_reopen(TDB_CONTEXT *tdb);
+int tdb_reopen_all(void);
+void tdb_logging_function(TDB_CONTEXT *tdb, tdb_log_func);
+enum TDB_ERROR tdb_error(TDB_CONTEXT *tdb);
+const char *tdb_errorstr(TDB_CONTEXT *tdb);
+TDB_DATA tdb_fetch(TDB_CONTEXT *tdb, TDB_DATA key);
+int tdb_delete(TDB_CONTEXT *tdb, TDB_DATA key);
+int tdb_store(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA dbuf, int flag);
+int tdb_append(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA new_dbuf);
+int tdb_close(TDB_CONTEXT *tdb);
+TDB_DATA tdb_firstkey(TDB_CONTEXT *tdb);
+TDB_DATA tdb_nextkey(TDB_CONTEXT *tdb, TDB_DATA key);
+int tdb_traverse(TDB_CONTEXT *tdb, tdb_traverse_func fn, void *state);
+int tdb_exists(TDB_CONTEXT *tdb, TDB_DATA key);
+int tdb_lockkeys(TDB_CONTEXT *tdb, u32 number, TDB_DATA keys[]);
+void tdb_unlockkeys(TDB_CONTEXT *tdb);
+int tdb_lockall(TDB_CONTEXT *tdb);
+void tdb_unlockall(TDB_CONTEXT *tdb);
+
+/* Low level locking functions: use with care */
+void tdb_set_lock_alarm(sig_atomic_t *palarm);
+int tdb_chainlock(TDB_CONTEXT *tdb, TDB_DATA key);
+int tdb_chainunlock(TDB_CONTEXT *tdb, TDB_DATA key);
+
+/* Debug functions. Not used in production. */
+void tdb_dump_all(TDB_CONTEXT *tdb);
+int tdb_printfreelist(TDB_CONTEXT *tdb);
+
+extern TDB_DATA tdb_null;
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif /* tdb.h */
index d3c3a44a4c3f01e7702a94d0f9bc1cc1e51111ec..e161b6859c1771c89288382b623b956808c09799 100644 (file)
 #define UAM_OPTION_RANDNUM      (1 << 4) /* request a random number */
 #define UAM_OPTION_HOSTNAME     (1 << 5) /* get host name */
 #define UAM_OPTION_COOKIE       (1 << 6) /* cookie handle */
-#define UAM_OPTION_PROTOCOL     (1 << 7) /* DSI or ASP */
+#define UAM_OPTION_PROTOCOL    (1 << 7) /* DSI or ASP */
 #define UAM_OPTION_CLIENTNAME   (1 << 8) /* get client IP address */
 #define UAM_OPTION_KRB5SERVICE  (1 << 9) /* service name for krb5 principal */
+#define UAM_OPTION_MACCHARSET   (1 << 10) /* mac charset handle */
+#define UAM_OPTION_UNIXCHARSET  (1 << 11) /* unix charset handle */
+#define UAM_OPTION_SESSIONINFO  (1 << 12) /* unix charset handle */
+#define UAM_OPTION_KRB5REALM    (1 << 13) /* krb realm */
+#define UAM_OPTION_FQDN         (1 << 14) /* fully qualified name */
 
 /* some password options. you pass these in the length parameter and
  * get back the corresponding option. not all of these are implemented. */
@@ -60,12 +65,24 @@ struct uam_export {
   void (*uam_cleanup)(void);
 };
 
+#define SESSIONKEY_LEN  64
+#define SESSIONTOKEN_LEN 8
+
+struct session_info {
+  void    *sessionkey;          /* random session key */
+  size_t  sessionkey_len;
+  void    *cryptedkey;         /* kerberos/gssapi crypted key */
+  size_t  cryptedkey_len;
+  void    *sessiontoken;        /* session token sent to the client on FPGetSessionToken*/
+  size_t  sessiontoken_len;
+};
+
 /* register and unregister uams with these functions */
 extern int uam_register __P((const int, const char *, const char *, ...));
 extern void uam_unregister __P((const int, const char *));
 
 /* helper functions */
-extern struct passwd *uam_getname __P((char *, const int));
+extern struct passwd *uam_getname __P((void*, char *, const int));
 extern int uam_checkuser __P((const struct passwd *));
 
 /* afp helper functions */
diff --git a/include/atalk/unicode.h b/include/atalk/unicode.h
new file mode 100644 (file)
index 0000000..e927b5e
--- /dev/null
@@ -0,0 +1,146 @@
+
+#ifndef _ATALK_UNICODE_H
+#define _ATALK_UNICODE_H 1
+
+#include <sys/cdefs.h>
+#include <netatalk/endian.h>
+#include <errno.h>
+#include <sys/param.h>
+
+#define ucs2_t u_int16_t
+
+#ifndef MIN
+#define MIN(a,b)     ((a)<(b)?(a):(b))
+#endif /* ! MIN */
+
+#ifndef MAX
+#define MAX(a,b)     ((a)>(b)?(a):(b))
+#endif /* ! MIN */
+
+#define SAFE_FREE(x) do { if ((x) != NULL) {free(x); x=NULL;} } while(0)
+
+#ifndef EILSEQ
+#define EILSEQ       84      /* Illegal byte sequence.  */
+#endif
+
+/* generic iconv conversion structure */
+typedef struct {
+        size_t (*direct)(void *cd, char **inbuf, size_t *inbytesleft,
+                         char **outbuf, size_t *outbytesleft);
+        size_t (*pull)(void *cd, char **inbuf, size_t *inbytesleft,
+                       char **outbuf, size_t *outbytesleft);
+        size_t (*push)(void *cd, char **inbuf, size_t *inbytesleft,
+                       char **outbuf, size_t *outbytesleft);
+        void *cd_direct, *cd_pull, *cd_push;
+        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) /* return the first convertable characters. */
+#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 */
+#define CONV_FORCE             (1<<8) /* force convertion */
+#define CONV__EILSEQ           (1<<9) /* ignore EILSEQ, replace with IGNORE_CHAR (try USC2) */
+
+/* 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, CH_UTF8_MAC=4} charset_t;
+
+#define NUM_CHARSETS 5
+
+/*
+ *   for each charset we have a function that pulls from that charset to
+ *     a ucs2 buffer, and a function that pushes to a ucs2 buffer
+ *     */
+
+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;
+        const char *iname;
+        struct charset_functions *prev, *next;
+};
+
+/* from iconv.c */
+extern atalk_iconv_t   atalk_iconv_open __P((const char *, const char *));
+extern size_t          atalk_iconv __P((atalk_iconv_t, const char **, size_t *, char **, size_t *));
+extern int             atalk_iconv_close __P((atalk_iconv_t));
+extern struct charset_functions *find_charset_functions __P((const char *));
+extern int             atalk_register_charset __P((struct charset_functions *));
+
+/* from util_unistr.c */
+extern ucs2_t  toupper_w  __P((ucs2_t));
+extern ucs2_t  tolower_w  __P((ucs2_t));
+extern int     strupper_w __P((ucs2_t *));
+extern int     strlower_w __P((ucs2_t *));
+extern int     islower_w  __P((ucs2_t));
+extern int     islower_w  __P((ucs2_t));
+extern size_t  strlen_w   __P((const ucs2_t *));
+extern size_t  strnlen_w  __P((const ucs2_t *, size_t));
+extern ucs2_t*         strchr_w   __P((const ucs2_t *, ucs2_t));
+extern int     strcmp_w   __P((const ucs2_t *, const ucs2_t *));
+extern int     strncmp_w  __P((const ucs2_t *, const ucs2_t *, size_t));
+extern int      strcasecmp_w  __P((const ucs2_t *, const ucs2_t *));
+extern int     strncasecmp_w __P((const ucs2_t *, const ucs2_t *, size_t));
+extern ucs2_t   *strcasestr_w __P((const ucs2_t *, const ucs2_t *));
+extern ucs2_t  *strndup_w __P((const ucs2_t *, size_t));
+extern ucs2_t          *strdup_w  __P((const ucs2_t *));
+extern ucs2_t  *strncpy_w __P((ucs2_t *, const ucs2_t *, const size_t));
+extern ucs2_t  *strncat_w __P((ucs2_t *, const ucs2_t *, const size_t));
+extern ucs2_t  *strcat_w  __P((ucs2_t *, const ucs2_t *));
+extern 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 *));
+
+/* from charcnv.c */
+extern void    init_iconv __P((void));
+extern size_t  convert_string __P((charset_t, charset_t, void const *, size_t, void *, size_t));
+extern size_t  convert_string_allocate __P((charset_t, charset_t, void const *, size_t, char **));
+extern size_t  utf8_strupper __P((const char *, size_t, char *, size_t));
+extern size_t  utf8_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  charset_to_ucs2_allocate __P((charset_t, ucs2_t **dest, const char *src));
+extern size_t  charset_to_utf8_allocate __P((charset_t, char **dest, const char *src));
+extern size_t  ucs2_to_charset_allocate __P((charset_t, char **dest, const ucs2_t *src));
+extern size_t  utf8_to_charset_allocate __P((charset_t, char **dest, const char *src));
+extern size_t  ucs2_to_charset __P((charset_t, const ucs2_t *src, char *dest, size_t));
+
+extern size_t  convert_charset __P((charset_t, charset_t, charset_t, char *, size_t, char *, size_t, u_int16_t *));
+
+extern size_t  charset_precompose __P(( charset_t, char *, size_t, char *, size_t));
+extern size_t  charset_decompose  __P(( charset_t, char *, size_t, char *, size_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));
+
+extern charset_t add_charset __P((char* name));
+
+
+
+#endif
index 8dc3a7a66268c7d687df9d2025ea122563767fe6..aa580bfc23ba474ec71da2ac03d7adcb0e144c86 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: util.h,v 1.7 2002-02-01 07:03:49 morgana Exp $
+ * $Id: util.h,v 1.8 2005-04-28 20:49:51 bfernhomberg Exp $
  */
 
 #ifndef _ATALK_UTIL_H
 #include <unistd.h>
 #endif /* HAVE_UNISTD_H */
 #include <netatalk/at.h>
+#include <atalk/unicode.h>
+
+/* exit error codes */
+#define EXITERR_CLNT 1  /* client related error */
+#define EXITERR_CONF 2  /* error in config files/cmd line parameters */
+#define EXITERR_SYS  3  /* local system error */
+
+
+extern int     sys_ftruncate __P((int fd, off_t length));
+
+#ifdef WITH_SENDFILE
+extern ssize_t sys_sendfile __P((int __out_fd, int __in_fd, off_t *__offset,size_t __count));
+#endif
 
 extern const int _diacasemap[], _dialowermap[];
 
@@ -25,8 +38,17 @@ extern int strdiacasecmp  __P((const char *, const char *));
 extern int strndiacasecmp __P((const char *, const char *, size_t));
 extern pid_t server_lock  __P((char * /*program*/, char * /*file*/, 
                               int /*debug*/));
+extern void fault_setup          __P((void (*fn)(void *)));
 #define server_unlock(x)  (unlink(x))
 
+#ifndef HAVE_STRLCPY
+size_t strlcpy __P((char *, const char *, size_t));
+#endif
+#ifndef HAVE_STRLCAT
+size_t strlcat __P((char *, const char *, size_t));
+#endif
+
 #ifndef HAVE_DLFCN_H
 extern void *mod_open    __P((const char *));
 extern void *mod_symbol  __P((void *, const char *));
@@ -39,10 +61,14 @@ extern void mod_close    __P((void *));
 #define RTLD_NOW 1
 #endif /* ! RTLD_NOW */
 
-/* NetBSD doesn't like RTLD_NOW for dlopen (it fails). Use RTLD_LAZY. */
+/* NetBSD doesn't like RTLD_NOW for dlopen (it fails). Use RTLD_LAZY.
+ * OpenBSD currently does not use the second arg for dlopen(). For
+ * future compatibility we define DL_LAZY */
 #ifdef __NetBSD__
 #define mod_open(a)      dlopen(a, RTLD_LAZY)
-#else /* ! __NetBSD__ */
+#elif defined(__OpenBSD__)
+#define mod_open(a)      dlopen(a, DL_LAZY)
+#else /* ! __NetBSD__ && ! __OpenBSD__ */
 #define mod_open(a)      dlopen(a, RTLD_NOW)
 #endif /* __NetBSD__ */
 
@@ -55,4 +81,29 @@ extern void *mod_symbol  __P((void *, const char *));
 #define mod_close(a)     dlclose(a)
 #endif /* ! HAVE_DLFCN_H */
 
+
+/* volinfo for shell utilities */
+
+#define VOLINFOFILE ".volinfo"
+
+struct volinfo {
+    char                *v_name;
+    char                *v_path;
+    int                 v_flags;
+    int                 v_casefold;
+    char                *v_cnidscheme;
+    char                *v_dbpath;
+    char                *v_volcodepage;
+    charset_t           v_volcharset;
+    char                *v_maccodepage;
+    charset_t           v_maccharset;
+    int                 v_adouble;  /* default adouble format */
+    char                *(*ad_path)(const char *, int);
+    char                *v_dbd_host;
+    int                 v_dbd_port;
+};
+
+extern int loadvolinfo __P((char *path, struct volinfo *vol));
+extern int vol_load_charsets __P(( struct volinfo *vol));
+
 #endif
diff --git a/include/atalk/volinfo.h b/include/atalk/volinfo.h
new file mode 100644 (file)
index 0000000..28caa33
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * $Id: volinfo.h,v 1.2 2005-04-28 20:49:51 bfernhomberg Exp $
+ */
+
+#ifndef _ATALK_VOLINFO_H
+#define _ATALK_VOLINFO_H 1
+
+/* FIXME: following duplicated from etc/afpd/volume.h  */
+
+/* flags that alter volume behaviour. */
+#define AFPVOL_A2VOL     (1 << 5)   /* prodos volume */
+#define AFPVOL_CRLF      (1 << 6)   /* cr/lf translation */
+#define AFPVOL_NOADOUBLE (1 << 7)   /* don't create .AppleDouble by default */
+#define AFPVOL_RO        (1 << 8)   /* read-only volume */
+#define AFPVOL_MSWINDOWS (1 << 9)   /* deal with ms-windows yuckiness. this is going away. */
+#define AFPVOL_NOHEX     (1 << 10)  /* don't do :hex translation */
+#define AFPVOL_USEDOTS   (1 << 11)  /* use real dots */
+#define AFPVOL_LIMITSIZE (1 << 12)  /* limit size for older macs */
+#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_NOSTAT    (1 << 16)  /* advertise the volume even if we can't stat() it
+                                     * maybe because it will be mounted later in preexec */
+#define AFPVOL_UNIX_PRIV (1 << 17)  /* support unix privileges */
+#define AFPVOL_NODEV     (1 << 18)  /* always use 0 for device number in cnid calls
+                                     * help if device number is notconsistent across reboot
+                                     * NOTE symlink to a different device will return an ACCESS error
+                                     */
+/* handle casefolding */
+#define AFPVOL_MTOUUPPER       (1 << 0)
+#define AFPVOL_MTOULOWER       (1 << 1)
+#define AFPVOL_UTOMUPPER       (1 << 2)
+#define AFPVOL_UTOMLOWER       (1 << 3)
+#define AFPVOL_UMLOWER         (AFPVOL_MTOULOWER | AFPVOL_UTOMLOWER)
+#define AFPVOL_UMUPPER         (AFPVOL_MTOUUPPER | AFPVOL_UTOMUPPER)
+#define AFPVOL_UUPPERMLOWER    (AFPVOL_MTOUUPPER | AFPVOL_UTOMLOWER)
+#define AFPVOL_ULOWERMUPPER    (AFPVOL_MTOULOWER | AFPVOL_UTOMUPPER)
+
+
+#endif
index 4545e59dbe418780566544a94a2712ca7f1e589d..0432e2575159a48500cc0360440ccac452462576 100644 (file)
@@ -1,6 +1,6 @@
 # Makefile.am for libatalk/
 
-SUBDIRS = adouble asp atp compat cnid dsi nbp netddp util
+SUBDIRS = adouble asp atp compat cnid dsi nbp netddp util tdb unicode
 
 lib_LTLIBRARIES = libatalk.la
 
@@ -9,11 +9,12 @@ LIBATALK_DEPS = \
        asp/libasp.la           \
        atp/libatp.la           \
        compat/libcompat.la     \
-       cnid/libcnid.la \
        dsi/libdsi.la           \
        nbp/libnbp.la           \
        netddp/libnetddp.la     \
-       util/libutil.la
+       util/libutil.la         \
+        tdb/libtdb.la           \
+       unicode/libunicode.la
 
 libatalk_la_SOURCES = dummy.c
 libatalk_la_LIBADD  = $(LIBATALK_DEPS)
index 7ce98dc15b31b22b0039747d1a75a7256461496d..299ab3441a7eddbe46ae47c9d3d21ab9cc815c07 100644 (file)
@@ -1,7 +1,5 @@
 # Makefile.am for libatalk/adouble/
 
-INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/sys
-
 noinst_LTLIBRARIES = libadouble.la
 
 libadouble_la_SOURCES = ad_open.c ad_flush.c ad_read.c ad_write.c ad_size.c ad_mmap.c ad_lock.c ad_date.c ad_attr.c ad_sendfile.c
index 947ba9123e562a8866c6c856411fa8a5486572b1..7168f8fecb5ba0da972bc872efb3fec336f55ce4 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: ad_attr.c,v 1.4 2002-09-29 17:39:59 didg Exp $
+ * $Id: ad_attr.c,v 1.5 2005-04-28 20:49:51 bfernhomberg Exp $
  */
 
 #ifdef HAVE_CONFIG_H
 
 int ad_getattr(const struct adouble *ad, u_int16_t *attr)
 {
-  if (ad->ad_version == AD_VERSION1)
-    memcpy(attr, ad_entry(ad, ADEID_FILEI) + FILEIOFF_ATTR,
-          sizeof(u_int16_t));
+   *attr = 0;
+        
+   if (ad->ad_version == AD_VERSION1) {
+       if (ad_getentryoff(ad, ADEID_FILEI)) {
+           memcpy(attr, ad_entry(ad, ADEID_FILEI) + FILEIOFF_ATTR,
+                 sizeof(u_int16_t));
+       }
+   }
 #if AD_VERSION == AD_VERSION2
-  else if (ad->ad_version == AD_VERSION2)
-    memcpy(attr, ad_entry(ad, ADEID_AFPFILEI) + AFPFILEIOFF_ATTR,
-          sizeof(u_int16_t));
+   else if (ad->ad_version == AD_VERSION2) {
+       if (ad_getentryoff(ad, ADEID_AFPFILEI)) {
+           memcpy(attr, ad_entry(ad, ADEID_AFPFILEI) + AFPFILEIOFF_ATTR,
+                 sizeof(u_int16_t));
+       }
+   }      
 #endif
-  else 
-    return -1;
+   else 
+      return -1;
 
-  return 0;
+   return 0;
 }
 
+/* ----------------- */
 int ad_setattr(const struct adouble *ad, const u_int16_t attr)
 {
-  if (ad->ad_version == AD_VERSION1)
-    memcpy(ad_entry(ad, ADEID_FILEI) + FILEIOFF_ATTR, &attr,
-          sizeof(attr));
+   if (ad->ad_version == AD_VERSION1) {
+       if (ad_getentryoff(ad, ADEID_FILEI)) {
+           memcpy(ad_entry(ad, ADEID_FILEI) + FILEIOFF_ATTR, &attr,
+                  sizeof(attr));
+       }
+   }      
 #if AD_VERSION == AD_VERSION2
-  else if (ad->ad_version == AD_VERSION2)
-    memcpy(ad_entry(ad, ADEID_AFPFILEI) + AFPFILEIOFF_ATTR, &attr,
-          sizeof(attr));
+   else if (ad->ad_version == AD_VERSION2) {
+       if (ad_getentryoff(ad, ADEID_AFPFILEI)) {
+            memcpy(ad_entry(ad, ADEID_AFPFILEI) + AFPFILEIOFF_ATTR, &attr,
+                   sizeof(attr));
+       }
+   }      
 #endif
-  else 
-    return -1;
+   else 
+      return -1;
 
-  return 0;
+   return 0;
+}
+
+/* -------------- 
+ * save file/folder ID in AppleDoubleV2 netatalk private parameters
+ * return 1 if resource fork has been modified
+*/
+#if AD_VERSION == AD_VERSION2
+int ad_setid (struct adouble *adp, const dev_t dev, const ino_t ino , const u_int32_t id, const cnid_t did, const void *stamp)
+{
+    if (adp->ad_flags == AD_VERSION2  && ( adp->ad_options & ADVOL_CACHE) &&
+                ad_getentryoff(adp, ADEID_PRIVDEV) &&
+                sizeof(dev_t) == ADEDLEN_PRIVDEV && sizeof(ino_t) == ADEDLEN_PRIVINO) 
+    {
+        ad_setentrylen( adp, ADEID_PRIVDEV, sizeof(dev_t));
+       if ((adp->ad_options & ADVOL_NODEV)) {
+            memset(ad_entry( adp, ADEID_PRIVDEV ), 0, sizeof(dev_t));
+        }
+       else {
+            memcpy(ad_entry( adp, ADEID_PRIVDEV ), &dev, sizeof(dev_t));
+        }
+
+        ad_setentrylen( adp, ADEID_PRIVINO, sizeof(ino_t));
+        memcpy(ad_entry( adp, ADEID_PRIVINO ), &ino, sizeof(ino_t));
+
+       ad_setentrylen( adp, ADEID_PRIVID, sizeof(id));
+        memcpy(ad_entry( adp, ADEID_PRIVID ), &id, sizeof(id));
+
+        ad_setentrylen( adp, ADEID_DID, sizeof(did));
+        memcpy(ad_entry( adp, ADEID_DID ), &did, sizeof(did));
+
+        ad_setentrylen( adp, ADEID_PRIVSYN, ADEDLEN_PRIVSYN);
+        memcpy(ad_entry( adp, ADEID_PRIVSYN ), stamp, ADEDLEN_PRIVSYN);
+        return 1;
+    }
+    return 0;
+}
+
+/* ----------------------------- */
+u_int32_t ad_getid (struct adouble *adp, const dev_t st_dev, const ino_t st_ino , const cnid_t did, const void *stamp)
+{
+u_int32_t aint = 0;
+dev_t  dev;
+ino_t  ino;
+cnid_t a_did;
+char   temp[ADEDLEN_PRIVSYN];
+
+    /* look in AD v2 header 
+     * note inode and device are opaques and not in network order
+     * only use the ID if adouble is writable for us.
+    */
+    if (adp && ( adp->ad_options & ADVOL_CACHE) && ( adp->ad_hf.adf_flags & O_RDWR )
+            && sizeof(dev_t) == ad_getentrylen(adp, ADEID_PRIVDEV)
+            && sizeof(ino_t) == ad_getentrylen(adp,ADEID_PRIVINO)
+            && sizeof(temp) == ad_getentrylen(adp,ADEID_PRIVSYN)
+            && sizeof(cnid_t) == ad_getentrylen(adp, ADEID_DID)
+            && sizeof(cnid_t) == ad_getentrylen(adp, ADEID_PRIVID)
+    ) {
+        memcpy(&dev, ad_entry(adp, ADEID_PRIVDEV), sizeof(dev_t));
+        memcpy(&ino, ad_entry(adp, ADEID_PRIVINO), sizeof(ino_t));
+        memcpy(temp, ad_entry(adp, ADEID_PRIVSYN), sizeof(temp));
+        memcpy(&a_did, ad_entry(adp, ADEID_DID), sizeof(cnid_t));
+
+        if (  ((adp->ad_options & ADVOL_NODEV) || dev == st_dev)
+              && ino == st_ino && a_did == did 
+              && !memcmp(stamp, temp, sizeof(temp))) { 
+            memcpy(&aint, ad_entry(adp, ADEID_PRIVID), sizeof(aint));
+            return aint;
+        }
+    }
+    return 0; 
+}
+
+#endif
+
+/* ----------------- 
+ * set resource fork filename attribute.
+*/
+int ad_setname(struct adouble *ad, const char *path)
+{
+    if (ad_getentryoff(ad, ADEID_NAME)) {
+        ad_setentrylen( ad, ADEID_NAME, strlen( path ));
+        memcpy(ad_entry( ad, ADEID_NAME ), path, ad_getentrylen( ad, ADEID_NAME ));
+        return 1;
+    }
+    return 0;
 }
index 082be9a4837859da636f6db90a23fed488a69372..6324679be57ff7ed8692a0525597120730af601c 100644 (file)
@@ -1,15 +1,12 @@
 /*
- * $Id: ad_date.c,v 1.3 2001-06-29 14:14:46 rufustfirefly Exp $
+ * $Id: ad_date.c,v 1.4 2005-04-28 20:49:51 bfernhomberg Exp $
  */
 
 #ifdef HAVE_CONFIG_H
 #include "config.h"
 #endif /* HAVE_CONFIG_H */
 
-#include <stdio.h>
-#include <stdlib.h>
 #include <string.h>
-
 #include <atalk/adouble.h>
 
 int ad_setdate(const struct adouble *ad, 
@@ -27,8 +24,11 @@ int ad_setdate(const struct adouble *ad,
     memcpy(ad_entry(ad, ADEID_FILEI) + dateoff, &date, sizeof(date));
 
   } else if (ad->ad_version == AD_VERSION2) {
+    if (!ad_getentryoff(ad, ADEID_FILEDATESI))
+        return -1;
+        
     if (dateoff > AD_DATE_ACCESS)
-      return -1;
+        return -1;
     memcpy(ad_entry(ad, ADEID_FILEDATESI) + dateoff, &date, sizeof(date));
 
   } else 
@@ -49,6 +49,9 @@ int ad_getdate(const struct adouble *ad,
     memcpy(date, ad_entry(ad, ADEID_FILEI) + dateoff, sizeof(u_int32_t));
 
   } else if (ad->ad_version == AD_VERSION2) {
+    if (!ad_getentryoff(ad, ADEID_FILEDATESI))
+        return -1;
+
     if (dateoff > AD_DATE_ACCESS)
       return -1;
     memcpy(date, ad_entry(ad, ADEID_FILEDATESI) + dateoff, sizeof(u_int32_t));
index 7eb6fba3d16783b24cc35aa627e65d70214ba534..c92daddffeee738a3b58013957f048975ddf2ed8 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: ad_flush.c,v 1.6 2003-01-28 15:30:56 srittau Exp $
+ * $Id: ad_flush.c,v 1.7 2005-04-28 20:49:52 bfernhomberg 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, AD_ID
+};
+
+#define EID_DISK(a) (set_eid[a])
+#endif
 
 /* rebuild the header */
 void ad_rebuild_header(struct adouble *ad)
@@ -67,7 +81,7 @@ void ad_rebuild_header(struct adouble *ad)
       if ( ad->ad_eid[ eid ].ade_off == 0 ) {
        continue;
       }
-      temp = htonl( eid );
+      temp = htonl( EID_DISK(eid) );
       memcpy(buf, &temp, sizeof( temp ));
       buf += sizeof( temp );
 
index 8222500b0c46135cda15a7eacd22b7aa4ad78340..77cd502526c9ead25e7cce94b611d622050deef1 100644 (file)
@@ -1,5 +1,5 @@
 /* 
- * $Id: ad_lock.c,v 1.11 2003-02-16 12:35:05 didg Exp $
+ * $Id: ad_lock.c,v 1.12 2005-04-28 20:49:52 bfernhomberg Exp $
  *
  * Copyright (c) 1998,1999 Adrian Sun (asun@zoology.washington.edu)
  * All Rights Reserved. See COPYRIGHT for more information.
 #include "config.h"
 #endif /* HAVE_CONFIG_H */
 
+#include <atalk/adouble.h>
+
 #include <stdio.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 <errno.h>
 
-#include <atalk/adouble.h>
+#include <string.h>
 
 #include "ad_private.h"
 
 ((type) == ADLOCK_WR ? LOCK_EX : \
  ((type) == ADLOCK_CLR ? LOCK_UN : -1)))
 
+#ifdef DISABLE_LOCKING
+#define fcntl(a, b, c ) (0)
+#endif
+
 /* ----------------------- */
 static int XLATE_FCNTL_LOCK(int type) 
 {
@@ -112,7 +111,7 @@ static __inline__ void adf_freelock(struct ad_fd *ad, const int i)
  * i converted to using arrays of locks. everytime a lock
  * gets removed, we shift all of the locks down.
  */
-static __inline__ void adf_unlock(struct ad_fd *ad, int fd, const int user)
+static __inline__ void adf_unlock(struct ad_fd *ad, const int user)
 {
     adf_lock_t *lock = ad->adf_lock;
     int i;
@@ -271,6 +270,14 @@ int ad_fcntl_lock(struct adouble *ad, const u_int32_t eid, const int locktype,
     }
   } else { /* rfork */
     adf = &ad->ad_hf;
+    if (adf->adf_fd == -1) {
+        /* there's no resource fork. return a lock error
+         * otherwise if a second process is able to create it
+         * locks are a mess.
+         */
+        errno = EACCES;
+        return -1;
+    }
     if (type & ADLOCK_FILELOCK) 
       lock.l_start = hf2off(off);
     else
@@ -396,9 +403,14 @@ int ad_testlock(struct adouble *ad, int eid, const off_t off)
     if ((ad_hfileno(ad) != -1)) {
        adf = &ad->ad_hf;
        lock.l_start = df2off(off);
-       }
-  } else { /* rfork */
-       adf = &ad->ad_hf;
+    }
+  } 
+  else { /* rfork */
+    if ((ad_hfileno(ad) == -1)) {
+        /* there's no resource fork. return no lock */
+        return 0;
+    }
+    adf = &ad->ad_hf;
     lock.l_start = hf2off(off);
   }
 
@@ -439,6 +451,10 @@ int ad_fcntl_tmplock(struct adouble *ad, const u_int32_t eid, const int locktype
     adf = &ad->ad_df;
   } else {
     adf = &ad->ad_hf;
+    if (adf->adf_fd == -1) {
+        /* there's no resource fork. return success */
+        return 0;
+    }
     /* if ADLOCK_FILELOCK we want a lock from offset 0
      * it's used when deleting a file:
      * in open we put read locks on meta datas
@@ -493,15 +509,17 @@ int ad_excl_lock(struct adouble *ad, const u_int32_t eid)
   struct flock lock;
   int    err;
   
+  lock.l_start = 0;
+  lock.l_type = F_WRLCK;
+  lock.l_whence = SEEK_SET;
+  lock.l_len = 0;
+
   if (eid == ADEID_DFORK) {
     adf = &ad->ad_df;
   } else {
     adf = &ad->ad_hf;
+    lock.l_start = ad_getentryoff(ad, eid);
   }
-  lock.l_start = 0;
-  lock.l_type = F_WRLCK;
-  lock.l_whence = SEEK_SET;
-  lock.l_len = 0;
   
   err = fcntl(adf->adf_fd, F_SETLK, &lock);
   if (!err)
@@ -513,9 +531,9 @@ int ad_excl_lock(struct adouble *ad, const u_int32_t eid)
 void ad_fcntl_unlock(struct adouble *ad, const int user)
 {
   if (ad->ad_df.adf_fd != -1) {
-    adf_unlock(&ad->ad_df, ad->ad_df.adf_fd, user);
+    adf_unlock(&ad->ad_df, user);
   }
   if (ad->ad_hf.adf_fd != -1) {
-    adf_unlock(&ad->ad_hf, ad->ad_hf.adf_fd, user);
+    adf_unlock(&ad->ad_hf, user);
   }
 }
index 6a04944b9e3f782eef2b9ed6606fecab47ee79f8..6695deca7f654612155abcb4c50478e10d3646ac 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: ad_mmap.c,v 1.4 2002-10-05 13:20:14 didg Exp $
+ * $Id: ad_mmap.c,v 1.5 2005-04-28 20:49:52 bfernhomberg Exp $
  *
  * ad_mmap provides interfaces to memory mapped files. as this is the
  * case, we don't have to deal w/ temporary buffers such as
 
 #ifdef USE_MMAPPED_HEADERS
 #include <stdio.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif /* HAVE_UNISTD_H */
-#ifdef HAVE_FCNTL_H
-#include <fcntl.h>
-#endif /* HAVE_FCNTL_H */
-#include <string.h>
 
 #include <atalk/adouble.h>
+#include <string.h>
 
 #include "ad_private.h"
 
index dc29f72b566214f5cf25bf18e8d5ba9922ac5a62..6c00aafd17403fef88be550d97f823899dfdd28f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: ad_open.c,v 1.31 2003-06-06 20:46:38 srittau Exp $
+ * $Id: ad_open.c,v 1.32 2005-04-28 20:49:52 bfernhomberg Exp $
  *
  * Copyright (c) 1999 Adrian Sun (asun@u.washington.edu)
  * Copyright (c) 1990,1991 Regents of The University of Michigan.
 #include "config.h"
 #endif /* HAVE_CONFIG_H */
 
-#include <string.h>
-#ifdef HAVE_FCNTL_H
-#include <fcntl.h>
-#endif /* HAVE_FCNTL_H */
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif /* HAVE_UNISTD_H */
 #include <errno.h>
-#include <atalk/logger.h>
 
-#include <sys/time.h>
-#include <sys/types.h>
-#include <sys/stat.h>
+#include <atalk/adouble.h>
 #include <sys/param.h>
-#include <sys/mman.h>
+#include <atalk/logger.h>
 
-#include <netatalk/endian.h>
-#include <atalk/adouble.h>
+#include <atalk/util.h>
+#include <string.h>
 
 #include "ad_private.h"
+#include <stdlib.h>
 
 #ifndef MAX
 #define MAX(a, b)  ((a) < (b) ? (b) : (a))
@@ -97,7 +88,6 @@
 #undef ADEDOFF_FILEI
 #endif /* ADEDOFF_FILEI */
 
-#define ADEID_NUM_V1         5
 #define ADEDOFF_NAME_V1             (AD_HEADER_LEN + ADEID_NUM_V1*AD_ENTRY_LEN)
 #define ADEDOFF_COMMENT_V1   (ADEDOFF_NAME_V1 + ADEDLEN_NAME)
 #define ADEDOFF_FILEI        (ADEDOFF_COMMENT_V1 + ADEDLEN_COMMENT)
 /* i stick things in a slightly different order than their eid order in 
  * case i ever want to separate RootInfo behaviour from the rest of the 
  * stuff. */
-#define ADEID_NUM_V2         9
 #define ADEDOFF_NAME_V2      (AD_HEADER_LEN + ADEID_NUM_V2*AD_ENTRY_LEN)
 #define ADEDOFF_COMMENT_V2   (ADEDOFF_NAME_V2 + ADEDLEN_NAME)
 #define ADEDOFF_FILEDATESI   (ADEDOFF_COMMENT_V2 + ADEDLEN_COMMENT)
 #define ADEDOFF_AFPFILEI     (ADEDOFF_DID + ADEDLEN_DID)
 #define ADEDOFF_SHORTNAME    (ADEDOFF_AFPFILEI + ADEDLEN_AFPFILEI)
 #define ADEDOFF_PRODOSFILEI  (ADEDOFF_SHORTNAME + ADEDLEN_SHORTNAME)
-#define ADEDOFF_RFORK_V2     (ADEDOFF_PRODOSFILEI + ADEDLEN_PRODOSFILEI)
+#define ADEDOFF_PRIVDEV      (ADEDOFF_PRODOSFILEI + ADEDLEN_PRODOSFILEI)
+#define ADEDOFF_PRIVINO      (ADEDOFF_PRIVDEV + ADEDLEN_PRIVDEV)
+#define ADEDOFF_PRIVSYN      (ADEDOFF_PRIVINO + ADEDLEN_PRIVINO)
+#define ADEDOFF_PRIVID       (ADEDOFF_PRIVSYN + ADEDLEN_PRIVSYN)
 
+#define ADEDOFF_RFORK_V2     (ADEDOFF_PRIVID + ADEDLEN_PRIVID)
 
+#define ADEID_NUM_OSX        2
+#define ADEDOFF_FINDERI_OSX  (AD_HEADER_LEN + ADEID_NUM_OSX*AD_ENTRY_LEN)
+#define ADEDOFF_RFORK_OSX    (ADEDOFF_FINDERI_OSX + ADEDLEN_FINDERI)
 
 /* we keep local copies of a bunch of stuff so that we can initialize things 
  * correctly. */
 
-/* Bits in the finderinfo data. 
- * see etc/afpd/{directory.c,file.c} for the finderinfo structure
- * layout. */
-#define FINDERINFO_CUSTOMICON 0x4
-#define FINDERINFO_CLOSEDVIEW 0x100
-
-/* offsets in finderinfo */
-#define FINDERINFO_FRTYPEOFF   0
-#define FINDERINFO_FRCREATOFF  4
-#define FINDERINFO_FRFLAGOFF   8
-#define FINDERINFO_FRVIEWOFF  14
-
 /* invisible bit for dot files */
 #define ATTRBIT_INVISIBLE     (1 << 0)
-#define FINDERINFO_INVISIBLE  (1 << 14)
 
 /* this is to prevent changing timezones from causing problems with
    localtime volumes. the screw-up is 30 years. we use a delta of 5
@@ -149,17 +132,41 @@ struct entry {
   u_int32_t id, offset, len;
 };
 
-#if AD_VERSION == AD_VERSION1 
-static const struct entry entry_order[] = {
-  {ADEID_NAME, ADEDOFF_NAME_V1, ADEDLEN_INIT},
-  {ADEID_COMMENT, ADEDOFF_COMMENT_V1, ADEDLEN_INIT},
-  {ADEID_FILEI, ADEDOFF_FILEI, ADEDLEN_FILEI},
-  {ADEID_FINDERI, ADEDOFF_FINDERI_V1, ADEDLEN_FINDERI},
-  {ADEID_RFORK, ADEDOFF_RFORK_V1, ADEDLEN_INIT},
+static const struct entry entry_order1[ADEID_NUM_V1 +1] = {
+  {ADEID_NAME,    ADEDOFF_NAME_V1,    ADEDLEN_INIT},      /* 3 */
+  {ADEID_COMMENT, ADEDOFF_COMMENT_V1, ADEDLEN_INIT},      /* 4 */
+  {ADEID_FILEI,   ADEDOFF_FILEI,      ADEDLEN_FILEI},     /* 7 */
+  {ADEID_FINDERI, ADEDOFF_FINDERI_V1, ADEDLEN_FINDERI},   /* 9 */
+  {ADEID_RFORK,   ADEDOFF_RFORK_V1,   ADEDLEN_INIT},      /* 2 */
   {0, 0, 0}
 };
+
+#if AD_VERSION == AD_VERSION1 
+#define DISK_EID(ad, a) (a)
+
 #else /* AD_VERSION == AD_VERSION2 */
-static const struct entry entry_order[] = {
+
+static u_int32_t get_eid(struct adouble *ad, u_int32_t eid) 
+{
+    if (eid <= 15)
+        return eid;
+    if (ad->ad_version == AD_VERSION1)
+        return 0;
+    if (eid == AD_DEV)
+        return ADEID_PRIVDEV;
+    if (eid == AD_INO)
+        return ADEID_PRIVINO;
+    if (eid == AD_SYN)
+        return ADEID_PRIVSYN;
+    if (eid == AD_ID)
+        return ADEID_PRIVID;
+
+    return 0;
+}
+
+#define DISK_EID(ad, a) get_eid(ad, a)
+
+static const struct entry entry_order2[ADEID_NUM_V2 +1] = {
   {ADEID_NAME, ADEDOFF_NAME_V2, ADEDLEN_INIT},
   {ADEID_COMMENT, ADEDOFF_COMMENT_V2, ADEDLEN_INIT},
   {ADEID_FILEDATESI, ADEDOFF_FILEDATESI, ADEDLEN_FILEDATESI},
@@ -168,64 +175,244 @@ static const struct entry entry_order[] = {
   {ADEID_AFPFILEI, ADEDOFF_AFPFILEI, ADEDLEN_AFPFILEI},
   {ADEID_SHORTNAME, ADEDOFF_SHORTNAME, ADEDLEN_INIT},
   {ADEID_PRODOSFILEI, ADEDOFF_PRODOSFILEI, ADEDLEN_PRODOSFILEI},
+  {ADEID_PRIVDEV,     ADEDOFF_PRIVDEV, ADEDLEN_INIT},
+  {ADEID_PRIVINO,     ADEDOFF_PRIVINO, ADEDLEN_INIT},
+  {ADEID_PRIVSYN,     ADEDOFF_PRIVSYN, ADEDLEN_INIT},
+  {ADEID_PRIVID,     ADEDOFF_PRIVID, ADEDLEN_INIT},
   {ADEID_RFORK, ADEDOFF_RFORK_V2, ADEDLEN_INIT},
+
+  {0, 0, 0}
+};
+
+/* OS X adouble finder info and resource fork only
+*/
+static const struct entry entry_order_osx[ADEID_NUM_OSX +1] = {
+  {ADEID_FINDERI, ADEDOFF_FINDERI_OSX, ADEDLEN_FINDERI},
+  {ADEID_RFORK, ADEDOFF_RFORK_OSX, ADEDLEN_INIT},
+
   {0, 0, 0}
 };
+
 #endif /* AD_VERSION == AD_VERSION2 */
 
 #if AD_VERSION == AD_VERSION2
 
+/* update a version 2 adouble resource fork with our private entries */
+static int ad_update(struct adouble *ad, const char *path)
+{
+  struct stat st;
+  u_int16_t nentries = 0;
+  off_t     off, shiftdata=0;
+  const struct entry  *eid;
+  static off_t entry_len[ADEID_MAX];
+  static char  databuf[ADEID_MAX][256], *buf;
+  int fd;
+  int ret = -1;
+
+  /* check to see if we should convert this header. */
+  if (!path || ad->ad_flags != AD_VERSION2)
+    return 0;
+  
+  if (!(ad->ad_hf.adf_flags & O_RDWR)) {
+      /* we were unable to open the file read write the last time */
+      return 0;
+  }
+
+  if (ad->ad_eid[ADEID_RFORK].ade_off) {
+      shiftdata = ADEDOFF_RFORK_V2 -ad->ad_eid[ADEID_RFORK].ade_off;
+  }
+
+  memcpy(&nentries, ad->ad_data + ADEDOFF_NENTRIES, sizeof( nentries ));
+  nentries = ntohs( nentries );
+
+  if ( shiftdata == 0 && nentries == ADEID_NUM_V2)
+    return 0;
+
+  memset(entry_len, 0, sizeof(entry_len));
+  memset(databuf, 0, sizeof(databuf));
+
+  /* bail if we can't get a lock */
+  if (ad_tmplock(ad, ADEID_RFORK, ADLOCK_WR, 0, 0, 0) < 0)
+    goto bail_err;
+
+  fd = ad->ad_hf.adf_fd;
+
+  if (fstat(fd, &st)) {
+    goto bail_lock;
+  }
+
+  if (st.st_size > 0x7fffffff) {
+      LOG(log_debug, logtype_default, "ad_update: file '%s' too big for update.", path);
+      errno = EIO;
+      goto bail_lock;
+  }
+
+  off = ad->ad_eid[ADEID_RFORK].ade_off;
+  if (off > st.st_size) {
+      LOG(log_error, logtype_default, "ad_update: invalid resource fork offset. (off: %u)", off); 
+      errno = EIO;
+      goto bail_lock;
+  }
+
+  if (ad->ad_eid[ADEID_RFORK].ade_len > st.st_size - off) {
+      LOG(log_error, logtype_default, "ad_update: invalid resource fork length. (rfork len: %u)", ad->ad_eid[ADEID_RFORK].ade_len); 
+      errno = EIO;
+      goto bail_lock;
+  }
+  
+  if ((void *) (buf = (char *)
+                mmap(NULL, st.st_size + shiftdata,
+                     PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)) ==
+          MAP_FAILED) {
+    goto bail_lock;
+  }
+
+  /* last place for failure. */
+  if (sys_ftruncate(fd, st.st_size + shiftdata) < 0) {
+    goto bail_lock;
+  }
+
+  /* move the RFORK. this assumes that the RFORK is at the end */
+  if (off) {
+    memmove(buf + ADEDOFF_RFORK_V2, buf + off, ad->ad_eid[ADEID_RFORK].ade_len);
+  }
+
+  munmap(buf, st.st_size + shiftdata);
+
+  /* now, fix up our copy of the header */
+  memset(ad->ad_filler, 0, sizeof(ad->ad_filler));
+  /* save the header entries */ 
+  eid = entry_order2;
+  while (eid->id) {
+    if( ad->ad_eid[eid->id].ade_off != 0) {
+      if ( eid->id > 2 && ad->ad_eid[eid->id].ade_len < 256)
+        memcpy( databuf[eid->id], ad->ad_data +ad->ad_eid[eid->id].ade_off, ad->ad_eid[eid->id].ade_len);
+      entry_len[eid->id] = ad->ad_eid[eid->id].ade_len;
+    }
+    eid++;
+  }
+
+  memset(ad->ad_data + AD_HEADER_LEN, 0, AD_DATASZ - AD_HEADER_LEN);
+
+  /* copy the saved entries to the new header */
+  eid = entry_order2;
+  while (eid->id) {
+    if ( eid->id > 2 && entry_len[eid->id] > 0) {
+      memcpy(ad->ad_data+eid->offset, databuf[eid->id], entry_len[eid->id]);
+    }
+    ad->ad_eid[eid->id].ade_off = eid->offset;
+    ad->ad_eid[eid->id].ade_len = entry_len[eid->id];
+    eid++;
+  }
+
+  /* rebuild the header and cleanup */
+  LOG(log_debug, logtype_default, "updated AD2 header %s", path);
+  ad_flush(ad, ADFLAGS_HF );
+  ret = 0;
+
+bail_lock:
+  ad_tmplock(ad, ADEID_RFORK, ADLOCK_CLR, 0, 0, 0);
+bail_err:
+  return ret;
+}
 
-static __inline__ int ad_v1tov2(struct adouble *ad, const char *path)
+/* ------------------------------------------
+   FIXME work only if < 2GB 
+*/
+static int ad_convert(struct adouble *ad, const char *path)
 {
   struct stat st;
   u_int16_t attr;
   char *buf;
   int fd, off;
+  int ret = -1;
+  /* use resource fork offset from file */
+  int shiftdata;
+  int toV2;
+  int toV1;
+  
+  if (!path) {
+      return 0;
+  }
   
+  if (!(ad->ad_hf.adf_flags & ( O_RDWR))) {
+      /* we were unable to open the file read write the last time */
+      return 0;
+  }
+
   /* check to see if we should convert this header. */
-  if (!path || (ad->ad_version != AD_VERSION1))
-    return 0;
+  toV2 = ad->ad_version == AD_VERSION1 && ad->ad_flags == AD_VERSION2;
+  toV1 = ad->ad_version == AD_VERSION2 && ad->ad_flags == AD_VERSION1;
+
+  if (!toV2 && !toV1)
+      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
    *  3) move FILEI attributes into AFPFILEI
    *  4) initialize ACCESS field of FILEDATESI.
-   *
-   *  so, we need 4*12 (entry ids) + 12 (shortname) + 4 (afpfilei) +
-   *  4 (did) + 8 (prodosi) = 76 more bytes.  */
+   *  5) move the resource fork
+   */
   
-#define SHIFTDATA (AD_DATASZ2 - AD_DATASZ1)
-
   /* bail if we can't get a lock */
   if (ad_tmplock(ad, ADEID_RFORK, ADLOCK_WR, 0, 0, 0) < 0) 
     goto bail_err;
+
+  /* we reuse fd from the resource fork */
+  fd = ad->ad_hf.adf_fd;
+
+  if (ad->ad_eid[ADEID_RFORK].ade_off) {
+      shiftdata = ADEDOFF_RFORK_V2 -ad->ad_eid[ADEID_RFORK].ade_off;
+  }
+  else {
+      shiftdata = ADEDOFF_RFORK_V2 -ADEDOFF_RFORK_V1; /* 136 */
+  }
+
+  if (fstat(fd, &st)) { 
+      goto bail_lock;
+  }
+
+  if (st.st_size > 0x7fffffff -shiftdata) {
+      LOG(log_debug, logtype_default, "ad_v1tov2: file too big."); 
+      errno = EIO;
+      goto bail_lock;
+  }
   
-  if ((fd = open(path, O_RDWR)) < 0) 
-    goto bail_lock;
-  
-  if (fstat(fd, &st) ||
-      ftruncate(fd, st.st_size + SHIFTDATA) < 0) {
-    goto bail_open;
+  off = ad->ad_eid[ADEID_RFORK].ade_off;
+
+  if (off > st.st_size) {
+      LOG(log_error, logtype_default, "ad_v1tov2: invalid resource fork offset. (off: %u)", off); 
+      errno = EIO;
+      goto bail_lock;
+  }
+
+  if (ad->ad_eid[ADEID_RFORK].ade_len > st.st_size - off) {
+      LOG(log_error, logtype_default, "ad_v1tov2: invalid resource fork length. (rfork len: %u)", ad->ad_eid[ADEID_RFORK].ade_len); 
+      errno = EIO;
+      goto bail_lock;
   }
   
-  /* last place for failure. */
   if ((void *) (buf = (char *) 
-               mmap(NULL, st.st_size + SHIFTDATA,
+               mmap(NULL, st.st_size + shiftdata,
                     PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)) == 
          MAP_FAILED) {
-    goto bail_truncate;
+    goto bail_lock;
   }
-  
-  off = ad->ad_eid[ADEID_RFORK].ade_off;
 
-  /* move the RFORK. this assumes that the RFORK is at the end */
-  memmove(buf + off + SHIFTDATA, buf + off, 
-         ad->ad_eid[ADEID_RFORK].ade_len);
+  /* last place for failure. */
+
+  if (sys_ftruncate(fd, st.st_size + shiftdata) < 0) {
+      goto bail_lock;
+  }
   
-  munmap(buf, st.st_size + SHIFTDATA);
-  close(fd);
+  /* move the RFORK. this assumes that the RFORK is at the end */
+  if (off) {
+      memmove(buf + ADEDOFF_RFORK_V2, buf + off, ad->ad_eid[ADEID_RFORK].ade_len);
+  }
+
+  munmap(buf, st.st_size + shiftdata);
 
   /* now, fix up our copy of the header */
   memset(ad->ad_filler, 0, sizeof(ad->ad_filler));
@@ -247,14 +434,23 @@ static __inline__ int ad_v1tov2(struct adouble *ad, const char *path)
   ad->ad_eid[ADEID_PRODOSFILEI].ade_off = ADEDOFF_PRODOSFILEI;
   ad->ad_eid[ADEID_PRODOSFILEI].ade_len = ADEDLEN_PRODOSFILEI;
   
+  ad->ad_eid[ADEID_PRIVDEV].ade_off = ADEDOFF_PRIVDEV;
+  ad->ad_eid[ADEID_PRIVDEV].ade_len = ADEDLEN_INIT;
+  ad->ad_eid[ADEID_PRIVINO].ade_off = ADEDOFF_PRIVINO;
+  ad->ad_eid[ADEID_PRIVINO].ade_len = ADEDLEN_INIT;
+  ad->ad_eid[ADEID_PRIVSYN].ade_off = ADEDOFF_PRIVSYN;
+  ad->ad_eid[ADEID_PRIVSYN].ade_len = ADEDLEN_INIT;
+  ad->ad_eid[ADEID_PRIVID].ade_off  = ADEDOFF_PRIVID;
+  ad->ad_eid[ADEID_PRIVID].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;
   ad->ad_eid[ADEID_FINDERI].ade_off = ADEDOFF_FINDERI_V2;
   ad->ad_eid[ADEID_RFORK].ade_off = ADEDOFF_RFORK_V2;
   
-  /* switch to v2 */
-  ad->ad_version = AD_VERSION2;
+  /* switch to dest version */
+  ad->ad_version = (toV2)?AD_VERSION2:AD_VERSION1;
   
   /* move our data buffer to make space for the new entries. */
   memmove(ad->ad_data + ADEDOFF_NAME_V2, ad->ad_data + ADEDOFF_NAME_V1,
@@ -271,23 +467,23 @@ static __inline__ int ad_v1tov2(struct adouble *ad, const char *path)
   
   /* rebuild the header and cleanup */
   ad_flush(ad, ADFLAGS_HF );
-  ad_tmplock(ad, ADEID_RFORK, ADLOCK_CLR, 0, 0, 0);
-
-  return 0;
+  ret = 0;
   
-bail_truncate:
-  ftruncate(fd, st.st_size);
-bail_open:
-  close(fd);
 bail_lock:
   ad_tmplock(ad, ADEID_RFORK, ADLOCK_CLR, 0, 0, 0);
 bail_err:
-  return -1;
+  return ret;
 }
 #endif /* AD_VERSION == AD_VERSION2 */
 
+/* --------------------------- */
+#ifdef ATACC
 mode_t ad_hf_mode (mode_t mode)
 {
+    /* we always need RW mode for file owner */
+#if 0
+    mode |= S_IRUSR;
+#endif    
     /* fnctl lock need write access */
     if ((mode & S_IRUSR))
         mode |= S_IWUSR;
@@ -306,6 +502,8 @@ mode_t ad_hf_mode (mode_t mode)
     return mode;
 }
 
+#endif
+
 /* ------------------------------------- 
   read in the entries 
 */
@@ -318,7 +516,7 @@ static void parse_entries(struct adouble *ad, char *buf,
     /* now, read in the entry bits */
     for (; nentries > 0; nentries-- ) {
        memcpy(&eid, buf, sizeof( eid ));
-       eid = ntohl( eid );
+       eid = DISK_EID(ad, ntohl( eid ));
        buf += sizeof( eid );
        memcpy(&off, buf, sizeof( off ));
        off = ntohl( off );
@@ -327,12 +525,13 @@ static void parse_entries(struct adouble *ad, char *buf,
        len = ntohl( len );
        buf += sizeof( len );
 
-       if ( 0 < eid && eid < ADEID_MAX ) {
+       if (eid && eid < ADEID_MAX && off < sizeof(ad->ad_data) && 
+                (off +len <= sizeof(ad->ad_data) || eid == ADEID_RFORK)) {
            ad->ad_eid[ eid ].ade_off = off;
            ad->ad_eid[ eid ].ade_len = len;
        } else if (!warning) {
            warning = 1;
-           LOG(log_debug, logtype_default, "ad_refresh: nentries %hd  eid %d\n",
+           LOG(log_debug, logtype_default, "ad_refresh: nentries %hd  eid %d",
                    nentries, eid );
        }
     }
@@ -426,8 +625,9 @@ static int ad_header_read(struct adouble *ad, struct stat *hst)
     if (!ad_getentryoff(ad, ADEID_RFORK)
        || (ad_getentryoff(ad, ADEID_RFORK) > sizeof(ad->ad_data))
        ) {
-      LOG(log_debug, logtype_default, "ad_header_read: problem with rfork entry offset."); 
-      return -1;
+        errno = EIO;
+        LOG(log_debug, logtype_default, "ad_header_read: problem with rfork entry offset."); 
+        return -1;
     }
 
     if (ad_getentryoff(ad, ADEID_RFORK) > header_len) {
@@ -463,13 +663,14 @@ static int ad_header_read(struct adouble *ad, struct stat *hst)
     return 0;
 }
 
-
-/*
+/* ---------------------------------------
  * Put the .AppleDouble where it needs to be:
  *
  *         /   a/.AppleDouble/b
  *     a/b
  *         \   b/.AppleDouble/.Parent
+ *
+ * FIXME: should do something for pathname > MAXPATHLEN
  */
 char *
 ad_path( path, adflags )
@@ -478,32 +679,173 @@ ad_path( path, adflags )
 {
     static char        pathbuf[ MAXPATHLEN + 1];
     char       c, *slash, buf[MAXPATHLEN + 1];
+    size_t      l;
 
-    strncpy(buf, path, MAXPATHLEN);
+    l = strlcpy(buf, path, MAXPATHLEN +1);
     if ( adflags & ADFLAGS_DIR ) {
-       strncpy( pathbuf, buf, MAXPATHLEN );
-       if ( *buf != '\0' ) {
-           strcat( pathbuf, "/" );
+       strcpy( pathbuf, buf);
+       if ( *buf != '\0' && l < MAXPATHLEN) {
+           pathbuf[l++] = '/';
+           pathbuf[l] = 0;
        }
        slash = ".Parent";
     } else {
        if (NULL != ( slash = strrchr( buf, '/' )) ) {
            c = *++slash;
            *slash = '\0';
-           strncpy( pathbuf, buf, MAXPATHLEN);
+           strcpy( pathbuf, buf);
            *slash = c;
        } else {
            pathbuf[ 0 ] = '\0';
            slash = buf;
        }
     }
-    strncat( pathbuf, ".AppleDouble/", MAXPATHLEN - strlen(pathbuf));
-    strncat( pathbuf, slash, MAXPATHLEN - strlen(pathbuf));
+    strlcat( pathbuf, ".AppleDouble/", MAXPATHLEN +1);
+    strlcat( pathbuf, slash, MAXPATHLEN +1);
 
     return( pathbuf );
 }
 
-/*
+/* -------------------- */
+static int ad_mkrf(char *path)
+{
+    char *slash;
+    /*
+     * Probably .AppleDouble doesn't exist, try to mkdir it.
+     */
+     if (NULL == ( slash = strrchr( path, '/' )) ) {
+         return -1;
+     }
+     *slash = '\0';
+     errno = 0;
+     if ( ad_mkdir( path, 0777 ) < 0 ) {
+          return -1;
+     }
+     *slash = '/';
+     return 0;
+}
+
+/* ---------------------------------------
+ * Put the resource fork where it needs to be:
+ * ._name
+ */
+char *
+ad_path_osx(const char *path, int adflags _U_)
+{
+    static char        pathbuf[ MAXPATHLEN + 1];
+    char       c, *slash, buf[MAXPATHLEN + 1];
+    
+    if (!strcmp(path,".")) {
+            /* fixme */
+        getcwd(buf, MAXPATHLEN);
+    }
+    else {
+        strlcpy(buf, path, MAXPATHLEN +1);
+    }
+    if (NULL != ( slash = strrchr( buf, '/' )) ) {
+       c = *++slash;
+       *slash = '\0';
+       strlcpy( pathbuf, buf, MAXPATHLEN +1);
+       *slash = c;
+    } else {
+       pathbuf[ 0 ] = '\0';
+       slash = buf;
+    }
+    strlcat( pathbuf, "._", MAXPATHLEN  +1);  
+    strlcat( pathbuf, slash, MAXPATHLEN +1);
+    return pathbuf;
+}
+/* -------------------- */
+static int ad_mkrf_osx(char *path _U_)
+{
+    return 0;
+}
+
+/* ---------------------------------------
+ * Put the .AppleDouble where it needs to be:
+ *
+ *         /   a/.AppleDouble/b/Afp_AfpInfo
+ *     a/b     
+ *         \   b/.AppleDouble/.Parent/Afp_AfpInfo
+ *
+ */
+char *
+ad_path_ads( path, adflags )
+    const char *path;
+    int                adflags;
+{
+    static char        pathbuf[ MAXPATHLEN + 1];
+    char       c, *slash, buf[MAXPATHLEN + 1];
+    size_t      l;
+
+    l = strlcpy(buf, path, MAXPATHLEN +1);
+    if ( adflags & ADFLAGS_DIR ) {
+       strcpy( pathbuf, buf);
+       if ( *buf != '\0' && l < MAXPATHLEN) {
+           pathbuf[l++] = '/';
+           pathbuf[l] = 0;
+       }
+       slash = ".Parent";
+    } else {
+       if (NULL != ( slash = strrchr( buf, '/' )) ) {
+           c = *++slash;
+           *slash = '\0';
+           strcpy( pathbuf, buf);
+           *slash = c;
+       } else {
+           pathbuf[ 0 ] = '\0';
+           slash = buf;
+       }
+    }
+    strlcat( pathbuf, ".AppleDouble/", MAXPATHLEN +1);
+    strlcat( pathbuf, slash, MAXPATHLEN +1);
+
+    strlcat( pathbuf, "/Afp_AfpInfo", MAXPATHLEN +1);
+
+#if 0
+    if ((adflags & ADFLAGS_HF)) {
+        strlcat( pathbuf, "Afp_AfpInfo", MAXPATHLEN +1);
+    else {
+        strlcat( pathbuf, "Afp_Resource", MAXPATHLEN +1);
+    }
+#endif      
+    return( pathbuf );
+}
+
+/* -------------------- */
+static int ad_mkrf_ads(char *path)
+{
+    char *slash;
+    /*
+     * Probably .AppleDouble doesn't exist, try to mkdir it.
+     */
+     if (NULL == ( slash = strrchr( path, '/' )) ) {
+         return -1;
+     }
+     *slash = 0;
+     errno = 0;
+     if ( ad_mkdir( path, 0777 ) < 0 ) {
+         if ( errno == ENOENT ) {
+             char *slash1;
+             
+             if (NULL == ( slash1 = strrchr( path, '/' )) ) 
+                 return -1;
+             errno = 0;
+             *slash1 = 0;
+             if ( ad_mkdir( path, 0777 ) < 0 ) 
+                  return -1;
+             *slash1 = '/';
+             if ( ad_mkdir( path, 0777 ) < 0 )
+                 return -1;
+         }
+         else
+            return -1;
+     }     
+     *slash = '/';
+     return 0;
+}
+
+/* -------------------------
  * Support inherited protection modes for AppleDouble files.  The supplied
  * mode is ANDed with the parent directory's mask value in lieu of "umask",
  * and that value is returned.
@@ -517,8 +859,9 @@ char
 {
     static char                modebuf[ MAXPATHLEN + 1];
     char               *slash;
+    size_t              len;
 
-    if ( strlen( path ) >= MAXPATHLEN ) {
+    if ( (len = strlen( path )) >= MAXPATHLEN ) {
         errno = ENAMETOOLONG;
        return NULL;  /* can't do it */
     }
@@ -529,7 +872,18 @@ char
      * For a path which is just a filename, use "." instead.
      */
     strcpy( modebuf, path );
-    if (NULL != ( slash = strrchr( modebuf, '/' )) ) {
+    slash = strrchr( modebuf, '/' );
+    /* is last char a '/' */
+    if (slash && slash[1] == 0) {
+        while (modebuf < slash && slash[-1] == '/') {
+            --slash;
+        }
+        if (modebuf < slash) {
+           *slash = '\0';              /* remove pathname component */
+           slash = strrchr( modebuf, '/' );
+       }
+    }
+    if (slash) {
        *slash = '\0';          /* remove pathname component */
     } else {
        modebuf[0] = '.';       /* use current directory */
@@ -556,7 +910,7 @@ uid_t ad_getfuid(void)
 /* ---------------- 
    return inode of path parent directory
 */
-static int ad_stat(const char *path, struct stat *stbuf)
+int ad_stat(const char *path, struct stat *stbuf)
 {
     char                *p;
 
@@ -650,12 +1004,14 @@ struct stat stbuf;
 /* ----------------- */
 static int ad_error(struct adouble *ad, int adflags)
 {
+int err = errno;
     if ((adflags & ADFLAGS_NOHF)) {
         /* FIXME double check : set header offset ?*/
         return 0;
     }
     if ((adflags & ADFLAGS_DF)) {
        ad_close( ad, ADFLAGS_DF );
+       err = errno;
     }
     return -1 ;
 }
@@ -667,7 +1023,27 @@ static int new_rfork(const char *path, struct adouble *ad, int adflags);
 #else 
 #define AD_SET(a) a = 0
 #endif
-/*
+
+void ad_init(struct adouble *ad, int flags, int options)
+{
+    memset( ad, 0, sizeof( struct adouble ) );
+    ad->ad_flags = flags;
+    if (flags == AD_VERSION2_OSX) {
+        ad->ad_path = ad_path_osx;
+        ad->ad_mkrf = ad_mkrf_osx;
+    }
+    else if (flags == AD_VERSION1_ADS) {
+        ad->ad_path = ad_path_ads;
+        ad->ad_mkrf = ad_mkrf_ads;
+    }
+    else {
+        ad->ad_path = ad_path;
+        ad->ad_mkrf = ad_mkrf;
+    }
+    ad->ad_options = options;
+}
+
+/* -------------------
  * It's not possible to open the header file O_RDONLY -- the read
  * will fail and return an error. this refcounts things now. 
  */
@@ -677,7 +1053,7 @@ int ad_open( path, adflags, oflags, mode, ad )
     struct adouble     *ad;
 {
     struct stat         st;
-    char               *slash, *ad_p;
+    char               *ad_p;
     int                        hoflags, admode;
     int                 st_invalid;
     int                 open_df = 0;
@@ -751,10 +1127,12 @@ int ad_open( path, adflags, oflags, mode, ad )
        return 0;
     }
 
-    ad_p = ad_path( path, adflags );
+    ad_p = ad->ad_path( path, adflags );
 
     hoflags = oflags & ~O_CREAT;
-    hoflags = (hoflags & ~(O_RDONLY | O_WRONLY)) | O_RDWR;
+    if (!(adflags & ADFLAGS_RDONLY)) {
+        hoflags = (hoflags & ~(O_RDONLY | O_WRONLY)) | O_RDWR;
+    }
     ad->ad_hf.adf_fd = open( ad_p, hoflags, 0 );
     if (ad->ad_hf.adf_fd < 0 ) {
         if ((errno == EACCES || errno == EROFS) && !(oflags & O_RDWR)) {
@@ -771,40 +1149,26 @@ int ad_open( path, adflags, oflags, mode, ad )
             * if ((oflags & O_CREAT) ==> (oflags & O_RDWR)
             */
            admode = mode;
+           errno = 0;
            st_invalid = ad_mode_st(ad_p, &admode, &st);
            admode = ad_hf_mode(admode); 
-           errno = 0;
+           if ( errno == ENOENT && !(adflags & ADFLAGS_NOADOUBLE) && ad->ad_flags != AD_VERSION2_OSX) {
+               if (ad->ad_mkrf( ad_p) < 0) {
+                   return ad_error(ad, adflags);
+               }
+               admode = mode;
+               st_invalid = ad_mode_st(ad_p, &admode, &st);
+               admode = ad_hf_mode(admode); 
+           }
+           /* retry with O_CREAT */
            ad->ad_hf.adf_fd = open( ad_p, oflags,admode );
            if ( ad->ad_hf.adf_fd < 0 ) {
-               /*
-                * Probably .AppleDouble doesn't exist, try to
-                * mkdir it.
-                */
-               if (errno == ENOENT && (adflags & ADFLAGS_NOADOUBLE) == 0) {
-                   if (NULL == ( slash = strrchr( ad_p, '/' )) ) {
-                       return ad_error(ad, adflags);
-                   }
-                   *slash = '\0';
-                   errno = 0;
-                   if ( ad_mkdir( ad_p, 0777 ) < 0 ) {
-                       return ad_error(ad, adflags);
-                   }
-                   *slash = '/';
-                   admode = mode;
-                   st_invalid = ad_mode_st(ad_p, &admode, &st);
-                   admode = ad_hf_mode(admode); 
-                   ad->ad_hf.adf_fd = open( ad_p, oflags, admode);
-                   if ( ad->ad_hf.adf_fd < 0 ) {
-                       return ad_error(ad, adflags);
-                   }
-               } else {
-                    return ad_error(ad, adflags);
-               }
+               return ad_error(ad, adflags);
            }
            ad->ad_hf.adf_flags = oflags;
            /* just created, set owner if admin owner (root) */
            if (!st_invalid) {
-               ad_chown(path, &st);
+               ad_chown(ad_p, &st);
            }
        }
        else {
@@ -812,7 +1176,7 @@ int ad_open( path, adflags, oflags, mode, ad )
        }
     } else if (fstat(ad->ad_hf.adf_fd, &st) == 0 && st.st_size == 0) {
        /* for 0 length files, treat them as new. */
-       ad->ad_hf.adf_flags = (oflags & ~(O_RDONLY | O_WRONLY)) | O_RDWR | O_TRUNC;
+       ad->ad_hf.adf_flags = hoflags| O_TRUNC;
     } else {
         ad->ad_hf.adf_flags = hoflags;
     }
@@ -826,41 +1190,81 @@ int ad_open( path, adflags, oflags, mode, ad )
          * instead of reading it.
         */
         if (new_rfork(path, ad, adflags) < 0) {
+            int err = errno;
             /* the file is already deleted, perm, whatever, so return an error*/
             ad_close(ad, adflags);
+            errno = err;
            return -1;
        }
     } else {
            /* Read the adouble header in and parse it.*/
        if ((ad_header_read( ad , &st) < 0)
 #if AD_VERSION == AD_VERSION2
-               || (ad_v1tov2(ad, ad_p) < 0)
+               || (ad_convert(ad, ad_p) < 0) || (ad_update(ad, ad_p) < 0)
 #endif /* AD_VERSION == AD_VERSION2 */
         ) {
+            int err = errno;
+            
             ad_close( ad, adflags );
-           return( -1 );
+            errno = err;
+           return -1;
        }
     }
     return 0 ;
 }
 
+/* ----------------------------------- 
+ * return only metadata but try very hard
+*/
+int ad_metadata(const char *name, int flags, struct adouble *adp)
+{
+    uid_t uid;
+    int   ret, err;
+
+    if ((ret = ad_open(name, ADFLAGS_HF | (flags), O_RDONLY, 0, adp)) < 0 && errno == EACCES) {
+        uid = geteuid();
+        if (seteuid(0)) {
+            LOG(log_error, logtype_default, "ad_metadata(%s): seteuid failed %s", name, strerror(errno));
+            errno = EACCES;
+            return -1;
+        }
+        /* we are root open read only */
+        ret = ad_open(name, ADFLAGS_HF|ADFLAGS_RDONLY|(flags), O_RDONLY, 0, adp);
+        err = errno;
+        if ( seteuid(uid) < 0) {
+            LOG(log_error, logtype_default, "ad_metadata: can't seteuid back");
+            exit(EXITERR_SYS);
+        }
+        errno = err;
+    }
+    return ret;
+}
+
 /* ----------------------------------- */
 static int new_rfork(const char *path, struct adouble *ad, int adflags)
 {
-#if 0
-    struct timeval      tv;
-#endif    
     const struct entry  *eid;
     u_int16_t           ashort;
     struct stat         st;
 
     ad->ad_magic = AD_MAGIC;
-    ad->ad_version = AD_VERSION;
+    ad->ad_version = ad->ad_flags & 0x0f0000;
+    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_flags == AD_VERSION2)
+       eid = entry_order2;
+    else if (ad->ad_flags == AD_VERSION2_OSX)
+       eid = entry_order_osx;
+    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;
@@ -868,15 +1272,15 @@ static int new_rfork(const char *path, struct adouble *ad, int adflags)
     }
            
     /* put something sane in the directory finderinfo */
-    if (adflags & ADFLAGS_DIR) {
+    if ((adflags & ADFLAGS_DIR)) {
         /* set default view */
        ashort = htons(FINDERINFO_CLOSEDVIEW);
        memcpy(ad_entry(ad, ADEID_FINDERI) + FINDERINFO_FRVIEWOFF, 
                     &ashort, sizeof(ashort));
     } else {
         /* set default creator/type fields */
-       memcpy(ad_entry(ad, ADEID_FINDERI) + FINDERINFO_FRTYPEOFF,"TEXT", 4);
-       memcpy(ad_entry(ad, ADEID_FINDERI) + FINDERINFO_FRCREATOFF,"UNIX", 4);
+       memcpy(ad_entry(ad, ADEID_FINDERI) + FINDERINFO_FRTYPEOFF,"\0\0\0\0", 4);
+       memcpy(ad_entry(ad, ADEID_FINDERI) + FINDERINFO_FRCREATOFF,"\0\0\0\0", 4);
     }
 
     /* make things invisible */
@@ -888,12 +1292,6 @@ static int new_rfork(const char *path, struct adouble *ad, int adflags)
                     &ashort, sizeof(ashort));
     }
 
-#if 0
-    if (gettimeofday(&tv, NULL) < 0) {
-       return -1;
-    } 
-#endif
-    
     if (stat(path, &st) < 0) {
        return -1;
     }
@@ -911,7 +1309,7 @@ static int new_rfork(const char *path, struct adouble *ad, int adflags)
 int ad_refresh(struct adouble *ad)
 {
 
-  if (ad->ad_hf.adf_fd < -1)
+  if (ad->ad_hf.adf_fd < 0)
     return -1;
 
   return ad_header_read(ad, NULL);
index 644e68db1eb5b4d49213be0559ec7a3b872d614b..5c3c93334c38d2c7a00bbb2337602ea3f8291527 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: ad_read.c,v 1.5 2003-02-09 15:36:13 didg Exp $
+ * $Id: ad_read.c,v 1.6 2005-04-28 20:49:52 bfernhomberg Exp $
  *
  * Copyright (c) 1990,1991 Regents of The University of Michigan.
  * All Rights Reserved.
@@ -75,6 +75,10 @@ ssize_t ad_read( ad, eid, off, buf, buflen)
     } else {
         off_t r_off;
         
+        if ( ad_hfileno( ad ) == -1 ) {
+             /* resource fork is not open ( cf etc/afp/fork.c) */
+             return 0;
+        }
         r_off = ad_getentryoff(ad, eid) + off;
        
        if (( cc = adf_pread( &ad->ad_hf, buf, buflen, r_off )) < 0 ) {
index 1803d71e564ffd9e933b97f83ec868faf8125f18..42971911f5beb4bedcb42482df89fa3d935f385e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: ad_sendfile.c,v 1.7 2003-06-06 20:43:14 srittau Exp $
+ * $Id: ad_sendfile.c,v 1.8 2005-04-28 20:49:52 bfernhomberg Exp $
  *
  * Copyright (c) 1999 Adrian Sun (asun@zoology.washington.edu)
  * All rights reserved. See COPYRIGHT.
  * NOTE: the following uses the fact that sendfile() only exists on
  * machines with SA_RESTART behaviour. this is all very machine specific. 
  *
- * 
+ * sendfile chainsaw from samba.
+ Unix SMB/Netbios implementation.
+ Version 2.2.x / 3.0.x
+ sendfile implementations.
+ Copyright (C) Jeremy Allison 2002.
+ 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 /* HAVE_CONFIG_H */
 
+#ifdef WITH_SENDFILE
+
+#include <atalk/adouble.h>
+
 #include <stdio.h>
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif /* HAVE_UNISTD_H */
-#include <sys/types.h>
-#include <sys/stat.h>
+
 #include <sys/socket.h>
 #include <sys/uio.h>
 
-#include <atalk/adouble.h>
+#include <errno.h>  
 
 #include <atalk/logger.h>
 
 #include "ad_private.h"
 
-#if defined(HAVE_SENDFILE_READ) || defined(HAVE_SENDFILE_WRITE)
+#if defined(LINUX_BROKEN_SENDFILE_API)
+
+extern int32_t sendfile (int fdout, int fdin, int32_t *offset, u_int32_t count);
+
+ssize_t sys_sendfile(int tofd, int fromfd, off_t *offset, size_t count)
+{
+u_int32_t small_total = 0;
+int32_t small_offset;
+
+    /*
+     * Fix for broken Linux 2.4 systems with no working sendfile64().
+     * If the offset+count > 2 GB then pretend we don't have the
+     * system call sendfile at all. The upper layer catches this
+     * and uses a normal read. JRA.
+     */
+     if ((sizeof(off_t) >= 8) && (*offset + count > (off_t)0x7FFFFFFF)) {
+         errno = ENOSYS;
+         return -1;
+     }
+     small_total = (u_int32_t)count;
+     small_offset = (int32_t)*offset;
+     while (small_total) {
+         int32_t nwritten;
+         do {
+             nwritten = sendfile(tofd, fromfd, &small_offset, small_total);
+         } while (nwritten == -1 && errno == EINTR);
+         if (nwritten == -1)
+             return -1;
+         if (nwritten == 0)
+             return -1; /* I think we're at EOF here... */
+         small_total -= nwritten;
+    }
+    *offset += count;
+    return count;
+}
+
+#elif defined(SENDFILE_FLAVOR_LINUX)
+#include <sys/sendfile.h>
+
+ssize_t sys_sendfile(int tofd, int fromfd, off_t *offset, size_t count)
+{
+size_t total=0;
+
+    total = count;
+    while (total) {
+        ssize_t nwritten;
+        do {
+            nwritten = sendfile(tofd, fromfd, offset, total);
+        } while (nwritten == -1 && errno == EINTR);
+        if (nwritten == -1)
+            return -1;
+        if (nwritten == 0)
+            return -1; /* I think we're at EOF here... */
+        total -= nwritten;
+    }
+    return count;
+}
+
+
+#elif defined(SENDFILE_FLAVOR_BSD )
+/* FIXME untested */
+#include <sys/sendfile.h>
+ssize_t sys_sendfile(int tofd, int fromfd, off_t *offset, size_t count)
+{
+size_t total=0;
+int    ret;
+
+    total = count;
+    while (total) {
+        ssize_t nwritten;
+        do {
+           ret = sendfile(fromfd, tofd, offset, count, NULL, &nwritten, 0);
+        while (ret == -1 && errno == EINTR);
+        if (ret == -1)
+            return -1;
+        total -= nwritten;
+        offset += nwritten;
+    }
+    return count;
+}
+
+#else
+
+ssize_t sys_sendfile(int out_fd, int in_fd, off_t *_offset, size_t count)
+{
+    /* No sendfile syscall. */
+    errno = ENOSYS;
+    return -1;
+}
+#endif
+
+/* ------------------------------- */
 static __inline__ int ad_sendfile_init(const struct adouble *ad, 
                                       const int eid, off_t *off,
                                       const int end)
@@ -48,12 +158,11 @@ static __inline__ int ad_sendfile_init(const struct adouble *ad,
 
   return fd;
 }
-#endif
 
 
-/* read from adouble file and write to socket. sendfile doesn't change
+/* --------------------------------
+ * read from adouble file and write to socket. sendfile doesn't change
  * the file pointer position. */
-#ifdef HAVE_SENDFILE_READ
 ssize_t ad_readfile(const struct adouble *ad, const int eid, 
                    const int sock, off_t off, const size_t len)
 {
@@ -61,19 +170,11 @@ ssize_t ad_readfile(const struct adouble *ad, const int eid,
   int fd;
 
   fd = ad_sendfile_init(ad, eid, &off, 0);
-#ifdef __linux__
-  cc = sendfile(sock, fd, &off, len);
-#endif /* __linux__ */
-
-#ifdef BSD4_4
-  if (sendfile(fd, sock, off, len, NULL, &cc, 0) < 0)
-    return -1;
-#endif /* BSD4_4 */
-
+  cc = sys_sendfile(sock, fd, &off, len);
   return cc;
 }
-#endif /* HAVE_SENDFILE_READ */
 
+/* ------------------------ */
 #if 0
 #ifdef HAVE_SENDFILE_WRITE
 /* read from a socket and write to an adouble file */
@@ -86,7 +187,7 @@ ssize_t ad_writefile(struct adouble *ad, const int eid,
   int fd;
 
   fd = ad_sendfile_init(ad, eid, &off, end);
-  if ((cc = sendfile(fd, sock, &off, len)) < 0)
+  if ((cc = sys_sendfile(fd, sock, &off, len)) < 0)
     return -1;
 
   if ((eid != ADEID_DFORK) && (off > ad_getentrylen(ad, eid))) 
@@ -97,3 +198,4 @@ ssize_t ad_writefile(struct adouble *ad, const int eid,
 }
 #endif /* HAVE_SENDFILE_WRITE */
 #endif /* 0 */
+#endif
index 5a63fc442f6c1779105ce1bb2338b2f246ef78dd..bada1c364a9f7c1ebf1f7b4315f9753b59aaa170 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: ad_size.c,v 1.5 2002-10-11 14:18:38 didg Exp $
+ * $Id: ad_size.c,v 1.6 2005-04-28 20:49:52 bfernhomberg Exp $
  *
  * Copyright (c) 1997 Adrian Sun (asun@zoology.washington.edu)
  * All rights reserved. See COPYRIGHT.
 #include "config.h"
 #endif /* HAVE_CONFIG_H */
 
-#include <stdio.h>
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif /* HAVE_UNISTD_H */
-#include <sys/types.h>
-#include <sys/stat.h>
 #include <atalk/logger.h>
-
 #include <atalk/adouble.h>
 
 off_t ad_size(const struct adouble *ad, const u_int32_t eid)
index f5c4eee8aa27908a0edd9f05cf8bd6d9f0211534..d7bb789a8b23c1531168d9e794de107d829358eb 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: ad_write.c,v 1.7 2003-02-09 15:36:13 didg Exp $
+ * $Id: ad_write.c,v 1.8 2005-04-28 20:49:52 bfernhomberg Exp $
  *
  * Copyright (c) 1990,1995 Regents of The University of Michigan.
  * All Rights Reserved.  See COPYRIGHT.
@@ -94,27 +94,81 @@ ssize_t ad_write( ad, eid, off, end, buf, buflen )
 
 /* 
  * the caller set the locks
- * we need tocopy and paste from samba code source/smbd/vfs_wrap.c
  * ftruncate is undefined when the file length is smaller than 'size'
  */
+int sys_ftruncate(int fd, off_t length)
+{
+
+#ifndef  HAVE_PWRITE
+off_t           curpos;
+#endif
+int             err;
+struct stat    st;
+char            c = 0;
+
+    if (!ftruncate(fd, length)) {
+        return 0;
+    }
+    /* maybe ftruncate doesn't work if we try to extend the size */
+    err = errno;
+
+#ifndef  HAVE_PWRITE
+    /* we only care about file pointer if we don't use pwrite */
+    if ((off_t)-1 == (curpos = lseek(fd, 0, SEEK_CUR)) ) {
+        errno = err;
+        return -1;
+    }
+#endif
+
+    if ( fstat( fd, &st ) < 0 ) {
+        errno = err;
+        return -1;
+    }
+    
+    if (st.st_size > length) {
+        errno = err;
+        return -1;
+    }
+
+    if (lseek(fd, length -1, SEEK_SET) != length -1) {
+        errno = err;
+        return -1;
+    }
+
+    if (1 != write( fd, &c, 1 )) {
+        /* return the write errno */
+        return -1;
+    }
+
+#ifndef  HAVE_PWRITE
+    if (curpos != lseek(fd, curpos,  SEEK_SET)) {
+        errno = err;
+        return -1;
+    }
+#endif
+
+    return 0;    
+}
+
+/* ------------------------ */
 int ad_rtruncate( ad, size )
     struct adouble     *ad;
     const off_t        size;
 {
-    if ( ftruncate( ad->ad_hf.adf_fd,
+    if ( sys_ftruncate( ad->ad_hf.adf_fd,
            size + ad->ad_eid[ ADEID_RFORK ].ade_off ) < 0 ) {
-       return( -1 );
+       return -1;
     }
     ad->ad_rlen = size;    
 
-    return( 0 );
+    return 0;
 }
 
 int ad_dtruncate(ad, size)
     struct adouble     *ad;
     const off_t        size;
 {
-    if (ftruncate(ad->ad_df.adf_fd, size) < 0) {
+    if (sys_ftruncate(ad->ad_df.adf_fd, size) < 0) {
       return -1;
     }
     return 0;
index 00b1caedf9e451d20008c95042a09382df88df95..ffc53876d48f156836b750ff2a1f3c9057bc8ef0 100644 (file)
@@ -1,6 +1,6 @@
 # Makefile.am for libatalk/asp/
 
-INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/sys
+CFLAGS = -I$(top_srcdir) @CFLAGS@
 
 noinst_LTLIBRARIES = libasp.la
 
index 2ed1eda7231762e6f8bca4429114a78a7a2b6b10..3d04c5fdff0e66111478ee052358c20b52687df8 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: asp_getsess.c,v 1.7 2002-06-18 23:45:16 didg Exp $
+ * $Id: asp_getsess.c,v 1.8 2005-04-28 20:49:55 bfernhomberg Exp $
  *
  * Copyright (c) 1990,1996 Regents of The University of Michigan.
  * All Rights Reserved.  See COPYRIGHT.
 #define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
 #endif /* ! WIFEXITED */
 
+#ifndef MIN
+#define MIN(a,b)     ((a)<(b)?(a):(b))
+#endif /* ! MIN */
+
 static ASP server_asp;
 static struct server_child *children = NULL;
 static struct asp_child    **asp_ac = NULL;
@@ -99,6 +103,14 @@ void asp_kill(int sig)
     server_child_kill(children, CHILD_ASPFORK, sig);
 }
 
+void asp_stop_tickle(void)
+{
+    if (server_asp && server_asp->inited) {
+       static const struct itimerval timer = {{0, 0}, {0, 0}};
+       
+       setitimer(ITIMER_REAL, &timer, NULL);
+    }
+}
 
 /*
  * This call handles open, tickle, and getstatus requests. On a
@@ -111,21 +123,24 @@ static void set_asp_ac(int sid, struct asp_child *tmp);
 ASP asp_getsession(ASP asp, server_child *server_children, 
                   const int tickleval)
 {
-    struct sigaction action;
-    struct itimerval timer;
-    struct sockaddr_at sat;
-    struct atp_block   atpb;
+    struct sigaction    action;
+    struct itimerval    timer;
+    struct sockaddr_at  sat;
+    struct atp_block    atpb;
     ATP                 atp;
-    struct iovec       iov[ 8 ];
+    struct iovec        iov[ 8 ];
     pid_t               pid;
-    int                        i, sid;
-    u_int16_t          asperr;
+    int                 i, iovcnt, sid;
+    u_int16_t           asperr;
+    char                *buf;
+    int                 buflen;
 
     if (!asp->inited) {
       if (!(children = server_children))
        return NULL;
 
-      if ((asp_ac = (struct asp_child **) 
+      /* only calloc once */
+      if (!asp_ac && (asp_ac = (struct asp_child **) 
           calloc(server_children->nsessions, sizeof(struct asp_child *)))
           == NULL)
        return NULL;
@@ -135,10 +150,15 @@ ASP asp_getsession(ASP asp, server_child *server_children,
       /* install cleanup pointer */
       server_child_setup(children, CHILD_ASPFORK, child_cleanup);
 
-      /* install tickle handler */
+      /* install tickle handler 
+       * we are the parent process
+       */
       memset(&action, 0, sizeof(action));
       action.sa_handler = tickle_handler;
       sigemptyset(&action.sa_mask);
+      sigaddset(&action.sa_mask, SIGHUP);
+      sigaddset(&action.sa_mask, SIGTERM);
+      sigaddset(&action.sa_mask, SIGCHLD);
       action.sa_flags = SA_RESTART;
 
       timer.it_interval.tv_sec = timer.it_value.tv_sec = tickleval;
@@ -146,6 +166,8 @@ ASP asp_getsession(ASP asp, server_child *server_children,
       if ((sigaction(SIGALRM, &action, NULL) < 0) ||
          (setitimer(ITIMER_REAL, &timer, NULL) < 0)) {
        free(asp_ac);
+       server_asp = NULL;
+       asp_ac = NULL;
        return NULL;
       }
 
@@ -182,13 +204,45 @@ ASP asp_getsession(ASP asp, server_child *server_children,
       printf( "asp stat\n" );
 #endif /* EBUG */
       if ( asp->asp_slen > 0 ) {
-       asp->cmdbuf[0] = 0;
-       memcpy( asp->cmdbuf + 4, asp->asp_status, asp->asp_slen );
-       iov[ 0 ].iov_base = asp->cmdbuf;
-       iov[ 0 ].iov_len = 4 + asp->asp_slen;
-       atpb.atp_sresiov = iov;
-       atpb.atp_sresiovcnt = 1;
-       atp_sresp( asp->asp_atp, &atpb );
+        i = 0;
+        while(atpb.atp_bitmap) {
+            i++;
+            atpb.atp_bitmap >>= 1;
+        }
+
+       /* asp->data is big enough ... */
+        memcpy( asp->data, asp->asp_status, MIN(asp->asp_slen, i*ASP_CMDSIZ));
+       
+        buflen = MIN(asp->asp_slen, i*ASP_CMDSIZ);
+        buf = asp->data;
+        iovcnt = 0;
+
+        /* If status information is too big to fit into the available
+         * ASP packets, we simply send as much as we can.
+         * Older client versions will most likely not be able to use
+         * the additional information anyway, like directory services
+         * or UTF8 server name. A very long fqdn could be a problem,
+         * we could end up with an invalid address list.
+         */
+        do {
+            iov[ iovcnt ].iov_base = buf;
+            memmove(buf + ASP_HDRSIZ, buf, buflen);
+            memset( iov[ iovcnt ].iov_base, 0, ASP_HDRSIZ );
+
+           if ( buflen > ASP_CMDSIZ ) {
+                buf += ASP_CMDMAXSIZ;
+                buflen -= ASP_CMDSIZ;
+                iov[ iovcnt ].iov_len = ASP_CMDMAXSIZ;
+            } else {
+                iov[ iovcnt ].iov_len = buflen + ASP_HDRSIZ;
+                buflen = 0;
+            }
+            iovcnt++;
+        } while ( iovcnt < i && buflen > 0 );
+
+        atpb.atp_sresiovcnt = iovcnt;
+        atpb.atp_sresiov = iov;
+        atp_sresp( asp->asp_atp, &atpb );
       }
       break;
 
@@ -214,8 +268,7 @@ ASP asp_getsession(ASP asp, server_child *server_children,
 
        switch ((pid = fork())) {
        case 0 : /* child */
-         signal(SIGTERM, SIG_DFL);
-         signal(SIGHUP, SIG_DFL);
+         server_reset_signal();
          /* free/close some things */
          for (i = 0; i < children->nsessions; i++ ) {
            if ( asp_ac[i] != NULL )
index 60ab228113f4728932b29a35cf0e0c4d0e45659c..fe553b0d07901f40b0f3d1143af3a296d0e3fa1e 100644 (file)
@@ -1,7 +1,5 @@
 # Makefile.am for libatalk/atp/
 
-INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/sys
-
 noinst_LTLIBRARIES = libatp.la
 
 libatp_la_SOURCES = atp_bufs.c atp_close.c atp_open.c atp_packet.c atp_rreq.c atp_rresp.c atp_rsel.c atp_sreq.c atp_sresp.c 
index 57c5281e828ec7bbf5624ae1919ef617e940f218..7b13bf4e485378d030e63e0a6a07ade153439420 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: atp_sresp.c,v 1.4 2001-06-29 14:14:46 rufustfirefly Exp $
+ * $Id: atp_sresp.c,v 1.5 2005-04-28 20:49:56 bfernhomberg Exp $
  *
  * Copyright (c) 1990,1991 Regents of The University of Michigan.
  * All Rights Reserved.
@@ -53,7 +53,7 @@ int atp_sresp( ah, atpb )
     int                        i;
     u_int8_t           ctrlinfo;
     struct atpbuf      *resp_buf;
-    struct atpbuf      *save_buf;
+    struct atpbuf      *save_buf; /* uninitialized, OK 310105 */
 
 #ifdef EBUG
     atp_print_bufuse( ah, "atp_sresp" );
index d82fec3233d796aff58967dbfdf1616e2243f283..0d0371d7dcb7693bf0795a758a399976c7938892 100644 (file)
@@ -1,7 +1,6 @@
-Makefile.in
 Makefile
-.libs
-.deps
+Makefile.in
 *.lo
 *.la
-*.o
+.deps
+.libs
index 0fa235c17dfeccd334a3cef02972ded64ae26797..1cb310afbf178a3e7fe306d6b19d48acabe577be 100644 (file)
@@ -1,12 +1,20 @@
 # Makefile.am for libatalk/cnid/
 
-INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/sys @BDB_CFLAGS@
+
+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_la_LIBADD = @BDB_LIBS@
+LIBCNID_DEPS = db3/libcnid_db3.la \
+               cdb/libcnid_cdb.la \
+               last/libcnid_last.la \
+               mtab/libcnid_mtab.la \
+               hash/libcnid_hash.la \
+               tdb/libcnid_tdb.la \
+               dbd/libcnid_dbd.la 
+
+libcnid_la_SOURCES = cnid.c cnid_init.c
+libcnid_la_LIBADD = $(LIBCNID_DEPS)
 
-noinst_HEADERS = cnid_meta.h cnid_private.h 
+EXTRA_DIST = README
 
-EXTRA_DIST = README cnid_meta.c cnid_nextid.c
index b39889bfcea84934f0e1f38dc3b79a0d91be168e..b78f9af8a7de434e40f9031fea6a9609a1a2c372 100644 (file)
@@ -1,35 +1,50 @@
-the catalog database keeps track of three mappings:
-    CNID     -> dev/ino and did/name
-    dev/ino  -> CNID
-    did/name -> CNID
-
-dev/ino is used to keep track of magically moved files. did/name is
-for quick lookups of CNIDs. 
-
-NOTE: the database will append a nul byte to the end of name. in
-addition, name should be given as it appears on disk. this allows the
-creation of cnid updating/cleaning programs that don't have to deal
-with knowing what the particular codepage is.
-
-here's the ritual:
-       1) open a volume. call cnid_open.
-       2) every time you need a CNID, call cnid_add(). it will
-          automatically look for an existing cnid and add a new one
-          if one isn't already there. you can pass a hint if you
-          want. the only use this has right now is to enable
-          consistency between AFP and HFS. in the future, it would
-          allow people to write conversion utilities that
-          pre-instantiate a database without needing to re-assign
-          CNIDs.
-       3) if you want to just look for a CNID without automatically
-          adding one in, you have two choices:
-            a) cnid_resolve takes a CNID, returns name, and
-               over-writes the CNID given with the parent DID. this
-               is good for FPResolveID.
-             b) cnid_lookup returns a CNID corresponding to the
-               dev/ino,did/name keys. it will auto-update the catalog
-               database if there's a discrepancy. 
-               NOTE: cnid_add calls this before adding a new CNID. 
-       4) when you delete a file or directory, you need to call
-          cnid_delete with the CNID for that file/directory.
-       5) call cnid_close when closing the volume.
+  
+  CNID back-end refactoring
+  
+This patch allows to compile all DID schemes into 
+afpd  binary and then select desired schemes at runtime,
+per volume.
+
+
+Changes:
+
+Libatalk/cnid directory as been restructured. Now it contains
+subdirectories representing particular back-end types and a
+simple cnid-object factory (cnid.c and cnid_init.c).
+
+All CNID functions have been grouped into a structure which 
+contains function pointers and some data. Main afpd code uses
+them in a object manner rather than structural: it calls cnid 
+functions through fields of cnid_db structure. 
+
+Actually there are standard backends: transactional db3, cdb, 
+last and mtab (I'm not sure how to call mtab - it does some magic
+with dev/inode numbers, but mtab has been removed some time ago).
+
+Changes in ./configure options:
+
+Options --with-did=xxx, --with-cdb have been removed.
+
+Instead, there are following options:
+--with-cnid-cdb-backend    - compile DB3 Concurrent Datastore backend
+--with-cnid-db3-backend    - compile DB3 transactional backend
+--with-cnid-last-backend   - compile LAST backend
+--with-cnid-mtab-backend   - compile MTAB backend
+--with-cnid-default-backend={cdb|db3|last|mtab}
+
+Some of the backend names should be (propably) changed (mtab? db3?).
+
+AppleVolumes.default file has a new option: -cnidscheme:{db3|cdb|last|mtab}
+
+Again, sorry for this weird naming. I didn't care about it while coding,
+some cleanups have to be done later.
+
+Was tested mainly against test-suite and against MacOS 9 client.
+
+Things to do:
+- some really reliable kind of backend should be developed
+- file-name mangling should be runtime option
+- naming- and code cleanups are still needed
+- optional dynamic CNID backend loading - lower priority, static linking
+option has still to be available
+
diff --git a/libatalk/cnid/cdb/.cvsignore b/libatalk/cnid/cdb/.cvsignore
new file mode 100644 (file)
index 0000000..0d0371d
--- /dev/null
@@ -0,0 +1,6 @@
+Makefile
+Makefile.in
+*.lo
+*.la
+.deps
+.libs
diff --git a/libatalk/cnid/cdb/Makefile.am b/libatalk/cnid/cdb/Makefile.am
new file mode 100644 (file)
index 0000000..6a04a54
--- /dev/null
@@ -0,0 +1,27 @@
+# Makefile.am for libatalk/cnid/
+
+CFLAGS = @CFLAGS@ @BDB_CFLAGS@
+
+noinst_LTLIBRARIES = libcnid_cdb.la
+if USE_CDB_BACKEND
+LIBS_db = @BDB_LIBS@
+else
+LIBS_db = 
+endif
+
+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_rebuild_add.c \
+                        cnid_cdb.h
+
+noinst_HEADERS = cnid_cdb_meta.h cnid_cdb_private.h 
+
+libcnid_cdb_la_LIBADD = $(LIBS_db)
+
+EXTRA_DIST = README cnid_cdb_meta.c cnid_cdb_nextid.c
diff --git a/libatalk/cnid/cdb/README b/libatalk/cnid/cdb/README
new file mode 100644 (file)
index 0000000..b39889b
--- /dev/null
@@ -0,0 +1,35 @@
+the catalog database keeps track of three mappings:
+    CNID     -> dev/ino and did/name
+    dev/ino  -> CNID
+    did/name -> CNID
+
+dev/ino is used to keep track of magically moved files. did/name is
+for quick lookups of CNIDs. 
+
+NOTE: the database will append a nul byte to the end of name. in
+addition, name should be given as it appears on disk. this allows the
+creation of cnid updating/cleaning programs that don't have to deal
+with knowing what the particular codepage is.
+
+here's the ritual:
+       1) open a volume. call cnid_open.
+       2) every time you need a CNID, call cnid_add(). it will
+          automatically look for an existing cnid and add a new one
+          if one isn't already there. you can pass a hint if you
+          want. the only use this has right now is to enable
+          consistency between AFP and HFS. in the future, it would
+          allow people to write conversion utilities that
+          pre-instantiate a database without needing to re-assign
+          CNIDs.
+       3) if you want to just look for a CNID without automatically
+          adding one in, you have two choices:
+            a) cnid_resolve takes a CNID, returns name, and
+               over-writes the CNID given with the parent DID. this
+               is good for FPResolveID.
+             b) cnid_lookup returns a CNID corresponding to the
+               dev/ino,did/name keys. it will auto-update the catalog
+               database if there's a discrepancy. 
+               NOTE: cnid_add calls this before adding a new CNID. 
+       4) when you delete a file or directory, you need to call
+          cnid_delete with the CNID for that file/directory.
+       5) call cnid_close when closing the volume.
diff --git a/libatalk/cnid/cdb/cnid_cdb.h b/libatalk/cnid/cdb/cnid_cdb.h
new file mode 100644 (file)
index 0000000..1646ed2
--- /dev/null
@@ -0,0 +1,53 @@
+/* 
+ * 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,
+                           char *, const int, cnid_t));
+extern int cnid_cdb_getstamp __P((struct _cnid_db *, void *, const int ));
+
+/* cnid_get.c */
+extern cnid_t cnid_cdb_get __P((struct _cnid_db *, const cnid_t, 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,
+                              char *, const int));
+
+/* cnid_update.c */
+extern int cnid_cdb_update __P((struct _cnid_db *, const cnid_t, const struct stat *,
+                           const cnid_t, 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 *));
+
+extern cnid_t cnid_cdb_rebuild_add __P((struct _cnid_db *, const struct stat *,
+                const cnid_t, const char *, const int, cnid_t));
+
+
+#endif /* include/atalk/cnid_cdb.h */
+
diff --git a/libatalk/cnid/cdb/cnid_cdb_add.c b/libatalk/cnid/cdb/cnid_cdb_add.c
new file mode 100644 (file)
index 0000000..e5e28ab
--- /dev/null
@@ -0,0 +1,296 @@
+/*
+ * $Id: cnid_cdb_add.c,v 1.2 2005-04-28 20:49:59 bfernhomberg 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 "cnid_cdb_private.h"
+
+#define tid    NULL
+
+#ifdef ATACC
+static void make_devino_data(unsigned char *buf, dev_t dev, ino_t ino)
+{
+    buf[CNID_DEV_LEN - 1] = dev; dev >>= 8;
+    buf[CNID_DEV_LEN - 2] = dev; dev >>= 8;
+    buf[CNID_DEV_LEN - 3] = dev; dev >>= 8;
+    buf[CNID_DEV_LEN - 4] = dev; dev >>= 8;
+    buf[CNID_DEV_LEN - 5] = dev; dev >>= 8;
+    buf[CNID_DEV_LEN - 6] = dev; dev >>= 8;
+    buf[CNID_DEV_LEN - 7] = dev; dev >>= 8;
+    buf[CNID_DEV_LEN - 8] = dev;
+
+    buf[CNID_DEV_LEN + CNID_INO_LEN - 1] = ino; ino >>= 8;
+    buf[CNID_DEV_LEN + CNID_INO_LEN - 2] = ino; ino >>= 8;
+    buf[CNID_DEV_LEN + CNID_INO_LEN - 3] = ino; ino >>= 8;
+    buf[CNID_DEV_LEN + CNID_INO_LEN - 4] = ino; ino >>= 8;
+    buf[CNID_DEV_LEN + CNID_INO_LEN - 5] = ino; ino >>= 8;
+    buf[CNID_DEV_LEN + CNID_INO_LEN - 6] = ino; ino >>= 8;
+    buf[CNID_DEV_LEN + CNID_INO_LEN - 7] = ino; ino >>= 8;
+    buf[CNID_DEV_LEN + CNID_INO_LEN - 8] = ino;    
+}
+
+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;
+
+    make_devino_data(buf, st->st_dev, st->st_ino);
+    buf += CNID_DEVINO_LEN;
+
+    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, char *name, const int len);
+
+/* --------------- */
+int db_stamp(void *buffer, size_t size)
+{
+time_t t;
+    memset(buffer, 0, size);
+    /* return the current time. */
+    if (size < sizeof(time_t))
+        return -1;
+    t = time(NULL);
+    memcpy(buffer,&t, sizeof(time_t));
+    return 0;
+
+}
+
+
+/* ----------------------------- */
+static cnid_t get_cnid(CNID_private *db)
+{
+    DBT rootinfo_key, rootinfo_data;
+    DBC  *cursor;
+    int rc;
+    int flag, setstamp=0;
+    cnid_t hint,id;
+    char buf[ROOTINFO_DATALEN];
+    char stamp[CNID_DEV_LEN];
+     
+    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;
+       setstamp = 1;
+        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));
+    if (setstamp) {
+        if (db_stamp(stamp, CNID_DEV_LEN) < 0) {
+            goto cleanup;
+        }
+        memcpy((char *)rootinfo_data.data +CNID_DEV_OFS, stamp, sizeof(stamp));
+    }
+
+    
+    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, 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;
+}
+
+/* cnid_cbd_getstamp */
+/*-----------------------*/
+int cnid_cdb_getstamp(struct _cnid_db *cdb, void *buffer, const int len)
+{
+    DBT key, data;
+    int rc;
+    CNID_private *db;
+
+    if (!cdb || !(db = cdb->_private) || !buffer || !len) {
+        errno = CNID_ERR_PARAM;
+        return -1;
+    }
+
+    memset(buffer, 0, len);
+    memset(&key, 0, sizeof(key));
+    memset(&data, 0, sizeof(data));
+
+    key.data = ROOTINFO_KEY;
+    key.size = ROOTINFO_KEYLEN;
+
+    if (0 != (rc = db->db_cnid->get(db->db_cnid, NULL, &key, &data, 0 )) ) {
+        if (rc != DB_NOTFOUND) {
+            LOG(log_error, logtype_default, "cnid_lookup: Unable to get database stamp: %s",
+               db_strerror(rc));
+            errno = CNID_ERR_DB;
+            return -1;
+        }
+       /* we waste a single ID here... */
+        get_cnid(db);
+        memset(&key, 0, sizeof(key));
+        memset(&data, 0, sizeof(data));
+        key.data = ROOTINFO_KEY;
+        key.size = ROOTINFO_KEYLEN;
+       if (0 != (rc = db->db_cnid->get(db->db_cnid, NULL, &key, &data, 0 )) ) {
+           LOG(log_error, logtype_default, "cnid_getstamp: failed to get rootinfo: %s", 
+               db_strerror(rc));
+            errno = CNID_ERR_DB;
+           return -1;
+        }
+    }
+
+    memcpy(buffer, (char*)data.data + CNID_DEV_OFS, len);
+#ifdef DEBUG
+    LOG(log_info, logtype_cnid, "cnid_getstamp: Returning stamp");
+#endif
+   return 0;
+}
+
+
+#endif /* CNID_BACKEND_CDB */
diff --git a/libatalk/cnid/cdb/cnid_cdb_close.c b/libatalk/cnid/cdb/cnid_cdb_close.c
new file mode 100644 (file)
index 0000000..92f8ce6
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * $Id: cnid_cdb_close.c,v 1.2 2005-04-28 20:49:59 bfernhomberg Exp $
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#ifdef CNID_BACKEND_CDB
+#include "cnid_cdb_private.h"
+
+void cnid_cdb_close(struct _cnid_db *cdb) {
+    CNID_private *db;
+
+    if (!cdb) {
+           LOG(log_error, logtype_afpd, "cnid_close called with NULL argument !");
+           return;
+    }
+
+    if (!(db = cdb->_private)) {
+        return;
+    }
+    db->db_didname->sync(db->db_didname, 0); 
+    db->db_devino->sync(db->db_devino, 0);
+    db->db_cnid->sync(db->db_cnid, 0);
+    
+    db->db_didname->close(db->db_didname, 0);
+    db->db_devino->close(db->db_devino, 0);
+    db->db_cnid->close(db->db_cnid, 0);
+
+    db->dbenv->close(db->dbenv, 0);
+
+    free(db);
+    free(cdb->volpath);
+    free(cdb);
+}
+
+#endif /* CNID_BACKEND_CDB */
diff --git a/libatalk/cnid/cdb/cnid_cdb_delete.c b/libatalk/cnid/cdb/cnid_cdb_delete.c
new file mode 100644 (file)
index 0000000..901b623
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * $Id: cnid_cdb_delete.c,v 1.2 2005-04-28 20:49:59 bfernhomberg 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 "cnid_cdb_private.h"
+
+#define tid    NULL
+
+int cnid_cdb_delete(struct _cnid_db *cdb, const cnid_t id) {
+    CNID_private *db;
+    DBT key;
+    int rc;
+
+    if (!cdb || !(db = cdb->_private) || !id || (db->flags & CNIDFLAG_DB_RO)) {
+        return -1;
+    }
+
+    memset(&key, 0, sizeof(key));
+
+    /* Get from ain CNID database. */
+    key.data = (cnid_t *)&id;
+    key.size = sizeof(id);
+    
+    if ((rc = db->db_cnid->del(db->db_cnid, tid, &key, 0))) {
+        LOG(log_error, logtype_default, "cnid_delete: Unable to delete CNID %u: %s",
+            ntohl(id), db_strerror(rc));
+    }
+    else {
+#ifdef DEBUG
+        LOG(log_info, logtype_default, "cnid_delete: Deleting CNID %u", ntohl(id));
+#endif
+    }
+    return rc;
+}
+
+#endif /* CNID_BACKEND_CDB */
diff --git a/libatalk/cnid/cdb/cnid_cdb_get.c b/libatalk/cnid/cdb/cnid_cdb_get.c
new file mode 100644 (file)
index 0000000..76cec48
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * $Id: cnid_cdb_get.c,v 1.2 2005-04-28 20:49:59 bfernhomberg Exp $
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#ifdef CNID_BACKEND_CDB
+#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, char *name,
+                const int len)
+{
+    char start[CNID_DID_LEN + MAXPATHLEN + 1], *buf;
+    CNID_private *db;
+    DBT key, data;
+    cnid_t id;
+    int rc;
+
+    if (!cdb || !(db = cdb->_private) || (len > MAXPATHLEN)) {
+        return 0;
+    }
+
+    memset(&key, 0, sizeof(key));
+    memset(&data, 0, sizeof(data));
+
+    buf = start;
+    memcpy(buf, &did, sizeof(did));
+    buf += sizeof(did);
+    memcpy(buf, name, len);
+    *(buf + len) = '\0'; /* Make it a C-string. */
+    key.data = start;
+    key.size = CNID_DID_LEN + len + 1;
+
+    while ((rc = db->db_didname->get(db->db_didname, NULL, &key, &data, 0))) {
+
+        if (rc != DB_NOTFOUND) {
+            LOG(log_error, logtype_default, "cnid_get: Unable to get CNID %u, name %s: %s",
+                ntohl(did), name, db_strerror(rc));
+        }
+
+        return 0;
+    }
+
+    memcpy(&id, data.data, sizeof(id));
+#ifdef DEBUG
+    LOG(log_info, logtype_default, "cnid_get: Returning CNID for %u, name %s as %u",
+        ntohl(did), name, ntohl(id));
+#endif
+    return id;
+}
+
+#endif /* CNID_BACKEND_CDB */
diff --git a/libatalk/cnid/cdb/cnid_cdb_lookup.c b/libatalk/cnid/cdb/cnid_cdb_lookup.c
new file mode 100644 (file)
index 0000000..a8d49f0
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+ * $Id: cnid_cdb_lookup.c,v 1.2 2005-04-28 20:49:59 bfernhomberg Exp $
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#ifdef CNID_BACKEND_CDB
+#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,
+                   char *name, const int len)
+{
+    char *buf;
+    CNID_private *db;
+    DBT key, devdata, diddata;
+    char dev[CNID_DEV_LEN];
+    char ino[CNID_INO_LEN];  
+    int devino = 1, didname = 1; 
+    u_int32_t type_devino  = (unsigned)-1;
+    u_int32_t type_didname = (unsigned)-1;
+    u_int32_t type;
+    int update = 0;
+    cnid_t id_devino, id_didname,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;
+    }
+
+    memcpy(&type, buf +CNID_TYPE_OFS, sizeof(type));
+    type = ntohl(type);
+
+    memset(&key, 0, sizeof(key));
+    memset(&diddata, 0, sizeof(diddata));
+    memset(&devdata, 0, sizeof(devdata));
+
+    /* Look for a CNID for our did/name */
+    key.data = buf +CNID_DEVINO_OFS;
+    key.size = CNID_DEVINO_LEN;
+
+    memcpy(dev, buf + CNID_DEV_OFS, CNID_DEV_LEN);
+    memcpy(ino, buf + CNID_INO_OFS, CNID_INO_LEN);
+    
+    if (0 != (rc = db->db_didname->get(db->db_devino, NULL, &key, &devdata, 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;
+        }
+        devino = 0;
+    }
+    else {
+        memcpy(&id_devino, devdata.data, sizeof(cnid_t));
+        memcpy(&type_devino, (char *)devdata.data +CNID_TYPE_OFS, sizeof(type_devino));
+        type_devino = ntohl(type_devino);
+    }
+
+    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->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;
+        }
+        didname = 0;
+    }
+    else {
+        memcpy(&id_didname, diddata.data, sizeof(cnid_t));
+        memcpy(&type_didname, (char *)diddata.data +CNID_TYPE_OFS, sizeof(type_didname));
+        type_didname = ntohl(type_didname);
+    }
+
+    if (!devino && !didname) {  
+        return 0;
+    }
+
+    if (devino && didname && id_devino == id_didname && type_devino == type) {
+        /* the same */
+        return id_didname;
+    }
+    if (didname) {
+        id = 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, CNID_DEV_LEN) ||
+                   type_didname != type) {
+            if (cnid_cdb_delete(cdb, id) < 0) {
+                return 0;
+            }
+        }
+        else {
+            update = 1;
+        }
+    }
+
+    if (devino) {
+        id = id_devino;
+        if (type_devino != 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 (cnid_cdb_delete(cdb, id) < 0) {
+                return 0;
+            }
+        }
+        else {
+            update = 1;
+        }
+    }
+    if (!update) {
+        return 0;
+    }
+    /* Fix up the database. assume it was a file move and rename */
+    cnid_cdb_update(cdb, id, st, did, name, len);
+
+#ifdef DEBUG
+    LOG(log_info, logtype_default, "cnid_lookup: Looked up did %u, name %s, as %u (needed update)", ntohl(did), name, ntohl(id));
+#endif
+    return id;
+}
+
+#endif /* CNID_BACKEND_CDB */
diff --git a/libatalk/cnid/cdb/cnid_cdb_meta.c b/libatalk/cnid/cdb/cnid_cdb_meta.c
new file mode 100644 (file)
index 0000000..9184264
--- /dev/null
@@ -0,0 +1,9 @@
+/*
+ * $Id: cnid_cdb_meta.c,v 1.2 2005-04-28 20:49:59 bfernhomberg Exp $
+ *
+ * Copyright (c) 1999. Adrian Sun (asun@zoology.washington.edu)
+ * All Rights Reserved. See COPYRIGHT.
+ *
+ * deal with metadata
+ *
+ */
diff --git a/libatalk/cnid/cdb/cnid_cdb_meta.h b/libatalk/cnid/cdb/cnid_cdb_meta.h
new file mode 100644 (file)
index 0000000..cf9d905
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * $Id: cnid_cdb_meta.h,v 1.2 2005-04-28 20:49:59 bfernhomberg Exp $
+ */
+
+#define CNID_META_CNID_LEN      4
+#define CNID_META_MDATE_LEN     4  /* space for 8 */
+#define CNID_META_CDATE_LEN     4  /* space for 8 */
+#define CNID_META_BDATE_LEN     4  /* ditto */
+#define CNID_META_ADATE_LEN     4  /* ditto */
+#define CNID_META_AFPI_LEN      4  /* plus permission bits */
+#define CNID_META_FINDERI_LEN   32 
+#define CNID_META_PRODOSI_LEN   8
+#define CNID_META_RFORKLEN_LEN  4  /* space for 8 */
+#define CNID_META_MACNAME_LEN   32 /* maximum size */
+#define CNID_META_SHORTNAME_LEN 12 /* max size (8.3) */
+#define CNID_META_FILLER_LEN    4
+
+#define CNID_META_CNID_OFF     0
+#define CNID_META_MDATE_OFF    (CNID_META_CNID_OFF + CNID_META_CNID_LEN + \
+                               CNID_META_FILLER_LEN)
+#define CNID_META_CDATE_OFF    (CNID_META_MDATE_OFF + CNID_META_MDATE_LEN + \
+                               CNID_META_FILLER_LEN)
+#define CNID_META_BDATE_OFF    (CNID_META_CDATE_OFF + CNID_META_CDATE_LEN + \
+                               CNID_META_FILLER_LEN)
+#define CNID_META_ADATE_OFF    (CNID_META_BDATE_OFF + CNID_META_BDATE_LEN + \
+                               CNID_META_FILLER_LEN)
+#define CNID_META_AFPI_OFF     (CNID_META_ADATE_OFF + CNID_META_ADATE_LEN)
+#define CNID_META_FINDERI_OFF  (CNID_META_AFPI_OFF + CNID_META_AFPI_LEN)
+#define CNID_META_PRODOSI_OFF  (CNID_META_FINDERI_OFF + CNID_META_FINDERI_LEN)
+#define CNID_META_RFORKLEN_OFF (CNID_META_PRODOSI_OFF + CNID_META_PRODOSI_LEN)
+#define CNID_META_MACNAME_OFF  (CNID_META_RFORKLEN_OFF + \
+                               CNID_META_RFORKLEN_LEN)
+#define CNID_META_SHORTNAME_OFF (CNID_META_MACNAME_OFF + 
+
+
+#define cnid_meta_clear(a)  
+#define cnid_meta_get(id)
+
+#define cnid_meta_cnid(a)  
+#define cnid_meta_modifydate(a)
+#define cnid_meta_createdate(a)
+#define cnid_meta_backupdate(a)
+#define cnid_meta_accessdate(a)
+#define cnid_meta_afpi(a)
+#define cnid_meta_finderi(a)
+#define cnid_meta_prodosi(a)
+#define cnid_meta_rforklen(a)
+#define cnid_meta_macname(a)
+#define cnid_meta_shortname(a)
+#define cnid_meta_longname(a)
+
diff --git a/libatalk/cnid/cdb/cnid_cdb_nextid.c b/libatalk/cnid/cdb/cnid_cdb_nextid.c
new file mode 100644 (file)
index 0000000..60141c3
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * $Id: cnid_cdb_nextid.c,v 1.2 2005-04-28 20:49:59 bfernhomberg Exp $
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#ifdef CNID_BACKEND_CDB
+
+#ifdef unused
+#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 */
diff --git a/libatalk/cnid/cdb/cnid_cdb_open.c b/libatalk/cnid/cdb/cnid_cdb_open.c
new file mode 100644 (file)
index 0000000..f645574
--- /dev/null
@@ -0,0 +1,436 @@
+
+/*
+ * $Id: cnid_cdb_open.c,v 1.2 2005-04-28 20:49:59 bfernhomberg 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 "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. */
+
+static char *old_dbfiles[] = {"cnid.db", NULL};
+
+/* -----------------------
+ * 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 _U_;
+const DBT *pkey _U_, *pdata;
+DBT *skey;
+{
+int len;
+    memset(skey, 0, sizeof(DBT));
+    skey->data = (char *)pdata->data + CNID_DID_OFS;
+    len = strlen((char *)skey->data + CNID_DID_LEN);
+    skey->size = CNID_DID_LEN + len + 1;
+    return (0);
+}
+/* --------------- */
+static int devino(dbp, pkey, pdata, skey)
+DB *dbp _U_;
+const DBT *pkey _U_, *pdata;
+DBT *skey;
+{
+    memset(skey, 0, sizeof(DBT));
+    skey->data = (char *)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
+#if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR == 0)
+    return p->associate(p,       s, callback, flags);
+#else
+    return 0; /* FIXME */
+#endif
+#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;
+    int major, minor, patch;
+    char *version_str;
+
+    version_str = db_version(&major, &minor, &patch);
+
+    /* check library match, ignore if only patch level changed */
+    if ( major != DB_VERSION_MAJOR || minor != DB_VERSION_MINOR)
+    {
+        LOG(log_error, logtype_cnid, "cnid_cdb_new: the Berkeley DB library version used does not match the version compiled with: (%u.%u)/(%u.%u)", DB_VERSION_MAJOR, DB_VERSION_MINOR, major, minor); 
+       return NULL;
+    }
+
+    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;
+    cdb->cnid_getstamp = cnid_cdb_getstamp;
+    cdb->cnid_rebuild_add = cnid_cdb_rebuild_add;
+
+    return cdb;
+}
+
+/* --------------- */
+static int upgrade_required(char *dbdir)
+{
+    char path[MAXPATHLEN + 1];
+    int len, i;
+    int found = 0;
+    struct stat st;
+    
+    strcpy(path, dbdir);
+
+    len = strlen(path);
+    if (path[len - 1] != '/') {
+        strcat(path, "/");
+        len++;
+    }
+    
+    for (i = 0; old_dbfiles[i] != NULL; i++) {
+       strcpy(path + len, old_dbfiles[i]);
+       if ( !(stat(path, &st) < 0) ) {
+           found++;
+           continue;
+       }
+       if (errno != ENOENT) {
+           LOG(log_error, logtype_default, "cnid_open: Checking %s gave %s", path, strerror(errno));
+           found++;
+       }
+    }
+    return found;
+}
+
+/* --------------- */
+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.
+       We need space for dir + '/' + DBHOMELEN + '/' + DBLEN */
+    if ((len = strlen(dir)) > (MAXPATHLEN - DBHOMELEN - DBLEN - 2)) {
+        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;
+    }
+
+    if (upgrade_required(path)) {
+       LOG(log_error, logtype_default, "cnid_open: Found version 1 of the CNID database. Please upgrade to version 2");
+       goto fail_adouble;
+    }
+
+    /* 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));
+    }
+
+    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) {
+       LOG(log_error, logtype_default, "cnid_open: dbenv->open (rw) of %s failed: %s", path, db_strerror(rc));
+       /* FIXME: This should probably go. Even if it worked, any use for a read-only DB? Didier? */
+        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_BTREE, 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_BTREE, 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_BTREE, 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 */
+
+    db_env_set_func_yield(my_yield);
+    return cdb;
+
+  fail_appinit:
+    if (db->db_didname)
+        db->db_didname->close(db->db_didname, 0);
+    if (db->db_devino)
+        db->db_devino->close(db->db_devino, 0);
+    if (db->db_cnid)
+        db->db_cnid->close(db->db_cnid, 0);
+    LOG(log_error, logtype_default, "cnid_open: Failed to setup CNID DB environment");
+    db->dbenv->close(db->dbenv, 0);
+
+  fail_lock:
+
+  fail_adouble:
+
+    free(db);
+
+  fail_cdb:
+    if (cdb->volpath != NULL)
+        free(cdb->volpath);
+    free(cdb);
+
+    return NULL;
+}
+
+struct _cnid_module cnid_cdb_module = {
+    "cdb",
+    {NULL, NULL},
+    cnid_cdb_open,
+    CNID_FLAG_SETUID | CNID_FLAG_BLOCK
+};
+
+
+#endif /* CNID_BACKEND_CDB */
diff --git a/libatalk/cnid/cdb/cnid_cdb_private.h b/libatalk/cnid/cdb/cnid_cdb_private.h
new file mode 100644 (file)
index 0000000..d349122
--- /dev/null
@@ -0,0 +1,231 @@
+/*
+ * $Id: cnid_cdb_private.h,v 1.2 2005-04-28 20:49:59 bfernhomberg Exp $
+ */
+
+#ifndef LIBATALK_CDB_PRIVATE_H
+#define LIBATALK_CDB_PRIVATE_H 1
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include <netatalk/endian.h>
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif /* HAVE_FCNTL_H */
+#include <sys/param.h>
+#include <sys/stat.h>
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif /* HAVE_SYS_TIME_H */
+#ifdef HAVE_TIME_H
+#include <time.h>
+#endif
+#include <sys/cdefs.h>
+#include <db.h>
+
+#include <atalk/logger.h>
+#include <atalk/adouble.h>
+#include <atalk/cnid.h>
+#include <atalk/util.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
+
+/*                         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 void make_devino_data(unsigned char *buf, dev_t dev, ino_t ino)
+{
+    buf[CNID_DEV_LEN - 1] = dev; dev >>= 8;
+    buf[CNID_DEV_LEN - 2] = dev; dev >>= 8;
+    buf[CNID_DEV_LEN - 3] = dev; dev >>= 8;
+    buf[CNID_DEV_LEN - 4] = dev; dev >>= 8;
+    buf[CNID_DEV_LEN - 5] = dev; dev >>= 8;
+    buf[CNID_DEV_LEN - 6] = dev; dev >>= 8;
+    buf[CNID_DEV_LEN - 7] = dev; dev >>= 8;
+    buf[CNID_DEV_LEN - 8] = dev;
+
+    buf[CNID_DEV_LEN + CNID_INO_LEN - 1] = ino; ino >>= 8;
+    buf[CNID_DEV_LEN + CNID_INO_LEN - 2] = ino; ino >>= 8;
+    buf[CNID_DEV_LEN + CNID_INO_LEN - 3] = ino; ino >>= 8;
+    buf[CNID_DEV_LEN + CNID_INO_LEN - 4] = ino; ino >>= 8;
+    buf[CNID_DEV_LEN + CNID_INO_LEN - 5] = ino; ino >>= 8;
+    buf[CNID_DEV_LEN + CNID_INO_LEN - 6] = ino; ino >>= 8;
+    buf[CNID_DEV_LEN + CNID_INO_LEN - 7] = ino; ino >>= 8;
+    buf[CNID_DEV_LEN + CNID_INO_LEN - 8] = ino;    
+}
+
+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;
+
+    make_devino_data(buf, st->st_dev, st->st_ino);
+    buf += CNID_DEVINO_LEN;
+
+    i = S_ISDIR(st->st_mode)?1:0;
+    i = htonl(i);
+    memcpy(buf, &i, sizeof(i));
+    buf += sizeof(i);
+    
+    /* did is already in network byte order */
+    memcpy(buf, &did, sizeof(did));
+    buf += sizeof(did);
+
+    memcpy(buf, name, len);
+    *(buf + len) = '\0';
+
+    return start;
+}
+#else
+extern char *make_cnid_data __P((const struct stat *,const cnid_t ,
+                                       const char *, const int ));
+#endif
+
+#endif /* atalk/cnid/cnid_private.h */
diff --git a/libatalk/cnid/cdb/cnid_cdb_rebuild_add.c b/libatalk/cnid/cdb/cnid_cdb_rebuild_add.c
new file mode 100644 (file)
index 0000000..7ea872e
--- /dev/null
@@ -0,0 +1,179 @@
+/*
+ * $Id: cnid_cdb_rebuild_add.c,v 1.2 2005-04-28 20:49:59 bfernhomberg Exp $
+ *
+ * All Rights Reserved. See COPYRIGHT.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#ifdef CNID_BACKEND_CDB
+#include "cnid_cdb_private.h"
+
+#define tid    NULL
+#define DEBUG 1
+
+#include "cnid_cdb.h"
+
+#ifdef ATACC
+/* FIXME: Enhance for 8 byte dev/inode */
+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
+
+
+/* ----------------------------- */
+static cnid_t set_max_cnid(CNID_private *db, cnid_t hint)
+{
+    DBT rootinfo_key, rootinfo_data;
+    int rc;
+    char buf[ROOTINFO_DATALEN];
+    cnid_t id, id1;
+    time_t t;
+    
+    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 = db->db_cnid->get(db->db_cnid, tid, &rootinfo_key, &rootinfo_data, 0))) {
+    case 0:
+       memcpy(buf, (char *)rootinfo_data.data, ROOTINFO_DATALEN);
+        break;
+    case DB_NOTFOUND:
+       /* FIXME: This duplicates stuff from cnid_cdb_add.c. 
+          We also implicitely assume that sizeof(time_t) <= CNID_DEV_LEN */
+       memcpy(buf, ROOTINFO_DATA, ROOTINFO_DATALEN);
+       t = time(NULL);
+       memset(buf + CNID_DEV_OFS, 0, CNID_DEV_LEN);
+       memcpy(buf + CNID_DEV_OFS, &t, sizeof(time_t));
+        id = htonl(CNID_START);
+       memcpy(buf + CNID_TYPE_OFS, &id, sizeof(id));
+       break;
+    default:
+        LOG(log_error, logtype_default, "set_max_cnid: Unable to read rootinfo: %s", db_strerror(rc));
+       errno = CNID_ERR_DB; 
+        goto cleanup;
+    }
+
+    memcpy(&id, buf + CNID_TYPE_OFS, sizeof(id));
+    id = ntohl(id);
+    id1 = ntohl(hint);
+
+    if (id1 > id) {
+       memcpy(buf + CNID_TYPE_OFS, &hint, sizeof(hint));
+       rootinfo_data.data = buf;
+       rootinfo_data.size = ROOTINFO_DATALEN;
+       if ((rc = db->db_cnid->put(db->db_cnid, tid, &rootinfo_key, &rootinfo_data, 0))) {
+           LOG(log_error, logtype_default, "set_max_cnid: Unable to write rootinfo: %s", db_strerror(rc));
+           errno = CNID_ERR_DB; 
+           goto cleanup;
+       }
+    }
+
+    return hint;
+
+cleanup:
+    return CNID_INVALID;
+}
+
+/* ------------------------ */
+cnid_t cnid_cdb_rebuild_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;
+    int rc;
+
+    if (!cdb || !(db = cdb->_private) || !st || !name || hint == CNID_INVALID || hint < CNID_START) {
+        errno = CNID_ERR_PARAM;
+        return CNID_INVALID;
+    }
+
+#if 0
+    /* FIXME: Bjoern does a lookup. Should we not overwrite unconditionally? */
+    /* 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;
+    }
+#endif
+
+    /* 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;
+    
+    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, 0))) {
+            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;
+           goto cleanup;
+    }
+
+    if (set_max_cnid(db, hint) == CNID_INVALID) {
+           errno = CNID_ERR_DB;
+           goto cleanup;
+    }
+
+#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;
+
+cleanup:
+    return CNID_INVALID;
+}
+
+#endif /* CNID_BACKEND_CDB */
diff --git a/libatalk/cnid/cdb/cnid_cdb_resolve.c b/libatalk/cnid/cdb/cnid_cdb_resolve.c
new file mode 100644 (file)
index 0000000..3441f3b
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * $Id: cnid_cdb_resolve.c,v 1.2 2005-04-28 20:49:59 bfernhomberg Exp $
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#ifdef CNID_BACKEND_CDB
+#include "cnid_cdb_private.h"
+
+/* Return the did/name pair corresponding to a CNID. */
+char *cnid_cdb_resolve(struct _cnid_db *cdb, cnid_t *id, void *buffer, u_int32_t len) {
+    CNID_private *db;
+    DBT key, data;
+    int rc;
+
+    if (!cdb || !(db = cdb->_private) || !id || !(*id)) {
+        return NULL;
+    }
+
+    memset(&key, 0, sizeof(key));
+    memset(&data, 0, sizeof(data));
+
+    data.data = buffer;
+    data.ulen = len;
+    data.flags = DB_DBT_USERMEM;
+
+    key.data = id;
+    key.size = sizeof(cnid_t);
+    while ((rc = db->db_cnid->get(db->db_cnid, NULL, &key, &data, 0))) {
+
+        if (rc != DB_NOTFOUND) {
+            LOG(log_error, logtype_default, "cnid_resolve: Unable to get did/name: %s",
+                db_strerror(rc));
+        }
+
+        *id = 0;
+        return NULL;
+    }
+
+    memcpy(id, (char *)data.data +CNID_DID_OFS, sizeof(cnid_t));
+#ifdef DEBUG
+    LOG(log_info, logtype_default, "cnid_resolve: Returning id = %u, did/name = %s",
+        ntohl(*id), (char *)data.data + CNID_NAME_OFS);
+#endif
+    return (char *)data.data +  CNID_NAME_OFS;
+}
+
+#endif
diff --git a/libatalk/cnid/cdb/cnid_cdb_update.c b/libatalk/cnid/cdb/cnid_cdb_update.c
new file mode 100644 (file)
index 0000000..80e08b7
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * $Id: cnid_cdb_update.c,v 1.2 2005-04-28 20:49:59 bfernhomberg Exp $
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#ifdef CNID_BACKEND_CDB
+#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, char *name, const int len
+                /*, const char *info, const int infolen*/)
+{
+    char *buf;
+    CNID_private *db;
+    DBT key, pkey, data;
+    int rc;
+    int notfound = 0;
+    char getbuf[CNID_HEADER_LEN + MAXPATHLEN +1];
+
+    if (!cdb || !(db = cdb->_private) || !id || !st || !name || (db->flags & CNIDFLAG_DB_RO)) {
+        return -1;
+    }
+
+    memset(&key, 0, sizeof(key));
+    memset(&pkey, 0, sizeof(pkey));
+    memset(&data, 0, sizeof(data));
+
+    buf = make_cnid_data(st, did, name, len);
+
+    key.data = buf +CNID_DEVINO_OFS;
+    key.size = CNID_DEVINO_LEN;
+    data.data = getbuf;
+    data.size = CNID_HEADER_LEN + MAXPATHLEN + 1;
+
+    if (0 != (rc = db->db_devino->pget(db->db_devino, tid, &key, &pkey, &data, 0)) ) {
+#if DB_VERSION_MAJOR >= 4
+        if (rc != DB_NOTFOUND && rc != DB_SECONDARY_BAD) {
+#else
+       if (rc != DB_NOTFOUND) {
+#endif
+           LOG(log_error, logtype_default, "cnid_update: Unable to get devino CNID %u, name %s: %s",
+               ntohl(did), name, db_strerror(rc));
+           goto fin;
+        }
+        notfound = 1;
+    } else {
+        if ((rc = db->db_cnid->del(db->db_cnid, tid, &pkey, 0))) {
+            LOG(log_error, logtype_default, "cnid_update: Unable to delete CNID %u: %s",
+                ntohl(id), db_strerror(rc));
+       }
+    }
+
+    memset(&pkey, 0, sizeof(pkey));
+    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->pget(db->db_didname, tid, &key, &pkey, &data, 0)) ) {
+#if DB_VERSION_MAJOR >= 4
+        if (rc != DB_NOTFOUND && rc != DB_SECONDARY_BAD) {
+#else
+       if (rc != DB_NOTFOUND) {
+#endif
+           LOG(log_error, logtype_default, "cnid_update: Unable to get didname CNID %u, name %s: %s",
+               ntohl(did), name, db_strerror(rc));
+           goto fin;
+        }
+        notfound |= 2;
+    } else {
+        if ((rc = db->db_cnid->del(db->db_cnid, tid, &pkey, 0))) {
+            LOG(log_error, logtype_default, "cnid_update: Unable to delete CNID %u: %s",
+                ntohl(id), db_strerror(rc));
+       }
+    }
+
+
+    memset(&key, 0, sizeof(key));
+    key.data = (cnid_t *)&id;
+    key.size = sizeof(id);
+
+    memset(&data, 0, sizeof(data));
+    /* Make a new entry. */
+    buf = make_cnid_data(st, did, name, len);
+    data.data = buf;
+    memcpy(data.data, &id, sizeof(id));
+    data.size = CNID_HEADER_LEN + len + 1;
+
+    /* Update the old CNID with the new info. */
+    if ((rc = db->db_cnid->put(db->db_cnid, tid, &key, &data, 0))) {
+        LOG(log_error, logtype_default, "cnid_update: (%d) Unable to update CNID %u:%s: %s",
+            notfound, ntohl(id), name, db_strerror(rc));
+        goto fin;
+    }
+
+    return 0;
+fin:
+    return -1;
+}
+
+#endif
diff --git a/libatalk/cnid/cnid.c b/libatalk/cnid/cnid.c
new file mode 100644 (file)
index 0000000..4e5f088
--- /dev/null
@@ -0,0 +1,298 @@
+/* 
+ * $Id: cnid.c,v 1.2 2005-04-28 20:49:57 bfernhomberg 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 <sys/param.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <signal.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <atalk/cnid.h>
+#include <atalk/list.h>
+#include <atalk/logger.h>
+#include <atalk/util.h>
+
+/* List of all registered modules. */
+static struct list_head modules = ATALK_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, st1; 
+   char tmp[MAXPATHLEN];
+
+   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 {
+       strlcpy(tmp, dir, sizeof(tmp));
+       strlcat(tmp, "/.AppleDB", sizeof(tmp));
+       if (stat(tmp, &st1) < 0) /* use .AppleDB owner, if folder already exists */
+           st1 = st; 
+       LOG(log_info, logtype_cnid, "Setting uid/gid to %d/%d", st1.st_uid, st1.st_gid);
+       if (setegid(st1.st_gid) < 0 || seteuid(st1.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, int flags)
+{
+    struct _cnid_db *db;
+    cnid_module *mod = NULL;
+    struct list_head *ptr;
+    uid_t uid;  /* uninitialized, OK 310105 */
+    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(EXITERR_SYS);
+            }
+            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(EXITERR_SYS);
+        }
+    }
+
+    if (NULL == db) {
+        LOG(log_error, logtype_afpd, "Cannot open CNID db at [%s].", volpath);
+        return NULL;
+    }
+    /* FIXME should module know about it ? */
+    if (flags) {
+        db->flags |= CNID_FLAG_NODEV;
+    }
+    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( u_int32_t flags)
+{
+    if ((flags & CNID_FLAG_BLOCK)) {
+        sigprocmask(SIG_BLOCK, &sigblockset, NULL);
+        setitimer(ITIMER_REAL, &none, &savetimer);
+    }
+}
+
+/* ------------------- */
+static void unblock_signal(u_int32_t flags)
+{
+    if ((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)
+{
+u_int32_t flags;
+
+    if (NULL == db) {
+        LOG(log_error, logtype_afpd, "Error: cnid_close called with NULL argument !");
+        return;
+    }
+    /* cnid_close free db */
+    flags = db->flags;
+    block_signal(flags);
+    db->cnid_close(db);
+    unblock_signal(flags);
+}
+
+/* --------------- */
+cnid_t cnid_add(struct _cnid_db *cdb, const struct stat *st, const cnid_t did, 
+                       char *name, const int len, cnid_t hint)
+{
+cnid_t ret;
+
+    block_signal(cdb->flags);
+    ret = cdb->cnid_add(cdb, st, did, name, len, hint);
+    unblock_signal(cdb->flags);
+    return ret;
+}
+
+/* --------------- */
+int cnid_delete(struct _cnid_db *cdb, cnid_t id)
+{
+int ret;
+
+    block_signal(cdb->flags);
+    ret = cdb->cnid_delete(cdb, id);
+    unblock_signal(cdb->flags);
+    return ret;
+}
+
+
+/* --------------- */
+cnid_t cnid_get(struct _cnid_db *cdb, const cnid_t did, char *name,const int len)
+{
+cnid_t ret;
+
+    block_signal(cdb->flags);
+    ret = cdb->cnid_get(cdb, did, name, len);
+    unblock_signal(cdb->flags);
+    return ret;
+}
+
+/* --------------- */
+int cnid_getstamp(struct _cnid_db *cdb,  void *buffer, const int len)
+{
+cnid_t ret;
+time_t t;
+
+    if (!cdb->cnid_getstamp) {
+        memset(buffer, 0, len);
+       /* return the current time. it will invalide cache */
+       if (len < sizeof(time_t))
+           return -1;
+       t = time(NULL);
+       memcpy(buffer, &t, sizeof(time_t));
+        return 0;
+    }
+    block_signal(cdb->flags);
+    ret = cdb->cnid_getstamp(cdb, buffer, len);
+    unblock_signal(cdb->flags);
+    return ret;
+}
+
+/* --------------- */
+cnid_t cnid_lookup(struct _cnid_db *cdb, const struct stat *st, const cnid_t did,
+                       char *name, const int len)
+{
+cnid_t ret;
+
+    block_signal(cdb->flags);
+    ret = cdb->cnid_lookup(cdb, st, did, name, len);
+    unblock_signal(cdb->flags);
+    return ret;
+}
+
+/* --------------- */
+char *cnid_resolve(struct _cnid_db *cdb, cnid_t *id, void *buffer, u_int32_t len)
+{
+char *ret;
+
+    block_signal(cdb->flags);
+    ret = cdb->cnid_resolve(cdb, id, buffer, len);
+    unblock_signal(cdb->flags);
+    return ret;
+}
+
+/* --------------- */
+int cnid_update   (struct _cnid_db *cdb, const cnid_t id, const struct stat *st, 
+                       const cnid_t did, char *name, const int len)
+{
+int ret;
+
+    block_signal(cdb->flags);
+    ret = cdb->cnid_update(cdb, id, st, did, name, len);
+    unblock_signal(cdb->flags);
+    return ret;
+}
+                       
+/* --------------- */
+cnid_t cnid_rebuild_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->flags);
+    ret = cdb->cnid_rebuild_add(cdb, st, did, name, len, hint);
+    unblock_signal(cdb->flags);
+    return ret;
+}
diff --git a/libatalk/cnid/cnid_add.c b/libatalk/cnid/cnid_add.c
deleted file mode 100644 (file)
index 3fd59e8..0000000
+++ /dev/null
@@ -1,371 +0,0 @@
-/*
- * $Id: cnid_add.c,v 1.35 2003-06-06 21:22:43 srittau 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_DB
-#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 <atalk/cnid.h>
-#include <atalk/util.h>
-
-#define use_make_cnid_data
-#include "cnid_private.h"
-
-#ifdef CNID_DB_CDB
-    #define tid    NULL
-#endif /* CNID_DB_CDB */
-
-/* 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;
-#ifndef CNID_DB_CDB
-    DB_TXN *tid;
-#endif /* CNID_DB_CDB */
-    int rc;
-
-    memset(&altkey, 0, sizeof(altkey));
-    memset(&altdata, 0, sizeof(altdata));
-
-#ifndef CNID_DB_CDB
-retry:
-    if ((rc = txn_begin(db->dbenv, NULL, &tid, 0)) != 0) {
-        return rc;
-    }
-#endif /* CNID_DB_CDB */
-
-    /* main database */
-    if ((rc = db->db_cnid->put(db->db_cnid, tid, key, data, DB_NOOVERWRITE))) {
-#ifndef CNID_DB_CDB
-        if (rc == DB_LOCK_DEADLOCK) {
-            if ((ret = txn_abort(tid)) != 0) {
-                return ret;
-            }
-            goto retry;
-        }
-#endif /* CNID_DB_CDB */
-        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))) {
-#ifndef CNID_DB_CDB
-        if (rc == DB_LOCK_DEADLOCK) {
-            if ((ret = txn_abort(tid)) != 0) {
-                return ret;
-            }
-            goto retry;
-        }
-#endif /* CNID_DB_CDB */
-        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))) {
-#ifndef CNID_DB_CDB
-        if (rc == DB_LOCK_DEADLOCK) {
-            if ((ret = txn_abort(tid)) != 0) {
-                return ret;
-            }
-            goto retry;
-        }
-#endif /* CNID_DB_CDB */
-        goto abort;
-    }
-
-#ifndef CNID_DB_CDB
-    if ((rc = txn_commit(tid, 0)) != 0) {
-        LOG(log_error, logtype_default, "add_cnid: Failed to commit transaction: %s", db_strerror(rc));
-        return rc;
-    }
-#endif /* CNID_DB_CDB */
-
-    return 0;
-
-abort:
-#ifndef CNID_DB_CDB
-    if ((ret = txn_abort(tid)) != 0) {
-        return ret;
-    }
-#endif    
-    return rc;
-}
-
-/* ---------------------- */
-#ifndef CNID_DB_CDB
-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 = 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 = 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) {
-            txn_abort(tid);
-            LOG(log_error, logtype_default, "cnid_add: FATAL: Cannot add CNID for %s.  CNID database has reached its limit.", name);
-            errno = CNID_ERR_MAX;
-            return CNID_INVALID;
-        }
-        hint = htonl(id);
-#ifdef DEBUG
-        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
-        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 = 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 = 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:
-    txn_abort(tid);
-    errno = CNID_ERR_DB;
-    return CNID_INVALID;
-}
-#else
-static cnid_t get_cnid(CNID_private *db)
-{
-    DBT rootinfo_key, rootinfo_data;
-    DBC  *cursor;
-    int rc;
-    int flag;
-    cnid_t hint,id;
-    
-    if ((rc = db->db_didname->cursor(db->db_didname, 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, 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) {
-            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;
-    }
-    
-    memset(&rootinfo_key, 0, sizeof(rootinfo_key));
-    memset(&rootinfo_data, 0, sizeof(rootinfo_data));
-    rootinfo_data.data = &hint;
-    rootinfo_data.size = sizeof(hint);
-    rootinfo_key.data = ROOTINFO_KEY;
-    rootinfo_key.size = ROOTINFO_KEYLEN;
-
-    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;
-}
-#endif /* CNID_DB_CDB */
-
-/* ------------------------ */
-cnid_t cnid_add(void *CNID, 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 (!(db = CNID) || !st || !name) {
-        errno = CNID_ERR_PARAM;
-        return CNID_INVALID;
-    }
-
-    /* Do a lookup. */
-    id = cnid_lookup(db, 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_DB */
-
diff --git a/libatalk/cnid/cnid_close.c b/libatalk/cnid/cnid_close.c
deleted file mode 100644 (file)
index b15b478..0000000
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * $Id: cnid_close.c,v 1.31 2003-06-26 02:15:21 didg Exp $
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif /* HAVE_CONFIG_H */
-
-#ifdef CNID_DB
-#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_private.h"
-#include <atalk/cnid.h>
-
-void cnid_close(void *CNID) {
-    CNID_private *db;
-    int rc;
-
-    if (!(db = CNID)) {
-        return;
-    }
-
-#ifndef CNID_DB_CDB
-    /* 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);
-            }
-        }
-    }
-#endif /* CNID_DB_CDB */
-
-    db->db_didname->sync(db->db_didname, 0);
-    db->db_didname->close(db->db_didname, 0);
-    db->db_devino->sync(db->db_devino, 0);
-    db->db_devino->close(db->db_devino, 0);
-    db->db_cnid->sync(db->db_cnid, 0);
-    db->db_cnid->close(db->db_cnid, 0);
-#ifdef FILE_MANGLING
-    db->db_mangle->sync(db->db_mangle, 0);
-    db->db_mangle->close(db->db_mangle, 0);
-#endif /* FILE_MANGLING */
-    db->dbenv->close(db->dbenv, 0);
-
-    LOG (log_debug, logtype_default, "Database closed");
-
-    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) {
-               (void)unlink(db->lock_file);
-       }
-    }
-    if ((db->lockfd > -1)) {
-        close(db->lockfd); /* This will also release any locks we have. */
-    }
-
-    free(db);
-}
-#endif /* CNID_DB */
diff --git a/libatalk/cnid/cnid_delete.c b/libatalk/cnid/cnid_delete.c
deleted file mode 100644 (file)
index 1b0d36d..0000000
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- * $Id: cnid_delete.c,v 1.14 2002-08-30 03:12:52 jmarcus 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_DB
-#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 <atalk/cnid.h>
-
-#include "cnid_private.h"
-
-#ifdef CNID_DB_CDB
-    #define tid    NULL
-#endif /* CNID_DB_CDB */
-
-int cnid_delete(void *CNID, const cnid_t id) {
-    CNID_private *db;
-    DBT key, data;
-#ifndef CNID_DB_CDB
-    DB_TXN *tid;
-#endif /* CNID_DB_CDB */
-    int rc, found = 0;
-
-    if (!(db = CNID) || !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;
-#ifndef CNID_DB_CDB
-        case DB_LOCK_DEADLOCK:
-            break;
-#endif /* CNID_DB_CDB */
-        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;
-        }
-    }
-
-#ifndef CNID_DB_CDB
-retry:
-    if ((rc = 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;
-    }
-#endif /* CNID_DB_CDB */
-
-    /* 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))) {
-#ifndef CNID_DB_CDB
-        int ret;
-        if ((ret = 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:
-#endif /* CNID_DB_CDB */
-            goto abort_err;
-#ifndef CNID_DB_CDB
-        }
-#endif /* CNID_DB_CDB */
-    }
-
-    /* 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) {
-#ifndef CNID_DB_CDB
-        case DB_LOCK_DEADLOCK:
-            if ((rc = txn_abort(tid)) != 0) {
-                LOG(log_error, logtype_default, "cnid_delete: txn_abort: %s",
-                    db_strerror(rc));
-                return rc;
-            }
-            goto retry;
-#endif /* CNID_DB_CDB */
-        case DB_NOTFOUND:
-            /* Quietly fall through if the entry isn't found. */
-            break;
-        default:
-#ifndef CNID_DB_CDB
-            if ((rc = txn_abort(tid)) != 0) {
-                LOG(log_error, logtype_default, "cnid_delete: txn_abort: %s",
-                    db_strerror(rc));
-                return rc;
-            }
-#endif /* CNID_DB_CDB */
-            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) {
-#ifndef CNID_DB_CDB
-        case DB_LOCK_DEADLOCK:
-            if ((rc = txn_abort(tid)) != 0) {
-                LOG(log_error, logtype_default, "cnid_delete: txn_abort: %s",
-                    db_strerror(rc));
-                return rc;
-            }
-            goto retry;
-#endif /* CNID_DB_CDB */
-        case DB_NOTFOUND:
-            break;
-        default:
-#ifndef CNID_DB_CDB
-            if ((rc = txn_abort(tid)) != 0) {
-                LOG(log_error, logtype_default, "cnid_delete: txn_abort: %s",
-                    db_strerror(rc));
-                return rc;
-            }
-#endif /* CNID_DB_CDB */
-            goto abort_err;
-        }
-    }
-
-#ifdef DEBUG
-    LOG(log_info, logtype_default, "cnid_delete: Deleting CNID %u", ntohl(id));
-#endif
-#ifndef CNID_DB_CDB
-    if ((rc = txn_commit(tid, 0)) != 0) {
-        LOG(log_error, logtype_default, "cnid_delete: Failed to commit transaction: %s",
-            db_strerror(rc));
-        return rc;
-    }
-#endif /* CNID_DB_CDB */
-    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_DB */
diff --git a/libatalk/cnid/cnid_get.c b/libatalk/cnid/cnid_get.c
deleted file mode 100644 (file)
index ffb7b0d..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * $Id: cnid_get.c,v 1.13 2002-08-30 03:12:52 jmarcus Exp $
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif /* HAVE_CONFIG_H */
-
-#ifdef CNID_DB
-#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 <atalk/cnid.h>
-
-#include "cnid_private.h"
-
-/* Return CNID for a given did/name. */
-cnid_t cnid_get(void *CNID, 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 (!(db = CNID) || (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))) {
-#ifndef CNID_DB_CDB
-        if (rc == DB_LOCK_DEADLOCK) {
-            continue;
-        }
-#endif /* CNID_DB_CDB */
-
-        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_DB */
diff --git a/libatalk/cnid/cnid_init.c b/libatalk/cnid/cnid_init.c
new file mode 100644 (file)
index 0000000..b1bfc59
--- /dev/null
@@ -0,0 +1,89 @@
+
+/* 
+ * $Id: cnid_init.c,v 1.2 2005-04-28 20:49:58 bfernhomberg Exp $
+ *
+ * Copyright (c) 2003 the Netatalk Team
+ * Copyright (c) 2003 Rafal Lewczuk <rlewczuk@pronet.pl>
+ * 
+ * This program is free software; you can redistribute and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation version 2 of the License or later
+ * version if explicitly stated by any of above copyright holders.
+ *
+ */
+
+/*
+ * This file contains initialization stuff for CNID backends.
+ * Currently it only employs static bindings. 
+ * No plans for dynamically loaded CNID backends here (temporary). 
+ * Maybe somewhere in the future.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include <atalk/cnid.h>
+#include <atalk/list.h>
+#include <atalk/logger.h>
+#include <stdlib.h>
+
+
+#ifdef CNID_BACKEND_DB3
+extern struct _cnid_module cnid_db3_module;
+#endif
+
+#ifdef CNID_BACKEND_HASH
+extern struct _cnid_module cnid_hash_module;
+#endif
+
+#ifdef CNID_BACKEND_LAST
+extern struct _cnid_module cnid_last_module;
+#endif
+
+#ifdef CNID_BACKEND_MTAB
+extern struct _cnid_module cnid_mtab_module;
+#endif
+
+#ifdef CNID_BACKEND_CDB
+extern struct _cnid_module cnid_cdb_module;
+#endif
+
+#ifdef CNID_BACKEND_DBD
+extern struct _cnid_module cnid_dbd_module;
+#endif
+
+#ifdef CNID_BACKEND_TDB
+extern struct _cnid_module cnid_tdb_module;
+#endif
+
+void cnid_init()
+{
+#ifdef CNID_BACKEND_DB3
+    cnid_register(&cnid_db3_module);
+#endif
+
+#ifdef CNID_BACKEND_HASH
+    cnid_register(&cnid_hash_module);
+#endif
+
+#ifdef CNID_BACKEND_LAST
+    cnid_register(&cnid_last_module);
+#endif
+
+#ifdef CNID_BACKEND_MTAB
+    cnid_register(&cnid_mtab_module);
+#endif
+
+#ifdef CNID_BACKEND_CDB
+    cnid_register(&cnid_cdb_module);
+#endif
+
+#ifdef CNID_BACKEND_DBD
+    cnid_register(&cnid_dbd_module);
+#endif
+
+#ifdef CNID_BACKEND_TDB
+    cnid_register(&cnid_tdb_module);
+#endif
+}
diff --git a/libatalk/cnid/cnid_lookup.c b/libatalk/cnid/cnid_lookup.c
deleted file mode 100644 (file)
index 153dcca..0000000
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * $Id: cnid_lookup.c,v 1.17 2003-06-06 21:22:44 srittau Exp $
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif /* HAVE_CONFIG_H */
-
-#ifdef CNID_DB
-#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 <atalk/cnid.h>
-
-#define use_make_cnid_data
-#include "cnid_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_lookup(void *CNID, 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 (!(db = CNID) || !st || !name) {
-        return 0;
-    }
-
-#ifndef CNID_DB_CDB
-    /* 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)
-        db->dbenv->txn_checkpoint(db->dbenv, LOGFILEMAX, CHECKTIMEMAX, 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) */
-#endif /* CNID_DB_CDB */
-
-        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))) {
-#ifndef CNID_DB_CDB
-            if (rc == DB_LOCK_DEADLOCK) {
-                continue;
-            }
-#endif /* CNID_DB_CDB */
-
-            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))) {
-#ifndef CNID_DB_CDB
-            if (rc == DB_LOCK_DEADLOCK) {
-                continue;
-            }
-#endif /* CNID_DB_CDB */
-
-            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_update(db, 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_DB */
-
-
diff --git a/libatalk/cnid/cnid_mangle_add.c b/libatalk/cnid/cnid_mangle_add.c
deleted file mode 100644 (file)
index 6439eb4..0000000
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * $Id: cnid_mangle_add.c,v 1.6 2003-06-06 21:22:44 srittau Exp $
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif /* HAVE_CONFIG_H */
-
-#ifdef FILE_MANGLING
-#include <stdio.h>
-#include <string.h>
-#include <sys/param.h>
-#include <sys/stat.h>
-#include <string.h>
-#include <atalk/logger.h>
-#include <errno.h>
-
-#include <db.h>
-#include <netatalk/endian.h>
-#include <atalk/adouble.h>
-#include <atalk/cnid.h>
-
-#include "cnid_private.h"
-
-#ifdef CNID_DB_CDB
-    #define tid    NULL
-#endif /* CNID_DB_CDB */
-
-/* Add a mangled filename. */
-int
-cnid_mangle_add(void *CNID, char *mfilename, char *filename)
-{
-    CNID_private *db;
-    DBT key, data;
-#ifndef CNID_DB_CDB
-    DB_TXN *tid;
-#endif /* CNID_DB_CDB */
-    int rc;
-
-    if (!(db = CNID)) {
-        return -1;
-    }
-
-    memset(&key, 0, sizeof(key));
-    memset(&data, 0, sizeof(data));
-
-    key.data = mfilename;
-    key.size = strlen(mfilename);
-    data.data = filename;
-    data.size = strlen(filename) + 1;
-
-#ifndef CNID_DB_CDB
-retry:
-    if ((rc = txn_begin(db->dbenv, NULL, &tid, 0)) != 0) {
-        LOG(log_error, logtype_default, "cnid_mangle_add: Failed to begin transaction: %s", db_strerror(rc));
-        return -1;
-    }
-#endif /* CNID_DB_CDB */
-
-    if ((rc = db->db_mangle->put(db->db_mangle, tid, &key, &data, 0))) {
-#ifndef CNID_DB_CDB
-        if ((ret = txn_abort(tid)) != 0) {
-            LOG(log_error, logtype_default, "cnid_mangle_add: txn_abort: %s", db_strerror(ret));
-            return -1;
-        }
-#endif /* CNID_DB_CDB */
-        switch (rc) {
-#ifndef CNID_DB_CDB
-        case DB_LOCK_DEADLOCK:
-            goto retry;
-#endif /* CNID_DB_CDB */
-        default:
-            LOG(log_error, logtype_default, "cnid_mangle_add: Failed to add mangled filename to the database: %s", db_strerror(rc));
-            return -1;
-        }
-    }
-
-#ifndef CNID_DB_CDB
-    if ((rc = txn_commit(tid, 0)) != 0) {
-        LOG(log_error, logtype_default, "cnid_mangle_add: Unable to commit transaction: %s", db_strerror(rc));
-        return -1;
-    }
-#endif /* CNID_DB_CDB */
-
-    return 0;
-}
-#endif /* FILE_MANGLING */
diff --git a/libatalk/cnid/cnid_mangle_get.c b/libatalk/cnid/cnid_mangle_get.c
deleted file mode 100644 (file)
index dec6c29..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * $Id: cnid_mangle_get.c,v 1.8 2003-06-06 21:22:45 srittau Exp $
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif /* HAVE_CONFIG_H */
-
-#ifdef FILE_MANGLING
-#include <stdio.h>
-#include <string.h>
-#include <sys/param.h>
-#include <sys/stat.h>
-#include <string.h>
-#include <atalk/logger.h>
-#include <errno.h>
-
-#include <db.h>
-#include <netatalk/endian.h>
-#include <atalk/adouble.h>
-#include <atalk/cnid.h>
-
-#include "cnid_private.h"
-
-/* Find a mangled filename entry. */
-char *
-cnid_mangle_get(void *CNID, char *mfilename)
-{
-    CNID_private *db;
-    DBT key, data;
-    char *filename;
-    int rc;
-
-    if (!(db = CNID)) {
-        return NULL;
-    }
-
-    memset(&key, 0, sizeof(key));
-    memset(&data, 0, sizeof(data));
-
-    key.data = mfilename;
-    key.size = strlen(mfilename);
-
-    while ((rc = db->db_mangle->get(db->db_mangle, NULL, &key, &data, 0))) {
-        if (rc == DB_LOCK_DEADLOCK) {
-            continue;
-        }
-
-        if (rc == DB_NOTFOUND) {
-            LOG(log_debug, logtype_default, "cnid_mangle_get: Failed to find mangled entry for %s", mfilename);
-            return NULL;
-
-        }
-
-        LOG(log_error, logtype_default, "cnid_mangle_get: Failed to get mangle entry from the database: %s", db_strerror(rc));
-        return NULL;
-    }
-
-    filename = (char *)data.data;
-
-    return filename;
-}
-#endif /* FILE_MANGLING */
diff --git a/libatalk/cnid/cnid_meta.c b/libatalk/cnid/cnid_meta.c
deleted file mode 100644 (file)
index c72fbf6..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-/*
- * $Id: cnid_meta.c,v 1.2 2001-06-29 14:14:46 rufustfirefly Exp $
- *
- * Copyright (c) 1999. Adrian Sun (asun@zoology.washington.edu)
- * All Rights Reserved. See COPYRIGHT.
- *
- * deal with metadata
- *
- */
diff --git a/libatalk/cnid/cnid_meta.h b/libatalk/cnid/cnid_meta.h
deleted file mode 100644 (file)
index 8f0b906..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * $Id: cnid_meta.h,v 1.2 2001-06-29 14:14:46 rufustfirefly Exp $
- */
-
-#define CNID_META_CNID_LEN      4
-#define CNID_META_MDATE_LEN     4  /* space for 8 */
-#define CNID_META_CDATE_LEN     4  /* space for 8 */
-#define CNID_META_BDATE_LEN     4  /* ditto */
-#define CNID_META_ADATE_LEN     4  /* ditto */
-#define CNID_META_AFPI_LEN      4  /* plus permission bits */
-#define CNID_META_FINDERI_LEN   32 
-#define CNID_META_PRODOSI_LEN   8
-#define CNID_META_RFORKLEN_LEN  4  /* space for 8 */
-#define CNID_META_MACNAME_LEN   32 /* maximum size */
-#define CNID_META_SHORTNAME_LEN 12 /* max size (8.3) */
-#define CNID_META_FILLER_LEN    4
-
-#define CNID_META_CNID_OFF     0
-#define CNID_META_MDATE_OFF    (CNID_META_CNID_OFF + CNID_META_CNID_LEN + \
-                               CNID_META_FILLER_LEN)
-#define CNID_META_CDATE_OFF    (CNID_META_MDATE_OFF + CNID_META_MDATE_LEN + \
-                               CNID_META_FILLER_LEN)
-#define CNID_META_BDATE_OFF    (CNID_META_CDATE_OFF + CNID_META_CDATE_LEN + \
-                               CNID_META_FILLER_LEN)
-#define CNID_META_ADATE_OFF    (CNID_META_BDATE_OFF + CNID_META_BDATE_LEN + \
-                               CNID_META_FILLER_LEN)
-#define CNID_META_AFPI_OFF     (CNID_META_ADATE_OFF + CNID_META_ADATE_LEN)
-#define CNID_META_FINDERI_OFF  (CNID_META_AFPI_OFF + CNID_META_AFPI_LEN)
-#define CNID_META_PRODOSI_OFF  (CNID_META_FINDERI_OFF + CNID_META_FINDERI_LEN)
-#define CNID_META_RFORKLEN_OFF (CNID_META_PRODOSI_OFF + CNID_META_PRODOSI_LEN)
-#define CNID_META_MACNAME_OFF  (CNID_META_RFORKLEN_OFF + \
-                               CNID_META_RFORKLEN_LEN)
-#define CNID_META_SHORTNAME_OFF (CNID_META_MACNAME_OFF + 
-
-
-#define cnid_meta_clear(a)  
-#define cnid_meta_get(id)
-
-#define cnid_meta_cnid(a)  
-#define cnid_meta_modifydate(a)
-#define cnid_meta_createdate(a)
-#define cnid_meta_backupdate(a)
-#define cnid_meta_accessdate(a)
-#define cnid_meta_afpi(a)
-#define cnid_meta_finderi(a)
-#define cnid_meta_prodosi(a)
-#define cnid_meta_rforklen(a)
-#define cnid_meta_macname(a)
-#define cnid_meta_shortname(a)
-#define cnid_meta_longname(a)
-
diff --git a/libatalk/cnid/cnid_nextid.c b/libatalk/cnid/cnid_nextid.c
deleted file mode 100644 (file)
index f77ca82..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * $Id: cnid_nextid.c,v 1.8 2002-01-04 04:45:48 sibaz Exp $
- */
-#ifdef unused
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif /* HAVE_CONFIG_H */
-
-#ifdef CNID_DB
-#include <db.h>
-
-#include <atalk/adouble.h>
-#include <atalk/cnid.h>
-
-#include <atalk/logger.h>
-
-#include "cnid_private.h"
-
-/* return the next id. we use the fact that ad files are memory
- * mapped. */
-cnid_t cnid_nextid(void *CNID)
-{
-    CNID_private *db;
-    cnid_t id;
-
-    if (!(db = CNID))
-        return 0;
-
-    memcpy(&id, ad_entry(&db->rootinfo, ADEID_DID), sizeof(id));
-    return id;
-}
-#endif /* CNID_DB */
-#endif
-
diff --git a/libatalk/cnid/cnid_open.c b/libatalk/cnid/cnid_open.c
deleted file mode 100644 (file)
index f56314b..0000000
+++ /dev/null
@@ -1,765 +0,0 @@
-/*
- * $Id: cnid_open.c,v 1.54 2003-07-10 13:50:39 rlewczuk 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_DB
-#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 <atalk/util.h>
-
-#include "cnid_private.h"
-
-#ifndef MIN
-#define MIN(a, b)  ((a) < (b) ? (a) : (b))
-#endif /* ! MIN */
-
-#ifndef MAX
-#define MAX(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 DBMANGLE      "mangle.db"    /* filename mangling */
-#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
-
-#ifdef CNID_DB_CDB
-#define DBOPTIONS    (DB_CREATE | DB_INIT_CDB | DB_INIT_MPOOL)
-#else /* !CNID_DB_CDB */
-#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 */
-#endif /* CNID_DB_CDB */
-
-#ifndef CNID_DB_CDB
-/* 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 */
-#endif /* CNID_DB_CDB */
-
-static cnid_t cnid_rebuild (CNID_private *, mode_t);
-static int    cnid_recover (char *, mode_t);
-
-#define MAXITER     0xFFFF /* maximum number of simultaneously open CNID
-* databases. */
-
-/* -----------------------
- * bandaid for LanTest performance pb.
-*/
-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, mode);
-#else
-    return p->open(p,       f, d, t, flags, mode);
-#endif
-}
-
-void *cnid_open(const char *dir, mode_t mask) {
-    struct stat st;
-    struct flock lock;
-    char path[MAXPATHLEN + 1];
-    CNID_private *db;
-    DBT key, data;
-    DB_TXN *tid;
-    int open_flag, len;
-    int rc;
-    int can_check = 0, require_rebuild = 0;
-    u_int32_t ncnid, ndidname, ndevino;
-    DB_HASH_STAT *sp;
-    static int first = 0;
-
-    ncnid = ndidname = ndevino = 0;
-
-
-    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 ((db = (CNID_private *)calloc(1, sizeof(CNID_private))) == NULL) {
-        LOG(log_error, logtype_default, "cnid_open: Unable to allocate memory for database");
-        return NULL;
-    }
-
-    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++;
-
-    strcat(path, DBLOCKFILE);
-    strcpy(db->lock_file, path);
-    if ( stat (path, &st) == 0)
-       can_check = 1;
-
-    if ((db->lockfd = open(path, O_RDWR | O_CREAT, 0666 & ~mask)) > -1) {
-        lock.l_start = 0;
-        lock.l_len = 1;
-        if (fcntl(db->lockfd, F_SETLK, &lock) < 0) {
-               /* Now try to get a shared lock */
-               lock.l_type = F_RDLCK;
-
-               while (fcntl(db->lockfd, F_SETLKW, &lock) < 0) {
-                       if ( errno != EINTR )
-                               goto fail_db;
-               }
-               can_check = 0;
-       }
-       else {
-               /* We got an exclusive lock, so we're the first/only process accessing the database */
-               if ( can_check ) {
-                       /* cnid.lock existed but we got an exclusive lock */
-                       /* This means the previous afpd probably crashed  */
-                       /* or got terminated so we run recovery           */
-
-                       path[len + DBHOMELEN] = '\0';
-                       if ( cnid_recover( path, mask) != 0)
-                               goto fail_lock;
-               }
-               else {
-                       /* We're the only process accesing the db, so lets do some constistency checks */
-                       can_check = 1; 
-               }
-       }
-    }
-    else
-    {
-        LOG(log_error, logtype_default, "cnid_open: Cannot open cnid.lock file in %s lock (lock failed)", path);
-        goto fail_db;
-    }
-
-    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;
-    }
-
-    if ((rc = db->dbenv->open(db->dbenv, path, DB_JOINENV, 0666 & ~mask)) !=0 &&
-        (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;
-    }
-
-    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));
-        /* We leak some memory here, but otherwise sometime we run into a SIGSEGV in close */  
-        db->db_didname = NULL; 
-       if (can_check) {
-               require_rebuild = 1;
-               goto rebuild;
-       }
-       else
-               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;
-
-    if ((rc = db->db_didname->get(db->db_didname, NULL, &key, &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_didname, NULL, &key, &data,
-                                       DB_NOOVERWRITE))) {
-            LOG(log_error, logtype_default, "cnid_open: Error putting new version: %s",
-                db_strerror(ret));
-            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));
-       db->db_devino = NULL; 
-       if (can_check) {
-               require_rebuild = 1;
-               goto rebuild;
-       }
-       else
-               goto fail_appinit;
-    }
-
-rebuild:
-
-    /* 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 cnid database: %s",
-            db_strerror(rc));
-       if ( require_rebuild )
-               LOG(log_error, logtype_default, "cnid_open: CNID Databases are corrupted beyond repair, your probably should delete all files in %s", path);
-        goto fail_appinit;
-    }
-
-    /* Check database consistency */
-    if ( can_check ) {
-       if ((db->db_didname) && ((rc = db->db_didname->stat(db->db_didname, &sp, 0)) != 0)) {
-               LOG(log_error, logtype_default, "cnid_open: Failed to stat did/macname database: %s",
-                   db_strerror(rc));
-               require_rebuild = 1;
-       }
-       if (sp) {
-               ndidname = (sp->hash_nkeys > 2) ? sp->hash_nkeys-2 : 0;
-               free (sp);
-       }
-
-       if ((db->db_devino) && ((rc = db->db_devino->stat(db->db_devino, &sp, 0)) != 0)) {
-               LOG(log_error, logtype_default, "cnid_open: Failed to stat dev/ino database: %s",
-                   db_strerror(rc));
-               require_rebuild = 1;
-       }
-       if (sp) {
-               ndevino = sp->hash_nkeys;
-               free (sp);
-       }
-
-       if ((rc = db->db_cnid->stat(db->db_cnid, &sp, 0)) != 0) {
-               LOG(log_error, logtype_default, "cnid_open: Failed to stat cnid database: %s",
-                   db_strerror(rc));
-               LOG(log_error, logtype_default, "cnid_open: CNID Databases are corrupted beyond repair, your probably should delete all files in %s", path);
-               goto fail_appinit;
-       }
-       ncnid = sp->hash_nkeys;
-
-       if ( require_rebuild || ndidname != ncnid || ndevino != ncnid ) {
-               LOG(log_error, logtype_default, "cnid_open: databases corrupt, number of entries mismatch (didname: %u, devino: %u, cnid: %u)", ndidname, ndevino, ncnid);
-               if ( CNID_INVALID == cnid_rebuild(db, mask) ) 
-                       goto fail_appinit;
-       }
-       /* now downgrade to a shared lock */
-
-       lock.l_type = F_RDLCK;
-       if (fcntl(db->lockfd, F_SETLK, &lock) < 0) {
-               LOG (log_error, logtype_default, "cnid_open: Cannot set shared lock");
-       }
-       can_check = 0;
-    }
-
-#ifdef FILE_MANGLING
-    /* filename mangling database.  Use a hash for this one. */
-    if ((rc = db_create(&db->db_mangle, db->dbenv, 0)) != 0) {
-        LOG(log_error, logtype_default, "cnid_open: Failed to create mangle database: %s", db_strerror(rc));
-        goto fail_appinit;
-    }
-
-    if ((rc = my_open(db->db_mangle, DBMANGLE, NULL, DB_HASH, open_flag, 0666 & ~mask))) {
-        LOG(log_error, logtype_default, "cnid_open: Failed to open mangle database: %s", db_strerror(rc));
-        goto fail_appinit;
-    }
-#endif /* FILE_MANGLING */
-
-    /* Print out the version of BDB we're linked against. only once */
-    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 db;
-
-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 && !can_check ) {
-        close(db->lockfd);
-        (void)remove(db->lock_file);
-    }
-
-fail_adouble:
-
-fail_db:
-    free(db);
-    return NULL;
-}
-
-
-/*-------------------------*/
-
-static int cnid_recover(char *path, mode_t mask)
-{
-       DB_ENV * dbenv;
-       int open_flag = 0, rc = 0;
-
-       if ( !path || strlen(path) == 0)
-               return -1;
-
-       LOG (log_info, logtype_default, "cnid_open: running recover on %s", path);
-
-       /* Remove any existing environment */
-
-       if ((rc = db_env_create(&dbenv, 0)) != 0) {
-                       LOG(log_error, logtype_default, "cnid_recover: db_env_create: %s", db_strerror(rc));
-               return rc;
-       }
-       if ((rc = dbenv->remove(dbenv, path, DB_FORCE)) != 0) {
-               LOG(log_error, logtype_default, "cnid_recover db_env_remove: %s", db_strerror(rc));
-               return rc;
-       }
-
-       /* Create and open recover environment */
-
-       if ((rc = db_env_create(&dbenv, 0)) != 0) {
-                       LOG(log_error, logtype_default, "cnid_recover: db_env_create: %s", db_strerror(rc));
-               return rc;
-       }
-
-       open_flag = DB_CREATE | DB_INIT_LOCK | DB_INIT_LOG | DB_INIT_MPOOL | DB_INIT_TXN | DB_RECOVER | DB_PRIVATE;             
-       if ((rc = dbenv->open(dbenv, path, open_flag, 0666 & ~mask)) != 0) {
-               LOG (log_error, logtype_default, "cnid_recover: RECOVERY failed with %s", db_strerror(rc));
-               return rc;
-       }
-
-       if ((rc = dbenv->close(dbenv, 0)) != 0) {
-                       LOG(log_error, logtype_default, "cnid_recover: dbenv->close: %s", db_strerror(rc));
-               return rc;
-       }
-
-       /* Remove recover environment */
-                       
-       if ((rc = db_env_create(&dbenv, 0)) != 0) {
-                       LOG(log_error, logtype_default, "cnid_recover: db_env_create: %s", db_strerror(rc));
-               return rc;
-       }
-
-       if ((rc = dbenv->remove(dbenv, path, DB_FORCE)) != 0) {
-               LOG(log_error, logtype_default, "cnid_recover: db_env_remove: %s", db_strerror(rc));
-               return rc;
-       }
-
-       return 0;
-}
-
-
-static cnid_t cnid_rebuild (CNID_private *db, mode_t mask)
-{
-
-#ifdef CNID_DB_CDB
-       DB *tmpdb;
-       DBC *cursor;
-       DBT key, data, altkey, altdata, dupkey, dupdata;
-       int rc;
-       cnid_t id, dupid, maxcnid = CNID_START;
-       u_int32_t countp;
-               u_int32_t version;
-
-       static char buffer[MAXPATHLEN + CNID_HEADER_LEN + 1];
-               LOG(log_info, logtype_default, "starting rebuild of databases");
-
-       if ((rc = db->db_cnid->cursor(db->db_cnid, NULL, &cursor, DB_WRITECURSOR) ) != 0) {
-               LOG(log_error, logtype_default, "cnid_rebuild: Unable to get a cursor: %s", db_strerror(rc));
-               return CNID_INVALID;
-       }
-
-       memset(&key, 0, sizeof(key));
-       memset(&data, 0, sizeof(data));
-       memset(&altkey, 0, sizeof(key));
-       memset(&altdata, 0, sizeof(data));
-       memset(&dupdata, 0, sizeof(dupdata));
-       memset(&dupkey, 0, sizeof(dupkey));
-
-       /* close didname and devino, then recreate them */
-       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 ((rc = db_create(&db->db_didname, db->dbenv, 0)) != 0) {
-               LOG(log_error, logtype_default, "cnid_rebuild: Failed to recreate did/name database: %s",
-                       db_strerror(rc));
-               goto abort;
-       }
-
-       if ((rc = my_open(db->db_didname, DBDIDNAME, NULL, DB_HASH, DB_CREATE|DB_TRUNCATE, 0666 & ~mask))) {
-               LOG(log_error, logtype_default, "cnid_rebuild: Failed to open did/name database: %s",
-                       db_strerror(rc));
-               goto abort;
-       }
-
-       if ((rc = db_create(&db->db_devino, db->dbenv, 0)) != 0) {
-               LOG(log_error, logtype_default, "cnid_rebuild: Failed to recreate dev/ino database: %s",
-                       db_strerror(rc));
-               goto abort;
-       }
-
-       if ((rc = my_open(db->db_devino, DBDEVINO, NULL, DB_HASH, DB_CREATE|DB_TRUNCATE, 0666 & ~mask))) {
-               LOG(log_error, logtype_default, "cnid_rebuild: Failed to open dev/ino database: %s",
-                       db_strerror(rc));
-               goto abort;
-       }
-
-       db->db_devino->sync( db->db_devino, 0);
-       db->db_didname->sync( db->db_didname, 0);
-
-
-       /* now create the temporary cnid database */
-       if ((rc = db_create(&tmpdb, db->dbenv, 0)) != 0) {
-               LOG(log_error, logtype_default, "cnid_rebuild: Failed to create tmp database: %s",
-                       db_strerror(rc));
-               goto abort;
-       }
-
-       if ((rc = my_open(tmpdb, DBRECOVERFILE, NULL, DB_HASH, DB_CREATE|DB_TRUNCATE, 0666 & ~mask))) {
-               LOG(log_error, logtype_default, "cnid_rebuild: Failed to open recover database: %s",
-                       db_strerror(rc));
-               goto abort;
-       }
-
-       /* add rootinfo and version to didname */
-       id = 0;
-       key.data = ROOTINFO_KEY;
-       key.size = ROOTINFO_KEYLEN;
-       data.data = &id;
-       data.size = sizeof(id);
-
-       if ((rc = db->db_didname->put(db->db_didname, NULL, &key, &data, 0))) {
-               LOG(log_error, logtype_default, "cnid_rebuild: Error adding ROOTINFO: %s", db_strerror(rc));
-               goto abort;
-       }
-
-       memset(&key, 0, sizeof(key));
-       memset(&data, 0, sizeof(data));
-       key.data = DBVERSION_KEY;
-       key.size = DBVERSION_KEYLEN;
-               version = htonl(DBVERSION);
-               data.data = &version;
-               data.size = sizeof(version);
-
-               if ((rc = db->db_didname->put(db->db_didname, NULL, &key, &data, 0))) {
-               LOG(log_error, logtype_default, "cnid_rebuild: Error putting version: %s",
-                       db_strerror(rc));
-               goto abort;
-        }
-
-       /* now recover the databases from cnid.db*/
-
-       memset(&key, 0, sizeof(key));
-       memset(&data, 0, sizeof(data));
-       data.data = buffer;
-       data.ulen = MAXPATHLEN + CNID_HEADER_LEN +1;
-       data.flags = DB_DBT_USERMEM;
-       countp = 0;
-
-       while ((rc = cursor->c_get(cursor, &key, &data, DB_NEXT)) == 0) {
-               memcpy ( &id, key.data, sizeof(id));
-               id = ntohl (id);
-               if ( id < CNID_START ) {
-                       LOG(log_error, logtype_default, "cnid_rebuild: Dropping invalid entry with id: %u", id);
-                       continue;
-               }
-                       
-               maxcnid = MAX( id, maxcnid);
-
-               /* check for duplicate cnid */
-
-               if ((rc = tmpdb->get(tmpdb, NULL, &key, &dupdata, 0))) {
-                       if ( rc != DB_NOTFOUND ) {
-                               LOG(log_error, logtype_default, "cnid_rebuild: Error getting entry from cnid: %s",
-                                       db_strerror(rc));
-                               goto abort;
-                       }
-               }
-               else /* duplicate cnid */
-               {
-                       LOG(log_error, logtype_default, "cnid_rebuild: Dropping duplicate file entry: %u", id);
-                       continue;
-               }
-
-               
-               /* 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, NULL, &altkey, &altdata, DB_NOOVERWRITE))) {
-                       if ( rc != DB_KEYEXIST) {
-                               LOG(log_error, logtype_default, "cnid_rebuild: Error adding entry %u to dev/ino: %s",
-                               id, db_strerror(rc));
-                               goto abort;
-                       }
-
-                       /* handle duplicate (file with 2 ids) */
-
-                       dupkey.data = data.data;
-                       dupkey.size = CNID_DEVINO_LEN;
-                       if (( rc = db->db_devino->get(db->db_devino, NULL, &dupkey, &dupdata, 0))) {
-                               LOG(log_error, logtype_default, "cnid_rebuild: Error getting entry from did/name: %s",
-                                       db_strerror(rc));
-                               goto abort;
-                       }
-                       memcpy ( &dupid, dupdata.data, sizeof(id));
-                       dupid = ntohl (dupid);
-                       LOG(log_error, logtype_default, "cnid_rebuild: Dropping duplicate file entry: %u", MIN(id,dupid));
-                       
-                       /* Use the entry with a higher cnid */
-                       if ( id < dupid)
-                               continue;       
-                       else
-                               if ((rc = db->db_devino->put(db->db_devino, NULL, &altkey, &altdata, 0))) {
-                                       LOG(log_error, logtype_default, "cnid_rebuild: Error adding entry %u to dev/ino: %s",
-                                       id, db_strerror(rc));
-                                       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, NULL, &altkey, &altdata, 0))) {
-                       LOG(log_error, logtype_default, "cnid_rebuild: Error adding entry to did/name: %s",
-                               db_strerror(rc));
-                       goto abort;
-               }
-
-               /* recover database */
-
-               if ((rc = tmpdb->put(tmpdb, NULL, &key, &data, 0))) {
-                       LOG(log_error, logtype_default, "cnid_rebuild: Error adding entry to recoverdb: %s",
-                               db_strerror(rc));
-                       goto abort;
-               }
-               countp++;
-       }
-
-       /* set ROOTINFO to maxcnid */
-       maxcnid = htonl(maxcnid);
-       key.data = ROOTINFO_KEY;
-       key.size = ROOTINFO_KEYLEN;
-       data.data = &maxcnid;
-       data.size = sizeof(maxcnid);
-
-       if ((rc = db->db_didname->put(db->db_didname, NULL, &key, &data, 0))) {
-               LOG (log_error, logtype_default, "cnid_rebuild: Failed to update ROOTINFO %s", db_strerror(rc));
-               goto abort;
-       }
-
-       /* delete cnid.db and rename cniddb.recover to cnid.db */
-
-       cursor->c_close(cursor);
-       db->db_cnid->close(db->db_cnid, 0);
-
-       if ((rc = db_create(&db->db_cnid, db->dbenv, 0)) != 0) {
-               LOG(log_error, logtype_default, "cnid_rebuild: Failed to create database: %s", db_strerror(rc));
-               goto fail;
-       }
-       if ((rc = db->db_cnid->remove(db->db_cnid, DBCNID, NULL, 0)) != 0) {
-               LOG(log_error, logtype_default, "cnid_rebuild: Failed to remove database: %s", db_strerror(rc));
-               db->db_cnid = NULL;
-               goto fail;
-       }
-
-       if ((rc = tmpdb->close(tmpdb, 0)) != 0) {
-               LOG(log_error, logtype_default, "cnid_rebuild: Failed to close database: %s", db_strerror(rc));
-               goto fail;
-       }
-       if ((rc = db_create(&tmpdb, db->dbenv, 0)) != 0) {
-               LOG(log_error, logtype_default, "cnid_rebuild: Failed to create database: %s", db_strerror(rc));
-               goto fail;
-       }
-       if ((rc = tmpdb->rename(tmpdb, DBRECOVERFILE, NULL, DBCNID, 0)) != 0) {
-               LOG(log_error, logtype_default, "cnid_rebuild: Rename database failed: %s", db_strerror(rc));
-               goto fail;
-       }
-
-       if ((rc = db_create(&db->db_cnid, db->dbenv, 0)) != 0) {
-               LOG(log_error, logtype_default, "cnid_rebuild: Failed to recreate cnid database: %s", db_strerror(rc));
-               goto fail;
-       }
-
-       if ((rc = my_open(db->db_cnid, DBCNID, NULL, DB_HASH, 0, 0666 & ~mask))) {
-               LOG(log_error, logtype_default, "cnid_rebuild: Failed to open cnid database: %s", db_strerror(rc));
-               goto fail;
-       }
-
-       db->db_devino->sync( db->db_devino, 0);
-       db->db_didname->sync( db->db_didname, 0);
-       db->db_cnid->sync( db->db_cnid, 0);
-       
-       LOG (log_info, logtype_default, "cnid_rebuild: Recovered %u entries, database rebuild complete", countp);
-       return 1;
-
-abort:
-       cursor->c_close(cursor);
-fail:
-       LOG (log_error, logtype_default, "cnid_rebuild: Database rebuild failed");
-       return CNID_INVALID;
-#else
-       return CNID_INVALID;
-#endif
-
-}
-
-#endif /* CNID_DB */
diff --git a/libatalk/cnid/cnid_private.h b/libatalk/cnid/cnid_private.h
deleted file mode 100644 (file)
index d5ee6a4..0000000
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * $Id: cnid_private.h,v 1.12 2003-06-06 21:22:45 srittau 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 <atalk/cnid.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;
-#ifdef FILE_MANGLING
-    DB *db_mangle;
-#endif /* FILE_MANGLING */
-#ifdef EXTENDED_DB
-    DB *db_shortname;
-    DB *db_macname;
-    DB *db_longname;
-#endif /* EXTENDED_DB */
-    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__ */
-
-#ifdef use_make_cnid_data
-/* 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 /* use_make_cnid_date */
-
-#endif /* atalk/cnid/cnid_private.h */
diff --git a/libatalk/cnid/cnid_resolve.c b/libatalk/cnid/cnid_resolve.c
deleted file mode 100644 (file)
index 86bc478..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * $Id: cnid_resolve.c,v 1.13 2002-08-30 03:12:52 jmarcus Exp $
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif /* HAVE_CONFIG_H */
-
-#ifdef CNID_DB
-#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 <atalk/cnid.h>
-
-#include "cnid_private.h"
-
-/* Return the did/name pair corresponding to a CNID. */
-char *cnid_resolve(void *CNID, cnid_t *id, void *buffer, u_int32_t len) {
-    CNID_private *db;
-    DBT key, data;
-    int rc;
-
-    if (!(db = CNID) || !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))) {
-#ifndef CNID_DB_CDB
-        if (rc == DB_LOCK_DEADLOCK) {
-            continue;
-        }
-#endif /* CNID_DB_CDB */
-
-        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_DB */
diff --git a/libatalk/cnid/cnid_update.c b/libatalk/cnid/cnid_update.c
deleted file mode 100644 (file)
index 92aafee..0000000
+++ /dev/null
@@ -1,192 +0,0 @@
-/*
- * $Id: cnid_update.c,v 1.21 2003-06-06 21:22:45 srittau Exp $
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif /* HAVE_CONFIG_H */
-
-#ifdef CNID_DB
-#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 <atalk/cnid.h>
-
-#define use_make_cnid_data
-#include "cnid_private.h"
-
-#ifdef CNID_DB_CDB
-    #define tid    NULL
-#endif /* CNID_DB_CDB */
-
-/* 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_update(void *CNID, 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;
-#ifndef CNID_DB_CDB
-    DB_TXN *tid;
-#endif /* CNID_DB_CDB */
-    int rc;
-
-    if (!(db = CNID) || !id || !st || !name || (db->flags & CNIDFLAG_DB_RO)) {
-        return -1;
-    }
-
-    memset(&key, 0, sizeof(key));
-    memset(&altdata, 0, sizeof(altdata));
-
-#ifndef CNID_DB_CDB
-retry:
-    if ((rc = txn_begin(db->dbenv, NULL, &tid, 0))) {
-        LOG(log_error, logtype_default, "cnid_update: Failed to begin transaction: %s", db_strerror(rc));
-        return rc;
-    }
-#endif /* CNID_DB_CDB */
-
-    /* Get the old info. */
-    key.data = (cnid_t *)&id;
-    key.size = sizeof(id);
-    memset(&data, 0, sizeof(data));
-#ifdef CNID_DB_CDB
-    if ((rc = db->db_cnid->get(db->db_cnid, NULL, &key, &data, 0))) {
-#else  /* CNID_DB_CDB */
-    if ((rc = db->db_cnid->get(db->db_cnid, tid, &key, &data, DB_RMW))) {
-        txn_abort(tid);
-#endif /* CNID_DB_CDB */
-        switch (rc) {
-#ifndef CNID_DB_CDB
-        case DB_LOCK_DEADLOCK:
-            goto retry;
-#endif /* CNID_DB_CDB */
-        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) {
-#ifndef CNID_DB_CDB
-        case DB_LOCK_DEADLOCK:
-            txn_abort(tid);
-            goto retry;
-#endif /* CNID_DB_CDB */
-        case DB_NOTFOUND:
-            break;
-        default:
-#ifndef CNID_DB_CDB
-            txn_abort(tid);
-#endif /* CNID_DB_CDB */
-            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) {
-#ifndef CNID_DB_CDB
-        case DB_LOCK_DEADLOCK:
-            txn_abort(tid);
-            goto retry;
-#endif /* CNID_DB_CDB */
-        case DB_NOTFOUND:
-            break;
-        default:
-#ifndef CNID_DB_CDB
-            txn_abort(tid);
-#endif /* CNID_DB_CDB */
-            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))) {
-#ifndef CNID_DB_CDB
-        txn_abort(tid);
-#endif /* CNID_DB_CDB */
-        switch (rc) {
-#ifndef CNID_DB_CDB
-        case DB_LOCK_DEADLOCK:
-            goto retry;
-#endif /* CNID_DB_CDB */
-        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))) {
-#ifndef CNID_DB_CDB
-        txn_abort(tid);
-#endif /* CNID_DB_CDB */
-        switch (rc) {
-#ifndef CNID_DB_CDB
-        case DB_LOCK_DEADLOCK:
-            goto retry;
-#endif /* CNID_DB_CDB */
-        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))) {
-#ifndef CNID_DB_CDB
-        txn_abort(tid);
-#endif /* CNID_DB_CDB */
-        switch (rc) {
-#ifndef CNID_DB_CDB
-        case DB_LOCK_DEADLOCK:
-            goto retry;
-#endif /* CNID_DB_CDB */
-        default:
-            goto update_err;
-        }
-    }
-
-
-#ifdef CNID_DB_CDB
-    return 0;
-#else  /* CNID_DB_CDB */
-    return txn_commit(tid, 0);
-#endif /* CNID_DB_CDB */
-
-update_err:
-    LOG(log_error, logtype_default, "cnid_update: Unable to update CNID %u: %s",
-        ntohl(id), db_strerror(rc));
-    return -1;
-}
-#endif /* CNID_DB */
diff --git a/libatalk/cnid/db3/.cvsignore b/libatalk/cnid/db3/.cvsignore
new file mode 100644 (file)
index 0000000..0d0371d
--- /dev/null
@@ -0,0 +1,6 @@
+Makefile
+Makefile.in
+*.lo
+*.la
+.deps
+.libs
diff --git a/libatalk/cnid/db3/Makefile.am b/libatalk/cnid/db3/Makefile.am
new file mode 100644 (file)
index 0000000..f05fe81
--- /dev/null
@@ -0,0 +1,26 @@
+# Makefile.am for libatalk/cnid/
+
+CFLAGS = @CFLAGS@ @BDB_CFLAGS@
+
+noinst_LTLIBRARIES = libcnid_db3.la
+if USE_CDB_BACKEND
+LIBS_db = @BDB_LIBS@
+else
+LIBS_db = 
+endif
+
+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 
+
+libcnid_db3_la_LIBADD = $(LIBS_db)
+
+EXTRA_DIST = README cnid_db3_meta.c cnid_db3_nextid.c
diff --git a/libatalk/cnid/db3/README b/libatalk/cnid/db3/README
new file mode 100644 (file)
index 0000000..b39889b
--- /dev/null
@@ -0,0 +1,35 @@
+the catalog database keeps track of three mappings:
+    CNID     -> dev/ino and did/name
+    dev/ino  -> CNID
+    did/name -> CNID
+
+dev/ino is used to keep track of magically moved files. did/name is
+for quick lookups of CNIDs. 
+
+NOTE: the database will append a nul byte to the end of name. in
+addition, name should be given as it appears on disk. this allows the
+creation of cnid updating/cleaning programs that don't have to deal
+with knowing what the particular codepage is.
+
+here's the ritual:
+       1) open a volume. call cnid_open.
+       2) every time you need a CNID, call cnid_add(). it will
+          automatically look for an existing cnid and add a new one
+          if one isn't already there. you can pass a hint if you
+          want. the only use this has right now is to enable
+          consistency between AFP and HFS. in the future, it would
+          allow people to write conversion utilities that
+          pre-instantiate a database without needing to re-assign
+          CNIDs.
+       3) if you want to just look for a CNID without automatically
+          adding one in, you have two choices:
+            a) cnid_resolve takes a CNID, returns name, and
+               over-writes the CNID given with the parent DID. this
+               is good for FPResolveID.
+             b) cnid_lookup returns a CNID corresponding to the
+               dev/ino,did/name keys. it will auto-update the catalog
+               database if there's a discrepancy. 
+               NOTE: cnid_add calls this before adding a new CNID. 
+       4) when you delete a file or directory, you need to call
+          cnid_delete with the CNID for that file/directory.
+       5) call cnid_close when closing the volume.
diff --git a/libatalk/cnid/db3/cnid_db3.h b/libatalk/cnid/db3/cnid_db3.h
new file mode 100644 (file)
index 0000000..dec9597
--- /dev/null
@@ -0,0 +1,85 @@
+/* 
+ * interface for database access to cnids. i do it this way to abstract
+ * things a bit in case we want to change the underlying implementation.
+ */
+
+#ifndef _ATALK_CNID_DB3__H
+#define _ATALK_CNID_DB3__H 1
+
+#include <sys/cdefs.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <string.h>
+
+#include <netatalk/endian.h>
+#include <atalk/cnid.h>
+
+static __inline__ int db3_txn_abort(DB_TXN *db_txn)
+{
+    int ret;
+#if DB_VERSION_MAJOR >= 4
+    ret = db_txn->abort(db_txn);
+#else
+    ret = txn_abort(db_txn);
+#endif
+    return ret;
+}
+
+/* -------------------- */
+static __inline__ int db3_txn_begin(DB_ENV *db_env, DB_TXN *parent, DB_TXN **db_txn, u_int32_t flags)
+{
+    int ret;
+#if DB_VERSION_MAJOR >= 4
+    ret = db_env->txn_begin(db_env, parent, db_txn, flags);
+#else
+    ret = txn_begin(db_env, paren, db_txn, flags);
+#endif
+    return ret;
+}
+            
+/* -------------------- */
+static __inline__ int db3_txn_commit(DB_TXN *db_txn, u_int32_t flags)
+{
+    int ret;
+#if DB_VERSION_MAJOR >= 4
+    ret = db_txn->commit(db_txn, flags);
+#else
+    ret = txn_commit(db_txn, flags);
+#endif
+    return ret;
+}
+
+/* -----------------------
+   cnid_open.c 
+*/
+extern struct _cnid_module cnid_db3_module;
+extern struct _cnid_db *cnid_db3_open __P((const char *, mode_t));
+
+/* cnid_close.c */
+extern void cnid_db3_close __P((struct _cnid_db *));
+
+/* cnid_add.c */
+extern cnid_t cnid_db3_add __P((struct _cnid_db *, const struct stat *, const cnid_t,
+                           char *, const int, cnid_t));
+
+/* cnid_get.c */
+extern cnid_t cnid_db3_get __P((struct _cnid_db *, const cnid_t, 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,
+                              char *, const int));
+
+/* cnid_update.c */
+extern int cnid_db3_update __P((struct _cnid_db *, const cnid_t, const struct stat *,
+                           const cnid_t, char *, int));
+
+/* cnid_delete.c */
+extern int cnid_db3_delete __P((struct _cnid_db *, const cnid_t));
+
+/* cnid_nextid.c */
+extern cnid_t cnid_db3_nextid __P((struct _cnid_db *));
+
+extern int cnid_db3_lock   __P((void *));
+extern int cnid_db3_unlock __P((void *));
+
+#endif /* include/atalk/cnid_db3.h */
+
diff --git a/libatalk/cnid/db3/cnid_db3_add.c b/libatalk/cnid/db3/cnid_db3_add.c
new file mode 100644 (file)
index 0000000..3879138
--- /dev/null
@@ -0,0 +1,286 @@
+/*
+ * $Id: cnid_db3_add.c,v 1.2 2005-04-28 20:49:59 bfernhomberg 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 */
+
+#ifdef HAVE_DB4_DB_H
+#include <db4/db.h>
+#else
+#include <db.h>
+#endif
+#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, char *name, const int len,
+                cnid_t hint)
+{
+    CNID_private *db;
+    DBT key, data;
+    cnid_t id;
+    int rc;
+
+    if (!cdb || !(db = cdb->_private) || !st || !name) {
+        errno = CNID_ERR_PARAM;
+        return CNID_INVALID;
+    }
+
+    /* Do a lookup. */
+    id = cnid_db3_lookup(cdb, st, did, name, len);
+    /* ... Return id if it is valid, or if Rootinfo is read-only. */
+    if (id || (db->flags & CNIDFLAG_DB_RO)) {
+#ifdef DEBUG
+        LOG(log_info, logtype_default, "cnid_add: Looked up did %u, name %s as %u", ntohl(did), name, ntohl(id));
+#endif
+        return id;
+    }
+
+    /* Initialize our DBT data structures. */
+    memset(&key, 0, sizeof(key));
+    memset(&data, 0, sizeof(data));
+
+    /* Just tickle hint, and the key will change (gotta love pointers). */
+    key.data = &hint;
+    key.size = sizeof(hint);
+
+    if ((data.data = make_cnid_data(st, did, name, len)) == NULL) {
+        LOG(log_error, logtype_default, "cnid_add: Path name is too long");
+        errno = CNID_ERR_PATH;
+        return CNID_INVALID;
+    }
+
+    data.size = CNID_HEADER_LEN + len + 1;
+
+    /* Start off with the hint.  It should be in network byte order.
+     * We need to make sure that somebody doesn't add in restricted
+     * cnid's to the database. */
+    if (ntohl(hint) >= CNID_START) {
+        /* If the key doesn't exist, add it in.  Don't fiddle with nextID. */
+        rc = add_cnid(db, &key, &data);
+        switch (rc) {
+        case DB_KEYEXIST: /* Need to use RootInfo after all. */
+            break;
+        default:
+            LOG(log_error, logtype_default, "cnid_add: Unable to add CNID %u: %s", ntohl(hint), db_strerror(rc));
+            errno = CNID_ERR_DB;
+            return CNID_INVALID;
+        case 0:
+#ifdef DEBUG
+            LOG(log_info, logtype_default, "cnid_add: Used hint for did %u, name %s as %u", ntohl(did), name, ntohl(hint));
+#endif
+            return hint;
+        }
+    }
+    hint = get_cnid(db);
+    if (hint == 0) {
+        errno = CNID_ERR_DB;
+        return CNID_INVALID;
+    }
+    
+    /* Now we need to add the CNID data to the databases. */
+    rc = add_cnid(db, &key, &data);
+    if (rc) {
+        LOG(log_error, logtype_default, "cnid_add: Failed to add CNID for %s to database using hint %u: %s", name, ntohl(hint), db_strerror(rc));
+        errno = CNID_ERR_DB;
+        return CNID_INVALID;
+    }
+
+#ifdef DEBUG
+    LOG(log_info, logtype_default, "cnid_add: Returned CNID for did %u, name %s as %u", ntohl(did), name, ntohl(hint));
+#endif
+
+    return hint;
+}
+
+#endif /* CNID_BACKEND_DB3 */
diff --git a/libatalk/cnid/db3/cnid_db3_close.c b/libatalk/cnid/db3/cnid_db3_close.c
new file mode 100644 (file)
index 0000000..b309c94
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * $Id: cnid_db3_close.c,v 1.2 2005-04-28 20:49:59 bfernhomberg 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>
+#ifdef HAVE_DB4_DB_H
+#include <db4/db.h>
+#else
+#include <db.h>
+#endif
+#include <errno.h>
+#include <string.h>
+
+#include "cnid_db3_private.h"
+#include "cnid_db3.h"
+
+void cnid_db3_close(struct _cnid_db *cdb) {
+    CNID_private *db;
+    int rc;
+
+    if (!cdb) {
+           LOG(log_error, logtype_afpd, "cnid_close called with NULL argument !");
+           return;
+    }
+
+    if (!(db = cdb->_private)) {
+        return;
+    }
+
+    /* Flush the transaction log and delete the log file if we can. */
+    if ((db->lockfd > -1) && ((db->flags & CNIDFLAG_DB_RO) == 0)) {
+        struct flock lock;
+
+    lock.l_type = F_WRLCK;
+    lock.l_whence = SEEK_SET;
+    lock.l_start = lock.l_len = 0;
+    if (fcntl(db->lockfd, F_SETLK, &lock) == 0) {
+            char **list, **first;
+
+
+            /* Checkpoint the databases until we can checkpoint no
+             * more. */
+#if DB_VERSION_MAJOR >= 4
+#if DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 1
+            db->dbenv->txn_checkpoint(db->dbenv, 0, 0, 0);
+#else
+            rc = db->dbenv->txn_checkpoint(db->dbenv, 0, 0, 0);
+#endif /* DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 1 */
+#else
+            rc = txn_checkpoint(db->dbenv, 0, 0, 0);
+#endif /* DB_VERSION_MAJOR >= 4 */
+#if DB_VERSION_MAJOR < 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR < 1)
+            while (rc == DB_INCOMPLETE) {
+#if DB_VERSION_MAJOR >= 4
+                rc = db->dbenv->txn_checkpoint(db->dbenv, 0, 0, 0);
+#else
+                rc = txn_checkpoint(db->dbenv, 0, 0, 0);
+#endif /* DB_VERSION_MAJOR >= 4 */
+            }
+#endif /* DB_VERSION_MAJOR < 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR < 1) */
+
+#if DB_VERSION_MAJOR >= 4
+            if ((rc = db->dbenv->log_archive(db->dbenv, &list, DB_ARCH_ABS)) != 0) {
+#elif DB_VERSION_MINOR > 2
+            if ((rc = log_archive(db->dbenv, &list, DB_ARCH_ABS)) != 0) {
+#else /* DB_VERSION_MINOR < 2 */
+            if ((rc = log_archive(db->dbenv, &list, DB_ARCH_ABS, NULL)) != 0) {
+#endif /* DB_VERSION_MINOR */
+                LOG(log_error, logtype_default, "cnid_close: Unable to archive logfiles: %s", db_strerror(rc));
+            }
+
+            if (list != NULL) {
+                for (first = list; *list != NULL; ++list) {
+                    if ((rc = remove(*list)) != 0) {
+#ifdef DEBUG
+                            LOG(log_info, logtype_default, "cnid_close: failed to remove %s: %s", *list, strerror(rc));
+#endif
+                        }
+                }
+                free(first);
+            }
+        }
+        (void)remove(db->lock_file);
+    }
+
+    db->db_didname->close(db->db_didname, 0);
+    db->db_devino->close(db->db_devino, 0);
+    db->db_cnid->close(db->db_cnid, 0);
+    db->dbenv->close(db->dbenv, 0);
+
+    if (db->lockfd > -1) {
+        close(db->lockfd); /* This will also release any locks we have. */
+    }
+
+    free(db);
+    free(cdb->volpath);
+    free(cdb);
+}
+
+#endif /* CNID_BACKEND_DB3 */
diff --git a/libatalk/cnid/db3/cnid_db3_delete.c b/libatalk/cnid/db3/cnid_db3_delete.c
new file mode 100644 (file)
index 0000000..ffebf69
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+ * $Id: cnid_db3_delete.c,v 1.2 2005-04-28 20:49:59 bfernhomberg 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>
+
+#ifdef HAVE_DB4_DB_H
+#include <db4/db.h>
+#else
+#include <db.h>
+#endif
+#include <netatalk/endian.h>
+#include <atalk/adouble.h>
+#include "cnid_db3.h"
+
+#include "cnid_db3_private.h"
+
+int cnid_db3_delete(struct _cnid_db *cdb, const cnid_t id) {
+    CNID_private *db;
+    DBT key, data;
+    DB_TXN *tid;
+    int rc, found = 0;
+
+    if (!cdb || !(db = cdb->_private) || !id || (db->flags & CNIDFLAG_DB_RO)) {
+        return -1;
+    }
+
+    memset(&key, 0, sizeof(key));
+    memset(&data, 0, sizeof(data));
+
+    /* Get from ain CNID database. */
+    key.data = (cnid_t *)&id;
+    key.size = sizeof(id);
+    while (!found) {
+        rc = db->db_cnid->get(db->db_cnid, NULL, &key, &data, 0);
+        switch (rc) {
+        case 0:
+            found = 1;
+            break;
+        case DB_LOCK_DEADLOCK:
+            break;
+        case DB_NOTFOUND:
+#ifdef DEBUG
+            LOG(log_info, logtype_default, "cnid_delete: CNID %u not in database",
+                ntohl(id));
+#endif
+            return 0;
+        default:
+            LOG(log_error, logtype_default, "cnid_delete: Unable to delete entry: %s",
+                db_strerror(rc));
+            return rc;
+        }
+    }
+
+retry:
+    if ((rc = db3_txn_begin(db->dbenv, NULL, &tid, 0)) != 0) {
+        LOG(log_error, logtype_default, "cnid_delete: Failed to begin transaction: %s",
+            db_strerror(rc));
+        return rc;
+    }
+
+    /* Now delete from the main CNID database. */
+    key.data = (cnid_t *)&id;
+    key.size = sizeof(id);
+    if ((rc = db->db_cnid->del(db->db_cnid, tid, &key, 0))) {
+        int ret;
+        if ((ret = db3_txn_abort(tid)) != 0) {
+            LOG(log_error, logtype_default, "cnid_delete: txn_abort: %s", db_strerror(ret));
+            return ret;
+        }
+        switch (rc) {
+        case DB_LOCK_DEADLOCK:
+            goto retry;
+        default:
+            goto abort_err;
+        }
+    }
+
+    /* Now delete from dev/ino database. */
+    key.data = data.data;
+    key.size = CNID_DEVINO_LEN;
+    if ((rc = db->db_devino->del(db->db_devino, tid, &key, 0))) {
+        switch (rc) {
+        case DB_LOCK_DEADLOCK:
+            if ((rc = db3_txn_abort(tid)) != 0) {
+                LOG(log_error, logtype_default, "cnid_delete: txn_abort: %s",
+                    db_strerror(rc));
+                return rc;
+            }
+            goto retry;
+        case DB_NOTFOUND:
+            /* Quietly fall through if the entry isn't found. */
+            break;
+        default:
+            if ((rc = db3_txn_abort(tid)) != 0) {
+                LOG(log_error, logtype_default, "cnid_delete: txn_abort: %s",
+                    db_strerror(rc));
+                return rc;
+            }
+            goto abort_err;
+        }
+    }
+
+    /* Get data from the did/name database.
+     * TODO Also handle did/macname, did/shortname, and did/longname. */
+    key.data = (char *)data.data + CNID_DEVINO_LEN;
+    key.size = data.size - CNID_DEVINO_LEN;
+    if ((rc = db->db_didname->del(db->db_didname, tid, &key, 0))) {
+        switch (rc) {
+        case DB_LOCK_DEADLOCK:
+            if ((rc = db3_txn_abort(tid)) != 0) {
+                LOG(log_error, logtype_default, "cnid_delete: txn_abort: %s",
+                    db_strerror(rc));
+                return rc;
+            }
+            goto retry;
+        case DB_NOTFOUND:
+            break;
+        default:
+            if ((rc = db3_txn_abort(tid)) != 0) {
+                LOG(log_error, logtype_default, "cnid_delete: txn_abort: %s",
+                    db_strerror(rc));
+                return rc;
+            }
+            goto abort_err;
+        }
+    }
+
+#ifdef DEBUG
+    LOG(log_info, logtype_default, "cnid_delete: Deleting CNID %u", ntohl(id));
+#endif
+    if ((rc = db3_txn_commit(tid, 0)) != 0) {
+        LOG(log_error, logtype_default, "cnid_delete: Failed to commit transaction: %s",
+            db_strerror(rc));
+        return rc;
+    }
+    return 0;
+
+abort_err:
+    LOG(log_error, logtype_default, "cnid_delete: Unable to delete CNID %u: %s",
+        ntohl(id), db_strerror(rc));
+    return rc;
+}
+
+#endif /* CNID_BACKEND_DB3 */
diff --git a/libatalk/cnid/db3/cnid_db3_get.c b/libatalk/cnid/db3/cnid_db3_get.c
new file mode 100644 (file)
index 0000000..6657ecf
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * $Id: cnid_db3_get.c,v 1.2 2005-04-28 20:49:59 bfernhomberg 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>
+
+#ifdef HAVE_DB4_DB_H
+#include <db4/db.h>
+#else
+#include <db.h>
+#endif
+#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, char *name,
+                const int len)
+{
+    char start[CNID_DID_LEN + MAXPATHLEN + 1], *buf;
+    CNID_private *db;
+    DBT key, data;
+    cnid_t id;
+    int rc;
+
+    if (!cdb || !(db = cdb->_private) || (len > MAXPATHLEN)) {
+        // FIXME: shall we report some error !
+        return 0;
+    }
+
+    memset(&key, 0, sizeof(key));
+    memset(&data, 0, sizeof(data));
+
+    buf = start;
+    memcpy(buf, &did, sizeof(did));
+    buf += sizeof(did);
+    memcpy(buf, name, len);
+    *(buf + len) = '\0'; /* Make it a C-string. */
+    key.data = start;
+    key.size = CNID_DID_LEN + len + 1;
+
+    while ((rc = db->db_didname->get(db->db_didname, NULL, &key, &data, 0))) {
+        if (rc == DB_LOCK_DEADLOCK) {
+            continue;
+        }
+
+        if (rc != DB_NOTFOUND) {
+            LOG(log_error, logtype_default, "cnid_get: Unable to get CNID %u, name %s: %s",
+                ntohl(did), name, db_strerror(rc));
+        }
+
+        return 0;
+    }
+
+    memcpy(&id, data.data, sizeof(id));
+#ifdef DEBUG
+    LOG(log_info, logtype_default, "cnid_get: Returning CNID for %u, name %s as %u",
+        ntohl(did), name, ntohl(id));
+#endif
+    return id;
+}
+
+#endif /* CNID_BACKEND_DB3 */
diff --git a/libatalk/cnid/db3/cnid_db3_lookup.c b/libatalk/cnid/db3/cnid_db3_lookup.c
new file mode 100644 (file)
index 0000000..cd4d78d
--- /dev/null
@@ -0,0 +1,148 @@
+
+/*
+ * $Id: cnid_db3_lookup.c,v 1.2 2005-04-28 20:49:59 bfernhomberg 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>
+
+#ifdef HAVE_DB4_DB_H
+#include <db4/db.h>
+#else
+#include <db.h>
+#endif
+#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, char *name, const int len)
+{
+    char *buf;
+    CNID_private *db;
+    DBT key, devdata, diddata;
+    int devino = 1, didname = 1;
+    cnid_t id = 0;
+    int rc;
+
+    if (!cdb || !(db = cdb->_private) || !st || !name) {
+        return 0;
+    }
+
+    /* Do a little checkpointing if necessary.  I stuck it here as cnid_lookup
+     * gets called when we do directory lookups.  Only do this if we're using
+     * a read-write database. */
+    if ((db->flags & CNIDFLAG_DB_RO) == 0) {
+#ifdef DEBUG
+        LOG(log_info, logtype_default, "cnid_lookup: Running database checkpoint");
+#endif
+#if DB_VERSION_MAJOR > 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 1)
+        if ((rc = db->dbenv->txn_checkpoint(db->dbenv, LOGFILEMAX, CHECKTIMEMAX, 0))) {
+            LOG(log_error, logtype_default, "cnid_lookup: txn_checkpoint: %s", db_strerror(rc));
+            return 0;
+        }
+#else
+#if DB_VERSION_MAJOR >= 4
+        switch (rc = db->dbenv->txn_checkpoint(db->dbenv, LOGFILEMAX, CHECKTIMEMAX, 0)) {
+#else
+        switch (rc = txn_checkpoint(db->dbenv, LOGFILEMAX, CHECKTIMEMAX, 0)) {
+#endif /* DB_VERSION_MAJOR >= 4 */
+        case 0:
+        case DB_INCOMPLETE:
+            break;
+        default:
+            LOG(log_error, logtype_default, "cnid_lookup: txn_checkpoint: %s", db_strerror(rc));
+            return 0;
+        }
+#endif /* DB_VERSION_MAJOR > 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 1) */
+    }
+
+    if ((buf = make_cnid_data(st, did, name, len)) == NULL) {
+        LOG(log_error, logtype_default, "cnid_lookup: Pathname is too long");
+        return 0;
+    }
+
+    memset(&key, 0, sizeof(key));
+    memset(&devdata, 0, sizeof(devdata));
+    memset(&diddata, 0, sizeof(diddata));
+
+    /* Look for a CNID.  We have two options: dev/ino or did/name.  If we
+     * only get a match in one of them, that means a file has moved. */
+    key.data = buf;
+    key.size = CNID_DEVINO_LEN;
+    while ((rc = db->db_devino->get(db->db_devino, NULL, &key, &devdata, 0))) {
+        if (rc == DB_LOCK_DEADLOCK) {
+            continue;
+        }
+
+        if (rc == DB_NOTFOUND) {
+            devino = 0;
+            break;
+        }
+
+        LOG(log_error, logtype_default, "cnid_lookup: Unable to get CNID dev %u, ino %u: %s",
+            st->st_dev, st->st_ino, db_strerror(rc));
+        return 0;
+    }
+
+    /* did/name now */
+    key.data = buf + CNID_DEVINO_LEN;
+    key.size = CNID_DID_LEN + len + 1;
+    while ((rc = db->db_didname->get(db->db_didname, NULL, &key, &diddata, 0))) {
+        if (rc == DB_LOCK_DEADLOCK) {
+            continue;
+        }
+
+        if (rc == DB_NOTFOUND) {
+            didname = 0;
+            break;
+        }
+
+        LOG(log_error, logtype_default, "cnid_lookup: Unable to get CNID %u, name %s: %s",
+            ntohl(did), name, db_strerror(rc));
+        return 0;
+    }
+
+    /* Set id.  Honor did/name over dev/ino as dev/ino isn't necessarily
+     * 1-1. */
+    if (didname) {
+        memcpy(&id, diddata.data, sizeof(id));
+    } else if (devino) {
+        memcpy(&id, devdata.data, sizeof(id));
+    }
+
+    /* Either entries are in both databases or neither of them. */
+    if ((devino && didname) || !(devino || didname)) {
+#ifdef DEBUG
+        LOG(log_info, logtype_default, "cnid_lookup: Looked up did %u, name %s, as %u", ntohl(did), name, ntohl(id));
+#endif
+        return id;
+    }
+
+    /* Fix up the database. */
+    cnid_db3_update(cdb, id, st, did, name, len);
+#ifdef DEBUG
+    LOG(log_info, logtype_default, "cnid_lookup: Looked up did %u, name %s, as %u (needed update)", ntohl(did), name,
+        ntohl(id));
+#endif
+    return id;
+}
+
+
+#endif /* CNID_BACKEND_DB3 */
diff --git a/libatalk/cnid/db3/cnid_db3_meta.c b/libatalk/cnid/db3/cnid_db3_meta.c
new file mode 100644 (file)
index 0000000..5b51ce5
--- /dev/null
@@ -0,0 +1,9 @@
+/*
+ * $Id: cnid_db3_meta.c,v 1.2 2005-04-28 20:49:59 bfernhomberg Exp $
+ *
+ * Copyright (c) 1999. Adrian Sun (asun@zoology.washington.edu)
+ * All Rights Reserved. See COPYRIGHT.
+ *
+ * deal with metadata
+ *
+ */
diff --git a/libatalk/cnid/db3/cnid_db3_meta.h b/libatalk/cnid/db3/cnid_db3_meta.h
new file mode 100644 (file)
index 0000000..f2426b5
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * $Id: cnid_db3_meta.h,v 1.2 2005-04-28 20:49:59 bfernhomberg Exp $
+ */
+
+#define CNID_META_CNID_LEN      4
+#define CNID_META_MDATE_LEN     4  /* space for 8 */
+#define CNID_META_CDATE_LEN     4  /* space for 8 */
+#define CNID_META_BDATE_LEN     4  /* ditto */
+#define CNID_META_ADATE_LEN     4  /* ditto */
+#define CNID_META_AFPI_LEN      4  /* plus permission bits */
+#define CNID_META_FINDERI_LEN   32 
+#define CNID_META_PRODOSI_LEN   8
+#define CNID_META_RFORKLEN_LEN  4  /* space for 8 */
+#define CNID_META_MACNAME_LEN   32 /* maximum size */
+#define CNID_META_SHORTNAME_LEN 12 /* max size (8.3) */
+#define CNID_META_FILLER_LEN    4
+
+#define CNID_META_CNID_OFF     0
+#define CNID_META_MDATE_OFF    (CNID_META_CNID_OFF + CNID_META_CNID_LEN + \
+                               CNID_META_FILLER_LEN)
+#define CNID_META_CDATE_OFF    (CNID_META_MDATE_OFF + CNID_META_MDATE_LEN + \
+                               CNID_META_FILLER_LEN)
+#define CNID_META_BDATE_OFF    (CNID_META_CDATE_OFF + CNID_META_CDATE_LEN + \
+                               CNID_META_FILLER_LEN)
+#define CNID_META_ADATE_OFF    (CNID_META_BDATE_OFF + CNID_META_BDATE_LEN + \
+                               CNID_META_FILLER_LEN)
+#define CNID_META_AFPI_OFF     (CNID_META_ADATE_OFF + CNID_META_ADATE_LEN)
+#define CNID_META_FINDERI_OFF  (CNID_META_AFPI_OFF + CNID_META_AFPI_LEN)
+#define CNID_META_PRODOSI_OFF  (CNID_META_FINDERI_OFF + CNID_META_FINDERI_LEN)
+#define CNID_META_RFORKLEN_OFF (CNID_META_PRODOSI_OFF + CNID_META_PRODOSI_LEN)
+#define CNID_META_MACNAME_OFF  (CNID_META_RFORKLEN_OFF + \
+                               CNID_META_RFORKLEN_LEN)
+#define CNID_META_SHORTNAME_OFF (CNID_META_MACNAME_OFF + 
+
+
+#define cnid_meta_clear(a)  
+#define cnid_meta_get(id)
+
+#define cnid_meta_cnid(a)  
+#define cnid_meta_modifydate(a)
+#define cnid_meta_createdate(a)
+#define cnid_meta_backupdate(a)
+#define cnid_meta_accessdate(a)
+#define cnid_meta_afpi(a)
+#define cnid_meta_finderi(a)
+#define cnid_meta_prodosi(a)
+#define cnid_meta_rforklen(a)
+#define cnid_meta_macname(a)
+#define cnid_meta_shortname(a)
+#define cnid_meta_longname(a)
+
diff --git a/libatalk/cnid/db3/cnid_db3_nextid.c b/libatalk/cnid/db3/cnid_db3_nextid.c
new file mode 100644 (file)
index 0000000..bf6115a
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * $Id: cnid_db3_nextid.c,v 1.2 2005-04-28 20:49:59 bfernhomberg Exp $
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#ifdef CNID_BACKEND_DB3
+
+#ifdef unused
+
+#ifdef HAVE_DB4_DB_H
+#include <db4/db.h>
+#else
+#include <db.h>
+#endif
+
+#include <atalk/adouble.h>
+#include "cnid_db3.h"
+
+#include <atalk/logger.h>
+
+#include "cnid_db3_private.h"
+
+/* return the next id. we use the fact that ad files are memory
+ * mapped. */
+cnid_t cnid_db3_nextid(struct _cnid_db *cdb)
+{
+    CNID_private *db;
+    cnid_t id;
+
+    if (!cdb || !(db = cdb->_private))
+        return 0;
+
+    memcpy(&id, ad_entry(&db->rootinfo, ADEID_DID), sizeof(id));
+    return id;
+}
+#endif
+
+#endif /* CNID_BACKEND_DB3 */
diff --git a/libatalk/cnid/db3/cnid_db3_open.c b/libatalk/cnid/db3/cnid_db3_open.c
new file mode 100644 (file)
index 0000000..824df3b
--- /dev/null
@@ -0,0 +1,518 @@
+
+/*
+ * $Id: cnid_db3_open.c,v 1.2 2005-04-28 20:49:59 bfernhomberg 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 */
+
+#ifdef HAVE_DB4_DB_H
+#include <db4/db.h>
+#else
+#include <db.h>
+#endif
+
+#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;
+
+    /* Print out the version of BDB we're linked against. */
+    LOG(log_info, logtype_default, "CNID DB initializing using %s", db_version(NULL, NULL, NULL));
+
+    /* 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_BTREE, 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_BTREE, 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_BTREE, open_flag, 0666 & ~mask))) {
+        LOG(log_error, logtype_default, "cnid_open: Failed to open dev/ino database: %s", db_strerror(rc));
+        goto fail_appinit;
+    }
+
+#if 0
+    db_env_set_func_yield(my_yield);
+#endif
+    return cdb;
+
+  fail_appinit:
+    if (db->db_didname)
+        db->db_didname->close(db->db_didname, 0);
+    if (db->db_devino)
+        db->db_devino->close(db->db_devino, 0);
+    if (db->db_cnid)
+        db->db_cnid->close(db->db_cnid, 0);
+    LOG(log_error, logtype_default, "cnid_open: Failed to setup CNID DB environment");
+    db->dbenv->close(db->dbenv, 0);
+
+  fail_lock:
+    if (db->lockfd > -1) {
+        close(db->lockfd);
+        (void) remove(db->lock_file);
+    }
+
+  fail_adouble:
+
+  fail_db:
+    free(db);
+
+  fail_cdb:
+    if (cdb->volpath != NULL)
+        free(cdb->volpath);
+    free(cdb);
+
+    return NULL;
+}
+
+struct _cnid_module cnid_db3_module = {
+    "db3",
+    {NULL, NULL},
+    cnid_db3_open,
+    CNID_FLAG_BLOCK
+};
+
+#endif /* CNID_BACKEND_DB3 */
diff --git a/libatalk/cnid/db3/cnid_db3_private.h b/libatalk/cnid/db3/cnid_db3_private.h
new file mode 100644 (file)
index 0000000..f39b9ac
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ * $Id: cnid_db3_private.h,v 1.2 2005-04-28 20:50:00 bfernhomberg 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 <sys/cdefs.h>
+#include <db.h>
+
+#include <atalk/adouble.h>
+#include "cnid_db3.h"
+
+#define CNID_DB_MAGIC   0x434E4944U  /* CNID */
+#define CNID_DATA_MAGIC 0x434E4945U  /* CNIE */
+
+#define CNID_DEVINO_LEN          8
+#define CNID_DID_LEN             4
+#define CNID_HEADER_LEN          (CNID_DEVINO_LEN + CNID_DID_LEN)
+
+#define CNID_START               17
+
+#define CNIDFLAG_ROOTINFO_RO     (1 << 0)
+#define CNIDFLAG_DB_RO           (1 << 1)
+
+/* the key is in the form of a did/name pair. in this case,
+ * we use 0/RootInfo. */
+#define ROOTINFO_KEY    "\0\0\0\0RootInfo"
+#define ROOTINFO_KEYLEN 12
+
+typedef struct CNID_private {
+    u_int32_t magic;
+    DB *db_cnid;
+    DB *db_didname;
+    DB *db_devino;
+    DB_ENV *dbenv;
+    int lockfd, flags;
+    char lock_file[MAXPATHLEN + 1];
+} CNID_private;
+
+/* on-disk data format (in network byte order where appropriate) --
+ * db_cnid:      (key: cnid)
+ * name          size (in bytes)
+ * dev           4
+ * ino           4
+ * did           4
+ * unix name     strlen(name) + 1 
+ *
+ * db_didname:   (key: did/unix name)
+ * -- this also caches the bits of .AppleDouble used by FPGetFilDirParam
+ *    so that we don't have to open the header file.
+ *    NOTE: FPCatSearch has to search through all of the directories as
+ *          this stuff doesn't get entered until needed.
+ *          if the entire volume is in the database, though, we can use
+ *          cursor operations to make this faster.
+ *
+ *    version number is stored with did/name key of 0/0
+ *
+ * cnid          4
+ * modfiller     4 (dates only use 4 bytes right now, but we leave space 
+ * moddate       4  for 8. moddate is also used to keep this info 
+ * createfiller  4  up-to-date.)
+ * createdate    4
+ * backfiller    4
+ * backupdate    4
+ * accfiller     4 (unused)
+ * accdate       4 (unused)
+ * AFP info      4 (stores a couple permission bits as well)
+ * finder info   32
+ * prodos info   8
+ * rforkfiller   4
+ * rforklen      4
+ * macname       32 (nul-terminated)
+ * shortname     12 (nul-terminated)
+ * longname      longnamelen (nul-terminated)
+ * ---------------
+ *             132 bytes + longnamelen
+ * 
+ * db_devino:    (key: dev/ino) 
+ * -- this is only used for consistency checks and isn't 1-1
+ * cnid          4 
+ *
+ * these correspond to the different path types. longname is for the
+ * 255 unicode character names (path type == ?), macname is for the
+ * 32-character names (path type == 2), and shortname is for the
+ * 8+3-character names (path type == 1).
+ *
+ * db_longname: (key: did/longname)
+ * name          namelen = strlen(name) + 1
+ *
+ * db_macname:   (key: did/macname)
+ * name          namelen = strlen(name) + 1
+ *
+ * db_shortname: (key: did/shortname)
+ * name namelen = strlen(name) + 1 
+ */
+
+#ifndef __inline__
+#define __inline__
+#endif /* __inline__ */
+
+/* construct db_cnid data. NOTE: this is not re-entrant.  */
+static __inline__ char *make_cnid_data(const struct stat *st,
+                                       const cnid_t did,
+                                       const char *name, const int len)
+{
+    static char start[CNID_HEADER_LEN + MAXPATHLEN + 1];
+    char *buf = start;
+    u_int32_t i;
+
+    if (len > MAXPATHLEN)
+        return NULL;
+
+    i = htonl(st->st_dev);
+    buf = memcpy(buf, &i, sizeof(i));
+    i = htonl(st->st_ino);
+    buf = memcpy(buf + sizeof(i), &i, sizeof(i));
+    /* did is already in network byte order */
+    buf = memcpy(buf + sizeof(i), &did, sizeof(did));
+    buf = memcpy(buf + sizeof(did), name, len);
+    *(buf + len) = '\0';
+    buf += len + 1;
+
+    return start;
+}
+
+#endif /* atalk/cnid/cnid_private.h */
diff --git a/libatalk/cnid/db3/cnid_db3_resolve.c b/libatalk/cnid/db3/cnid_db3_resolve.c
new file mode 100644 (file)
index 0000000..987a8f4
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * $Id: cnid_db3_resolve.c,v 1.2 2005-04-28 20:50:00 bfernhomberg 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>
+
+#ifdef HAVE_DB4_DB_H
+#include <db4/db.h>
+#else
+#include <db.h>
+#endif
+#include <netatalk/endian.h>
+#include <atalk/adouble.h>
+#include "cnid_db3.h"
+
+#include "cnid_db3_private.h"
+
+/* Return the did/name pair corresponding to a CNID. */
+char *cnid_db3_resolve(struct _cnid_db *cdb, cnid_t *id, void *buffer, u_int32_t len) {
+    CNID_private *db;
+    DBT key, data;
+    int rc;
+
+    if (!cdb || !(db = cdb->_private) || !id || !(*id)) {
+        return NULL;
+    }
+
+    memset(&key, 0, sizeof(key));
+    memset(&data, 0, sizeof(data));
+
+    data.data = buffer;
+    data.ulen = len;
+    data.flags = DB_DBT_USERMEM;
+
+    key.data = id;
+    key.size = sizeof(cnid_t);
+    while ((rc = db->db_cnid->get(db->db_cnid, NULL, &key, &data, 0))) {
+        if (rc == DB_LOCK_DEADLOCK) {
+            continue;
+        }
+
+        if (rc != DB_NOTFOUND) {
+            LOG(log_error, logtype_default, "cnid_resolve: Unable to get did/name: %s",
+                db_strerror(rc));
+        }
+
+        *id = 0;
+        return NULL;
+    }
+
+    memcpy(id, (char *)data.data + CNID_DEVINO_LEN, sizeof(cnid_t));
+#ifdef DEBUG
+    LOG(log_info, logtype_default, "cnid_resolve: Returning id = %u, did/name = %s",
+        ntohl(*id), (char *)data.data + CNID_HEADER_LEN);
+#endif
+    return (char *)data.data + CNID_HEADER_LEN;
+}
+
+#endif /* CNID_BACKEND_DB3 */
diff --git a/libatalk/cnid/db3/cnid_db3_update.c b/libatalk/cnid/db3/cnid_db3_update.c
new file mode 100644 (file)
index 0000000..eb7dc2d
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+ * $Id: cnid_db3_update.c,v 1.2 2005-04-28 20:50:00 bfernhomberg 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>
+
+#ifdef HAVE_DB4_DB_H
+#include <db4/db.h>
+#else
+#include <db.h>
+#endif
+#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, char *name, const int len
+                /*, const char *info, const int infolen*/)
+{
+    CNID_private *db;
+    DBT key, data, altdata;
+    DB_TXN *tid;
+    int rc;
+
+    if (!cdb || !(db = cdb->_private) || !id || !st || !name || (db->flags & CNIDFLAG_DB_RO)) {
+        return -1;
+    }
+
+    memset(&key, 0, sizeof(key));
+    memset(&altdata, 0, sizeof(altdata));
+
+retry:
+    if ((rc = db3_txn_begin(db->dbenv, NULL, &tid, 0))) {
+        LOG(log_error, logtype_default, "cnid_update: Failed to begin transaction: %s", db_strerror(rc));
+        return rc;
+    }
+
+    /* Get the old info. */
+    key.data = (cnid_t *)&id;
+    key.size = sizeof(id);
+    memset(&data, 0, sizeof(data));
+    if ((rc = db->db_cnid->get(db->db_cnid, tid, &key, &data, DB_RMW))) {
+        db3_txn_abort(tid);
+        switch (rc) {
+        case DB_LOCK_DEADLOCK:
+            goto retry;
+        case DB_NOTFOUND:
+            /* Silently fail here.  We're allowed to do this since this CNID
+             * might have been deleted out from under us, or someone has
+             * called cnid_lookup then cnid_update (which is redundant). */
+            return 0;
+        default:
+            goto update_err;
+        }
+    }
+
+    /* Delete the old dev/ino mapping. */
+    key.data = data.data;
+    key.size = CNID_DEVINO_LEN;
+    if ((rc = db->db_devino->del(db->db_devino, tid, &key, 0))) {
+        switch (rc) {
+        case DB_LOCK_DEADLOCK:
+            db3_txn_abort(tid);
+            goto retry;
+        case DB_NOTFOUND:
+            break;
+        default:
+            db3_txn_abort(tid);
+            goto update_err;
+        }
+    }
+
+    /* Delete the old did/name mapping. */
+    key.data = (char *) data.data + CNID_DEVINO_LEN;
+    key.size = data.size - CNID_DEVINO_LEN;
+    if ((rc = db->db_didname->del(db->db_didname, tid, &key, 0))) {
+        switch (rc) {
+        case DB_LOCK_DEADLOCK:
+            db3_txn_abort(tid);
+            goto retry;
+        case DB_NOTFOUND:
+            break;
+        default:
+            db3_txn_abort(tid);
+            goto update_err;
+        }
+    }
+
+    /* Make a new entry. */
+    data.data = make_cnid_data(st, did, name, len);
+    data.size = CNID_HEADER_LEN + len + 1;
+
+    /* Update the old CNID with the new info. */
+    key.data = (cnid_t *) &id;
+    key.size = sizeof(id);
+    if ((rc = db->db_cnid->put(db->db_cnid, tid, &key, &data, 0))) {
+        db3_txn_abort(tid);
+        switch (rc) {
+        case DB_LOCK_DEADLOCK:
+            goto retry;
+        default:
+            goto update_err;
+        }
+    }
+
+    /* Put in a new dev/ino mapping. */
+    key.data = data.data;
+    key.size = CNID_DEVINO_LEN;
+    altdata.data = (cnid_t *) &id;
+    altdata.size = sizeof(id);
+    if ((rc = db->db_devino->put(db->db_devino, tid, &key, &altdata, 0))) {
+        db3_txn_abort(tid);
+        switch (rc) {
+        case DB_LOCK_DEADLOCK:
+            goto retry;
+        default:
+            goto update_err;
+        }
+    }
+
+    /* put in a new did/name mapping. */
+    key.data = (char *) data.data + CNID_DEVINO_LEN;
+    key.size = data.size - CNID_DEVINO_LEN;
+    if ((rc = db->db_didname->put(db->db_didname, tid, &key, &altdata, 0))) {
+        db3_txn_abort(tid);
+        switch (rc) {
+        case DB_LOCK_DEADLOCK:
+            goto retry;
+        default:
+            goto update_err;
+        }
+    }
+
+
+    return db3_txn_commit(tid, 0);
+
+update_err:
+    LOG(log_error, logtype_default, "cnid_update: Unable to update CNID %u: %s",
+        ntohl(id), db_strerror(rc));
+    return -1;
+}
+
+#endif /* CNID_BACKEND_DB3 */
diff --git a/libatalk/cnid/dbd/.cvsignore b/libatalk/cnid/dbd/.cvsignore
new file mode 100644 (file)
index 0000000..0d0371d
--- /dev/null
@@ -0,0 +1,6 @@
+Makefile
+Makefile.in
+*.lo
+*.la
+.deps
+.libs
diff --git a/libatalk/cnid/dbd/Makefile.am b/libatalk/cnid/dbd/Makefile.am
new file mode 100644 (file)
index 0000000..ecbaa0f
--- /dev/null
@@ -0,0 +1,6 @@
+# Makefile.am for libatalk/cnid/
+
+noinst_LTLIBRARIES = libcnid_dbd.la
+
+libcnid_dbd_la_SOURCES = cnid_dbd.c cnid_dbd.h
+
diff --git a/libatalk/cnid/dbd/cnid_dbd.c b/libatalk/cnid/dbd/cnid_dbd.c
new file mode 100644 (file)
index 0000000..07a601e
--- /dev/null
@@ -0,0 +1,888 @@
+/*
+ * $Id: cnid_dbd.c,v 1.2 2005-04-28 20:50:00 bfernhomberg Exp $
+ *
+ * Copyright (C) Joerg Lenneis 2003
+ * All Rights Reserved.  See COPYING.
+ */
+
+#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 */
+#ifdef HAVE_SYS_UIO_H
+#include <sys/uio.h>
+#endif /* HAVE_SYS_UIO_H */
+#ifdef HAVE_STRINGS_H
+#include <strings.h>
+#endif
+#include <sys/time.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 <time.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>
+
+#ifndef SOL_TCP
+#define SOL_TCP IPPROTO_TCP
+#endif /* ! SOL_TCP */
+
+static void RQST_RESET(struct cnid_dbd_rqst  *r) 
+{ 
+   memset(r, 0, sizeof(struct cnid_dbd_rqst ));
+}
+
+/* ----------- */
+extern char             Cnid_srv[MAXHOSTNAMELEN + 1];
+extern int              Cnid_port;
+
+static int tsock_getfd(char *host, int port)
+{
+int sock;
+struct sockaddr_in server;
+struct hostent* hp;
+int attr;
+int err;
+
+    server.sin_family=AF_INET;
+    server.sin_port=htons((unsigned short)port);
+    if (!host) {
+        LOG(log_error, logtype_cnid, "getfd: -cnidserver not defined");
+        return -1;
+    }
+    
+    hp=gethostbyname(host);
+    if (!hp) {
+       unsigned long int addr=inet_addr(host);
+       LOG(log_warning, logtype_cnid, "getfd: Could not resolve host %s, trying numeric address instead", host);
+        if (addr!= (unsigned)-1)
+            hp=gethostbyaddr((char*)addr,sizeof(addr),AF_INET);
+       if (!hp) {
+           LOG(log_error, logtype_cnid, "getfd: Could not resolve host %s", host);
+           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) {
+       LOG(log_error, logtype_cnid, "getfd: socket %s: %s", host, strerror(errno));
+       return(-1);
+    }
+    attr = 1;
+    if (setsockopt(sock, SOL_TCP, TCP_NODELAY, &attr, sizeof(attr)) == -1) {
+       LOG(log_error, logtype_cnid, "getfd: set TCP_NODELAY %s: %s", host, strerror(errno));
+       close(sock);
+       return(-1);
+    }
+    if(connect(sock ,(struct sockaddr*)&server,sizeof(server))==-1) {
+        struct timeval tv;
+        err = errno;
+       close(sock);
+       sock=-1;
+       LOG(log_error, logtype_cnid, "getfd: connect %s: %s", host, strerror(err));
+        switch (err) {
+        case ENETUNREACH:
+        case ECONNREFUSED: 
+            
+            tv.tv_usec = 0;
+            tv.tv_sec  = 5;
+            select(0, NULL, NULL, NULL, &tv);
+            break;
+        }
+    }
+    return(sock);
+}
+
+/* --------------------- */
+static int write_vec(int fd, struct iovec *iov, size_t towrite)
+{
+    ssize_t len;
+    size_t len1;
+    
+    len1 =  iov[1].iov_len;
+    while (towrite > 0) {
+        if (((len = writev(fd, iov, 2)) == -1 && errno == EINTR) || !len)
+            continue;
+        if ((size_t)len == towrite) /* wrote everything out */
+            break;
+        else if (len < 0) { /* error */
+            return -1;
+        }
+        towrite -= len;
+        if (towrite > len1) { /* 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 init_tsock(CNID_private *db)
+{
+    int fd;
+    int len;
+    struct iovec iov[2];
+    
+    if ((fd = tsock_getfd(Cnid_srv, Cnid_port)) < 0) 
+        return -1;
+
+    len = strlen(db->db_dir);
+
+    iov[0].iov_base = &len;
+    iov[0].iov_len  = sizeof(int);
+
+    iov[1].iov_base = db->db_dir;
+    iov[1].iov_len  = len;
+
+    if (write_vec(fd, iov, len + sizeof(int)) < 0) {
+        LOG(log_error, logtype_cnid, "init_tsock: Error/short write: %s", strerror(errno));
+        close(fd);
+        return -1;
+    }
+    return fd;
+}
+
+/* --------------------- */
+static int send_packet(CNID_private *db, struct cnid_dbd_rqst *rqst, int silent)
+{
+    struct iovec iov[2];
+    size_t towrite;
+  
+    
+    if (!rqst->namelen) {
+        if (write(db->fd, rqst, sizeof(struct cnid_dbd_rqst)) != sizeof(struct cnid_dbd_rqst)) {
+           if (!silent)
+               LOG(log_warning, logtype_cnid, "send_packet: Error/short write rqst (db_dir %s): %s", 
+                   db->db_dir, strerror(errno));
+            return -1;
+        }
+        return 0;
+    }
+
+    iov[0].iov_base = rqst;
+    iov[0].iov_len  = sizeof(struct cnid_dbd_rqst);
+
+    iov[1].iov_base = rqst->name;
+    iov[1].iov_len  = rqst->namelen;
+
+    towrite = sizeof(struct cnid_dbd_rqst) +rqst->namelen;
+
+    if (write_vec(db->fd, iov, towrite) < 0) {
+       if (!silent)
+           LOG(log_warning, logtype_cnid, "send_packet: Error writev rqst (db_dir %s): %s", 
+                     db->db_dir, strerror(errno));
+       return -1;            
+    }
+
+    return 0;
+}
+
+/* ------------------- */
+static void dbd_initstamp(struct cnid_dbd_rqst *rqst)
+{
+    RQST_RESET(rqst);
+    rqst->op = CNID_DBD_OP_GETSTAMP;
+}
+
+/* ------------------- */
+static int dbd_reply_stamp(struct cnid_dbd_rply *rply)
+{
+    switch (rply->result) {
+    case CNID_DBD_RES_OK:
+        break;
+    case CNID_DBD_RES_NOTFOUND:
+        return -1;
+    case CNID_DBD_RES_ERR_DB:
+    default:
+        errno = CNID_ERR_DB;
+        return -1;
+    }
+    return 0;
+}
+
+/* --------------------- 
+ * send a request and get reply
+ * assume send is non blocking
+ * if no answer after sometime (at least MAX_DELAY secondes) return an error
+*/
+#define MAX_DELAY 40
+static int dbd_rpc(CNID_private *db, struct cnid_dbd_rqst *rqst, struct cnid_dbd_rply *rply, int silent)
+{
+    ssize_t ret;
+    char *nametmp;
+    struct timeval tv;
+    fd_set readfds;
+    int    maxfd;
+    size_t len;
+
+    if (send_packet(db, rqst, silent) < 0) {
+        return -1;
+    }
+    FD_ZERO(&readfds);
+    FD_SET(db->fd, &readfds);
+    maxfd = db->fd +1;
+        
+    tv.tv_usec = 0;
+    tv.tv_sec  = MAX_DELAY;
+    while ((ret = select(maxfd + 1, &readfds, NULL, NULL, &tv)) < 0 && errno == EINTR);
+
+    if (ret < 0) {
+       if (!silent)
+           LOG(log_error, logtype_cnid, "dbd_rpc: Error in select (db_dir %s): %s",
+               db->db_dir, strerror(errno));
+        return ret;
+    }
+    /* signal ? */
+    if (!ret) {
+        /* no answer */
+       if (!silent)
+           LOG(log_error, logtype_cnid, "dbd_rpc: select timed out (db_dir %s)",
+               db->db_dir);
+        return -1;
+    }
+
+    len = rply->namelen;
+    nametmp = rply->name;
+    /* assume that if we have something then everything is there (doesn't sleep) */ 
+    if ((ret = read(db->fd, rply, sizeof(struct cnid_dbd_rply))) != sizeof(struct cnid_dbd_rply)) {
+       if (!silent)
+           LOG(log_error, logtype_cnid, "dbd_rpc: Error reading header from fd (db_dir %s): %s",
+                db->db_dir, ret == -1?strerror(errno):"closed");
+        rply->name = nametmp;
+        return -1;
+    }
+    rply->name = nametmp;
+    if (rply->namelen && rply->namelen > len) {
+       if (!silent)
+            LOG(log_error, logtype_cnid, 
+                 "dbd_rpc: Error reading name (db_dir %s): %s name too long wanted %d only %d, garbage?",
+                 db->db_dir, rply->namelen, len);
+        return -1;
+    }
+    if (rply->namelen && (ret = read(db->fd, rply->name, rply->namelen)) != (ssize_t)rply->namelen) {
+       if (!silent)
+            LOG(log_error, logtype_cnid, "dbd_rpc: Error reading name from fd (db_dir %s): %s",
+                db->db_dir, ret == -1?strerror(errno):"closed");
+        return -1;
+    }
+    return 0;
+}
+
+/* -------------------- */
+static int transmit(CNID_private *db, struct cnid_dbd_rqst *rqst, struct cnid_dbd_rply *rply)
+{
+    struct timeval tv;
+    time_t orig, t;
+    int silent = 1;
+    
+    if (db->changed) {
+        /* volume and db don't have the same timestamp
+        */
+        return -1;
+    }
+    time(&orig);
+    while (1) {
+
+        if (db->fd == -1) {
+            if ((db->fd = init_tsock(db)) < 0) {
+                time(&t);
+                if (t - orig > MAX_DELAY)
+                    return -1;
+               continue;
+            }
+            if (db->notfirst) {
+                struct cnid_dbd_rqst rqst_stamp;
+                struct cnid_dbd_rply rply_stamp;
+                char  stamp[ADEDLEN_PRIVSYN];
+                
+                dbd_initstamp(&rqst_stamp);
+               memset(stamp, 0, ADEDLEN_PRIVSYN);
+                rply_stamp.name = stamp;
+                rply_stamp.namelen = ADEDLEN_PRIVSYN;
+                
+               if (dbd_rpc(db, &rqst_stamp, &rply_stamp, silent) < 0)
+                   goto transmit_fail;
+               if (dbd_reply_stamp(&rply_stamp ) < 0)
+                   goto transmit_fail;
+               if (memcmp(stamp, db->stamp, ADEDLEN_PRIVSYN)) {
+                    LOG(log_error, logtype_cnid, "transmit: not the same db!");
+                   db->changed = 1;
+                   return -1;
+               }
+            }
+
+        }
+        if (!dbd_rpc(db, rqst, rply, silent))
+            return 0;
+
+transmit_fail:
+       silent = 0; /* From now on dbd_rpc and subroutines called from there
+                       will log messages if something goes wrong again */
+        if (db->fd != -1) {
+            close(db->fd);
+        }
+        time(&t);
+        if (t - orig > MAX_DELAY) {
+           LOG(log_error, logtype_cnid, "transmit: Request to dbd daemon (db_dir %s) timed out.", db->db_dir);
+            return -1;
+       }
+
+        /* sleep a little before retry */
+        db->fd = -1;
+        tv.tv_usec = 0;
+        tv.tv_sec  = 5;
+        select(0, NULL, NULL, NULL, &tv);
+    }
+    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_rebuild_add = cnid_dbd_rebuild_add;
+    cdb->cnid_close = cnid_dbd_close;
+    
+    return cdb;
+}
+
+/* ---------------------- */
+struct _cnid_db *cnid_dbd_open(const char *dir, mode_t mask _U_)
+{
+    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->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, char *name, const int len,
+                cnid_t hint _U_)
+{
+    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;
+
+    if (!(cdb->flags & CNID_FLAG_NODEV)) {
+        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;
+
+    rply.namelen = 0;
+    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, 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;
+
+    rply.namelen = 0;
+    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 = (char *)buffer + CNID_HEADER_LEN;
+    rply.namelen = len - 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;
+}
+
+/* --------------------- */
+static int dbd_getstamp(CNID_private *db, void *buffer, const size_t len)
+{
+    struct cnid_dbd_rqst rqst;
+    struct cnid_dbd_rply rply;
+
+    memset(buffer, 0, len);
+    dbd_initstamp(&rqst);
+
+    rply.name = buffer;
+    rply.namelen = len;
+
+    if (transmit(db, &rqst, &rply) < 0) {
+        errno = CNID_ERR_DB;
+        return -1;
+    }
+    return dbd_reply_stamp(&rply);
+}
+
+/* ---------------------- */
+int cnid_dbd_getstamp(struct _cnid_db *cdb, void *buffer, const int len)
+{
+    CNID_private *db;
+    int ret;
+
+    if (!cdb || !(db = cdb->_private) || len != ADEDLEN_PRIVSYN) {
+        LOG(log_error, logtype_cnid, "cnid_getstamp: Parameter error");
+        errno = CNID_ERR_PARAM;                
+        return -1;
+    }
+    ret = dbd_getstamp(db, buffer, len);
+    if (!ret) {
+       db->notfirst = 1;
+       memcpy(db->stamp, buffer, len);
+    }
+    return ret;
+}
+
+/* ---------------------- */
+cnid_t cnid_dbd_lookup(struct _cnid_db *cdb, const struct stat *st, const cnid_t did,
+                   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;
+
+    if (!(cdb->flags & CNID_FLAG_NODEV)) {
+        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;
+
+    rply.namelen = 0;
+    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, 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;
+    if (!(cdb->flags & CNID_FLAG_NODEV)) {
+        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;
+
+    rply.namelen = 0;
+    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();
+    }
+}
+
+/* ---------------------- */
+cnid_t cnid_dbd_rebuild_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 || hint == CNID_INVALID) {
+        LOG(log_error, logtype_cnid, "cnid_rebuild_add: Parameter error");
+        errno = CNID_ERR_PARAM;
+        return CNID_INVALID;
+    }
+
+    if (len > MAXPATHLEN) {
+        LOG(log_error, logtype_cnid, "cnid_rebuild_add: Path name is too long");
+        errno = CNID_ERR_PATH;
+        return CNID_INVALID;
+    }
+
+    RQST_RESET(&rqst);
+    rqst.op = CNID_DBD_OP_REBUILD_ADD;
+
+    if (!(cdb->flags & CNID_FLAG_NODEV)) {
+        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;
+    rqst.cnid = hint;
+
+    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;
+}
+
+/* ---------------------- */
+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;
+
+    rply.namelen = 0;
+    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,
+    0
+};
+
+#endif /* CNID_DBD */
+
diff --git a/libatalk/cnid/dbd/cnid_dbd.h b/libatalk/cnid/dbd/cnid_dbd.h
new file mode 100644 (file)
index 0000000..098fafe
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * $Id: cnid_dbd.h,v 1.2 2005-04-28 20:50:01 bfernhomberg Exp $
+ *
+ * Copyright (C) Joerg Lenneis 2003
+ * All Rights Reserved.  See COPYING.
+ */
+
+
+#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,
+                           char *, const int, cnid_t));
+extern cnid_t cnid_dbd_get __P((struct _cnid_db *, const cnid_t, 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 *, const int )); 
+extern cnid_t cnid_dbd_lookup __P((struct _cnid_db *, const struct stat *, const cnid_t,
+                              char *, const int));
+extern int cnid_dbd_update __P((struct _cnid_db *, const cnid_t, const struct stat *,
+                           const cnid_t, char *, int));
+extern int cnid_dbd_delete __P((struct _cnid_db *, const cnid_t));
+extern cnid_t cnid_dbd_rebuild_add __P((struct _cnid_db *, const struct stat *,
+                const cnid_t, const char *, const int, cnid_t));
+
+/* FIXME: These functions could be static in cnid_dbd.c */
+
+#endif /* include/atalk/cnid_dbd.h */
+
diff --git a/libatalk/cnid/hash/.cvsignore b/libatalk/cnid/hash/.cvsignore
new file mode 100644 (file)
index 0000000..0d0371d
--- /dev/null
@@ -0,0 +1,6 @@
+Makefile
+Makefile.in
+*.lo
+*.la
+.deps
+.libs
diff --git a/libatalk/cnid/hash/Makefile.am b/libatalk/cnid/hash/Makefile.am
new file mode 100644 (file)
index 0000000..40dc3b0
--- /dev/null
@@ -0,0 +1,15 @@
+# Makefile.am for libatalk/cnid/
+
+noinst_LTLIBRARIES = libcnid_hash.la
+
+libcnid_hash_la_SOURCES = cnid_hash_add.c \
+                        cnid_hash_close.c \
+                        cnid_hash_delete.c \
+                        cnid_hash_get.c \
+                        cnid_hash_lookup.c \
+                        cnid_hash_open.c \
+                        cnid_hash_resolve.c \
+                        cnid_hash_update.c \
+                        cnid_hash.h
+
+EXTRA_DIST = README cnid_hash_nextid.c
diff --git a/libatalk/cnid/hash/README b/libatalk/cnid/hash/README
new file mode 100644 (file)
index 0000000..b39889b
--- /dev/null
@@ -0,0 +1,35 @@
+the catalog database keeps track of three mappings:
+    CNID     -> dev/ino and did/name
+    dev/ino  -> CNID
+    did/name -> CNID
+
+dev/ino is used to keep track of magically moved files. did/name is
+for quick lookups of CNIDs. 
+
+NOTE: the database will append a nul byte to the end of name. in
+addition, name should be given as it appears on disk. this allows the
+creation of cnid updating/cleaning programs that don't have to deal
+with knowing what the particular codepage is.
+
+here's the ritual:
+       1) open a volume. call cnid_open.
+       2) every time you need a CNID, call cnid_add(). it will
+          automatically look for an existing cnid and add a new one
+          if one isn't already there. you can pass a hint if you
+          want. the only use this has right now is to enable
+          consistency between AFP and HFS. in the future, it would
+          allow people to write conversion utilities that
+          pre-instantiate a database without needing to re-assign
+          CNIDs.
+       3) if you want to just look for a CNID without automatically
+          adding one in, you have two choices:
+            a) cnid_resolve takes a CNID, returns name, and
+               over-writes the CNID given with the parent DID. this
+               is good for FPResolveID.
+             b) cnid_lookup returns a CNID corresponding to the
+               dev/ino,did/name keys. it will auto-update the catalog
+               database if there's a discrepancy. 
+               NOTE: cnid_add calls this before adding a new CNID. 
+       4) when you delete a file or directory, you need to call
+          cnid_delete with the CNID for that file/directory.
+       5) call cnid_close when closing the volume.
diff --git a/libatalk/cnid/hash/cnid_hash.h b/libatalk/cnid/hash/cnid_hash.h
new file mode 100644 (file)
index 0000000..f27ef1c
--- /dev/null
@@ -0,0 +1,67 @@
+/* 
+ * interface for database access to cnids. i do it this way to abstract
+ * things a bit in case we want to change the underlying implementation.
+ */
+
+#ifndef _ATALK_CNID_HASH__H
+#define _ATALK_CNID_HASH__H 1
+
+#include <sys/cdefs.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <string.h>
+
+#include <netatalk/endian.h>
+#include <atalk/cnid.h>
+#define STANDALONE 1
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <signal.h>
+#include <atalk/tdb.h>
+
+#define HASH_ERROR_LINK  1
+#define HASH_ERROR_DEV   2
+#define HASH_ERROR_INODE 4
+
+struct _cnid_hash_private {
+    dev_t  st_dev;
+    int    st_set;
+    int    error;
+    TDB_CONTEXT *tdb;  
+};
+
+/* cnid_open.c */
+extern struct _cnid_module cnid_hash_module;
+extern struct _cnid_db *cnid_hash_open __P((const char *, mode_t));
+
+/* cnid_close.c */
+extern void cnid_hash_close __P((struct _cnid_db *));
+
+/* cnid_add.c */
+extern cnid_t cnid_hash_add __P((struct _cnid_db *, const struct stat *, const cnid_t,
+                                 char *, const int, cnid_t));
+
+/* cnid_get.c */
+extern cnid_t cnid_hash_get __P((struct _cnid_db *, const cnid_t, 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, char *, const int));
+
+/* cnid_update.c */
+extern int cnid_hash_update __P((struct _cnid_db *, const cnid_t, const struct stat *,
+                                 const cnid_t, char *, int));
+
+/* cnid_delete.c */
+extern int cnid_hash_delete __P((struct _cnid_db *, const cnid_t));
+
+/* cnid_nextid.c */
+extern cnid_t cnid_hash_nextid __P((struct _cnid_db *));
+
+#endif /* include/atalk/cnid_hash.h */
diff --git a/libatalk/cnid/hash/cnid_hash_add.c b/libatalk/cnid/hash/cnid_hash_add.c
new file mode 100644 (file)
index 0000000..6bf1607
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * $Id: cnid_hash_add.c,v 1.2 2005-04-28 20:50:01 bfernhomberg 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, char *name, const int len, cnid_t hint)
+{
+    struct stat lst;
+    const struct stat *lstp;
+    cnid_t aint;
+    struct _cnid_hash_private *priv;
+    static char buffer[sizeof(cnid_t) + MAXPATHLEN + 1];        
+    TDB_DATA key, data;       
+    
+    if (!cdb || !(cdb->_private))
+        return CNID_INVALID;
+
+    priv = (struct _cnid_hash_private *) (cdb->_private);
+    lstp = lstat(name, &lst) < 0 ? st : &lst;
+    aint = lstp->st_ino & 0xffffffff;
+
+    if (!priv->st_set) {
+        priv->st_set = 1;
+        priv->st_dev = lstp->st_dev;
+    }
+    if (!(priv->error & HASH_ERROR_DEV)) {
+        if (lstp->st_dev != priv->st_dev) {
+            priv->error |= HASH_ERROR_DEV;
+            LOG(log_error, logtype_default, "cnid_hash_add: %s not on the same device", name);
+        }
+    }
+    if (!(priv->error & HASH_ERROR_LINK)) {
+        if (!S_ISDIR(lstp->st_mode) && lstp->st_nlink > 1) {
+            priv->error |= HASH_ERROR_DEV;
+            LOG(log_error, logtype_default, "cnid_hash_add: %s more than one hardlink", name);
+        }
+    }
+    if (sizeof(ino_t) > 4 && !(priv->error & HASH_ERROR_INODE)) {
+        if (aint != lstp->st_ino) {
+            priv->error |= HASH_ERROR_INODE;
+            LOG(log_error, logtype_default, "cnid_hash_add: %s high bits set, duplicate", name);
+        }
+    }
+    key.dptr = (char *)&aint;
+    key.dsize = sizeof(cnid_t);
+                
+    memcpy(buffer, &did, sizeof(cnid_t));
+    memcpy(buffer+sizeof(cnid_t), name, len +1);
+    data.dptr = buffer;
+    data.dsize = len+1 +sizeof(cnid_t);
+    if (tdb_store(priv->tdb, key, data, TDB_REPLACE)) {
+        LOG(log_error, logtype_default, "cnid_hash_add: unable to add %s", name);
+    }
+    return aint;
+}
+
+#endif /* CNID_BACKEND_HASH */
diff --git a/libatalk/cnid/hash/cnid_hash_close.c b/libatalk/cnid/hash/cnid_hash_close.c
new file mode 100644 (file)
index 0000000..e99bfdf
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * $Id: cnid_hash_close.c,v 1.2 2005-04-28 20:50:01 bfernhomberg Exp $
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#ifdef CNID_BACKEND_HASH
+
+#include "cnid_hash.h"
+
+void cnid_hash_close(struct _cnid_db *cdb)
+{
+    struct _cnid_hash_private *db;
+
+    free(cdb->volpath);
+    db = (struct _cnid_hash_private *)cdb->_private;
+    tdb_close(db->tdb);    
+    free(cdb->_private);
+    free(cdb);
+}
+
+#endif /* CNID_BACKEND_HASH */
diff --git a/libatalk/cnid/hash/cnid_hash_delete.c b/libatalk/cnid/hash/cnid_hash_delete.c
new file mode 100644 (file)
index 0000000..999dfa0
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * $Id: cnid_hash_delete.c,v 1.2 2005-04-28 20:50:01 bfernhomberg Exp $
+ *
+ * Copyright (c) 1999. Adrian Sun (asun@zoology.washington.edu)
+ * All Rights Reserved. See COPYRIGHT.
+ *
+ * cnid_delete: delete a CNID from the database 
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#ifdef CNID_BACKEND_HASH
+
+#include "cnid_hash.h"
+
+int cnid_hash_delete(struct _cnid_db *cdb, const cnid_t id)
+{
+    struct _cnid_hash_private *db;
+    TDB_DATA key;      
+
+    if (!cdb || !(db = cdb->_private) || !id) {
+        return -1;
+    }
+    key.dptr  = (char *)&id;
+    key.dsize = sizeof(cnid_t);
+    tdb_delete(db->tdb, key); 
+
+    return 0;
+}
+
+#endif /* CNID_BACKEND_HASH */
diff --git a/libatalk/cnid/hash/cnid_hash_get.c b/libatalk/cnid/hash/cnid_hash_get.c
new file mode 100644 (file)
index 0000000..db1b542
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ * $Id: cnid_hash_get.c,v 1.2 2005-04-28 20:50:01 bfernhomberg 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, char *name, const int len)
+{
+    return CNID_INVALID;
+}
+
+#endif /* CNID_BACKEND_HASH */
diff --git a/libatalk/cnid/hash/cnid_hash_lookup.c b/libatalk/cnid/hash/cnid_hash_lookup.c
new file mode 100644 (file)
index 0000000..13705f4
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * $Id: cnid_hash_lookup.c,v 1.2 2005-04-28 20:50:01 bfernhomberg 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, char *name, const int len)
+{
+    return cnid_hash_add(cdb, st, did, name, len, 0  /*hint*/);
+}
+
+#endif /* CNID_BACKEND_HASH */
diff --git a/libatalk/cnid/hash/cnid_hash_nextid.c b/libatalk/cnid/hash/cnid_hash_nextid.c
new file mode 100644 (file)
index 0000000..a18d1d8
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * $Id: cnid_hash_nextid.c,v 1.2 2005-04-28 20:50:01 bfernhomberg Exp $
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#ifdef CNID_BACKEND_HASH
+
+#include "cnid_hash.h"
+
+cnid_t cnid_hash_nextid(struct _cnid_db *cdb)
+{
+    return CNID_INVALID;
+}
+
+#endif /* CNID_BACKEND_HASH */
diff --git a/libatalk/cnid/hash/cnid_hash_open.c b/libatalk/cnid/hash/cnid_hash_open.c
new file mode 100644 (file)
index 0000000..8a0d51c
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ * $Id: cnid_hash_open.c,v 1.2 2005-04-28 20:50:01 bfernhomberg Exp $
+ *
+ * Copyright (c) 1999. Adrian Sun (asun@zoology.washington.edu)
+ * All Rights Reserved. See COPYRIGHT.
+ *
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef CNID_BACKEND_HASH
+#include <sys/param.h>   
+
+#include "cnid_hash.h"
+#include <atalk/logger.h>
+#include <stdlib.h>
+#define DBHOME       ".AppleDB" 
+#define DBNAME       "private_tdb.%sX"
+#define DBHOMELEN    9
+#define DBLEN        24 
+
+static struct _cnid_db *cnid_hash_new(const char *volpath)
+{
+    struct _cnid_db *cdb;
+    struct _cnid_hash_private *priv;
+
+    if ((cdb = (struct _cnid_db *) calloc(1, sizeof(struct _cnid_db))) == NULL)
+        return NULL;
+
+    if ((cdb->volpath = strdup(volpath)) == NULL) {
+        free(cdb);
+        return NULL;
+    }
+
+    if ((cdb->_private = calloc(1, sizeof(struct _cnid_hash_private))) == NULL) {
+        free(cdb->volpath);
+        free(cdb);
+        return NULL;
+    }
+
+    /* Set up private state */
+    priv = (struct _cnid_hash_private *) (cdb->_private);
+
+    /* Set up standard fields */
+    cdb->flags = CNID_FLAG_PERSISTENT;
+
+    cdb->cnid_add = cnid_hash_add;
+    cdb->cnid_delete = cnid_hash_delete;
+    cdb->cnid_get = cnid_hash_get;
+    cdb->cnid_lookup = cnid_hash_lookup;
+    cdb->cnid_nextid = NULL;    /*cnid_hash_nextid;*/
+    cdb->cnid_resolve = cnid_hash_resolve;
+    cdb->cnid_update = cnid_hash_update;
+    cdb->cnid_close = cnid_hash_close;
+    
+    return cdb;
+}
+
+/* ---------------------------- */
+struct _cnid_db *cnid_hash_open(const char *dir, mode_t mask)
+{
+    struct stat               st;
+    struct _cnid_db           *cdb;
+    struct _cnid_hash_private *db;
+    size_t                    len;
+    char                      path[MAXPATHLEN + 1];
+    
+    if (!dir) {
+        return NULL;
+    }
+
+    if ((len = strlen(dir)) > (MAXPATHLEN - DBLEN - 1)) {
+        LOG(log_error, logtype_default, "cnid_open: Pathname too large: %s", dir);
+        return NULL;
+    }
+    
+    if ((cdb = cnid_hash_new(dir)) == NULL) {
+        LOG(log_error, logtype_default, "cnid_open: Unable to allocate memory for hash");
+        return NULL;
+    }
+    strcpy(path, dir);
+    if (path[len - 1] != '/') {
+        strcat(path, "/");
+        len++;
+    }
+    strcpy(path + len, DBHOME);
+    if ((stat(path, &st) < 0) && (ad_mkdir(path, 0777 & ~mask) < 0)) {
+        LOG(log_error, logtype_default, "cnid_open: DBHOME mkdir failed for %s", path);
+        goto fail;
+    }
+    strcat(path, "/");
+    path[len + DBHOMELEN] = '\0';
+    strcat(path, DBNAME);
+    db = (struct _cnid_hash_private *)cdb->_private;
+    db->tdb = tdb_open(path, 0, TDB_CLEAR_IF_FIRST | TDB_INTERNAL, O_RDWR | O_CREAT | O_TRUNC, 0600);
+    if (!db->tdb) {
+        LOG(log_error, logtype_default, "cnid_open: unable to open tdb", path);
+        goto fail;
+    }
+
+    return cdb;
+
+fail:
+    free(cdb->_private);
+    free(cdb->volpath);
+    free(cdb);
+    
+    return NULL;
+}
+
+struct _cnid_module cnid_hash_module = {
+    "hash",
+    {NULL, NULL},
+    cnid_hash_open,
+};
+
+
+#endif /* CNID_BACKEND_HASH */
diff --git a/libatalk/cnid/hash/cnid_hash_resolve.c b/libatalk/cnid/hash/cnid_hash_resolve.c
new file mode 100644 (file)
index 0000000..d0d26f0
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * $Id: cnid_hash_resolve.c,v 1.2 2005-04-28 20:50:01 bfernhomberg Exp $
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#ifdef CNID_BACKEND_HASH
+
+#include "cnid_hash.h"
+
+/* Return the did/name pair corresponding to a CNID. */
+char *cnid_hash_resolve(struct _cnid_db *cdb, cnid_t * id, void *buffer, u_int32_t len)
+{
+    struct _cnid_hash_private *db;
+    TDB_DATA key, data;      
+
+    if (!cdb || !(db = cdb->_private) || !id || !(*id)) {
+        return NULL;
+    }
+    key.dptr  = (char *)id;
+    key.dsize = sizeof(cnid_t);
+    data = tdb_fetch(db->tdb, key);
+    if (data.dptr) 
+    {
+        if (data.dsize < len && data.dsize > sizeof(cnid_t)) {
+            memcpy(id, data.dptr, sizeof(cnid_t));
+            memcpy(buffer, data.dptr +sizeof(cnid_t), data.dsize -sizeof(cnid_t));
+            free(data.dptr);
+            return buffer;
+        }
+        free(data.dptr);
+    }
+    return NULL;
+}
+
+#endif /* CNID_BACKEND_HASH */
diff --git a/libatalk/cnid/hash/cnid_hash_update.c b/libatalk/cnid/hash/cnid_hash_update.c
new file mode 100644 (file)
index 0000000..e70da0d
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * $Id: cnid_hash_update.c,v 1.2 2005-04-28 20:50:01 bfernhomberg 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, char *name, const int len
+                     /*, const char *info, const int infolen */ )
+{
+    return 0;
+}
+
+#endif  /* CNID_BACKEND_HASH */
diff --git a/libatalk/cnid/last/.cvsignore b/libatalk/cnid/last/.cvsignore
new file mode 100644 (file)
index 0000000..0d0371d
--- /dev/null
@@ -0,0 +1,6 @@
+Makefile
+Makefile.in
+*.lo
+*.la
+.deps
+.libs
diff --git a/libatalk/cnid/last/Makefile.am b/libatalk/cnid/last/Makefile.am
new file mode 100644 (file)
index 0000000..f2c7bb6
--- /dev/null
@@ -0,0 +1,8 @@
+# Makefile.am for libatalk/cnid/
+
+noinst_LTLIBRARIES = libcnid_last.la
+
+libcnid_last_la_SOURCES = cnid_last.c \
+                        cnid_last.h
+
+EXTRA_DIST = README 
diff --git a/libatalk/cnid/last/README b/libatalk/cnid/last/README
new file mode 100644 (file)
index 0000000..3fe80f6
--- /dev/null
@@ -0,0 +1,4 @@
+This is [last] DID scheme implementation. 
+
+TODO: this scheme doesn't exactly mimic real, persistent CNID schemes, so 
+      things like name mangling won't work. 
diff --git a/libatalk/cnid/last/cnid_last.c b/libatalk/cnid/last/cnid_last.c
new file mode 100644 (file)
index 0000000..98fb0cf
--- /dev/null
@@ -0,0 +1,185 @@
+
+/*
+ * $Id: cnid_last.c,v 1.2 2005-04-28 20:50:01 bfernhomberg 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, 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, 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, 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,
+    0
+};
+
+/* 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, char *name, const int len
+                     /*, const char *info, const int infolen */ )
+{
+    return 0;
+}
+
+
+#endif /* CNID_BACKEND_LAST */
diff --git a/libatalk/cnid/last/cnid_last.h b/libatalk/cnid/last/cnid_last.h
new file mode 100644 (file)
index 0000000..2a32527
--- /dev/null
@@ -0,0 +1,34 @@
+
+/* 
+ * interface for database access to cnids. i do it this way to abstract
+ * things a bit in case we want to change the underlying implementation.
+ */
+
+#ifndef _ATALK_CNID_LAST__H
+#define _ATALK_CNID_LAST__H 1
+
+#include <sys/cdefs.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <string.h>
+
+#include <netatalk/endian.h>
+#include <atalk/cnid.h>
+
+struct _cnid_last_private {
+    cnid_t last_did;
+};
+
+extern struct _cnid_module cnid_last_module;
+extern struct _cnid_db *cnid_last_open __P((const char *, mode_t));
+extern void cnid_last_close __P((struct _cnid_db *));
+extern cnid_t cnid_last_add __P((struct _cnid_db *, const struct stat *, const cnid_t,
+                                 char *, const int, cnid_t));
+extern cnid_t cnid_last_get __P((struct _cnid_db *, const cnid_t, 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, char *, const int));
+extern int cnid_last_update __P((struct _cnid_db *, const cnid_t, const struct stat *,
+                                 const cnid_t, char *, int));
+extern int cnid_last_delete __P((struct _cnid_db *, const cnid_t));
+
+#endif /* include/atalk/cnid_last.h */
diff --git a/libatalk/cnid/mtab/.cvsignore b/libatalk/cnid/mtab/.cvsignore
new file mode 100644 (file)
index 0000000..0d0371d
--- /dev/null
@@ -0,0 +1,6 @@
+Makefile
+Makefile.in
+*.lo
+*.la
+.deps
+.libs
diff --git a/libatalk/cnid/mtab/Makefile.am b/libatalk/cnid/mtab/Makefile.am
new file mode 100644 (file)
index 0000000..0d1ff40
--- /dev/null
@@ -0,0 +1,8 @@
+# Makefile.am for libatalk/cnid/
+
+noinst_LTLIBRARIES = libcnid_mtab.la
+
+libcnid_mtab_la_SOURCES = cnid_mtab.c \
+                        cnid_mtab.h
+
+EXTRA_DIST = README
diff --git a/libatalk/cnid/mtab/README b/libatalk/cnid/mtab/README
new file mode 100644 (file)
index 0000000..19e634f
--- /dev/null
@@ -0,0 +1 @@
+There are still things to do. See ../last/README for details.
diff --git a/libatalk/cnid/mtab/cnid_mtab.c b/libatalk/cnid/mtab/cnid_mtab.c
new file mode 100644 (file)
index 0000000..03a110f
--- /dev/null
@@ -0,0 +1,137 @@
+
+/*
+ * $Id: cnid_mtab.c,v 1.2 2005-04-28 20:50:01 bfernhomberg 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, 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, 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, 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, char *name, const int len
+                     /*, const char *info, const int infolen */ )
+{
+    return 0;
+}
+
+#endif /* CNID_BACKEND_MTAB */
diff --git a/libatalk/cnid/mtab/cnid_mtab.h b/libatalk/cnid/mtab/cnid_mtab.h
new file mode 100644 (file)
index 0000000..27d2a7b
--- /dev/null
@@ -0,0 +1,31 @@
+
+/* 
+ * interface for database access to cnids. i do it this way to abstract
+ * things a bit in case we want to change the underlying implementation.
+ */
+
+#ifndef _ATALK_CNID_MTAB__H
+#define _ATALK_CNID_MTAB__H 1
+
+#include <sys/cdefs.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <string.h>
+
+#include <netatalk/endian.h>
+#include <atalk/cnid.h>
+
+extern struct _cnid_module cnid_mtab_module;
+
+extern struct _cnid_db *cnid_mtab_open __P((const char *, mode_t));
+extern void cnid_mtab_close __P((struct _cnid_db *));
+extern cnid_t cnid_mtab_add __P((struct _cnid_db *, const struct stat *, const cnid_t,
+                                 char *, const int, cnid_t));
+extern cnid_t cnid_mtab_get __P((struct _cnid_db *, const cnid_t, 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, char *, const int));
+extern int cnid_mtab_update __P((struct _cnid_db *, const cnid_t, const struct stat *,
+                                 const cnid_t, char *, int));
+extern int cnid_mtab_delete __P((struct _cnid_db *, const cnid_t));
+
+#endif /* include/atalk/cnid_mtab.h */
diff --git a/libatalk/cnid/qdbm/.cvsignore b/libatalk/cnid/qdbm/.cvsignore
new file mode 100644 (file)
index 0000000..0d0371d
--- /dev/null
@@ -0,0 +1,6 @@
+Makefile
+Makefile.in
+*.lo
+*.la
+.deps
+.libs
diff --git a/libatalk/cnid/tdb/.cvsignore b/libatalk/cnid/tdb/.cvsignore
new file mode 100644 (file)
index 0000000..0d0371d
--- /dev/null
@@ -0,0 +1,6 @@
+Makefile
+Makefile.in
+*.lo
+*.la
+.deps
+.libs
diff --git a/libatalk/cnid/tdb/Makefile.am b/libatalk/cnid/tdb/Makefile.am
new file mode 100644 (file)
index 0000000..23692fa
--- /dev/null
@@ -0,0 +1,15 @@
+# Makefile.am for libatalk/cnid/
+
+noinst_LTLIBRARIES = libcnid_tdb.la
+
+libcnid_tdb_la_SOURCES = cnid_tdb_add.c \
+                        cnid_tdb_close.c \
+                        cnid_tdb_delete.c \
+                        cnid_tdb_get.c \
+                        cnid_tdb_lookup.c \
+                        cnid_tdb_open.c \
+                        cnid_tdb_resolve.c \
+                        cnid_tdb_update.c \
+                        cnid_tdb.h
+
+EXTRA_DIST = README cnid_tdb_nextid.c
diff --git a/libatalk/cnid/tdb/README b/libatalk/cnid/tdb/README
new file mode 100644 (file)
index 0000000..b39889b
--- /dev/null
@@ -0,0 +1,35 @@
+the catalog database keeps track of three mappings:
+    CNID     -> dev/ino and did/name
+    dev/ino  -> CNID
+    did/name -> CNID
+
+dev/ino is used to keep track of magically moved files. did/name is
+for quick lookups of CNIDs. 
+
+NOTE: the database will append a nul byte to the end of name. in
+addition, name should be given as it appears on disk. this allows the
+creation of cnid updating/cleaning programs that don't have to deal
+with knowing what the particular codepage is.
+
+here's the ritual:
+       1) open a volume. call cnid_open.
+       2) every time you need a CNID, call cnid_add(). it will
+          automatically look for an existing cnid and add a new one
+          if one isn't already there. you can pass a hint if you
+          want. the only use this has right now is to enable
+          consistency between AFP and HFS. in the future, it would
+          allow people to write conversion utilities that
+          pre-instantiate a database without needing to re-assign
+          CNIDs.
+       3) if you want to just look for a CNID without automatically
+          adding one in, you have two choices:
+            a) cnid_resolve takes a CNID, returns name, and
+               over-writes the CNID given with the parent DID. this
+               is good for FPResolveID.
+             b) cnid_lookup returns a CNID corresponding to the
+               dev/ino,did/name keys. it will auto-update the catalog
+               database if there's a discrepancy. 
+               NOTE: cnid_add calls this before adding a new CNID. 
+       4) when you delete a file or directory, you need to call
+          cnid_delete with the CNID for that file/directory.
+       5) call cnid_close when closing the volume.
diff --git a/libatalk/cnid/tdb/cnid_tdb.h b/libatalk/cnid/tdb/cnid_tdb.h
new file mode 100644 (file)
index 0000000..fb12dc0
--- /dev/null
@@ -0,0 +1,115 @@
+/* 
+ * interface for database access to cnids. i do it this way to abstract
+ * things a bit in case we want to change the underlying implementation.
+ */
+
+#ifndef _ATALK_CNID_TDB__H
+#define _ATALK_CNID_TDB__H 1
+
+#include <sys/cdefs.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <string.h>
+
+#include <sys/param.h>
+
+#include <netatalk/endian.h>
+#include <atalk/cnid.h>
+#define STANDALONE 1
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <signal.h>
+#include <atalk/tdb.h>
+
+#define TDB_ERROR_LINK  1
+#define TDB_ERROR_DEV   2
+#define TDB_ERROR_INODE 4
+
+#define TDB_DB_MAGIC   0x434E4944U  /* CNID */
+#define TDB_DATA_MAGIC 0x434E4945U  /* CNIE */
+
+#define TDB_DEVINO_LEN          8
+#define TDB_DID_LEN             4
+#define TDB_HEADER_LEN          (TDB_DEVINO_LEN + TDB_DID_LEN)
+
+#define TDB_START               17
+
+#define TDBFLAG_ROOTINFO_RO     (1 << 0)
+#define TDBFLAG_DB_RO           (1 << 1)
+
+/* the key is in the form of a did/name pair. in this case,
+ * we use 0/RootInfo. */
+#define ROOTINFO_KEY    "\0\0\0\0RootInfo"
+#define ROOTINFO_KEYLEN 12
+
+struct _cnid_tdb_private {
+    dev_t  st_dev;
+    int    st_set;
+    int    error;
+    int    flags;
+    TDB_CONTEXT *tdb_cnid;
+    TDB_CONTEXT *tdb_didname;
+    TDB_CONTEXT *tdb_devino;
+
+};
+
+/* cnid_open.c */
+extern struct _cnid_module cnid_tdb_module;
+extern struct _cnid_db *cnid_tdb_open __P((const char *, mode_t));
+
+/* cnid_close.c */
+extern void cnid_tdb_close __P((struct _cnid_db *));
+
+/* cnid_add.c */
+extern cnid_t cnid_tdb_add __P((struct _cnid_db *, const struct stat *, const cnid_t,
+                                 char *, const int, cnid_t));
+
+/* cnid_get.c */
+extern cnid_t cnid_tdb_get __P((struct _cnid_db *, const cnid_t, 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, char *, const int));
+
+/* cnid_update.c */
+extern int cnid_tdb_update __P((struct _cnid_db *, const cnid_t, const struct stat *,
+                                 const cnid_t, char *, int));
+
+/* cnid_delete.c */
+extern int cnid_tdb_delete __P((struct _cnid_db *, const cnid_t));
+
+/* cnid_nextid.c */
+extern cnid_t cnid_tdb_nextid __P((struct _cnid_db *));
+
+/* construct db_cnid data. NOTE: this is not re-entrant.  */
+static __inline__ char *make_tdb_data(const struct stat *st,
+                                       const cnid_t did,
+                                       const char *name, const int len)
+{
+    static char start[TDB_HEADER_LEN + MAXPATHLEN + 1];
+    char *buf = start;
+    u_int32_t i;
+
+    if (len > MAXPATHLEN)
+        return NULL;
+
+    i = htonl(st->st_dev);
+    buf = memcpy(buf, &i, sizeof(i));
+    i = htonl(st->st_ino);
+    buf = memcpy(buf + sizeof(i), &i, sizeof(i));
+    /* did is already in network byte order */
+    buf = memcpy(buf + sizeof(i), &did, sizeof(did));
+    buf = memcpy(buf + sizeof(did), name, len);
+    *(buf + len) = '\0';
+    buf += len + 1;
+
+    return start;
+}
+
+#endif /* include/atalk/cnid_tdb.h */
diff --git a/libatalk/cnid/tdb/cnid_tdb_add.c b/libatalk/cnid/tdb/cnid_tdb_add.c
new file mode 100644 (file)
index 0000000..d54a88d
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+ * $Id: cnid_tdb_add.c,v 1.2 2005-04-28 20:50:02 bfernhomberg 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;
+
+    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 -1;
+}
+
+/* ----------------------- */
+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, char *name, const int len, cnid_t hint)
+{
+    const struct stat *lstp;
+    cnid_t id;
+    struct _cnid_tdb_private *priv;
+    TDB_DATA key, data; 
+    int rc;      
+    
+    if (!cdb || !(priv = cdb->_private) || !st || !name) {
+        errno = CNID_ERR_PARAM;
+        return CNID_INVALID;
+    }
+    /* Do a lookup. */
+    id = cnid_tdb_lookup(cdb, st, did, name, len);
+    /* ... Return id if it is valid, or if Rootinfo is read-only. */
+    if (id || (priv->flags & TDBFLAG_DB_RO)) {
+        return id;
+    }
+
+#if 0
+    struct stat lst;
+    lstp = lstat(name, &lst) < 0 ? st : &lst;
+#endif
+    lstp = st;
+
+    /* Initialize our DBT data structures. */
+    memset(&key, 0, sizeof(key));
+    memset(&data, 0, sizeof(data));
+
+    key.dptr = (char *)&hint;
+    key.dsize = sizeof(cnid_t);
+    if ((data.dptr = make_tdb_data(lstp, did, name, len)) == NULL) {
+        LOG(log_error, logtype_default, "tdb_add: Path name is too long");
+        errno = CNID_ERR_PATH;
+        return CNID_INVALID;
+    }
+    data.dsize = TDB_HEADER_LEN + len + 1;
+    hint = get_cnid(priv);
+    if (hint == 0) {
+        errno = CNID_ERR_DB;
+        return CNID_INVALID;
+    }
+    
+    /* Now we need to add the CNID data to the databases. */
+    rc = add_cnid(priv, &key, &data);
+    if (rc) {
+        LOG(log_error, logtype_default, "tdb_add: Failed to add CNID for %s to database using hint %u", name, ntohl(hint));
+        errno = CNID_ERR_DB;
+        return CNID_INVALID;
+    }
+
+    return hint;
+}
+
+#endif
diff --git a/libatalk/cnid/tdb/cnid_tdb_close.c b/libatalk/cnid/tdb/cnid_tdb_close.c
new file mode 100644 (file)
index 0000000..b6ce546
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * $Id: cnid_tdb_close.c,v 1.2 2005-04-28 20:50:02 bfernhomberg Exp $
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef CNID_BACKEND_TDB
+
+#include "cnid_tdb.h"
+
+void cnid_tdb_close(struct _cnid_db *cdb)
+{
+    struct _cnid_tdb_private *db;
+
+    free(cdb->volpath);
+    db = (struct _cnid_tdb_private *)cdb->_private;
+    tdb_close(db->tdb_cnid);
+    tdb_close(db->tdb_didname);
+    tdb_close(db->tdb_devino);
+    free(cdb->_private);
+    free(cdb);
+}
+
+#endif
diff --git a/libatalk/cnid/tdb/cnid_tdb_delete.c b/libatalk/cnid/tdb/cnid_tdb_delete.c
new file mode 100644 (file)
index 0000000..9c9d6ff
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * $Id: cnid_tdb_delete.c,v 1.2 2005-04-28 20:50:02 bfernhomberg Exp $
+ *
+ * Copyright (c) 1999. Adrian Sun (asun@zoology.washington.edu)
+ * All Rights Reserved. See COPYRIGHT.
+ *
+ * cnid_delete: delete a CNID from the database 
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif 
+
+#ifdef CNID_BACKEND_TDB
+
+#include "cnid_tdb.h"
+
+int cnid_tdb_delete(struct _cnid_db *cdb, const cnid_t id)
+{
+    struct _cnid_tdb_private *db;
+    TDB_DATA key, data;
+
+    if (!cdb || !(db = cdb->_private) || !id) {
+        return -1;
+    }
+    memset(&key, 0, sizeof(key));
+    memset(&data, 0, sizeof(data));
+
+    key.dptr  = (char *)&id;
+    key.dsize = sizeof(cnid_t);
+    data = tdb_fetch(db->tdb_cnid, key);
+    if (!data.dptr)
+    {
+        return 0;
+    }
+    
+    tdb_delete(db->tdb_cnid, key); 
+
+    key.dptr = data.dptr;
+    key.dsize = TDB_DEVINO_LEN;
+    tdb_delete(db->tdb_devino, key); 
+
+    key.dptr = (char *)data.dptr + TDB_DEVINO_LEN;
+    key.dsize = data.dsize - TDB_DEVINO_LEN;
+    tdb_delete(db->tdb_didname, key); 
+
+    free(data.dptr);
+    return 0;
+}
+
+#endif 
diff --git a/libatalk/cnid/tdb/cnid_tdb_get.c b/libatalk/cnid/tdb/cnid_tdb_get.c
new file mode 100644 (file)
index 0000000..4dce62d
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * $Id: cnid_tdb_get.c,v 1.2 2005-04-28 20:50:02 bfernhomberg 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, char *name, const int len)
+{
+    char start[TDB_DID_LEN + MAXPATHLEN + 1], *buf;
+    struct _cnid_tdb_private *db;
+    TDB_DATA key, data;
+    cnid_t id;
+
+    if (!cdb || !(db = cdb->_private) || (len > MAXPATHLEN)) {
+        return 0;
+    }
+
+    memset(&key, 0, sizeof(key));
+    memset(&data, 0, sizeof(data));
+
+    buf = start;
+    memcpy(buf, &did, sizeof(did));
+    buf += sizeof(did);
+    memcpy(buf, name, len);
+    *(buf + len) = '\0'; /* Make it a C-string. */
+    key.dptr = start;
+    key.dsize = TDB_DID_LEN + len + 1;
+    data = tdb_fetch(db->tdb_didname, key);
+    if (!data.dptr)
+        return 0;
+
+    memcpy(&id, data.dptr, sizeof(id));
+    free(data.dptr);
+    return id;
+}
+
+#endif
diff --git a/libatalk/cnid/tdb/cnid_tdb_lookup.c b/libatalk/cnid/tdb/cnid_tdb_lookup.c
new file mode 100644 (file)
index 0000000..6072ce3
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * $Id: cnid_tdb_lookup.c,v 1.2 2005-04-28 20:50:02 bfernhomberg 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, char *name, const int len)
+{
+    char *buf;
+    struct _cnid_tdb_private *db;
+    TDB_DATA key, devdata, diddata;
+    int devino = 1, didname = 1;
+    cnid_t id = 0;
+
+    if (!cdb || !(db = cdb->_private) || !st || !name) {
+        return 0;
+    }
+
+    if ((buf = make_tdb_data(st, did, name, len)) == NULL) {
+        LOG(log_error, logtype_default, "tdb_lookup: Pathname is too long");
+        return 0;
+    }
+
+    memset(&key, 0, sizeof(key));
+    memset(&devdata, 0, sizeof(devdata));
+    memset(&diddata, 0, sizeof(diddata));
+
+    /* Look for a CNID.  We have two options: dev/ino or did/name.  If we
+    * only get a match in one of them, that means a file has moved. */
+    key.dptr = buf;
+    key.dsize  = TDB_DEVINO_LEN;
+    devdata = tdb_fetch(db->tdb_devino, key);
+    if (!devdata.dptr) {
+         devino = 0;
+    }
+    /* did/name now */
+    key.dptr = buf + TDB_DEVINO_LEN;
+    key.dsize = TDB_DID_LEN + len + 1;
+    diddata = tdb_fetch(db->tdb_didname, key);
+    if (!diddata.dptr) {
+        didname = 0;
+    }
+    /* Set id.  Honor did/name over dev/ino as dev/ino isn't necessarily
+     * 1-1. */
+    if (didname) {
+        memcpy(&id, diddata.dptr, sizeof(id));
+    }
+    else if (devino) {
+        memcpy(&id, devdata.dptr, sizeof(id));
+    }
+    free(devdata.dptr);
+    free(diddata.dptr);
+    /* Either entries are in both databases or neither of them. */
+    if ((devino && didname) || !(devino || didname)) {
+        return id;
+    }
+
+    /* Fix up the database. */
+    cnid_tdb_update(cdb, id, st, did, name, len);
+    return id;
+}
+
+#endif
diff --git a/libatalk/cnid/tdb/cnid_tdb_nextid.c b/libatalk/cnid/tdb/cnid_tdb_nextid.c
new file mode 100644 (file)
index 0000000..8aefa42
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * $Id: cnid_tdb_nextid.c,v 1.2 2005-04-28 20:50:02 bfernhomberg Exp $
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif 
+
+#ifdef CNID_BACKEND_TDB
+
+#include "cnid_tdb.h"
+
+cnid_t cnid_tdb_nextid(struct _cnid_db *cdb)
+{
+    return CNID_INVALID;
+}
+
+#endif 
diff --git a/libatalk/cnid/tdb/cnid_tdb_open.c b/libatalk/cnid/tdb/cnid_tdb_open.c
new file mode 100644 (file)
index 0000000..170e01b
--- /dev/null
@@ -0,0 +1,171 @@
+/*
+ * $Id: cnid_tdb_open.c,v 1.2 2005-04-28 20:50:02 bfernhomberg Exp $
+ *
+ * Copyright (c) 1999. Adrian Sun (asun@zoology.washington.edu)
+ * All Rights Reserved. See COPYRIGHT.
+ *
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef CNID_BACKEND_TDB
+#include <sys/param.h>   
+
+#include "cnid_tdb.h"
+#include <atalk/logger.h>
+#include <stdlib.h>
+#define DBHOME       ".AppleDB"
+#define DBNAME       "private_tdb.%sX"
+#define DBHOMELEN    9                  /* strlen(DBHOME) +1 for / */
+#define DBLEN        12
+#define DBCNID       "cnid.tdb"
+#define DBDEVINO     "devino.tdb"
+#define DBDIDNAME    "didname.tdb"      /* did/full name mapping */
+
+#define DBVERSION_KEY    "\0\0\0\0\0"
+#define DBVERSION_KEYLEN 5
+#define DBVERSION1       0x00000001U
+#define DBVERSION        DBVERSION1
+
+static struct _cnid_db *cnid_tdb_new(const char *volpath)
+{
+    struct _cnid_db *cdb;
+    struct _cnid_tdb_private *priv;
+
+    if ((cdb = (struct _cnid_db *) calloc(1, sizeof(struct _cnid_db))) == NULL)
+        return NULL;
+
+    if ((cdb->volpath = strdup(volpath)) == NULL) {
+        free(cdb);
+        return NULL;
+    }
+
+    if ((cdb->_private = calloc(1, sizeof(struct _cnid_tdb_private))) == NULL) {
+        free(cdb->volpath);
+        free(cdb);
+        return NULL;
+    }
+
+    /* Set up private state */
+    priv = (struct _cnid_tdb_private *) (cdb->_private);
+
+    /* Set up standard fields */
+    cdb->flags = CNID_FLAG_PERSISTENT;
+
+    cdb->cnid_add = cnid_tdb_add;
+    cdb->cnid_delete = cnid_tdb_delete;
+    cdb->cnid_get = cnid_tdb_get;
+    cdb->cnid_lookup = cnid_tdb_lookup;
+    cdb->cnid_nextid = NULL;    /*cnid_tdb_nextid;*/
+    cdb->cnid_resolve = cnid_tdb_resolve;
+    cdb->cnid_update = cnid_tdb_update;
+    cdb->cnid_close = cnid_tdb_close;
+    
+    return cdb;
+}
+
+/* ---------------------------- */
+struct _cnid_db *cnid_tdb_open(const char *dir, mode_t mask)
+{
+    struct stat               st;
+    struct _cnid_db           *cdb;
+    struct _cnid_tdb_private *db;
+    size_t                    len;
+    char                      path[MAXPATHLEN + 1];
+    TDB_DATA                  key, data;
+    
+    if (!dir) {
+        return NULL;
+    }
+
+    if ((len = strlen(dir)) > (MAXPATHLEN - DBLEN - 1)) {
+        LOG(log_error, logtype_default, "tdb_open: Pathname too large: %s", dir);
+        return NULL;
+    }
+    
+    if ((cdb = cnid_tdb_new(dir)) == NULL) {
+        LOG(log_error, logtype_default, "tdb_open: Unable to allocate memory for tdb");
+        return NULL;
+    }
+    strcpy(path, dir);
+    if (path[len - 1] != '/') {
+        strcat(path, "/");
+        len++;
+    }
+    strcpy(path + len, DBHOME);
+    if ((stat(path, &st) < 0) && (ad_mkdir(path, 0777 & ~mask) < 0)) {
+        LOG(log_error, logtype_default, "tdb_open: DBHOME mkdir failed for %s", path);
+        goto fail;
+    }
+    strcat(path, "/");
+    db = (struct _cnid_tdb_private *)cdb->_private;
+
+    path[len + DBHOMELEN] = '\0';
+    strcat(path, DBCNID);
+    db->tdb_cnid = tdb_open(path, 0, 0 , O_RDWR | O_CREAT, 0666 & ~mask);
+    if (!db->tdb_cnid) {
+        LOG(log_error, logtype_default, "tdb_open: unable to open tdb", path);
+        goto fail;
+    }
+    /* ------------- */
+
+    path[len + DBHOMELEN] = '\0';
+    strcat(path, DBDIDNAME);
+    db->tdb_didname = tdb_open(path, 0, 0 , O_RDWR | O_CREAT, 0666 & ~mask);
+    if (!db->tdb_cnid) {
+        LOG(log_error, logtype_default, "tdb_open: unable to open tdb", path);
+        goto fail;
+    }
+    /* Check for version.  This way we can update the database if we need
+     * to change the format in any way. */
+    memset(&key, 0, sizeof(key));
+    memset(&data, 0, sizeof(data));
+    key.dptr = DBVERSION_KEY;
+    key.dsize = DBVERSION_KEYLEN;
+
+    data = tdb_fetch(db->tdb_didname, key);
+    if (!data.dptr) {
+        u_int32_t version = htonl(DBVERSION);
+
+        data.dptr = (char *)&version;
+        data.dsize = sizeof(version);
+        if (tdb_store(db->tdb_didname, key, data, TDB_REPLACE)) {
+            LOG(log_error, logtype_default, "tdb_open: Error putting new version");
+            goto fail;
+        }
+    }
+    else {
+        free(data.dptr);
+    }
+        
+    /* ------------- */
+    path[len + DBHOMELEN] = '\0';
+    strcat(path, DBDEVINO);
+    db->tdb_devino = tdb_open(path, 0, 0 , O_RDWR | O_CREAT, 0666 & ~mask);
+    if (!db->tdb_devino) {
+        LOG(log_error, logtype_default, "tdb_open: unable to open tdb", path);
+        goto fail;
+    }
+
+    return cdb;
+
+fail:
+    free(cdb->_private);
+    free(cdb->volpath);
+    free(cdb);
+    
+    return NULL;
+}
+
+struct _cnid_module cnid_tdb_module = {
+    "tdb",
+    {NULL, NULL},
+    cnid_tdb_open,
+    CNID_FLAG_SETUID
+};
+
+
+#endif
diff --git a/libatalk/cnid/tdb/cnid_tdb_resolve.c b/libatalk/cnid/tdb/cnid_tdb_resolve.c
new file mode 100644 (file)
index 0000000..0f18e82
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * $Id: cnid_tdb_resolve.c,v 1.2 2005-04-28 20:50:02 bfernhomberg Exp $
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef CNID_BACKEND_TDB
+
+#include "cnid_tdb.h"
+
+/* Return the did/name pair corresponding to a CNID. */
+char *cnid_tdb_resolve(struct _cnid_db *cdb, cnid_t * id, void *buffer, u_int32_t len)
+{
+    struct _cnid_tdb_private *db;
+    TDB_DATA key, data;      
+
+    if (!cdb || !(db = cdb->_private) || !id || !(*id)) {
+        return NULL;
+    }
+    key.dptr  = (char *)id;
+    key.dsize = sizeof(cnid_t);
+    data = tdb_fetch(db->tdb_cnid, key);
+    if (data.dptr) 
+    {
+        if (data.dsize < len && data.dsize > sizeof(cnid_t)) {
+            memcpy(id, (char *)data.dptr + TDB_DEVINO_LEN, sizeof(cnid_t));
+            strcpy(buffer, (char *)data.dptr + TDB_HEADER_LEN);
+            free(data.dptr);
+            return buffer;
+        }
+        free(data.dptr);
+    }
+    return NULL;
+}
+
+#endif
diff --git a/libatalk/cnid/tdb/cnid_tdb_update.c b/libatalk/cnid/tdb/cnid_tdb_update.c
new file mode 100644 (file)
index 0000000..b3abc14
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * $Id: cnid_tdb_update.c,v 1.2 2005-04-28 20:50:02 bfernhomberg 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, char *name, const int len
+                     /*, const char *info, const int infolen */ )
+{
+    struct _cnid_tdb_private *db;
+    TDB_DATA key, data, altdata;
+
+    if (!cdb || !(db = cdb->_private) || !id || !st || !name || (db->flags & TDBFLAG_DB_RO)) {
+        return -1;
+    }
+
+    memset(&key, 0, sizeof(key));
+    memset(&altdata, 0, sizeof(altdata));
+
+
+    /* Get the old info. */
+    key.dptr = (char *)&id;
+    key.dsize = sizeof(id);
+    memset(&data, 0, sizeof(data));
+    data = tdb_fetch(db->tdb_cnid, key);
+    if (!data.dptr)
+        return 0;
+
+    key.dptr = data.dptr;
+    key.dsize = TDB_DEVINO_LEN;
+    tdb_delete(db->tdb_devino, key); 
+
+    key.dptr = (char *)data.dptr + TDB_DEVINO_LEN;
+    key.dsize = data.dsize - TDB_DEVINO_LEN;
+    tdb_delete(db->tdb_didname, key); 
+
+    free(data.dptr);
+    /* Make a new entry. */
+    data.dptr = make_tdb_data(st, did, name, len);
+    data.dsize = TDB_HEADER_LEN + len + 1;
+
+    /* Update the old CNID with the new info. */
+    key.dptr = (char *) &id;
+    key.dsize = sizeof(id);
+    if (tdb_store(db->tdb_cnid, key, data, TDB_REPLACE)) {
+        goto update_err;
+    }
+
+    /* Put in a new dev/ino mapping. */
+    key.dptr = data.dptr;
+    key.dsize = TDB_DEVINO_LEN;
+    altdata.dptr  = (char *) &id;
+    altdata.dsize = sizeof(id);
+    if (tdb_store(db->tdb_devino, key, altdata, TDB_REPLACE)) {
+        goto update_err;
+    }
+    /* put in a new did/name mapping. */
+    key.dptr = (char *) data.dptr + TDB_DEVINO_LEN;
+    key.dsize = data.dsize - TDB_DEVINO_LEN;
+    if (tdb_store(db->tdb_didname, key, altdata, TDB_REPLACE)) {
+        goto update_err;
+    }
+
+    return 0;
+update_err:
+    LOG(log_error, logtype_default, "cnid_update: Unable to update CNID %u",
+        ntohl(id));
+    return -1;
+
+}
+
+#endif
index dc22844d8295b654dcbef7de548b3de44d43dd3f..63ccddd4dcc6fbd9d48f3df38ff4e69c49b0745f 100644 (file)
@@ -1,7 +1,5 @@
 # Makefile.am for libatalk/compat/
 
-INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/sys
-
 noinst_LTLIBRARIES = libcompat.la
 
 libcompat_la_SOURCES = \
index 2c53e9c6e31d14e5c96851a527f0087ce1e7a5ae..d64cbed69f8babe20481577e9e13905219195877 100644 (file)
@@ -2,6 +2,8 @@
 
 INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/sys
 
+LIBS = @LIBS@
+
 noinst_LTLIBRARIES = libdsi.la
 
 libdsi_la_SOURCES = dsi_attn.c dsi_close.c dsi_cmdreply.c dsi_getsess.c dsi_getstat.c dsi_init.c dsi_opensess.c dsi_read.c dsi_tcp.c dsi_tickle.c dsi_write.c dsi_stream.c
index b22db8d652563b1091337f4522035f347449dfc4..30ec736df7458df8da3039ff976404f40c9b4674 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: dsi_attn.c,v 1.5 2003-03-12 15:07:05 didg Exp $
+ * $Id: dsi_attn.c,v 1.6 2005-04-28 20:50:02 bfernhomberg Exp $
  *
  * Copyright (c) 1997 Adrian Sun (asun@zoology.washington.edu)
  * All rights reserved. See COPYRIGHT.
@@ -54,7 +54,7 @@ int dsi_attention(DSI *dsi, AFPUserBytes flags)
 
   /* send an attention */
   sigprocmask(SIG_BLOCK, &dsi->sigblockset, &oldset);
-  len = dsi_stream_write(dsi, block, DSI_BLOCKSIZ + len);
+  len = dsi_stream_write(dsi, block, DSI_BLOCKSIZ + len, 0);
   sigprocmask(SIG_SETMASK, &oldset, NULL);
 
   return len;
index fbd084a7e98aebabda20a265e0d3a0ca3a7c1144..f2223fff8f7400795ff27f92501f9ad21c711448 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: dsi_cmdreply.c,v 1.3 2001-06-29 14:14:46 rufustfirefly Exp $
+ * $Id: dsi_cmdreply.c,v 1.4 2005-04-28 20:50:02 bfernhomberg Exp $
  *
  * Copyright (c) 1997 Adrian Sun (asun@zoology.washington.edu)
  * All rights reserved. See COPYRIGHT.
  * reserved field are assumed to already be set. */ 
 int dsi_cmdreply(DSI *dsi, const int err)
 {
+int ret;
   dsi->header.dsi_flags = DSIFL_REPLY;
   /*dsi->header.dsi_command = DSIFUNC_CMD;*/
   dsi->header.dsi_len = htonl(dsi->datalen);
   dsi->header.dsi_code = htonl(err);
 
-  return dsi_stream_send(dsi, dsi->data, dsi->datalen);
+  ret = dsi_stream_send(dsi, dsi->data, dsi->datalen);
+  if (dsi->sigblocked)  {
+      sigprocmask(SIG_SETMASK, &dsi->oldset, NULL);
+      dsi->sigblocked = 0;
+  }
+  return ret;
 }
index 2ad64b439200e0eace53c66c62342ee9b3478a25..a348b41279063352dec31ea17653fdf2e5b75cc5 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: dsi_getsess.c,v 1.6 2002-01-04 04:45:48 sibaz Exp $
+ * $Id: dsi_getsess.c,v 1.7 2005-04-28 20:50:02 bfernhomberg Exp $
  *
  * Copyright (c) 1997 Adrian Sun (asun@zoology.washington.edu)
  * All rights reserved. See COPYRIGHT.
@@ -32,6 +32,7 @@
 
 #include <sys/time.h>
 #include <atalk/logger.h>
+#include <atalk/util.h>
 
 #include <atalk/dsi.h>
 #include <atalk/server_child.h>
@@ -91,7 +92,7 @@ DSI *dsi_getsession(DSI *dsi, server_child *serv_children,
     dsi->header.dsi_flags = DSIFL_REPLY;
     dsi->header.dsi_code = DSIERR_TOOMANY;
     dsi_send(dsi);
-    exit(1);
+    exit(EXITERR_CLNT);
   }
 
   /* get rid of some stuff */
@@ -134,6 +135,6 @@ DSI *dsi_getsession(DSI *dsi, server_child *serv_children,
   default: /* just close */
     LOG(log_info, logtype_default, "DSIUnknown %d", dsi->header.dsi_command);
     dsi->proto_close(dsi);
-    exit(1);
+    exit(EXITERR_CLNT);
   }
 }
index 6d4dd0d342c6b3241ffc1c805a39bdb5f94959a3..4d0e3026fb3967746f0f1940e3f9f9278008bca6 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: dsi_init.c,v 1.3 2001-06-29 14:14:46 rufustfirefly Exp $
+ * $Id: dsi_init.c,v 1.4 2005-04-28 20:50:02 bfernhomberg Exp $
  *
  * Copyright (c) 1997 Adrian Sun (asun@zoology.washington.edu)
  * All rights reserved. See COPYRIGHT.
@@ -34,7 +34,9 @@ DSI *dsi_init(const dsi_proto protocol, const char *program,
     sigaddset(&dsi->sigblockset, SIGTERM);
     sigaddset(&dsi->sigblockset, SIGHUP);
     sigaddset(&dsi->sigblockset, SIGALRM);
-    
+    sigaddset(&dsi->sigblockset, SIGUSR1);
+    /* always block SIGUSR2 even if SERVERTEXT is not defined */
+    sigaddset(&dsi->sigblockset, SIGUSR2);
     switch (protocol) {
       /* currently the only transport protocol that exists for dsi */
     case DSI_TCPIP: 
index 0f33c174b9f7dacd10cc9b90a00c4ed8ef89d414..92dd7eef8dff11b7a4d29fbe46549ad433b31012 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: dsi_read.c,v 1.3 2001-06-29 14:14:46 rufustfirefly Exp $
+ * $Id: dsi_read.c,v 1.4 2005-04-28 20:50:02 bfernhomberg Exp $
  *
  * Copyright (c) 1997 Adrian Sun (asun@zoology.washington.edu)
  * All rights reserved. See COPYRIGHT.
 #include <signal.h>
 #include <sys/types.h>
 #include <sys/time.h>
+#ifdef HAVE_SYS_FILIO_H
+#include <sys/filio.h>
+#endif
 
 #include <atalk/dsi.h>
+#include <sys/ioctl.h> 
 
 #ifndef min
 #define min(a,b)   ((a) < (b) ? (a) : (b))
@@ -32,7 +36,9 @@
 ssize_t dsi_readinit(DSI *dsi, void *buf, const size_t buflen,
                    const size_t size, const int err)
 {
+#ifdef TIMER_ON_WRITE
   const struct itimerval none = {{0, 0}, {0, 0}};
+#endif
 
   dsi->noreply = 1; /* we will handle our own replies */
   dsi->header.dsi_flags = DSIFL_REPLY;
@@ -40,8 +46,11 @@ ssize_t dsi_readinit(DSI *dsi, void *buf, const size_t buflen,
   dsi->header.dsi_len = htonl(size);
   dsi->header.dsi_code = htonl(err);
 
-  sigprocmask(SIG_BLOCK, &dsi->sigblockset, NULL);
+  sigprocmask(SIG_BLOCK, &dsi->sigblockset, &dsi->oldset);
+  dsi->sigblocked = 1;
+#ifdef TIMER_ON_WRITE
   setitimer(ITIMER_REAL, &none, &dsi->savetimer);
+#endif  
   if (dsi_stream_send(dsi, buf, buflen)) {
     dsi->datasize = size - buflen;
     return min(dsi->datasize, buflen);
@@ -52,14 +61,38 @@ ssize_t dsi_readinit(DSI *dsi, void *buf, const size_t buflen,
 
 void dsi_readdone(DSI *dsi)
 {
+#ifdef TIMER_ON_WRITE
   setitimer(ITIMER_REAL, &dsi->savetimer, NULL);
-  sigprocmask(SIG_UNBLOCK, &dsi->sigblockset, NULL);
+#endif
+  sigprocmask(SIG_SETMASK, &dsi->oldset, NULL);
+  dsi->sigblocked = 0;
+}
+
+/* */
+int dsi_block(DSI *dsi, const int mode)
+{
+#if 0
+    dsi->noblocking = mode;
+    return 0;
+#else
+    int adr = mode;
+    int ret;
+    
+    ret = ioctl(dsi->socket, FIONBIO, &adr);
+    if (!ret) {
+        dsi->noblocking = mode;
+    }
+    return ret;
+#endif    
 }
 
 /* send off the data */
 ssize_t dsi_read(DSI *dsi, void *buf, const size_t buflen)
 {
-  size_t len = dsi_stream_write(dsi, buf, buflen);
+  size_t len;
+  int delay = (dsi->datasize != buflen)?1:0;
+  
+  len  = dsi_stream_write(dsi, buf, buflen, delay);
 
   if (len == buflen) {
     dsi->datasize -= len;
index b177b579dde077b1ea17e87a95236cf049f203d0..fbbfbcc974b3d5b60cfd723331342c6a2b471b20 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: dsi_stream.c,v 1.11 2003-03-12 15:07:06 didg Exp $
+ * $Id: dsi_stream.c,v 1.12 2005-04-28 20:50:02 bfernhomberg Exp $
  *
  * Copyright (c) 1998 Adrian Sun (asun@zoology.washington.edu)
  * All rights reserved. See COPYRIGHT.
 
 #include <stdio.h>
 #include <stdlib.h>
+
 #ifdef HAVE_UNISTD_H
 #include <unistd.h>
-#endif /* HAVE_UNISTD_H */
+#endif
+
 #include <string.h>
 #include <errno.h>
 #include <sys/types.h>
+#include <sys/socket.h>
+
 #ifdef USE_WRITEV
 #include <sys/uio.h>
-#endif /* USE_WRITEV */
+#endif
+
 #include <atalk/logger.h>
 
 #include <atalk/dsi.h>
 
 #define min(a,b)  ((a) < (b) ? (a) : (b))
 
+#ifndef MSG_MORE
+#define MSG_MORE 0x8000
+#endif
+
+#ifndef MSG_DONTWAIT
+#define MSG_DONTWAIT 0x40
+#endif
 
-/* write raw data. return actual bytes read. checks against EINTR
+/* ------------------------- 
+ * we don't use a circular buffer.
+*/
+void dsi_buffer(DSI *dsi)
+{
+    fd_set readfds, writefds;
+    int    len;
+    int    maxfd;
+
+    FD_ZERO(&readfds);
+    FD_ZERO(&writefds);
+    FD_SET( dsi->socket, &readfds);
+    FD_SET( dsi->socket, &writefds);
+    maxfd = dsi->socket +1;
+    while (1) {
+        FD_SET( dsi->socket, &readfds);
+        FD_SET( dsi->socket, &writefds);
+        if (select( maxfd, &readfds, &writefds, NULL, NULL) <= 0)
+            return;
+
+        if ( !FD_ISSET(dsi->socket, &readfds)) {
+            /* nothing waiting in the read queue */
+            return;
+        }
+        if (!dsi->buffer) {
+            /* XXX config options */
+            dsi->maxsize = 6 * dsi->server_quantum;
+            if (!dsi->maxsize)
+                dsi->maxsize = 6 * DSI_SERVQUANT_DEF;
+            dsi->buffer = malloc(dsi->maxsize);
+            if (!dsi->buffer) {
+                /* fall back to blocking IO */
+                dsi_block(dsi, 0);
+                return;
+            }
+            dsi->start = dsi->buffer;
+            dsi->eof = dsi->buffer;
+            dsi->end = dsi->buffer + dsi->maxsize;
+        }
+        len = dsi->end - dsi->eof;
+
+        if (len <= 0) {
+            /* ouch, our buffer is full ! 
+             * fall back to blocking IO 
+             * could block and disconnect but it's better than a cpu hog
+             */
+            dsi_block(dsi, 0);
+            return;
+        }
+
+        len = read(dsi->socket, dsi->eof, len);
+        if (len <= 0)
+            return;
+        dsi->eof += len;
+        if ( FD_ISSET(dsi->socket, &writefds)) {
+            return;
+        }
+    }
+}
+
+/* ------------------------------
+ * write raw data. return actual bytes read. checks against EINTR
  * aren't necessary if all of the signals have SA_RESTART
  * specified. */
-size_t dsi_stream_write(DSI *dsi, void *data, const size_t length)
+size_t dsi_stream_write(DSI *dsi, void *data, const size_t length, int mode _U_)
 {
   size_t written;
   ssize_t len;
+#if 0
+  /* FIXME sometime it's slower */
+  unsigned int flags = (mode)?MSG_MORE:0;
+#endif
+  unsigned int flags = 0;
 
+#if 0
+  /* XXX there's no MSG_DONTWAIT in recv ?? so we have to play with ioctl
+  */ 
+  if (dsi->noblocking) {
+      flags |= MSG_DONTWAIT;
+  }
+#endif
+  
   written = 0;
   while (written < length) {
-    if ((-1 == (len = write(dsi->socket, (u_int8_t *) data + written,
-                     length - written)) && errno == EINTR) ||
+    if ((-1 == (len = send(dsi->socket, (u_int8_t *) data + written,
+                     length - written, flags)) && errno == EINTR) ||
        !len)
       continue;
 
     if (len < 0) {
-      LOG(log_error, logtype_default, "dsi_stream_write: %s", strerror(errno));
-      break;
+      if (dsi->noblocking && errno ==  EAGAIN) {
+         /* non blocking mode but will block 
+          * read data in input queue.
+          * 
+         */
+         dsi_buffer(dsi);
+      }
+      else {
+          LOG(log_error, logtype_default, "dsi_stream_write: %s", strerror(errno));
+          break;
+      }
+    }
+    else {
+        written += len;
     }
-    
-    written += len;
   }
 
   dsi->write_count += written;
   return written;
 }
 
-/* read raw data. return actual bytes read. this will wait until 
- * it gets length bytes */
+/* ---------------------------------
+*/
+static ssize_t buf_read(DSI *dsi, u_int8_t *buf, size_t count)
+{
+    ssize_t nbe = 0;
+    ssize_t ret;
+    
+    if (!count)
+        return 0;
+        
+    if (dsi->start) {        
+        nbe = dsi->eof - dsi->start;
+
+        if (nbe > 0) {
+           nbe = min((size_t)nbe, count);
+           memcpy(buf, dsi->start, nbe);
+           dsi->start += nbe;
+
+           if (dsi->eof == dsi->start) 
+               dsi->start = dsi->eof = dsi->buffer;
+
+           if (nbe == count)
+               return nbe;
+           count -= nbe;
+           buf += nbe;
+        }
+        else 
+           nbe = 0;
+    }
+  
+    ret = read(dsi->socket, buf, count);
+    if (ret <= 0)
+        return ret;
+
+    return ret +nbe;
+}
+
+/* ---------------------------------------
+ * read raw data. return actual bytes read. this will wait until 
+ * it gets length bytes 
+ */
 size_t dsi_stream_read(DSI *dsi, void *data, const size_t length)
 {
   size_t stored;
@@ -72,13 +207,16 @@ size_t dsi_stream_read(DSI *dsi, void *data, const size_t length)
   
   stored = 0;
   while (stored < length) {
-    len = read(dsi->socket, (u_int8_t *) data + stored, length - stored);
+    len = buf_read(dsi, (u_int8_t *) data + stored, length - stored);
     if (len == -1 && errno == EINTR)
       continue;
     else if (len > 0)
       stored += len;
     else { /* eof or error */
-      LOG(log_error, logtype_default, "dsi_stream_read(%d): %s", len, (len < 0)?strerror(errno):"unexpected EOF");
+      /* don't log EOF error if it's just after connect (OSX 10.3 probe) */
+      if (len || stored || dsi->read_count) {
+          LOG(log_error, logtype_default, "dsi_stream_read(%d): %s", len, (len < 0)?strerror(errno):"unexpected EOF");
+      }
       break;
     }
   }
@@ -87,17 +225,34 @@ size_t dsi_stream_read(DSI *dsi, void *data, const size_t length)
   return stored;
 }
 
+/* ---------------------------------------
+*/
 void dsi_sleep(DSI *dsi, const int state)
 {
     dsi->asleep = state;
 }
 
-/* write data. 0 on failure. this assumes that dsi_len will never
- * cause an overflow in the data buffer. */
+/* ---------------------------------------
+*/
+static void block_sig(DSI *dsi)
+{
+  if (!dsi->sigblocked) sigprocmask(SIG_BLOCK, &dsi->sigblockset, &dsi->oldset);
+}
+
+/* ---------------------------------------
+*/
+static void unblock_sig(DSI *dsi)
+{
+  if (!dsi->sigblocked) sigprocmask(SIG_SETMASK, &dsi->oldset, NULL);
+}
+
+/* ---------------------------------------
+ * write data. 0 on failure. this assumes that dsi_len will never
+ * cause an overflow in the data buffer. 
+ */
 int dsi_stream_send(DSI *dsi, void *buf, size_t length)
 {
   char block[DSI_BLOCKSIZ];
-  sigset_t oldset;
 #ifdef USE_WRITEV
   struct iovec iov[2];
   size_t towrite;
@@ -113,15 +268,13 @@ int dsi_stream_send(DSI *dsi, void *buf, size_t length)
   memcpy(block + 12, &dsi->header.dsi_reserved,
         sizeof(dsi->header.dsi_reserved));
 
-  /* block signals */
-  sigprocmask(SIG_BLOCK, &dsi->sigblockset, &oldset);
-
   if (!length) { /* just write the header */
-    length = (dsi_stream_write(dsi, block, sizeof(block)) == sizeof(block));
-    sigprocmask(SIG_SETMASK, &oldset, NULL);
+    length = (dsi_stream_write(dsi, block, sizeof(block), 0) == sizeof(block));
     return length; /* really 0 on failure, 1 on success */
   }
   
+  /* block signals */
+  block_sig(dsi);
 #ifdef USE_WRITEV
   iov[0].iov_base = block;
   iov[0].iov_len = sizeof(block);
@@ -139,7 +292,7 @@ int dsi_stream_send(DSI *dsi, void *buf, size_t length)
       break;
     else if (len < 0) { /* error */
       LOG(log_error, logtype_default, "dsi_stream_send: %s", strerror(errno));
-      sigprocmask(SIG_SETMASK, &oldset, NULL);
+      unblock_sig(dsi);
       return 0;
     }
     
@@ -159,19 +312,20 @@ int dsi_stream_send(DSI *dsi, void *buf, size_t length)
   
 #else /* USE_WRITEV */
   /* write the header then data */
-  if ((dsi_stream_write(dsi, block, sizeof(block)) != sizeof(block)) ||
-      (dsi_stream_write(dsi, buf, length) != length)) {
-    sigprocmask(SIG_SETMASK, &oldset, NULL);
-    return 0;
+  if ((dsi_stream_write(dsi, block, sizeof(block), 1) != sizeof(block)) ||
+            (dsi_stream_write(dsi, buf, length, 0) != length)) {
+      unblock_sig(dsi);
+      return 0;
   }
 #endif /* USE_WRITEV */
 
-  sigprocmask(SIG_SETMASK, &oldset, NULL);
+  unblock_sig(dsi);
   return 1;
 }
 
 
-/* read data. function on success. 0 on failure. data length gets
+/* ---------------------------------------
+ * read data. function on success. 0 on failure. data length gets
  * stored in length variable. this should really use size_t's, but
  * that would require changes elsewhere. */
 int dsi_stream_receive(DSI *dsi, void *buf, const size_t ilength,
index 008edf895eeb72220627abcf234b24d9ad9a51f4..0b12e5564284866fa8dc6f41a9b66c447dc1d552 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: dsi_tcp.c,v 1.9 2002-01-24 16:27:31 jmarcus Exp $
+ * $Id: dsi_tcp.c,v 1.10 2005-04-28 20:50:02 bfernhomberg Exp $
  *
  * Copyright (c) 1997, 1998 Adrian Sun (asun@zoology.washington.edu)
  * All rights reserved. See COPYRIGHT.
@@ -90,9 +90,14 @@ static void dsi_tcp_close(DSI *dsi)
 static void timeout_handler()
 {
   LOG(log_error, logtype_default, "dsi_tcp_open: connection timed out");
-  exit(1);
+  exit(EXITERR_CLNT);
 }
 
+#ifdef ATACC
+#define fork aTaC_fork
+#endif
+
+static struct itimerval itimer;
 /* accept the socket and do a little sanity checking */
 static int dsi_tcp_open(DSI *dsi)
 {
@@ -120,15 +125,15 @@ static int dsi_tcp_open(DSI *dsi)
   if (dsi->socket < 0)
     return -1;
 
-  if ((pid = fork()) == 0) { /* child */
-    static const struct itimerval timer = {{0, 0}, {DSI_TCPTIMEOUT, 0}};
+  getitimer(ITIMER_PROF, &itimer);
+  if (0 == (pid = fork()) ) { /* child */
+    static struct itimerval timer = {{0, 0}, {DSI_TCPTIMEOUT, 0}};
     struct sigaction newact, oldact;
     u_int8_t block[DSI_BLOCKSIZ];
     size_t stored;
     
-    /* reset a couple signals */
-    signal(SIGTERM, SIG_DFL); 
-    signal(SIGHUP, SIG_DFL);
+    /* reset signals */
+    server_reset_signal();
 
     /* install an alarm to deal with non-responsive connections */
     newact.sa_handler = timeout_handler;
@@ -136,10 +141,12 @@ static int dsi_tcp_open(DSI *dsi)
     newact.sa_flags = 0;
     sigemptyset(&oldact.sa_mask);
     oldact.sa_flags = 0;
+    setitimer(ITIMER_PROF, &itimer, NULL);
+
     if ((sigaction(SIGALRM, &newact, &oldact) < 0) ||
         (setitimer(ITIMER_REAL, &timer, NULL) < 0)) {
        LOG(log_error, logtype_default, "dsi_tcp_open: %s", strerror(errno));
-       exit(1);
+       exit(EXITERR_SYS);
     }
     
     /* read in commands. this is similar to dsi_receive except
@@ -148,9 +155,13 @@ static int dsi_tcp_open(DSI *dsi)
     
     /* read in the first two bytes */
     len = dsi_stream_read(dsi, block, 2);
-    if (len <= 0 || (block[0] > DSIFL_MAX) || (block[1] > DSIFUNC_MAX)) {
+    if (!len ) {
+      /* connection already closed, don't log it (normal OSX 10.3 behaviour) */
+      exit(EXITERR_CLNT);
+    }
+    if (len < 2 || (block[0] > DSIFL_MAX) || (block[1] > DSIFUNC_MAX)) {
       LOG(log_error, logtype_default, "dsi_tcp_open: invalid header");
-      exit(1);
+      exit(EXITERR_CLNT);
     }      
     
     /* read in the rest of the header */
@@ -161,7 +172,7 @@ static int dsi_tcp_open(DSI *dsi)
        stored += len;
       else {
        LOG(log_error, logtype_default, "dsi_tcp_open: stream_read: %s", strerror(errno));
-       exit(1);
+       exit(EXITERR_CLNT);
       }
     }
     
@@ -185,11 +196,13 @@ static int dsi_tcp_open(DSI *dsi)
        stored += len;
       else {
        LOG(log_error, logtype_default, "dsi_tcp_open: stream_read: %s", strerror(errno));
-       exit(1);
+       exit(EXITERR_CLNT);
       }
     }
     
-    /* restore signal */
+    /* stop timer and restore signal handler */
+    memset(&timer, 0, sizeof(timer));
+    setitimer(ITIMER_REAL, &timer, NULL);
     sigaction(SIGALRM, &oldact, NULL);
 
     LOG(log_info, logtype_default,"ASIP session:%u(%d) from %s:%u(%d)", 
@@ -242,12 +255,14 @@ int dsi_tcp_init(DSI *dsi, const char *hostname, const char *address,
 #ifdef SO_REUSEADDR
     port = 1;
     setsockopt(dsi->serversock, SOL_SOCKET, SO_REUSEADDR, &port, sizeof(port));
-#endif /* SO_REUSEADDR */
+#endif
 
 #ifdef USE_TCP_NODELAY 
+
 #ifndef SOL_TCP
 #define SOL_TCP IPPROTO_TCP
-#endif /* ! SOL_TCP */
+#endif 
+
     port = 1;
     setsockopt(dsi->serversock, SOL_TCP, TCP_NODELAY, &port, sizeof(port));
 #endif /* USE_TCP_NODELAY */
@@ -261,58 +276,74 @@ int dsi_tcp_init(DSI *dsi, const char *hostname, const char *address,
     }
   }
 
+  /* Point protocol specific functions to tcp versions */
+  dsi->proto_open = dsi_tcp_open;
+  dsi->proto_close = dsi_tcp_close;
+
   /* get real address for GetStatus. we'll go through the list of 
    * interfaces if necessary. */
-  if (!address) {
-    if ((host = gethostbyname(hostname))) /* we can resolve the name */
-      dsi->server.sin_addr.s_addr = ((struct in_addr *) host->h_addr)->s_addr;
-    else {
+
+  if (address) {
+      /* address is a parameter, use it 'as is' */
+      return 1;
+  }
+  
+  if (!(host = gethostbyname(hostname)) ) { /* we can't resolve the name */
+
+      LOG(log_info, logtype_default, "dsi_tcp: cannot resolve hostname '%s'", hostname);
+      if (proxy) {
+         /* give up we have nothing to advertise */
+         return 0;
+      }
+  }
+  else {
+      if (((struct in_addr *) host->h_addr)->s_addr != 0x100007F) { /* FIXME ugly check */
+          dsi->server.sin_addr.s_addr = ((struct in_addr *) host->h_addr)->s_addr;
+          return 1;
+      }
+      LOG(log_info, logtype_default, "dsi_tcp: hostname '%s' resolves to loopback address", hostname);
+  }
+  {
       char **start, **list;
       struct ifreq ifr;
 
       /* get it from the interface list */
       start = list = getifacelist();
       while (list && *list) {
-       strncpy(ifr.ifr_name, *list, sizeof(ifr.ifr_name));
-       list++;
+          strlcpy(ifr.ifr_name, *list, sizeof(ifr.ifr_name));
+         list++;
 
 #ifndef IFF_SLAVE
 #define IFF_SLAVE 0
-#endif /* ! IFF_SLAVE */
-       if (ioctl(dsi->serversock, SIOCGIFFLAGS, &ifr) < 0)
-         continue;
+#endif
 
-       if (ifr.ifr_flags & (IFF_LOOPBACK | IFF_POINTOPOINT | IFF_SLAVE))
-         continue;
+         if (ioctl(dsi->serversock, SIOCGIFFLAGS, &ifr) < 0)
+           continue;
 
-       if ((ifr.ifr_flags & IFF_UP) == 0)
-         continue;
+         if (ifr.ifr_flags & (IFF_LOOPBACK | IFF_POINTOPOINT | IFF_SLAVE))
+           continue;
 
-       if (ioctl(dsi->serversock, SIOCGIFADDR, &ifr) < 0)
-         continue;
+         if (!(ifr.ifr_flags & (IFF_UP | IFF_RUNNING)) )
+           continue;
+
+         if (ioctl(dsi->serversock, SIOCGIFADDR, &ifr) < 0)
+           continue;
        
-       dsi->server.sin_addr.s_addr = 
-         ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr;
-       LOG(log_info, logtype_default, "dsi_tcp: Can't resolve hostname (%s).\n"
-              "%s on interface %s will be used instead.", hostname,
+         dsi->server.sin_addr.s_addr = 
+           ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr;
+         LOG(log_info, logtype_default, "dsi_tcp: '%s' on interface '%s' will be used instead.",
               inet_ntoa(dsi->server.sin_addr), ifr.ifr_name);
-       goto iflist_done;
-
+         goto iflist_done;
       }
-      LOG(log_info, logtype_default, "dsi_tcp (Chooser will not select afp/tcp)\n\
-Check to make sure %s is in /etc/hosts and the correct domain is in\n\
+      LOG(log_info, logtype_default, "dsi_tcp (Chooser will not select afp/tcp) \
+Check to make sure %s is in /etc/hosts and the correct domain is in \
 /etc/resolv.conf: %s", hostname, strerror(errno));
 
 iflist_done:
       if (start)
-       freeifacelist(start);
-    }
+          freeifacelist(start);
   }
 
-  /* everything's set up. now point protocol specific functions to 
-   * tcp versions */
-  dsi->proto_open = dsi_tcp_open;
-  dsi->proto_close = dsi_tcp_close;
   return 1;
 
 }
index 6f1e095d533ad1707f083e41e0617f40af08375e..98606d4017cb61d8945b91b91b5c2415087b4e51 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: dsi_tickle.c,v 1.5 2003-03-12 15:07:07 didg Exp $
+ * $Id: dsi_tickle.c,v 1.6 2005-04-28 20:50:02 bfernhomberg Exp $
  *
  * Copyright (c) 1997 Adrian Sun (asun@zoology.washington.edu)
  * All rights reserved. See COPYRIGHT.
@@ -39,7 +39,7 @@ int dsi_tickle(DSI *dsi)
   /* code = len = reserved = 0 */
 
   sigprocmask(SIG_BLOCK, &dsi->sigblockset, &oldset);
-  ret = dsi_stream_write(dsi, block, DSI_BLOCKSIZ) == DSI_BLOCKSIZ;
+  ret = dsi_stream_write(dsi, block, DSI_BLOCKSIZ, 0) == DSI_BLOCKSIZ;
   sigprocmask(SIG_SETMASK, &oldset, NULL);
   return ret;
 }
index 8ce85c2ca547f4cff7977681b4e5e6d549f06a96..59f8e387191e7eb0fe5abdc18177b2eea846014c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: dsi_write.c,v 1.3 2001-06-29 14:14:46 rufustfirefly Exp $
+ * $Id: dsi_write.c,v 1.4 2005-04-28 20:50:02 bfernhomberg Exp $
  *
  * Copyright (c) 1997 Adrian Sun (asun@zoology.washington.edu)
  * All rights reserved. See COPYRIGHT.
 /* initialize relevant things for dsi_write. this returns the amount
  * of data in the data buffer. the interface has been reworked to allow
  * for arbitrary buffers. */
-size_t dsi_writeinit(DSI *dsi, void *buf, const size_t buflen)
+size_t dsi_writeinit(DSI *dsi, void *buf, const size_t buflen _U_)
 {
+#ifdef TIMER_ON_READ
   const struct itimerval none = {{0, 0}, {0, 0}};
+#endif  
   size_t len, header;
 
   /* figure out how much data we have. do a couple checks for 0 
@@ -54,11 +56,14 @@ size_t dsi_writeinit(DSI *dsi, void *buf, const size_t buflen)
   } else
     len = 0;
 
+#ifdef TIMER_ON_READ
   /* deal with signals. i'm doing it this way to ensure that we don't
    * get confused if a writeflush on zero remaining data is, for some
    * reason, needed. */
-  sigprocmask(SIG_BLOCK, &dsi->sigblockset, NULL);
+  sigprocmask(SIG_BLOCK, &dsi->sigblockset, &dsi->oldset);
+  dsi->sigblocked = 1;
   setitimer(ITIMER_REAL, &none, &dsi->savetimer);
+#endif  
   return len;
 }
 
@@ -74,9 +79,10 @@ size_t dsi_write(DSI *dsi, void *buf, const size_t buflen)
     dsi->datasize -= length;
     return length;
   }
-
+#ifdef TIMER_ON_READ
   setitimer(ITIMER_REAL, &dsi->savetimer, NULL);
-  sigprocmask(SIG_UNBLOCK, &dsi->sigblockset, NULL);
+  sigprocmask(SIG_SETMASK, &dsi->oldset, NULL);
+#endif
   return 0;
 }
 
@@ -93,7 +99,8 @@ void dsi_writeflush(DSI *dsi)
     else
       break;
   }
-
+#ifdef TIMER_ON_READ
   setitimer(ITIMER_REAL, &dsi->savetimer, NULL);
-  sigprocmask(SIG_UNBLOCK, &dsi->sigblockset, NULL);
+  sigprocmask(SIG_SETMASK, &dsi->oldset, NULL);
+#endif  
 }
index 9b56d18794131b796f3c98beff7c2597ab3bb310..1a6404dd6f74b7449e01e2d1b7f08504f784408b 100644 (file)
@@ -1,7 +1,5 @@
 # Makefile.am for libatalk/nbp/
 
-INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/sys
-
 noinst_LTLIBRARIES = libnbp.la
 
 libnbp_la_SOURCES = nbp_util.c nbp_lkup.c nbp_rgstr.c nbp_unrgstr.c
index 31745584e2fffd580f97ef65444e564b81a02964..9f6208794986d948fba718667d985bc24bce8854 100644 (file)
@@ -1,7 +1,5 @@
 # Makefile.am for libatalk/netddp/
 
-INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/sys
-
 noinst_LTLIBRARIES = libnetddp.la
 
 libnetddp_la_SOURCES = netddp_open.c netddp_sendto.c netddp_recvfrom.c
index 1e1bf5430f0237ac3380cd8f00bf06741f76a651..20ab8efc3b8c98433d7d10bceb47d771f57bfcf9 100644 (file)
@@ -1,5 +1,5 @@
 /* 
- * $Id: netddp_open.c,v 1.8 2003-02-17 02:02:25 srittau Exp $
+ * $Id: netddp_open.c,v 1.9 2005-04-28 20:50:02 bfernhomberg Exp $
  *
  * Copyright (c) 1999 Adrian Sun (asun@zoology.washington.edu)
  * Copyright (c) 1990,1991 Regents of The University of Michigan.
@@ -59,7 +59,7 @@ int netddp_open(struct sockaddr_at *addr, struct sockaddr_at *bridge)
       bridge->sat_port = baddress.socket;
     }
 #else /* MACOSX_SERVER */
-    size_t len;
+    socklen_t len;
 
     if ((s = socket( AF_APPLETALK, SOCK_DGRAM, 0 )) < 0) 
        return -1;
index 1a95b68d547008ec01005328c47c6300597552d4..407b94d0f89ab687e524d07926049b33d4555884 100644 (file)
@@ -1,5 +1,5 @@
 /* 
- * $Id: netddp_sendto.c,v 1.6 2003-02-17 02:02:25 srittau Exp $
+ * $Id: netddp_sendto.c,v 1.7 2005-04-28 20:50:02 bfernhomberg Exp $
  *
  * Copyright (c) 1999 Adrian Sun (asun@zoology.washington.edu)
  * Copyright (c) 1990,1991 Regents of The University of Michigan.
@@ -54,7 +54,7 @@ int netddp_sendto(int fd, void *buf, size_t buflen, unsigned int dummy,
       return -1;
 
     memset(&ddphdr, 0, sizeof(ddphdr));
-    ddphdr.deh_len = htons(sizeof(ddphdr) + (uint16_t) buflen);
+    ddphdr.deh_len = htons(sizeof(ddphdr) + (u_int16_t) buflen);
     ddphdr.deh_dnet = sat->sat_addr.s_net;
     ddphdr.deh_dnode = sat->sat_addr.s_node;
     ddphdr.deh_dport = sat->sat_port;
diff --git a/libatalk/pap/.cvsignore b/libatalk/pap/.cvsignore
new file mode 100644 (file)
index 0000000..0d0371d
--- /dev/null
@@ -0,0 +1,6 @@
+Makefile
+Makefile.in
+*.lo
+*.la
+.deps
+.libs
diff --git a/libatalk/tdb/.cvsignore b/libatalk/tdb/.cvsignore
new file mode 100644 (file)
index 0000000..0d0371d
--- /dev/null
@@ -0,0 +1,6 @@
+Makefile
+Makefile.in
+*.lo
+*.la
+.deps
+.libs
diff --git a/libatalk/tdb/Makefile.am b/libatalk/tdb/Makefile.am
new file mode 100644 (file)
index 0000000..78be1af
--- /dev/null
@@ -0,0 +1,10 @@
+# Makefile.am for libatalk/tdb/
+
+CFLAGS = @CFLAGS@ 
+
+noinst_LTLIBRARIES = libtdb.la
+
+libtdb_la_SOURCES = tdb.c \
+                    spinlock.c \
+                    spinlock.h
+
diff --git a/libatalk/tdb/spinlock.c b/libatalk/tdb/spinlock.c
new file mode 100644 (file)
index 0000000..7d20106
--- /dev/null
@@ -0,0 +1,431 @@
+/* 
+   Unix SMB/CIFS implementation.
+   Samba database functions
+   Copyright (C) Anton Blanchard                   2001
+   
+   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.
+*/
+#define STANDALONE 1
+
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#if STANDALONE
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <time.h>
+#include <signal.h>
+#include "spinlock.h"
+
+#define DEBUG
+#else
+#include "includes.h"
+#endif
+
+#ifdef USE_SPINLOCKS
+
+/*
+ * ARCH SPECIFIC
+ */
+
+#if defined(SPARC_SPINLOCKS)
+
+static inline int __spin_trylock(spinlock_t *lock)
+{
+       unsigned int result;
+
+       asm volatile("ldstub    [%1], %0"
+               : "=r" (result)
+               : "r" (lock)
+               : "memory");
+
+       return (result == 0) ? 0 : EBUSY;
+}
+
+static inline void __spin_unlock(spinlock_t *lock)
+{
+       asm volatile("":::"memory");
+       *lock = 0;
+}
+
+static inline void __spin_lock_init(spinlock_t *lock)
+{
+       *lock = 0;
+}
+
+static inline int __spin_is_locked(spinlock_t *lock)
+{
+       return (*lock != 0);
+}
+
+#elif defined(POWERPC_SPINLOCKS) 
+
+static inline int __spin_trylock(spinlock_t *lock)
+{
+       unsigned int result;
+
+       __asm__ __volatile__(
+"1:    lwarx           %0,0,%1\n\
+       cmpwi           0,%0,0\n\
+       li              %0,0\n\
+       bne-            2f\n\
+       li              %0,1\n\
+       stwcx.          %0,0,%1\n\
+       bne-            1b\n\
+       isync\n\
+2:"    : "=&r"(result)
+       : "r"(lock)
+       : "cr0", "memory");
+
+       return (result == 1) ? 0 : EBUSY;
+}
+
+static inline void __spin_unlock(spinlock_t *lock)
+{
+       asm volatile("eieio":::"memory");
+       *lock = 0;
+}
+
+static inline void __spin_lock_init(spinlock_t *lock)
+{
+       *lock = 0;
+}
+
+static inline int __spin_is_locked(spinlock_t *lock)
+{
+       return (*lock != 0);
+}
+
+#elif defined(INTEL_SPINLOCKS) 
+
+static inline int __spin_trylock(spinlock_t *lock)
+{
+       int oldval;
+
+       asm volatile("xchgl %0,%1"
+               : "=r" (oldval), "=m" (*lock)
+               : "0" (0)
+               : "memory");
+
+       return oldval > 0 ? 0 : EBUSY;
+}
+
+static inline void __spin_unlock(spinlock_t *lock)
+{
+       asm volatile("":::"memory");
+       *lock = 1;
+}
+
+static inline void __spin_lock_init(spinlock_t *lock)
+{
+       *lock = 1;
+}
+
+static inline int __spin_is_locked(spinlock_t *lock)
+{
+       return (*lock != 1);
+}
+
+#elif defined(MIPS_SPINLOCKS) 
+
+static inline unsigned int load_linked(unsigned long addr)
+{
+       unsigned int res;
+
+       __asm__ __volatile__("ll\t%0,(%1)"
+               : "=r" (res)
+               : "r" (addr));
+
+       return res;
+}
+
+static inline unsigned int store_conditional(unsigned long addr, unsigned int value)
+{
+       unsigned int res;
+
+       __asm__ __volatile__("sc\t%0,(%2)"
+               : "=r" (res)
+               : "0" (value), "r" (addr));
+       return res;
+}
+
+static inline int __spin_trylock(spinlock_t *lock)
+{
+       unsigned int mw;
+
+       do {
+               mw = load_linked(lock);
+               if (mw) 
+                       return EBUSY;
+       } while (!store_conditional(lock, 1));
+
+       asm volatile("":::"memory");
+
+       return 0;
+}
+
+static inline void __spin_unlock(spinlock_t *lock)
+{
+       asm volatile("":::"memory");
+       *lock = 0;
+}
+
+static inline void __spin_lock_init(spinlock_t *lock)
+{
+       *lock = 0;
+}
+
+static inline int __spin_is_locked(spinlock_t *lock)
+{
+       return (*lock != 0);
+}
+
+#else
+#error Need to implement spinlock code in spinlock.c
+#endif
+
+/*
+ * OS SPECIFIC
+ */
+
+static void yield_cpu(void)
+{
+       struct timespec tm;
+
+#ifdef USE_SCHED_YIELD
+       sched_yield();
+#else
+       /* Linux will busy loop for delays < 2ms on real time tasks */
+       tm.tv_sec = 0;
+       tm.tv_nsec = 2000000L + 1;
+       nanosleep(&tm, NULL);
+#endif
+}
+
+static int this_is_smp(void)
+{
+       return 0;
+}
+
+/*
+ * GENERIC
+ */
+
+static int smp_machine = 0;
+
+static inline void __spin_lock(spinlock_t *lock)
+{
+       int ntries = 0;
+
+       while(__spin_trylock(lock)) {
+               while(__spin_is_locked(lock)) {
+                       if (smp_machine && ntries++ < MAX_BUSY_LOOPS)
+                               continue;
+                       yield_cpu();
+               }
+       }
+}
+
+static void __read_lock(tdb_rwlock_t *rwlock)
+{
+       int ntries = 0;
+
+       while(1) {
+               __spin_lock(&rwlock->lock);
+
+               if (!(rwlock->count & RWLOCK_BIAS)) {
+                       rwlock->count++;
+                       __spin_unlock(&rwlock->lock);
+                       return;
+               }
+       
+               __spin_unlock(&rwlock->lock);
+
+               while(rwlock->count & RWLOCK_BIAS) {
+                       if (smp_machine && ntries++ < MAX_BUSY_LOOPS)
+                               continue;
+                       yield_cpu();
+               }
+       }
+}
+
+static void __write_lock(tdb_rwlock_t *rwlock)
+{
+       int ntries = 0;
+
+       while(1) {
+               __spin_lock(&rwlock->lock);
+
+               if (rwlock->count == 0) {
+                       rwlock->count |= RWLOCK_BIAS;
+                       __spin_unlock(&rwlock->lock);
+                       return;
+               }
+
+               __spin_unlock(&rwlock->lock);
+
+               while(rwlock->count != 0) {
+                       if (smp_machine && ntries++ < MAX_BUSY_LOOPS)
+                               continue;
+                       yield_cpu();
+               }
+       }
+}
+
+static void __write_unlock(tdb_rwlock_t *rwlock)
+{
+       __spin_lock(&rwlock->lock);
+
+#ifdef DEBUG
+       if (!(rwlock->count & RWLOCK_BIAS))
+               fprintf(stderr, "bug: write_unlock\n");
+#endif
+
+       rwlock->count &= ~RWLOCK_BIAS;
+       __spin_unlock(&rwlock->lock);
+}
+
+static void __read_unlock(tdb_rwlock_t *rwlock)
+{
+       __spin_lock(&rwlock->lock);
+
+#ifdef DEBUG
+       if (!rwlock->count)
+               fprintf(stderr, "bug: read_unlock\n");
+
+       if (rwlock->count & RWLOCK_BIAS)
+               fprintf(stderr, "bug: read_unlock\n");
+#endif
+
+       rwlock->count--;
+       __spin_unlock(&rwlock->lock);
+}
+
+/* TDB SPECIFIC */
+
+/* lock a list in the database. list -1 is the alloc list */
+int tdb_spinlock(TDB_CONTEXT *tdb, int list, int rw_type)
+{
+       tdb_rwlock_t *rwlocks;
+
+       if (!tdb->map_ptr) return -1;
+       rwlocks = (tdb_rwlock_t *)((char *)tdb->map_ptr + tdb->header.rwlocks);
+
+       switch(rw_type) {
+       case F_RDLCK:
+               __read_lock(&rwlocks[list+1]);
+               break;
+
+       case F_WRLCK:
+               __write_lock(&rwlocks[list+1]);
+               break;
+
+       default:
+               return TDB_ERRCODE(TDB_ERR_LOCK, -1);
+       }
+       return 0;
+}
+
+/* unlock the database. */
+int tdb_spinunlock(TDB_CONTEXT *tdb, int list, int rw_type)
+{
+       tdb_rwlock_t *rwlocks;
+
+       if (!tdb->map_ptr) return -1;
+       rwlocks = (tdb_rwlock_t *)((char *)tdb->map_ptr + tdb->header.rwlocks);
+
+       switch(rw_type) {
+       case F_RDLCK:
+               __read_unlock(&rwlocks[list+1]);
+               break;
+
+       case F_WRLCK:
+               __write_unlock(&rwlocks[list+1]);
+               break;
+
+       default:
+               return TDB_ERRCODE(TDB_ERR_LOCK, -1);
+       }
+
+       return 0;
+}
+
+int tdb_create_rwlocks(int fd, unsigned int hash_size)
+{
+       unsigned size, i;
+       tdb_rwlock_t *rwlocks;
+
+       size = (hash_size + 1) * sizeof(tdb_rwlock_t);
+       rwlocks = malloc(size);
+       if (!rwlocks)
+               return -1;
+
+       for(i = 0; i < hash_size+1; i++) {
+               __spin_lock_init(&rwlocks[i].lock);
+               rwlocks[i].count = 0;
+       }
+
+       /* Write it out (appending to end) */
+       if (write(fd, rwlocks, size) != size) {
+               free(rwlocks);
+               return -1;
+       }
+       smp_machine = this_is_smp();
+       free(rwlocks);
+       return 0;
+}
+
+int tdb_clear_spinlocks(TDB_CONTEXT *tdb)
+{
+       tdb_rwlock_t *rwlocks;
+       unsigned i;
+
+       if (tdb->header.rwlocks == 0) return 0;
+       if (!tdb->map_ptr) return -1;
+
+       /* We're mmapped here */
+       rwlocks = (tdb_rwlock_t *)((char *)tdb->map_ptr + tdb->header.rwlocks);
+       for(i = 0; i < tdb->header.hash_size+1; i++) {
+               __spin_lock_init(&rwlocks[i].lock);
+               rwlocks[i].count = 0;
+       }
+       return 0;
+}
+#else
+int tdb_create_rwlocks(int fd, unsigned int hash_size) { return 0; }
+int tdb_spinlock(TDB_CONTEXT *tdb, int list, int rw_type) { return -1; }
+int tdb_spinunlock(TDB_CONTEXT *tdb, int list, int rw_type) { return -1; }
+
+/* Non-spinlock version: remove spinlock pointer */
+int tdb_clear_spinlocks(TDB_CONTEXT *tdb)
+{
+       tdb_off off = (tdb_off)((char *)&tdb->header.rwlocks
+                               - (char *)&tdb->header);
+
+       tdb->header.rwlocks = 0;
+       if (lseek(tdb->fd, off, SEEK_SET) != off
+           || write(tdb->fd, (void *)&tdb->header.rwlocks,
+                    sizeof(tdb->header.rwlocks)) 
+           != sizeof(tdb->header.rwlocks))
+               return -1;
+       return 0;
+}
+#endif
diff --git a/libatalk/tdb/spinlock.h b/libatalk/tdb/spinlock.h
new file mode 100644 (file)
index 0000000..3c5d47a
--- /dev/null
@@ -0,0 +1,55 @@
+#ifndef __SPINLOCK_H__
+#define __SPINLOCK_H__
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <atalk/tdb.h>
+
+#ifdef USE_SPINLOCKS
+
+#define RWLOCK_BIAS 0x1000UL
+
+/* OS SPECIFIC */
+#define MAX_BUSY_LOOPS 1000
+#undef USE_SCHED_YIELD
+
+/* ARCH SPECIFIC */
+/* We should make sure these are padded to a cache line */
+#if defined(SPARC_SPINLOCKS)
+typedef volatile char spinlock_t;
+#elif defined(POWERPC_SPINLOCKS)
+typedef volatile unsigned long spinlock_t;
+#elif defined(INTEL_SPINLOCKS)
+typedef volatile int spinlock_t;
+#elif defined(MIPS_SPINLOCKS)
+typedef volatile unsigned long spinlock_t;
+#else
+#error Need to implement spinlock code in spinlock.h
+#endif
+
+typedef struct {
+       spinlock_t lock;
+       volatile int count;
+} tdb_rwlock_t;
+
+int tdb_spinlock(TDB_CONTEXT *tdb, int list, int rw_type);
+int tdb_spinunlock(TDB_CONTEXT *tdb, int list, int rw_type);
+int tdb_create_rwlocks(int fd, unsigned int hash_size);
+int tdb_clear_spinlocks(TDB_CONTEXT *tdb);
+
+#else /* !USE_SPINLOCKS */
+#if 0
+#define tdb_create_rwlocks(fd, hash_size) 0
+#define tdb_spinlock(tdb, list, rw_type) (-1)
+#define tdb_spinunlock(tdb, list, rw_type) (-1)
+#else
+int tdb_spinlock(TDB_CONTEXT *tdb, int list, int rw_type);
+int tdb_spinunlock(TDB_CONTEXT *tdb, int list, int rw_type);
+int tdb_create_rwlocks(int fd, unsigned int hash_size);
+#endif
+int tdb_clear_spinlocks(TDB_CONTEXT *tdb);
+#endif
+
+#endif
diff --git a/libatalk/tdb/tdb.c b/libatalk/tdb/tdb.c
new file mode 100644 (file)
index 0000000..369bf04
--- /dev/null
@@ -0,0 +1,2044 @@
+ /* 
+   Unix SMB/CIFS implementation.
+   Samba database functions
+   Copyright (C) Andrew Tridgell              1999-2000
+   Copyright (C) Luke Kenneth Casson Leighton      2000
+   Copyright (C) Paul `Rusty' Russell             2000
+   Copyright (C) Jeremy Allison                           2000-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.
+*/
+
+#define STANDALONE 1
+
+/* NOTE: If you use tdbs under valgrind, and in particular if you run
+ * tdbtorture, you may get spurious "uninitialized value" warnings.  I
+ * think this is because valgrind doesn't understand that the mmap'd
+ * area may be written to by other processes.  Memory can, from the
+ * point of view of the grinded process, spontaneously become
+ * initialized.
+ *
+ * I can think of a few solutions.  [mbp 20030311]
+ *
+ * 1 - Write suppressions for Valgrind so that it doesn't complain
+ * about this.  Probably the most reasonable but people need to
+ * remember to use them.
+ *
+ * 2 - Use IO not mmap when running under valgrind.  Not so nice.
+ *
+ * 3 - Use the special valgrind macros to mark memory as valid at the
+ * right time.  Probably too hard -- the process just doesn't know.
+ */ 
+
+#ifdef STANDALONE
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#define _XOPEN_SOURCE 500
+#include <unistd.h>
+#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 "spinlock.h"
+#else
+#include "includes.h"
+#endif
+
+#define TDB_MAGIC_FOOD "TDB file\n"
+#define TDB_VERSION (0x26011967 + 6)
+#define TDB_MAGIC (0x26011999U)
+#define TDB_FREE_MAGIC (~TDB_MAGIC)
+#define TDB_DEAD_MAGIC (0xFEE1DEAD)
+#define TDB_ALIGNMENT 4
+#define MIN_REC_SIZE (2*sizeof(struct list_struct) + TDB_ALIGNMENT)
+#define DEFAULT_HASH_SIZE 131
+#define TDB_PAGE_SIZE 0x2000
+#define FREELIST_TOP (sizeof(struct tdb_header))
+#define TDB_ALIGN(x,a) (((x) + (a)-1) & ~((a)-1))
+#define TDB_BYTEREV(x) (((((x)&0xff)<<24)|((x)&0xFF00)<<8)|(((x)>>8)&0xFF00)|((x)>>24))
+#define TDB_DEAD(r) ((r)->magic == TDB_DEAD_MAGIC)
+#define TDB_BAD_MAGIC(r) ((r)->magic != TDB_MAGIC && !TDB_DEAD(r))
+#define TDB_HASH_TOP(hash) (FREELIST_TOP + (BUCKET(hash)+1)*sizeof(tdb_off))
+
+/* NB assumes there is a local variable called "tdb" that is the
+ * current context, also takes doubly-parenthesized print-style
+ * argument. */
+#define TDB_LOG(x) (tdb->log_fn?((tdb->log_fn x),0) : 0)
+
+/* lock offsets */
+#define GLOBAL_LOCK 0
+#define ACTIVE_LOCK 4
+
+#ifndef MAP_FILE
+#define MAP_FILE 0
+#endif
+
+#ifndef MAP_FAILED
+#define MAP_FAILED ((void *)-1)
+#endif
+
+/* free memory if the pointer is valid and zero the pointer */
+#ifndef SAFE_FREE
+#define SAFE_FREE(x) do { if ((x) != NULL) {free((x)); (x)=NULL;} } while(0)
+#endif
+
+#define BUCKET(hash) ((hash) % tdb->header.hash_size)
+TDB_DATA tdb_null;
+
+/* all contexts, to ensure no double-opens (fcntl locks don't nest!) */
+static TDB_CONTEXT *tdbs = NULL;
+
+static int tdb_munmap(TDB_CONTEXT *tdb)
+{
+       if (tdb->flags & TDB_INTERNAL)
+               return 0;
+
+#ifdef HAVE_MMAP
+       if (tdb->map_ptr) {
+               int ret = munmap(tdb->map_ptr, tdb->map_size);
+               if (ret != 0)
+                       return ret;
+       }
+#endif
+       tdb->map_ptr = NULL;
+       return 0;
+}
+
+static void tdb_mmap(TDB_CONTEXT *tdb)
+{
+       if (tdb->flags & TDB_INTERNAL)
+               return;
+
+#ifdef HAVE_MMAP
+       if (!(tdb->flags & TDB_NOMMAP)) {
+               tdb->map_ptr = mmap(NULL, tdb->map_size, 
+                                   PROT_READ|(tdb->read_only? 0:PROT_WRITE), 
+                                   MAP_SHARED|MAP_FILE, tdb->fd, 0);
+
+               /*
+                * NB. When mmap fails it returns MAP_FAILED *NOT* NULL !!!!
+                */
+
+               if (tdb->map_ptr == MAP_FAILED) {
+                       tdb->map_ptr = NULL;
+                       TDB_LOG((tdb, 2, "tdb_mmap failed for size %d (%s)\n", 
+                                tdb->map_size, strerror(errno)));
+               }
+       } else {
+               tdb->map_ptr = NULL;
+       }
+#else
+       tdb->map_ptr = NULL;
+#endif
+}
+
+/* Endian conversion: we only ever deal with 4 byte quantities */
+static void *convert(void *buf, u32 size)
+{
+       u32 i, *p = buf;
+       for (i = 0; i < size / 4; i++)
+               p[i] = TDB_BYTEREV(p[i]);
+       return buf;
+}
+#define DOCONV() (tdb->flags & TDB_CONVERT)
+#define CONVERT(x) (DOCONV() ? convert(&x, sizeof(x)) : &x)
+
+/* the body of the database is made of one list_struct for the free space
+   plus a separate data list for each hash value */
+struct list_struct {
+       tdb_off next; /* offset of the next record in the list */
+       tdb_len rec_len; /* total byte length of record */
+       tdb_len key_len; /* byte length of key */
+       tdb_len data_len; /* byte length of data */
+       u32 full_hash; /* the full 32 bit hash of the key */
+       u32 magic;   /* try to catch errors */
+       /* the following union is implied:
+               union {
+                       char record[rec_len];
+                       struct {
+                               char key[key_len];
+                               char data[data_len];
+                       }
+                       u32 totalsize; (tailer)
+               }
+       */
+};
+
+/***************************************************************
+ Allow a caller to set a "alarm" flag that tdb can check to abort
+ a blocking lock on SIGALRM.
+***************************************************************/
+
+static sig_atomic_t *palarm_fired;
+
+void tdb_set_lock_alarm(sig_atomic_t *palarm)
+{
+       palarm_fired = palarm;
+}
+
+/* a byte range locking function - return 0 on success
+   this functions locks/unlocks 1 byte at the specified offset.
+
+   On error, errno is also set so that errors are passed back properly
+   through tdb_open(). */
+static int tdb_brlock(TDB_CONTEXT *tdb, tdb_off offset, 
+                     int rw_type, int lck_type, int probe)
+{
+       struct flock fl;
+       int ret;
+
+       if (tdb->flags & TDB_NOLOCK)
+               return 0;
+       if ((rw_type == F_WRLCK) && (tdb->read_only)) {
+               errno = EACCES;
+               return -1;
+       }
+
+       fl.l_type = rw_type;
+       fl.l_whence = SEEK_SET;
+       fl.l_start = offset;
+       fl.l_len = 1;
+       fl.l_pid = 0;
+
+       do {
+               ret = fcntl(tdb->fd,lck_type,&fl);
+               if (ret == -1 && errno == EINTR && palarm_fired && *palarm_fired)
+                       break;
+       } while (ret == -1 && errno == EINTR);
+
+       if (ret == -1) {
+               if (!probe && lck_type != F_SETLK) {
+                       /* Ensure error code is set for log fun to examine. */
+                       if (errno == EINTR && palarm_fired && *palarm_fired)
+                               tdb->ecode = TDB_ERR_LOCK_TIMEOUT;
+                       else
+                               tdb->ecode = TDB_ERR_LOCK;
+                       TDB_LOG((tdb, 5,"tdb_brlock failed (fd=%d) at offset %d rw_type=%d lck_type=%d\n", 
+                                tdb->fd, offset, rw_type, lck_type));
+               }
+               /* Was it an alarm timeout ? */
+               if (errno == EINTR && palarm_fired && *palarm_fired)
+                       return TDB_ERRCODE(TDB_ERR_LOCK_TIMEOUT, -1);
+               /* Otherwise - generic lock error. */
+               /* errno set by fcntl */
+               return TDB_ERRCODE(TDB_ERR_LOCK, -1);
+       }
+       return 0;
+}
+
+/* lock a list in the database. list -1 is the alloc list */
+static int tdb_lock(TDB_CONTEXT *tdb, int list, int ltype)
+{
+       if (list < -1 || list >= (int)tdb->header.hash_size) {
+               TDB_LOG((tdb, 0,"tdb_lock: invalid list %d for ltype=%d\n", 
+                          list, ltype));
+               return -1;
+       }
+       if (tdb->flags & TDB_NOLOCK)
+               return 0;
+
+       /* Since fcntl locks don't nest, we do a lock for the first one,
+          and simply bump the count for future ones */
+       if (tdb->locked[list+1].count == 0) {
+               if (!tdb->read_only && tdb->header.rwlocks) {
+                       if (tdb_spinlock(tdb, list, ltype)) {
+                               TDB_LOG((tdb, 0, "tdb_lock spinlock failed on list ltype=%d\n", 
+                                          list, ltype));
+                               return -1;
+                       }
+               } else if (tdb_brlock(tdb,FREELIST_TOP+4*list,ltype,F_SETLKW, 0)) {
+                       TDB_LOG((tdb, 0,"tdb_lock failed on list %d ltype=%d (%s)\n", 
+                                          list, ltype, strerror(errno)));
+                       return -1;
+               }
+               tdb->locked[list+1].ltype = ltype;
+       }
+       tdb->locked[list+1].count++;
+       return 0;
+}
+
+/* unlock the database: returns void because it's too late for errors. */
+       /* changed to return int it may be interesting to know there
+          has been an error  --simo */
+static int tdb_unlock(TDB_CONTEXT *tdb, int list, int ltype)
+{
+       int ret = -1;
+
+       if (tdb->flags & TDB_NOLOCK)
+               return 0;
+
+       /* Sanity checks */
+       if (list < -1 || list >= (int)tdb->header.hash_size) {
+               TDB_LOG((tdb, 0, "tdb_unlock: list %d invalid (%d)\n", list, tdb->header.hash_size));
+               return ret;
+       }
+
+       if (tdb->locked[list+1].count==0) {
+               TDB_LOG((tdb, 0, "tdb_unlock: count is 0\n"));
+               return ret;
+       }
+
+       if (tdb->locked[list+1].count == 1) {
+               /* Down to last nested lock: unlock underneath */
+               if (!tdb->read_only && tdb->header.rwlocks) {
+                       ret = tdb_spinunlock(tdb, list, ltype);
+               } else {
+                       ret = tdb_brlock(tdb, FREELIST_TOP+4*list, F_UNLCK, F_SETLKW, 0);
+               }
+       } else {
+               ret = 0;
+       }
+       tdb->locked[list+1].count--;
+
+       if (ret)
+               TDB_LOG((tdb, 0,"tdb_unlock: An error occurred unlocking!\n")); 
+       return ret;
+}
+
+/* This is based on the hash algorithm from gdbm */
+static u32 tdb_hash(TDB_DATA *key)
+{
+       u32 value;      /* Used to compute the hash value.  */
+       u32   i;        /* Used to cycle through random values. */
+
+       /* Set the initial value from the key size. */
+       for (value = 0x238F13AF * key->dsize, i=0; i < key->dsize; i++)
+               value = (value + (key->dptr[i] << (i*5 % 24)));
+
+       return (1103515243 * value + 12345);  
+}
+
+/* check for an out of bounds access - if it is out of bounds then
+   see if the database has been expanded by someone else and expand
+   if necessary 
+   note that "len" is the minimum length needed for the db
+*/
+static int tdb_oob(TDB_CONTEXT *tdb, tdb_off len, int probe)
+{
+       struct stat st;
+       if (len <= tdb->map_size)
+               return 0;
+       if (tdb->flags & TDB_INTERNAL) {
+               if (!probe) {
+                       /* Ensure ecode is set for log fn. */
+                       tdb->ecode = TDB_ERR_IO;
+                       TDB_LOG((tdb, 0,"tdb_oob len %d beyond internal malloc size %d\n",
+                                (int)len, (int)tdb->map_size));
+               }
+               return TDB_ERRCODE(TDB_ERR_IO, -1);
+       }
+
+       if (fstat(tdb->fd, &st) == -1)
+               return TDB_ERRCODE(TDB_ERR_IO, -1);
+
+       if (st.st_size < (size_t)len) {
+               if (!probe) {
+                       /* Ensure ecode is set for log fn. */
+                       tdb->ecode = TDB_ERR_IO;
+                       TDB_LOG((tdb, 0,"tdb_oob len %d beyond eof at %d\n",
+                                (int)len, (int)st.st_size));
+               }
+               return TDB_ERRCODE(TDB_ERR_IO, -1);
+       }
+
+       /* Unmap, update size, remap */
+       if (tdb_munmap(tdb) == -1)
+               return TDB_ERRCODE(TDB_ERR_IO, -1);
+       tdb->map_size = st.st_size;
+       tdb_mmap(tdb);
+       return 0;
+}
+
+/* write a lump of data at a specified offset */
+static int tdb_write(TDB_CONTEXT *tdb, tdb_off off, void *buf, tdb_len len)
+{
+       if (tdb_oob(tdb, off + len, 0) != 0)
+               return -1;
+
+       if (tdb->map_ptr)
+               memcpy(off + (char *)tdb->map_ptr, buf, len);
+#ifdef HAVE_PWRITE
+       else if (pwrite(tdb->fd, buf, len, off) != (ssize_t)len) {
+#else
+       else if (lseek(tdb->fd, off, SEEK_SET) != off
+                || write(tdb->fd, buf, len) != (ssize_t)len) {
+#endif
+               /* Ensure ecode is set for log fn. */
+               tdb->ecode = TDB_ERR_IO;
+               TDB_LOG((tdb, 0,"tdb_write failed at %d len=%d (%s)\n",
+                          off, len, strerror(errno)));
+               return TDB_ERRCODE(TDB_ERR_IO, -1);
+       }
+       return 0;
+}
+
+/* read a lump of data at a specified offset, maybe convert */
+static int tdb_read(TDB_CONTEXT *tdb,tdb_off off,void *buf,tdb_len len,int cv)
+{
+       if (tdb_oob(tdb, off + len, 0) != 0)
+               return -1;
+
+       if (tdb->map_ptr)
+               memcpy(buf, off + (char *)tdb->map_ptr, len);
+#ifdef HAVE_PREAD
+       else if (pread(tdb->fd, buf, len, off) != (ssize_t)len) {
+#else
+       else if (lseek(tdb->fd, off, SEEK_SET) != off
+                || read(tdb->fd, buf, len) != (ssize_t)len) {
+#endif
+               /* Ensure ecode is set for log fn. */
+               tdb->ecode = TDB_ERR_IO;
+               TDB_LOG((tdb, 0,"tdb_read failed at %d len=%d (%s)\n",
+                          off, len, strerror(errno)));
+               return TDB_ERRCODE(TDB_ERR_IO, -1);
+       }
+       if (cv)
+               convert(buf, len);
+       return 0;
+}
+
+/* read a lump of data, allocating the space for it */
+static char *tdb_alloc_read(TDB_CONTEXT *tdb, tdb_off offset, tdb_len len)
+{
+       char *buf;
+
+       if (!(buf = malloc(len))) {
+               /* Ensure ecode is set for log fn. */
+               tdb->ecode = TDB_ERR_OOM;
+               TDB_LOG((tdb, 0,"tdb_alloc_read malloc failed len=%d (%s)\n",
+                          len, strerror(errno)));
+               return TDB_ERRCODE(TDB_ERR_OOM, buf);
+       }
+       if (tdb_read(tdb, offset, buf, len, 0) == -1) {
+               SAFE_FREE(buf);
+               return NULL;
+       }
+       return buf;
+}
+
+/* read/write a tdb_off */
+static int ofs_read(TDB_CONTEXT *tdb, tdb_off offset, tdb_off *d)
+{
+       return tdb_read(tdb, offset, (char*)d, sizeof(*d), DOCONV());
+}
+static int ofs_write(TDB_CONTEXT *tdb, tdb_off offset, tdb_off *d)
+{
+       tdb_off off = *d;
+       return tdb_write(tdb, offset, CONVERT(off), sizeof(*d));
+}
+
+/* read/write a record */
+static int rec_read(TDB_CONTEXT *tdb, tdb_off offset, struct list_struct *rec)
+{
+       if (tdb_read(tdb, offset, rec, sizeof(*rec),DOCONV()) == -1)
+               return -1;
+       if (TDB_BAD_MAGIC(rec)) {
+               /* Ensure ecode is set for log fn. */
+               tdb->ecode = TDB_ERR_CORRUPT;
+               TDB_LOG((tdb, 0,"rec_read bad magic 0x%x at offset=%d\n", rec->magic, offset));
+               return TDB_ERRCODE(TDB_ERR_CORRUPT, -1);
+       }
+       return tdb_oob(tdb, rec->next+sizeof(*rec), 0);
+}
+static int rec_write(TDB_CONTEXT *tdb, tdb_off offset, struct list_struct *rec)
+{
+       struct list_struct r = *rec;
+       return tdb_write(tdb, offset, CONVERT(r), sizeof(r));
+}
+
+/* read a freelist record and check for simple errors */
+static int rec_free_read(TDB_CONTEXT *tdb, tdb_off off, struct list_struct *rec)
+{
+       if (tdb_read(tdb, off, rec, sizeof(*rec),DOCONV()) == -1)
+               return -1;
+
+       if (rec->magic == TDB_MAGIC) {
+               /* this happens when a app is showdown while deleting a record - we should
+                  not completely fail when this happens */
+               TDB_LOG((tdb, 0,"rec_free_read non-free magic at offset=%d - fixing\n", 
+                        rec->magic, off));
+               rec->magic = TDB_FREE_MAGIC;
+               if (tdb_write(tdb, off, rec, sizeof(*rec)) == -1)
+                       return -1;
+       }
+
+       if (rec->magic != TDB_FREE_MAGIC) {
+               /* Ensure ecode is set for log fn. */
+               tdb->ecode = TDB_ERR_CORRUPT;
+               TDB_LOG((tdb, 0,"rec_free_read bad magic 0x%x at offset=%d\n", 
+                          rec->magic, off));
+               return TDB_ERRCODE(TDB_ERR_CORRUPT, -1);
+       }
+       if (tdb_oob(tdb, rec->next+sizeof(*rec), 0) != 0)
+               return -1;
+       return 0;
+}
+
+/* update a record tailer (must hold allocation lock) */
+static int update_tailer(TDB_CONTEXT *tdb, tdb_off offset,
+                        const struct list_struct *rec)
+{
+       tdb_off totalsize;
+
+       /* Offset of tailer from record header */
+       totalsize = sizeof(*rec) + rec->rec_len;
+       return ofs_write(tdb, offset + totalsize - sizeof(tdb_off),
+                        &totalsize);
+}
+
+static tdb_off tdb_dump_record(TDB_CONTEXT *tdb, tdb_off offset)
+{
+       struct list_struct rec;
+       tdb_off tailer_ofs, tailer;
+
+       if (tdb_read(tdb, offset, (char *)&rec, sizeof(rec), DOCONV()) == -1) {
+               printf("ERROR: failed to read record at %u\n", offset);
+               return 0;
+       }
+
+       printf(" rec: offset=%u next=%d rec_len=%d key_len=%d data_len=%d full_hash=0x%x magic=0x%x\n",
+              offset, rec.next, rec.rec_len, rec.key_len, rec.data_len, rec.full_hash, rec.magic);
+
+       tailer_ofs = offset + sizeof(rec) + rec.rec_len - sizeof(tdb_off);
+       if (ofs_read(tdb, tailer_ofs, &tailer) == -1) {
+               printf("ERROR: failed to read tailer at %u\n", tailer_ofs);
+               return rec.next;
+       }
+
+       if (tailer != rec.rec_len + sizeof(rec)) {
+               printf("ERROR: tailer does not match record! tailer=%u totalsize=%u\n",
+                               (unsigned)tailer, (unsigned)(rec.rec_len + sizeof(rec)));
+       }
+       return rec.next;
+}
+
+static int tdb_dump_chain(TDB_CONTEXT *tdb, int i)
+{
+       tdb_off rec_ptr, top;
+
+       top = TDB_HASH_TOP(i);
+
+       if (tdb_lock(tdb, i, F_WRLCK) != 0)
+               return -1;
+
+       if (ofs_read(tdb, top, &rec_ptr) == -1)
+               return tdb_unlock(tdb, i, F_WRLCK);
+
+       if (rec_ptr)
+               printf("hash=%d\n", i);
+
+       while (rec_ptr) {
+               rec_ptr = tdb_dump_record(tdb, rec_ptr);
+       }
+
+       return tdb_unlock(tdb, i, F_WRLCK);
+}
+
+void tdb_dump_all(TDB_CONTEXT *tdb)
+{
+       unsigned int i;
+       for (i=0;i<tdb->header.hash_size;i++) {
+               tdb_dump_chain(tdb, i);
+       }
+       printf("freelist:\n");
+       tdb_dump_chain(tdb, -1);
+}
+
+int tdb_printfreelist(TDB_CONTEXT *tdb)
+{
+       int ret;
+       long total_free = 0;
+       tdb_off offset, rec_ptr;
+       struct list_struct rec;
+
+       if ((ret = tdb_lock(tdb, -1, F_WRLCK)) != 0)
+               return ret;
+
+       offset = FREELIST_TOP;
+
+       /* read in the freelist top */
+       if (ofs_read(tdb, offset, &rec_ptr) == -1) {
+               tdb_unlock(tdb, -1, F_WRLCK);
+               return 0;
+       }
+
+       printf("freelist top=[0x%08x]\n", rec_ptr );
+       while (rec_ptr) {
+               if (tdb_read(tdb, rec_ptr, (char *)&rec, sizeof(rec), DOCONV()) == -1) {
+                       tdb_unlock(tdb, -1, F_WRLCK);
+                       return -1;
+               }
+
+               if (rec.magic != TDB_FREE_MAGIC) {
+                       printf("bad magic 0x%08x in free list\n", rec.magic);
+                       tdb_unlock(tdb, -1, F_WRLCK);
+                       return -1;
+               }
+
+               printf("entry offset=[0x%08x], rec.rec_len = [0x%08x (%d)]\n", rec.next, rec.rec_len, rec.rec_len );
+               total_free += rec.rec_len;
+
+               /* move to the next record */
+               rec_ptr = rec.next;
+       }
+       printf("total rec_len = [0x%08x (%d)]\n", (int)total_free, 
+               (int)total_free);
+
+       return tdb_unlock(tdb, -1, F_WRLCK);
+}
+
+/* Remove an element from the freelist.  Must have alloc lock. */
+static int remove_from_freelist(TDB_CONTEXT *tdb, tdb_off off, tdb_off next)
+{
+       tdb_off last_ptr, i;
+
+       /* read in the freelist top */
+       last_ptr = FREELIST_TOP;
+       while (ofs_read(tdb, last_ptr, &i) != -1 && i != 0) {
+               if (i == off) {
+                       /* We've found it! */
+                       return ofs_write(tdb, last_ptr, &next);
+               }
+               /* Follow chain (next offset is at start of record) */
+               last_ptr = i;
+       }
+       TDB_LOG((tdb, 0,"remove_from_freelist: not on list at off=%d\n", off));
+       return TDB_ERRCODE(TDB_ERR_CORRUPT, -1);
+}
+
+/* Add an element into the freelist. Merge adjacent records if
+   neccessary. */
+static int tdb_free(TDB_CONTEXT *tdb, tdb_off offset, struct list_struct *rec)
+{
+       tdb_off right, left;
+
+       /* Allocation and tailer lock */
+       if (tdb_lock(tdb, -1, F_WRLCK) != 0)
+               return -1;
+
+       /* set an initial tailer, so if we fail we don't leave a bogus record */
+       if (update_tailer(tdb, offset, rec) != 0) {
+               TDB_LOG((tdb, 0, "tdb_free: upfate_tailer failed!\n"));
+               goto fail;
+       }
+
+       /* Look right first (I'm an Australian, dammit) */
+       right = offset + sizeof(*rec) + rec->rec_len;
+       if (right + sizeof(*rec) <= tdb->map_size) {
+               struct list_struct r;
+
+               if (tdb_read(tdb, right, &r, sizeof(r), DOCONV()) == -1) {
+                       TDB_LOG((tdb, 0, "tdb_free: right read failed at %u\n", right));
+                       goto left;
+               }
+
+               /* If it's free, expand to include it. */
+               if (r.magic == TDB_FREE_MAGIC) {
+                       if (remove_from_freelist(tdb, right, r.next) == -1) {
+                               TDB_LOG((tdb, 0, "tdb_free: right free failed at %u\n", right));
+                               goto left;
+                       }
+                       rec->rec_len += sizeof(r) + r.rec_len;
+               }
+       }
+
+left:
+       /* Look left */
+       left = offset - sizeof(tdb_off);
+       if (left > TDB_HASH_TOP(tdb->header.hash_size-1)) {
+               struct list_struct l;
+               tdb_off leftsize;
+
+               /* Read in tailer and jump back to header */
+               if (ofs_read(tdb, left, &leftsize) == -1) {
+                       TDB_LOG((tdb, 0, "tdb_free: left offset read failed at %u\n", left));
+                       goto update;
+               }
+               left = offset - leftsize;
+
+               /* Now read in record */
+               if (tdb_read(tdb, left, &l, sizeof(l), DOCONV()) == -1) {
+                       TDB_LOG((tdb, 0, "tdb_free: left read failed at %u (%u)\n", left, leftsize));
+                       goto update;
+               }
+
+               /* If it's free, expand to include it. */
+               if (l.magic == TDB_FREE_MAGIC) {
+                       if (remove_from_freelist(tdb, left, l.next) == -1) {
+                               TDB_LOG((tdb, 0, "tdb_free: left free failed at %u\n", left));
+                               goto update;
+                       } else {
+                               offset = left;
+                               rec->rec_len += leftsize;
+                       }
+               }
+       }
+
+update:
+       if (update_tailer(tdb, offset, rec) == -1) {
+               TDB_LOG((tdb, 0, "tdb_free: update_tailer failed at %u\n", offset));
+               goto fail;
+       }
+
+       /* Now, prepend to free list */
+       rec->magic = TDB_FREE_MAGIC;
+
+       if (ofs_read(tdb, FREELIST_TOP, &rec->next) == -1 ||
+           rec_write(tdb, offset, rec) == -1 ||
+           ofs_write(tdb, FREELIST_TOP, &offset) == -1) {
+               TDB_LOG((tdb, 0, "tdb_free record write failed at offset=%d\n", offset));
+               goto fail;
+       }
+
+       /* And we're done. */
+       tdb_unlock(tdb, -1, F_WRLCK);
+       return 0;
+
+ fail:
+       tdb_unlock(tdb, -1, F_WRLCK);
+       return -1;
+}
+
+
+/* expand a file.  we prefer to use ftruncate, as that is what posix
+  says to use for mmap expansion */
+static int expand_file(TDB_CONTEXT *tdb, tdb_off size, tdb_off addition)
+{
+       char buf[1024];
+#if HAVE_FTRUNCATE_EXTEND
+       if (ftruncate(tdb->fd, size+addition) != 0) {
+               TDB_LOG((tdb, 0, "expand_file ftruncate to %d failed (%s)\n", 
+                          size+addition, strerror(errno)));
+               return -1;
+       }
+#else
+       char b = 0;
+
+#ifdef HAVE_PWRITE
+       if (pwrite(tdb->fd,  &b, 1, (size+addition) - 1) != 1) {
+#else
+       if (lseek(tdb->fd, (size+addition) - 1, SEEK_SET) != (size+addition) - 1 || 
+           write(tdb->fd, &b, 1) != 1) {
+#endif
+               TDB_LOG((tdb, 0, "expand_file to %d failed (%s)\n", 
+                          size+addition, strerror(errno)));
+               return -1;
+       }
+#endif
+
+       /* now fill the file with something. This ensures that the file isn't sparse, which would be
+          very bad if we ran out of disk. This must be done with write, not via mmap */
+       memset(buf, 0x42, sizeof(buf));
+       while (addition) {
+               int n = addition>sizeof(buf)?sizeof(buf):addition;
+#ifdef HAVE_PWRITE
+               int ret = pwrite(tdb->fd, buf, n, size);
+#else
+               int ret;
+               if (lseek(tdb->fd, size, SEEK_SET) != size)
+                       return -1;
+               ret = write(tdb->fd, buf, n);
+#endif
+               if (ret != n) {
+                       TDB_LOG((tdb, 0, "expand_file write of %d failed (%s)\n", 
+                                  n, strerror(errno)));
+                       return -1;
+               }
+               addition -= n;
+               size += n;
+       }
+       return 0;
+}
+
+
+/* expand the database at least size bytes by expanding the underlying
+   file and doing the mmap again if necessary */
+static int tdb_expand(TDB_CONTEXT *tdb, tdb_off size)
+{
+       struct list_struct rec;
+       tdb_off offset;
+
+       if (tdb_lock(tdb, -1, F_WRLCK) == -1) {
+               TDB_LOG((tdb, 0, "lock failed in tdb_expand\n"));
+               return -1;
+       }
+
+       /* must know about any previous expansions by another process */
+       tdb_oob(tdb, tdb->map_size + 1, 1);
+
+       /* always make room for at least 10 more records, and round
+           the database up to a multiple of TDB_PAGE_SIZE */
+       size = TDB_ALIGN(tdb->map_size + size*10, TDB_PAGE_SIZE) - tdb->map_size;
+
+       if (!(tdb->flags & TDB_INTERNAL))
+               tdb_munmap(tdb);
+
+       /*
+        * We must ensure the file is unmapped before doing this
+        * to ensure consistency with systems like OpenBSD where
+        * writes and mmaps are not consistent.
+        */
+
+       /* expand the file itself */
+       if (!(tdb->flags & TDB_INTERNAL)) {
+               if (expand_file(tdb, tdb->map_size, size) != 0)
+                       goto fail;
+       }
+
+       tdb->map_size += size;
+
+       if (tdb->flags & TDB_INTERNAL)
+               tdb->map_ptr = realloc(tdb->map_ptr, tdb->map_size);
+       else {
+               /*
+                * We must ensure the file is remapped before adding the space
+                * to ensure consistency with systems like OpenBSD where
+                * writes and mmaps are not consistent.
+                */
+
+               /* We're ok if the mmap fails as we'll fallback to read/write */
+               tdb_mmap(tdb);
+       }
+
+       /* form a new freelist record */
+       memset(&rec,'\0',sizeof(rec));
+       rec.rec_len = size - sizeof(rec);
+
+       /* link it into the free list */
+       offset = tdb->map_size - size;
+       if (tdb_free(tdb, offset, &rec) == -1)
+               goto fail;
+
+       tdb_unlock(tdb, -1, F_WRLCK);
+       return 0;
+ fail:
+       tdb_unlock(tdb, -1, F_WRLCK);
+       return -1;
+}
+
+/* allocate some space from the free list. The offset returned points
+   to a unconnected list_struct within the database with room for at
+   least length bytes of total data
+
+   0 is returned if the space could not be allocated
+ */
+static tdb_off tdb_allocate(TDB_CONTEXT *tdb, tdb_len length,
+                           struct list_struct *rec)
+{
+       tdb_off rec_ptr, last_ptr, newrec_ptr;
+       struct list_struct newrec;
+
+       if (tdb_lock(tdb, -1, F_WRLCK) == -1)
+               return 0;
+
+       /* Extra bytes required for tailer */
+       length += sizeof(tdb_off);
+
+ again:
+       last_ptr = FREELIST_TOP;
+
+       /* read in the freelist top */
+       if (ofs_read(tdb, FREELIST_TOP, &rec_ptr) == -1)
+               goto fail;
+
+       /* keep looking until we find a freelist record big enough */
+       while (rec_ptr) {
+               if (rec_free_read(tdb, rec_ptr, rec) == -1)
+                       goto fail;
+
+               if (rec->rec_len >= length) {
+                       /* found it - now possibly split it up  */
+                       if (rec->rec_len > length + MIN_REC_SIZE) {
+                               /* Length of left piece */
+                               length = TDB_ALIGN(length, TDB_ALIGNMENT);
+
+                               /* Right piece to go on free list */
+                               newrec.rec_len = rec->rec_len
+                                       - (sizeof(*rec) + length);
+                               newrec_ptr = rec_ptr + sizeof(*rec) + length;
+
+                               /* And left record is shortened */
+                               rec->rec_len = length;
+                       } else
+                               newrec_ptr = 0;
+
+                       /* Remove allocated record from the free list */
+                       if (ofs_write(tdb, last_ptr, &rec->next) == -1)
+                               goto fail;
+
+                       /* Update header: do this before we drop alloc
+                           lock, otherwise tdb_free() might try to
+                           merge with us, thinking we're free.
+                           (Thanks Jeremy Allison). */
+                       rec->magic = TDB_MAGIC;
+                       if (rec_write(tdb, rec_ptr, rec) == -1)
+                               goto fail;
+
+                       /* Did we create new block? */
+                       if (newrec_ptr) {
+                               /* Update allocated record tailer (we
+                                   shortened it). */
+                               if (update_tailer(tdb, rec_ptr, rec) == -1)
+                                       goto fail;
+
+                               /* Free new record */
+                               if (tdb_free(tdb, newrec_ptr, &newrec) == -1)
+                                       goto fail;
+                       }
+
+                       /* all done - return the new record offset */
+                       tdb_unlock(tdb, -1, F_WRLCK);
+                       return rec_ptr;
+               }
+               /* move to the next record */
+               last_ptr = rec_ptr;
+               rec_ptr = rec->next;
+       }
+       /* we didn't find enough space. See if we can expand the
+          database and if we can then try again */
+       if (tdb_expand(tdb, length + sizeof(*rec)) == 0)
+               goto again;
+ fail:
+       tdb_unlock(tdb, -1, F_WRLCK);
+       return 0;
+}
+
+/* initialise a new database with a specified hash size */
+static int tdb_new_database(TDB_CONTEXT *tdb, int hash_size)
+{
+       struct tdb_header *newdb;
+       int size, ret = -1;
+
+       /* We make it up in memory, then write it out if not internal */
+       size = sizeof(struct tdb_header) + (hash_size+1)*sizeof(tdb_off);
+       if (!(newdb = calloc(size, 1)))
+               return TDB_ERRCODE(TDB_ERR_OOM, -1);
+
+       /* Fill in the header */
+       newdb->version = TDB_VERSION;
+       newdb->hash_size = hash_size;
+#ifdef USE_SPINLOCKS
+       newdb->rwlocks = size;
+#endif
+       if (tdb->flags & TDB_INTERNAL) {
+               tdb->map_size = size;
+               tdb->map_ptr = (char *)newdb;
+               memcpy(&tdb->header, newdb, sizeof(tdb->header));
+               /* Convert the `ondisk' version if asked. */
+               CONVERT(*newdb);
+               return 0;
+       }
+       if (lseek(tdb->fd, 0, SEEK_SET) == -1)
+               goto fail;
+
+       if (ftruncate(tdb->fd, 0) == -1)
+               goto fail;
+
+       /* This creates an endian-converted header, as if read from disk */
+       CONVERT(*newdb);
+       memcpy(&tdb->header, newdb, sizeof(tdb->header));
+       /* Don't endian-convert the magic food! */
+       memcpy(newdb->magic_food, TDB_MAGIC_FOOD, strlen(TDB_MAGIC_FOOD)+1);
+       if (write(tdb->fd, newdb, size) != size)
+               ret = -1;
+       else
+               ret = tdb_create_rwlocks(tdb->fd, hash_size);
+
+  fail:
+       SAFE_FREE(newdb);
+       return ret;
+}
+
+/* Returns 0 on fail.  On success, return offset of record, and fills
+   in rec */
+static tdb_off tdb_find(TDB_CONTEXT *tdb, TDB_DATA key, u32 hash,
+                       struct list_struct *r)
+{
+       tdb_off rec_ptr;
+       
+       /* read in the hash top */
+       if (ofs_read(tdb, TDB_HASH_TOP(hash), &rec_ptr) == -1)
+               return 0;
+
+       /* keep looking until we find the right record */
+       while (rec_ptr) {
+               if (rec_read(tdb, rec_ptr, r) == -1)
+                       return 0;
+
+               if (!TDB_DEAD(r) && hash==r->full_hash && key.dsize==r->key_len) {
+                       char *k;
+                       /* a very likely hit - read the key */
+                       k = tdb_alloc_read(tdb, rec_ptr + sizeof(*r), 
+                                          r->key_len);
+                       if (!k)
+                               return 0;
+
+                       if (memcmp(key.dptr, k, key.dsize) == 0) {
+                               SAFE_FREE(k);
+                               return rec_ptr;
+                       }
+                       SAFE_FREE(k);
+               }
+               rec_ptr = r->next;
+       }
+       return TDB_ERRCODE(TDB_ERR_NOEXIST, 0);
+}
+
+/* If they do lockkeys, check that this hash is one they locked */
+static int tdb_keylocked(TDB_CONTEXT *tdb, u32 hash)
+{
+       u32 i;
+       if (!tdb->lockedkeys)
+               return 1;
+       for (i = 0; i < tdb->lockedkeys[0]; i++)
+               if (tdb->lockedkeys[i+1] == hash)
+                       return 1;
+       return TDB_ERRCODE(TDB_ERR_NOLOCK, 0);
+}
+
+/* As tdb_find, but if you succeed, keep the lock */
+static tdb_off tdb_find_lock(TDB_CONTEXT *tdb, TDB_DATA key, int locktype,
+                            struct list_struct *rec)
+{
+       u32 hash, rec_ptr;
+
+       hash = tdb_hash(&key);
+       if (!tdb_keylocked(tdb, hash))
+               return 0;
+       if (tdb_lock(tdb, BUCKET(hash), locktype) == -1)
+               return 0;
+       if (!(rec_ptr = tdb_find(tdb, key, hash, rec)))
+               tdb_unlock(tdb, BUCKET(hash), locktype);
+       return rec_ptr;
+}
+
+enum TDB_ERROR tdb_error(TDB_CONTEXT *tdb)
+{
+       return tdb->ecode;
+}
+
+static struct tdb_errname {
+       enum TDB_ERROR ecode; const char *estring;
+} emap[] = { {TDB_SUCCESS, "Success"},
+            {TDB_ERR_CORRUPT, "Corrupt database"},
+            {TDB_ERR_IO, "IO Error"},
+            {TDB_ERR_LOCK, "Locking error"},
+            {TDB_ERR_OOM, "Out of memory"},
+            {TDB_ERR_EXISTS, "Record exists"},
+            {TDB_ERR_NOLOCK, "Lock exists on other keys"},
+            {TDB_ERR_NOEXIST, "Record does not exist"} };
+
+/* Error string for the last tdb error */
+const char *tdb_errorstr(TDB_CONTEXT *tdb)
+{
+       u32 i;
+       for (i = 0; i < sizeof(emap) / sizeof(struct tdb_errname); i++)
+               if (tdb->ecode == emap[i].ecode)
+                       return emap[i].estring;
+       return "Invalid error code";
+}
+
+/* update an entry in place - this only works if the new data size
+   is <= the old data size and the key exists.
+   on failure return -1.
+*/
+
+static int tdb_update(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA dbuf)
+{
+       struct list_struct rec;
+       tdb_off rec_ptr;
+
+       /* find entry */
+       if (!(rec_ptr = tdb_find(tdb, key, tdb_hash(&key), &rec)))
+               return -1;
+
+       /* must be long enough key, data and tailer */
+       if (rec.rec_len < key.dsize + dbuf.dsize + sizeof(tdb_off)) {
+               tdb->ecode = TDB_SUCCESS; /* Not really an error */
+               return -1;
+       }
+
+       if (tdb_write(tdb, rec_ptr + sizeof(rec) + rec.key_len,
+                     dbuf.dptr, dbuf.dsize) == -1)
+               return -1;
+
+       if (dbuf.dsize != rec.data_len) {
+               /* update size */
+               rec.data_len = dbuf.dsize;
+               return rec_write(tdb, rec_ptr, &rec);
+       }
+       return 0;
+}
+
+/* find an entry in the database given a key */
+/* If an entry doesn't exist tdb_err will be set to
+ * TDB_ERR_NOEXIST. If a key has no data attached
+ * tdb_err will not be set. Both will return a
+ * zero pptr and zero dsize.
+ */
+
+TDB_DATA tdb_fetch(TDB_CONTEXT *tdb, TDB_DATA key)
+{
+       tdb_off rec_ptr;
+       struct list_struct rec;
+       TDB_DATA ret;
+
+       /* find which hash bucket it is in */
+       if (!(rec_ptr = tdb_find_lock(tdb,key,F_RDLCK,&rec)))
+               return tdb_null;
+
+       if (rec.data_len)
+               ret.dptr = tdb_alloc_read(tdb, rec_ptr + sizeof(rec) + rec.key_len,
+                                         rec.data_len);
+       else
+               ret.dptr = NULL;
+       ret.dsize = rec.data_len;
+       tdb_unlock(tdb, BUCKET(rec.full_hash), F_RDLCK);
+       return ret;
+}
+
+/* check if an entry in the database exists 
+
+   note that 1 is returned if the key is found and 0 is returned if not found
+   this doesn't match the conventions in the rest of this module, but is
+   compatible with gdbm
+*/
+int tdb_exists(TDB_CONTEXT *tdb, TDB_DATA key)
+{
+       struct list_struct rec;
+       
+       if (tdb_find_lock(tdb, key, F_RDLCK, &rec) == 0)
+               return 0;
+       tdb_unlock(tdb, BUCKET(rec.full_hash), F_RDLCK);
+       return 1;
+}
+
+/* record lock stops delete underneath */
+static int lock_record(TDB_CONTEXT *tdb, tdb_off off)
+{
+       return off ? tdb_brlock(tdb, off, F_RDLCK, F_SETLKW, 0) : 0;
+}
+/*
+  Write locks override our own fcntl readlocks, so check it here.
+  Note this is meant to be F_SETLK, *not* F_SETLKW, as it's not
+  an error to fail to get the lock here.
+*/
+static int write_lock_record(TDB_CONTEXT *tdb, tdb_off off)
+{
+       struct tdb_traverse_lock *i;
+       for (i = &tdb->travlocks; i; i = i->next)
+               if (i->off == off)
+                       return -1;
+       return tdb_brlock(tdb, off, F_WRLCK, F_SETLK, 1);
+}
+
+/*
+  Note this is meant to be F_SETLK, *not* F_SETLKW, as it's not
+  an error to fail to get the lock here.
+*/
+
+static int write_unlock_record(TDB_CONTEXT *tdb, tdb_off off)
+{
+       return tdb_brlock(tdb, off, F_UNLCK, F_SETLK, 0);
+}
+/* fcntl locks don't stack: avoid unlocking someone else's */
+static int unlock_record(TDB_CONTEXT *tdb, tdb_off off)
+{
+       struct tdb_traverse_lock *i;
+       u32 count = 0;
+
+       if (off == 0)
+               return 0;
+       for (i = &tdb->travlocks; i; i = i->next)
+               if (i->off == off)
+                       count++;
+       return (count == 1 ? tdb_brlock(tdb, off, F_UNLCK, F_SETLKW, 0) : 0);
+}
+
+/* actually delete an entry in the database given the offset */
+static int do_delete(TDB_CONTEXT *tdb, tdb_off rec_ptr, struct list_struct*rec)
+{
+       tdb_off last_ptr, i;
+       struct list_struct lastrec;
+
+       if (tdb->read_only) return -1;
+
+       if (write_lock_record(tdb, rec_ptr) == -1) {
+               /* Someone traversing here: mark it as dead */
+               rec->magic = TDB_DEAD_MAGIC;
+               return rec_write(tdb, rec_ptr, rec);
+       }
+       if (write_unlock_record(tdb, rec_ptr) != 0)
+               return -1;
+
+       /* find previous record in hash chain */
+       if (ofs_read(tdb, TDB_HASH_TOP(rec->full_hash), &i) == -1)
+               return -1;
+       for (last_ptr = 0; i != rec_ptr; last_ptr = i, i = lastrec.next)
+               if (rec_read(tdb, i, &lastrec) == -1)
+                       return -1;
+
+       /* unlink it: next ptr is at start of record. */
+       if (last_ptr == 0)
+               last_ptr = TDB_HASH_TOP(rec->full_hash);
+       if (ofs_write(tdb, last_ptr, &rec->next) == -1)
+               return -1;
+
+       /* recover the space */
+       if (tdb_free(tdb, rec_ptr, rec) == -1)
+               return -1;
+       return 0;
+}
+
+/* Uses traverse lock: 0 = finish, -1 = error, other = record offset */
+static int tdb_next_lock(TDB_CONTEXT *tdb, struct tdb_traverse_lock *tlock,
+                        struct list_struct *rec)
+{
+       int want_next = (tlock->off != 0);
+
+       /* No traversal allows if you've called tdb_lockkeys() */
+       if (tdb->lockedkeys)
+               return TDB_ERRCODE(TDB_ERR_NOLOCK, -1);
+
+       /* Lock each chain from the start one. */
+       for (; tlock->hash < tdb->header.hash_size; tlock->hash++) {
+               if (tdb_lock(tdb, tlock->hash, F_WRLCK) == -1)
+                       return -1;
+
+               /* No previous record?  Start at top of chain. */
+               if (!tlock->off) {
+                       if (ofs_read(tdb, TDB_HASH_TOP(tlock->hash),
+                                    &tlock->off) == -1)
+                               goto fail;
+               } else {
+                       /* Otherwise unlock the previous record. */
+                       if (unlock_record(tdb, tlock->off) != 0)
+                               goto fail;
+               }
+
+               if (want_next) {
+                       /* We have offset of old record: grab next */
+                       if (rec_read(tdb, tlock->off, rec) == -1)
+                               goto fail;
+                       tlock->off = rec->next;
+               }
+
+               /* Iterate through chain */
+               while( tlock->off) {
+                       tdb_off current;
+                       if (rec_read(tdb, tlock->off, rec) == -1)
+                               goto fail;
+                       if (!TDB_DEAD(rec)) {
+                               /* Woohoo: we found one! */
+                               if (lock_record(tdb, tlock->off) != 0)
+                                       goto fail;
+                               return tlock->off;
+                       }
+                       /* Try to clean dead ones from old traverses */
+                       current = tlock->off;
+                       tlock->off = rec->next;
+                       if (do_delete(tdb, current, rec) != 0)
+                               goto fail;
+               }
+               tdb_unlock(tdb, tlock->hash, F_WRLCK);
+               want_next = 0;
+       }
+       /* We finished iteration without finding anything */
+       return TDB_ERRCODE(TDB_SUCCESS, 0);
+
+ fail:
+       tlock->off = 0;
+       if (tdb_unlock(tdb, tlock->hash, F_WRLCK) != 0)
+               TDB_LOG((tdb, 0, "tdb_next_lock: On error unlock failed!\n"));
+       return -1;
+}
+
+/* traverse the entire database - calling fn(tdb, key, data) on each element.
+   return -1 on error or the record count traversed
+   if fn is NULL then it is not called
+   a non-zero return value from fn() indicates that the traversal should stop
+  */
+int tdb_traverse(TDB_CONTEXT *tdb, tdb_traverse_func fn, void *state)
+{
+       TDB_DATA key, dbuf;
+       struct list_struct rec;
+       struct tdb_traverse_lock tl = { NULL, 0, 0 };
+       int ret, count = 0;
+
+       /* This was in the initializaton, above, but the IRIX compiler
+        * did not like it.  crh
+        */
+       tl.next = tdb->travlocks.next;
+
+       /* fcntl locks don't stack: beware traverse inside traverse */
+       tdb->travlocks.next = &tl;
+
+       /* tdb_next_lock places locks on the record returned, and its chain */
+       while ((ret = tdb_next_lock(tdb, &tl, &rec)) > 0) {
+               count++;
+               /* now read the full record */
+               key.dptr = tdb_alloc_read(tdb, tl.off + sizeof(rec), 
+                                         rec.key_len + rec.data_len);
+               if (!key.dptr) {
+                       ret = -1;
+                       if (tdb_unlock(tdb, tl.hash, F_WRLCK) != 0)
+                               goto out;
+                       if (unlock_record(tdb, tl.off) != 0)
+                               TDB_LOG((tdb, 0, "tdb_traverse: key.dptr == NULL and unlock_record failed!\n"));
+                       goto out;
+               }
+               key.dsize = rec.key_len;
+               dbuf.dptr = key.dptr + rec.key_len;
+               dbuf.dsize = rec.data_len;
+
+               /* Drop chain lock, call out */
+               if (tdb_unlock(tdb, tl.hash, F_WRLCK) != 0) {
+                       ret = -1;
+                       goto out;
+               }
+               if (fn && fn(tdb, key, dbuf, state)) {
+                       /* They want us to terminate traversal */
+                       ret = count;
+                       if (unlock_record(tdb, tl.off) != 0) {
+                               TDB_LOG((tdb, 0, "tdb_traverse: unlock_record failed!\n"));;
+                               ret = -1;
+                       }
+                       tdb->travlocks.next = tl.next;
+                       SAFE_FREE(key.dptr);
+                       return count;
+               }
+               SAFE_FREE(key.dptr);
+       }
+out:
+       tdb->travlocks.next = tl.next;
+       if (ret < 0)
+               return -1;
+       else
+               return count;
+}
+
+/* find the first entry in the database and return its key */
+TDB_DATA tdb_firstkey(TDB_CONTEXT *tdb)
+{
+       TDB_DATA key;
+       struct list_struct rec;
+
+       /* release any old lock */
+       if (unlock_record(tdb, tdb->travlocks.off) != 0)
+               return tdb_null;
+       tdb->travlocks.off = tdb->travlocks.hash = 0;
+
+       if (tdb_next_lock(tdb, &tdb->travlocks, &rec) <= 0)
+               return tdb_null;
+       /* now read the key */
+       key.dsize = rec.key_len;
+       key.dptr =tdb_alloc_read(tdb,tdb->travlocks.off+sizeof(rec),key.dsize);
+       if (tdb_unlock(tdb, BUCKET(tdb->travlocks.hash), F_WRLCK) != 0)
+               TDB_LOG((tdb, 0, "tdb_firstkey: error occurred while tdb_unlocking!\n"));
+       return key;
+}
+
+/* find the next entry in the database, returning its key */
+TDB_DATA tdb_nextkey(TDB_CONTEXT *tdb, TDB_DATA oldkey)
+{
+       u32 oldhash;
+       TDB_DATA key = tdb_null;
+       struct list_struct rec;
+       char *k = NULL;
+
+       /* Is locked key the old key?  If so, traverse will be reliable. */
+       if (tdb->travlocks.off) {
+               if (tdb_lock(tdb,tdb->travlocks.hash,F_WRLCK))
+                       return tdb_null;
+               if (rec_read(tdb, tdb->travlocks.off, &rec) == -1
+                   || !(k = tdb_alloc_read(tdb,tdb->travlocks.off+sizeof(rec),
+                                           rec.key_len))
+                   || memcmp(k, oldkey.dptr, oldkey.dsize) != 0) {
+                       /* No, it wasn't: unlock it and start from scratch */
+                       if (unlock_record(tdb, tdb->travlocks.off) != 0)
+                               return tdb_null;
+                       if (tdb_unlock(tdb, tdb->travlocks.hash, F_WRLCK) != 0)
+                               return tdb_null;
+                       tdb->travlocks.off = 0;
+               }
+
+               SAFE_FREE(k);
+       }
+
+       if (!tdb->travlocks.off) {
+               /* No previous element: do normal find, and lock record */
+               tdb->travlocks.off = tdb_find_lock(tdb, oldkey, F_WRLCK, &rec);
+               if (!tdb->travlocks.off)
+                       return tdb_null;
+               tdb->travlocks.hash = BUCKET(rec.full_hash);
+               if (lock_record(tdb, tdb->travlocks.off) != 0) {
+                       TDB_LOG((tdb, 0, "tdb_nextkey: lock_record failed (%s)!\n", strerror(errno)));
+                       return tdb_null;
+               }
+       }
+       oldhash = tdb->travlocks.hash;
+
+       /* Grab next record: locks chain and returned record,
+          unlocks old record */
+       if (tdb_next_lock(tdb, &tdb->travlocks, &rec) > 0) {
+               key.dsize = rec.key_len;
+               key.dptr = tdb_alloc_read(tdb, tdb->travlocks.off+sizeof(rec),
+                                         key.dsize);
+               /* Unlock the chain of this new record */
+               if (tdb_unlock(tdb, tdb->travlocks.hash, F_WRLCK) != 0)
+                       TDB_LOG((tdb, 0, "tdb_nextkey: WARNING tdb_unlock failed!\n"));
+       }
+       /* Unlock the chain of old record */
+       if (tdb_unlock(tdb, BUCKET(oldhash), F_WRLCK) != 0)
+               TDB_LOG((tdb, 0, "tdb_nextkey: WARNING tdb_unlock failed!\n"));
+       return key;
+}
+
+/* delete an entry in the database given a key */
+int tdb_delete(TDB_CONTEXT *tdb, TDB_DATA key)
+{
+       tdb_off rec_ptr;
+       struct list_struct rec;
+       int ret;
+
+       if (!(rec_ptr = tdb_find_lock(tdb, key, F_WRLCK, &rec)))
+               return -1;
+       ret = do_delete(tdb, rec_ptr, &rec);
+       if (tdb_unlock(tdb, BUCKET(rec.full_hash), F_WRLCK) != 0)
+               TDB_LOG((tdb, 0, "tdb_delete: WARNING tdb_unlock failed!\n"));
+       return ret;
+}
+
+/* store an element in the database, replacing any existing element
+   with the same key 
+
+   return 0 on success, -1 on failure
+*/
+int tdb_store(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA dbuf, int flag)
+{
+       struct list_struct rec;
+       u32 hash;
+       tdb_off rec_ptr;
+       char *p = NULL;
+       int ret = 0;
+
+       /* find which hash bucket it is in */
+       hash = tdb_hash(&key);
+       if (!tdb_keylocked(tdb, hash))
+               return -1;
+       if (tdb_lock(tdb, BUCKET(hash), F_WRLCK) == -1)
+               return -1;
+
+       /* check for it existing, on insert. */
+       if (flag == TDB_INSERT) {
+               if (tdb_exists(tdb, key)) {
+                       tdb->ecode = TDB_ERR_EXISTS;
+                       goto fail;
+               }
+       } else {
+               /* first try in-place update, on modify or replace. */
+               if (tdb_update(tdb, key, dbuf) == 0)
+                       goto out;
+               if (flag == TDB_MODIFY && tdb->ecode == TDB_ERR_NOEXIST)
+                       goto fail;
+       }
+       /* reset the error code potentially set by the tdb_update() */
+       tdb->ecode = TDB_SUCCESS;
+
+       /* delete any existing record - if it doesn't exist we don't
+           care.  Doing this first reduces fragmentation, and avoids
+           coalescing with `allocated' block before it's updated. */
+       if (flag != TDB_INSERT)
+               tdb_delete(tdb, key);
+
+       /* Copy key+value *before* allocating free space in case malloc
+          fails and we are left with a dead spot in the tdb. */
+
+       if (!(p = (char *)malloc(key.dsize + dbuf.dsize))) {
+               tdb->ecode = TDB_ERR_OOM;
+               goto fail;
+       }
+
+       memcpy(p, key.dptr, key.dsize);
+       if (dbuf.dsize)
+               memcpy(p+key.dsize, dbuf.dptr, dbuf.dsize);
+
+       /* now we're into insert / modify / replace of a record which
+        * we know could not be optimised by an in-place store (for
+        * various reasons).  */
+       if (!(rec_ptr = tdb_allocate(tdb, key.dsize + dbuf.dsize, &rec)))
+               goto fail;
+
+       /* Read hash top into next ptr */
+       if (ofs_read(tdb, TDB_HASH_TOP(hash), &rec.next) == -1)
+               goto fail;
+
+       rec.key_len = key.dsize;
+       rec.data_len = dbuf.dsize;
+       rec.full_hash = hash;
+       rec.magic = TDB_MAGIC;
+
+       /* write out and point the top of the hash chain at it */
+       if (rec_write(tdb, rec_ptr, &rec) == -1
+           || tdb_write(tdb, rec_ptr+sizeof(rec), p, key.dsize+dbuf.dsize)==-1
+           || ofs_write(tdb, TDB_HASH_TOP(hash), &rec_ptr) == -1) {
+               /* Need to tdb_unallocate() here */
+               goto fail;
+       }
+ out:
+       SAFE_FREE(p); 
+       tdb_unlock(tdb, BUCKET(hash), F_WRLCK);
+       return ret;
+fail:
+       ret = -1;
+       goto out;
+}
+
+/* Attempt to append data to an entry in place - this only works if the new data size
+   is <= the old data size and the key exists.
+   on failure return -1. Record must be locked before calling.
+*/
+static int tdb_append_inplace(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA new_dbuf)
+{
+       struct list_struct rec;
+       tdb_off rec_ptr;
+
+       /* find entry */
+       if (!(rec_ptr = tdb_find(tdb, key, tdb_hash(&key), &rec)))
+               return -1;
+
+       /* Append of 0 is always ok. */
+       if (new_dbuf.dsize == 0)
+               return 0;
+
+       /* must be long enough for key, old data + new data and tailer */
+       if (rec.rec_len < key.dsize + rec.data_len + new_dbuf.dsize + sizeof(tdb_off)) {
+               /* No room. */
+               tdb->ecode = TDB_SUCCESS; /* Not really an error */
+               return -1;
+       }
+
+       if (tdb_write(tdb, rec_ptr + sizeof(rec) + rec.key_len + rec.data_len,
+                     new_dbuf.dptr, new_dbuf.dsize) == -1)
+               return -1;
+
+       /* update size */
+       rec.data_len += new_dbuf.dsize;
+       return rec_write(tdb, rec_ptr, &rec);
+}
+
+/* Append to an entry. Create if not exist. */
+
+int tdb_append(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA new_dbuf)
+{
+       struct list_struct rec;
+       u32 hash;
+       tdb_off rec_ptr;
+       char *p = NULL;
+       int ret = 0;
+       size_t new_data_size = 0;
+
+       /* find which hash bucket it is in */
+       hash = tdb_hash(&key);
+       if (!tdb_keylocked(tdb, hash))
+               return -1;
+       if (tdb_lock(tdb, BUCKET(hash), F_WRLCK) == -1)
+               return -1;
+
+       /* first try in-place. */
+       if (tdb_append_inplace(tdb, key, new_dbuf) == 0)
+               goto out;
+
+       /* reset the error code potentially set by the tdb_append_inplace() */
+       tdb->ecode = TDB_SUCCESS;
+
+       /* find entry */
+       if (!(rec_ptr = tdb_find(tdb, key, hash, &rec))) {
+               if (tdb->ecode != TDB_ERR_NOEXIST)
+                       goto fail;
+
+               /* Not found - create. */
+
+               ret = tdb_store(tdb, key, new_dbuf, TDB_INSERT);
+               goto out;
+       }
+
+       new_data_size = rec.data_len + new_dbuf.dsize;
+
+       /* Copy key+old_value+value *before* allocating free space in case malloc
+          fails and we are left with a dead spot in the tdb. */
+
+       if (!(p = (char *)malloc(key.dsize + new_data_size))) {
+               tdb->ecode = TDB_ERR_OOM;
+               goto fail;
+       }
+
+       /* Copy the key in place. */
+       memcpy(p, key.dptr, key.dsize);
+
+       /* Now read the old data into place. */
+       if (rec.data_len &&
+               tdb_read(tdb, rec_ptr + sizeof(rec) + rec.key_len, p + key.dsize, rec.data_len, 0) == -1)
+                       goto fail;
+
+       /* Finally append the new data. */
+       if (new_dbuf.dsize)
+               memcpy(p+key.dsize+rec.data_len, new_dbuf.dptr, new_dbuf.dsize);
+
+       /* delete any existing record - if it doesn't exist we don't
+           care.  Doing this first reduces fragmentation, and avoids
+           coalescing with `allocated' block before it's updated. */
+
+       tdb_delete(tdb, key);
+
+       if (!(rec_ptr = tdb_allocate(tdb, key.dsize + new_data_size, &rec)))
+               goto fail;
+
+       /* Read hash top into next ptr */
+       if (ofs_read(tdb, TDB_HASH_TOP(hash), &rec.next) == -1)
+               goto fail;
+
+       rec.key_len = key.dsize;
+       rec.data_len = new_data_size;
+       rec.full_hash = hash;
+       rec.magic = TDB_MAGIC;
+
+       /* write out and point the top of the hash chain at it */
+       if (rec_write(tdb, rec_ptr, &rec) == -1
+           || tdb_write(tdb, rec_ptr+sizeof(rec), p, key.dsize+new_data_size)==-1
+           || ofs_write(tdb, TDB_HASH_TOP(hash), &rec_ptr) == -1) {
+               /* Need to tdb_unallocate() here */
+               goto fail;
+       }
+
+ out:
+       SAFE_FREE(p); 
+       tdb_unlock(tdb, BUCKET(hash), F_WRLCK);
+       return ret;
+
+fail:
+       ret = -1;
+       goto out;
+}
+
+static int tdb_already_open(dev_t device,
+                           ino_t ino)
+{
+       TDB_CONTEXT *i;
+       
+       for (i = tdbs; i; i = i->next) {
+               if (i->device == device && i->inode == ino) {
+                       return 1;
+               }
+       }
+
+       return 0;
+}
+
+/* open the database, creating it if necessary 
+
+   The open_flags and mode are passed straight to the open call on the
+   database file. A flags value of O_WRONLY is invalid. The hash size
+   is advisory, use zero for a default value.
+
+   Return is NULL on error, in which case errno is also set.  Don't 
+   try to call tdb_error or tdb_errname, just do strerror(errno).
+
+   @param name may be NULL for internal databases. */
+TDB_CONTEXT *tdb_open(const char *name, int hash_size, int tdb_flags,
+                     int open_flags, mode_t mode)
+{
+       return tdb_open_ex(name, hash_size, tdb_flags, open_flags, mode, NULL);
+}
+
+
+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)
+{
+       TDB_CONTEXT *tdb;
+       struct stat st;
+       int rev = 0, locked;
+       unsigned char *vp;
+       u32 vertest;
+
+       if (!(tdb = calloc(1, sizeof *tdb))) {
+               /* Can't log this */
+               errno = ENOMEM;
+               goto fail;
+       }
+       tdb->fd = -1;
+       tdb->name = NULL;
+       tdb->map_ptr = NULL;
+       tdb->lockedkeys = NULL;
+       tdb->flags = tdb_flags;
+       tdb->open_flags = open_flags;
+       tdb->log_fn = log_fn;
+       
+       if ((open_flags & O_ACCMODE) == O_WRONLY) {
+               TDB_LOG((tdb, 0, "tdb_open_ex: can't open tdb %s write-only\n",
+                        name));
+               errno = EINVAL;
+               goto fail;
+       }
+       
+       if (hash_size == 0)
+               hash_size = DEFAULT_HASH_SIZE;
+       if ((open_flags & O_ACCMODE) == O_RDONLY) {
+               tdb->read_only = 1;
+               /* read only databases don't do locking or clear if first */
+               tdb->flags |= TDB_NOLOCK;
+               tdb->flags &= ~TDB_CLEAR_IF_FIRST;
+       }
+
+       /* internal databases don't mmap or lock, and start off cleared */
+       if (tdb->flags & TDB_INTERNAL) {
+               tdb->flags |= (TDB_NOLOCK | TDB_NOMMAP);
+               tdb->flags &= ~TDB_CLEAR_IF_FIRST;
+               if (tdb_new_database(tdb, hash_size) != 0) {
+                       TDB_LOG((tdb, 0, "tdb_open_ex: tdb_new_database failed!"));
+                       goto fail;
+               }
+               goto internal;
+       }
+
+       if ((tdb->fd = open(name, open_flags, mode)) == -1) {
+               TDB_LOG((tdb, 5, "tdb_open_ex: could not open file %s: %s\n",
+                        name, strerror(errno)));
+               goto fail;      /* errno set by open(2) */
+       }
+
+       /* ensure there is only one process initialising at once */
+       if (tdb_brlock(tdb, GLOBAL_LOCK, F_WRLCK, F_SETLKW, 0) == -1) {
+               TDB_LOG((tdb, 0, "tdb_open_ex: failed to get global lock on %s: %s\n",
+                        name, strerror(errno)));
+               goto fail;      /* errno set by tdb_brlock */
+       }
+
+       /* we need to zero database if we are the only one with it open */
+       if ((locked = (tdb_brlock(tdb, ACTIVE_LOCK, F_WRLCK, F_SETLK, 0) == 0))
+           && (tdb_flags & TDB_CLEAR_IF_FIRST)) {
+               open_flags |= O_CREAT;
+               if (ftruncate(tdb->fd, 0) == -1) {
+                       TDB_LOG((tdb, 0, "tdb_open_ex: "
+                                "failed to truncate %s: %s\n",
+                                name, strerror(errno)));
+                       goto fail; /* errno set by ftruncate */
+               }
+       }
+
+       if (read(tdb->fd, &tdb->header, sizeof(tdb->header)) != sizeof(tdb->header)
+           || strcmp(tdb->header.magic_food, TDB_MAGIC_FOOD) != 0
+           || (tdb->header.version != TDB_VERSION
+               && !(rev = (tdb->header.version==TDB_BYTEREV(TDB_VERSION))))) {
+               /* its not a valid database - possibly initialise it */
+               if (!(open_flags & O_CREAT) || tdb_new_database(tdb, hash_size) == -1) {
+                       errno = EIO; /* ie bad format or something */
+                       goto fail;
+               }
+               rev = (tdb->flags & TDB_CONVERT);
+       }
+       vp = (unsigned char *)&tdb->header.version;
+       vertest = (((u32)vp[0]) << 24) | (((u32)vp[1]) << 16) |
+                 (((u32)vp[2]) << 8) | (u32)vp[3];
+       tdb->flags |= (vertest==TDB_VERSION) ? TDB_BIGENDIAN : 0;
+       if (!rev)
+               tdb->flags &= ~TDB_CONVERT;
+       else {
+               tdb->flags |= TDB_CONVERT;
+               convert(&tdb->header, sizeof(tdb->header));
+       }
+       if (fstat(tdb->fd, &st) == -1)
+               goto fail;
+
+       /* Is it already in the open list?  If so, fail. */
+       if (tdb_already_open(st.st_dev, st.st_ino)) {
+               TDB_LOG((tdb, 2, "tdb_open_ex: "
+                        "%s (%d,%d) is already open in this process\n",
+                        name, st.st_dev, st.st_ino));
+               errno = EBUSY;
+               goto fail;
+       }
+
+       if (!(tdb->name = (char *)strdup(name))) {
+               errno = ENOMEM;
+               goto fail;
+       }
+
+       tdb->map_size = st.st_size;
+       tdb->device = st.st_dev;
+       tdb->inode = st.st_ino;
+       tdb->locked = calloc(tdb->header.hash_size+1, sizeof(tdb->locked[0]));
+       if (!tdb->locked) {
+               TDB_LOG((tdb, 2, "tdb_open_ex: "
+                        "failed to allocate lock structure for %s\n",
+                        name));
+               errno = ENOMEM;
+               goto fail;
+       }
+       tdb_mmap(tdb);
+       if (locked) {
+               if (!tdb->read_only)
+                       if (tdb_clear_spinlocks(tdb) != 0) {
+                               TDB_LOG((tdb, 0, "tdb_open_ex: "
+                               "failed to clear spinlock\n"));
+                               goto fail;
+                       }
+               if (tdb_brlock(tdb, ACTIVE_LOCK, F_UNLCK, F_SETLK, 0) == -1) {
+                       TDB_LOG((tdb, 0, "tdb_open_ex: "
+                                "failed to take ACTIVE_LOCK on %s: %s\n",
+                                name, strerror(errno)));
+                       goto fail;
+               }
+       }
+       /* leave this lock in place to indicate it's in use */
+       if (tdb_brlock(tdb, ACTIVE_LOCK, F_RDLCK, F_SETLKW, 0) == -1)
+               goto fail;
+
+ internal:
+       /* Internal (memory-only) databases skip all the code above to
+        * do with disk files, and resume here by releasing their
+        * global lock and hooking into the active list. */
+       if (tdb_brlock(tdb, GLOBAL_LOCK, F_UNLCK, F_SETLKW, 0) == -1)
+               goto fail;
+       tdb->next = tdbs;
+       tdbs = tdb;
+       return tdb;
+
+ fail:
+       { int save_errno = errno;
+
+       if (!tdb)
+               return NULL;
+       
+       if (tdb->map_ptr) {
+               if (tdb->flags & TDB_INTERNAL)
+                       SAFE_FREE(tdb->map_ptr);
+               else
+                       tdb_munmap(tdb);
+       }
+       SAFE_FREE(tdb->name);
+       if (tdb->fd != -1)
+               if (close(tdb->fd) != 0)
+                       TDB_LOG((tdb, 5, "tdb_open_ex: failed to close tdb->fd on error!\n"));
+       SAFE_FREE(tdb->locked);
+       SAFE_FREE(tdb);
+       errno = save_errno;
+       return NULL;
+       }
+}
+
+/**
+ * Close a database.
+ *
+ * @returns -1 for error; 0 for success.
+ **/
+int tdb_close(TDB_CONTEXT *tdb)
+{
+       TDB_CONTEXT **i;
+       int ret = 0;
+
+       if (tdb->map_ptr) {
+               if (tdb->flags & TDB_INTERNAL)
+                       SAFE_FREE(tdb->map_ptr);
+               else
+                       tdb_munmap(tdb);
+       }
+       SAFE_FREE(tdb->name);
+       if (tdb->fd != -1)
+               ret = close(tdb->fd);
+       SAFE_FREE(tdb->locked);
+       SAFE_FREE(tdb->lockedkeys);
+
+       /* Remove from contexts list */
+       for (i = &tdbs; *i; i = &(*i)->next) {
+               if (*i == tdb) {
+                       *i = tdb->next;
+                       break;
+               }
+       }
+
+       memset(tdb, 0, sizeof(*tdb));
+       SAFE_FREE(tdb);
+
+       return ret;
+}
+
+/* lock/unlock entire database */
+int tdb_lockall(TDB_CONTEXT *tdb)
+{
+       u32 i;
+
+       /* There are no locks on read-only dbs */
+       if (tdb->read_only)
+               return TDB_ERRCODE(TDB_ERR_LOCK, -1);
+       if (tdb->lockedkeys)
+               return TDB_ERRCODE(TDB_ERR_NOLOCK, -1);
+       for (i = 0; i < tdb->header.hash_size; i++) 
+               if (tdb_lock(tdb, i, F_WRLCK))
+                       break;
+
+       /* If error, release locks we have... */
+       if (i < tdb->header.hash_size) {
+               u32 j;
+
+               for ( j = 0; j < i; j++)
+                       tdb_unlock(tdb, j, F_WRLCK);
+               return TDB_ERRCODE(TDB_ERR_NOLOCK, -1);
+       }
+
+       return 0;
+}
+void tdb_unlockall(TDB_CONTEXT *tdb)
+{
+       u32 i;
+       for (i=0; i < tdb->header.hash_size; i++)
+               tdb_unlock(tdb, i, F_WRLCK);
+}
+
+int tdb_lockkeys(TDB_CONTEXT *tdb, u32 number, TDB_DATA keys[])
+{
+       u32 i, j, hash;
+
+       /* Can't lock more keys if already locked */
+       if (tdb->lockedkeys)
+               return TDB_ERRCODE(TDB_ERR_NOLOCK, -1);
+       if (!(tdb->lockedkeys = malloc(sizeof(u32) * (number+1))))
+               return TDB_ERRCODE(TDB_ERR_OOM, -1);
+       /* First number in array is # keys */
+       tdb->lockedkeys[0] = number;
+
+       /* Insertion sort by bucket */
+       for (i = 0; i < number; i++) {
+               hash = tdb_hash(&keys[i]);
+               for (j = 0; j < i && BUCKET(tdb->lockedkeys[j+1]) < BUCKET(hash); j++);
+                       memmove(&tdb->lockedkeys[j+2], &tdb->lockedkeys[j+1], sizeof(u32) * (i-j));
+               tdb->lockedkeys[j+1] = hash;
+       }
+       /* Finally, lock in order */
+       for (i = 0; i < number; i++)
+               if (tdb_lock(tdb, i, F_WRLCK))
+                       break;
+
+       /* If error, release locks we have... */
+       if (i < number) {
+               for ( j = 0; j < i; j++)
+                       tdb_unlock(tdb, j, F_WRLCK);
+               SAFE_FREE(tdb->lockedkeys);
+               return TDB_ERRCODE(TDB_ERR_NOLOCK, -1);
+       }
+       return 0;
+}
+
+/* Unlock the keys previously locked by tdb_lockkeys() */
+void tdb_unlockkeys(TDB_CONTEXT *tdb)
+{
+       u32 i;
+       if (!tdb->lockedkeys)
+               return;
+       for (i = 0; i < tdb->lockedkeys[0]; i++)
+               tdb_unlock(tdb, tdb->lockedkeys[i+1], F_WRLCK);
+       SAFE_FREE(tdb->lockedkeys);
+}
+
+/* lock/unlock one hash chain. This is meant to be used to reduce
+   contention - it cannot guarantee how many records will be locked */
+int tdb_chainlock(TDB_CONTEXT *tdb, TDB_DATA key)
+{
+       return tdb_lock(tdb, BUCKET(tdb_hash(&key)), F_WRLCK);
+}
+
+int tdb_chainunlock(TDB_CONTEXT *tdb, TDB_DATA key)
+{
+       return tdb_unlock(tdb, BUCKET(tdb_hash(&key)), F_WRLCK);
+}
+
+int tdb_chainlock_read(TDB_CONTEXT *tdb, TDB_DATA key)
+{
+       return tdb_lock(tdb, BUCKET(tdb_hash(&key)), F_RDLCK);
+}
+
+int tdb_chainunlock_read(TDB_CONTEXT *tdb, TDB_DATA key)
+{
+       return tdb_unlock(tdb, BUCKET(tdb_hash(&key)), F_RDLCK);
+}
+
+
+/* register a loging function */
+void tdb_logging_function(TDB_CONTEXT *tdb, void (*fn)(TDB_CONTEXT *, int , const char *, ...))
+{
+       tdb->log_fn = fn;
+}
+
+
+/* reopen a tdb - this is used after a fork to ensure that we have an independent
+   seek pointer from our parent and to re-establish locks */
+int tdb_reopen(TDB_CONTEXT *tdb)
+{
+       struct stat st;
+
+       if (tdb_munmap(tdb) != 0) {
+               TDB_LOG((tdb, 0, "tdb_reopen: munmap failed (%s)\n", strerror(errno)));
+               goto fail;
+       }
+       if (close(tdb->fd) != 0)
+               TDB_LOG((tdb, 0, "tdb_reopen: WARNING closing tdb->fd failed!\n"));
+       tdb->fd = open(tdb->name, tdb->open_flags & ~(O_CREAT|O_TRUNC), 0);
+       if (tdb->fd == -1) {
+               TDB_LOG((tdb, 0, "tdb_reopen: open failed (%s)\n", strerror(errno)));
+               goto fail;
+       }
+       if (fstat(tdb->fd, &st) != 0) {
+               TDB_LOG((tdb, 0, "tdb_reopen: fstat failed (%s)\n", strerror(errno)));
+               goto fail;
+       }
+       if (st.st_ino != tdb->inode || st.st_dev != tdb->device) {
+               TDB_LOG((tdb, 0, "tdb_reopen: file dev/inode has changed!\n"));
+               goto fail;
+       }
+       tdb_mmap(tdb);
+       if (tdb_brlock(tdb, ACTIVE_LOCK, F_RDLCK, F_SETLKW, 0) == -1) {
+               TDB_LOG((tdb, 0, "tdb_reopen: failed to obtain active lock\n"));
+               goto fail;
+       }
+
+       return 0;
+
+fail:
+       tdb_close(tdb);
+       return -1;
+}
+
+/* reopen all tdb's */
+int tdb_reopen_all(void)
+{
+       TDB_CONTEXT *tdb;
+
+       for (tdb=tdbs; tdb; tdb = tdb->next) {
+               if (tdb_reopen(tdb) != 0) return -1;
+       }
+
+       return 0;
+}
diff --git a/libatalk/unicode/.cvsignore b/libatalk/unicode/.cvsignore
new file mode 100644 (file)
index 0000000..0d0371d
--- /dev/null
@@ -0,0 +1,6 @@
+Makefile
+Makefile.in
+*.lo
+*.la
+.deps
+.libs
diff --git a/libatalk/unicode/Makefile.am b/libatalk/unicode/Makefile.am
new file mode 100644 (file)
index 0000000..9b8ba09
--- /dev/null
@@ -0,0 +1,22 @@
+# Makefile.am for libatalk/util/
+
+noinst_LTLIBRARIES = libunicode.la
+
+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       \
+       utf8.c
+
+libunicode_la_LIBADD = $(LIBUNICODE_DEPS)
+
+noinst_HEADERS = ucs2_casetable.h precompose.h byteorder.h
+
+LIBS=@ICONV_LIBS@
diff --git a/libatalk/unicode/byteorder.h b/libatalk/unicode/byteorder.h
new file mode 100644 (file)
index 0000000..3cf3dcc
--- /dev/null
@@ -0,0 +1,189 @@
+/* 
+   Unix SMB/CIFS implementation.
+   SMB Byte 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.
+*/
+
+#ifndef _BYTEORDER_H
+#define _BYTEORDER_H
+#include <netatalk/endian.h>
+
+/*
+   This file implements macros for machine independent short and 
+   int manipulation
+
+Here is a description of this file that I emailed to the samba list once:
+
+> I am confused about the way that byteorder.h works in Samba. I have
+> looked at it, and I would have thought that you might make a distinction
+> between LE and BE machines, but you only seem to distinguish between 386
+> and all other architectures.
+> 
+> Can you give me a clue?
+
+sure.
+
+The distinction between 386 and other architectures is only there as
+an optimisation. You can take it out completely and it will make no
+difference. The routines (macros) in byteorder.h are totally byteorder
+independent. The 386 optimsation just takes advantage of the fact that
+the x86 processors don't care about alignment, so we don't have to
+align ints on int boundaries etc. If there are other processors out
+there that aren't alignment sensitive then you could also define
+CAREFUL_ALIGNMENT=0 on those processors as well.
+
+Ok, now to the macros themselves. I'll take a simple example, say we
+want to extract a 2 byte integer from a SMB packet and put it into a
+type called uint16 that is in the local machines byte order, and you
+want to do it with only the assumption that uint16 is _at_least_ 16
+bits long (this last condition is very important for architectures
+that don't have any int types that are 2 bytes long)
+
+You do this:
+
+#define CVAL(buf,pos) (((unsigned char *)(buf))[pos])
+#define PVAL(buf,pos) ((unsigned)CVAL(buf,pos))
+#define SVAL(buf,pos) (PVAL(buf,pos)|PVAL(buf,(pos)+1)<<8)
+
+then to extract a uint16 value at offset 25 in a buffer you do this:
+
+char *buffer = foo_bar();
+uint16 xx = SVAL(buffer,25);
+
+We are using the byteoder independence of the ANSI C bitshifts to do
+the work. A good optimising compiler should turn this into efficient
+code, especially if it happens to have the right byteorder :-)
+
+I know these macros can be made a bit tidier by removing some of the
+casts, but you need to look at byteorder.h as a whole to see the
+reasoning behind them. byteorder.h defines the following macros:
+
+SVAL(buf,pos) - extract a 2 byte SMB value
+IVAL(buf,pos) - extract a 4 byte SMB value
+SVALS(buf,pos) signed version of SVAL()
+IVALS(buf,pos) signed version of IVAL()
+
+SSVAL(buf,pos,val) - put a 2 byte SMB value into a buffer
+SIVAL(buf,pos,val) - put a 4 byte SMB value into a buffer
+SSVALS(buf,pos,val) - signed version of SSVAL()
+SIVALS(buf,pos,val) - signed version of SIVAL()
+
+RSVAL(buf,pos) - like SVAL() but for NMB byte ordering
+RSVALS(buf,pos) - like SVALS() but for NMB byte ordering
+RIVAL(buf,pos) - like IVAL() but for NMB byte ordering
+RIVALS(buf,pos) - like IVALS() but for NMB byte ordering
+RSSVAL(buf,pos,val) - like SSVAL() but for NMB ordering
+RSIVAL(buf,pos,val) - like SIVAL() but for NMB ordering
+RSIVALS(buf,pos,val) - like SIVALS() but for NMB ordering
+
+it also defines lots of intermediate macros, just ignore those :-)
+
+*/
+
+#undef CAREFUL_ALIGNMENT
+
+/* we know that the 386 can handle misalignment and has the "right" 
+   byteorder */
+#ifdef __i386__
+#define CAREFUL_ALIGNMENT 0
+#endif
+
+#ifndef CAREFUL_ALIGNMENT
+#define CAREFUL_ALIGNMENT 1
+#endif
+
+#define CVAL(buf,pos) ((unsigned)(((const unsigned char *)(buf))[pos]))
+#define CVAL_NC(buf,pos) (((unsigned char *)(buf))[pos]) /* Non-const version of CVAL */
+#define PVAL(buf,pos) (CVAL(buf,pos))
+#define SCVAL(buf,pos,val) (CVAL_NC(buf,pos) = (val))
+
+
+#if CAREFUL_ALIGNMENT
+
+#if BYTE_ORDER==BIG_ENDIAN
+
+#define SVAL(buf,pos) (PVAL(buf,(pos)+1)|PVAL(buf,pos)<<8)
+#define IVAL(buf,pos) (SVAL(buf,pos)|SVAL(buf,(pos)+2)<<16)
+#define SSVALX(buf,pos,val) (CVAL_NC(buf,pos+1)=(unsigned char)((val)&0xFF),CVAL_NC(buf,pos)=(unsigned char)((val)>>8))
+#define SIVALX(buf,pos,val) (SSVALX(buf,pos,val&0xFFFF),SSVALX(buf,pos+2,val>>16))
+#define SVALS(buf,pos) ((int16)SVAL(buf,pos))
+#define IVALS(buf,pos) ((int32_t)IVAL(buf,pos))
+#define SSVAL(buf,pos,val) SSVALX((buf),(pos),((u_int16_t)(val)))
+#define SIVAL(buf,pos,val) SIVALX((buf),(pos),((u_int32_t)(val)))
+#define SSVALS(buf,pos,val) SSVALX((buf),(pos),((int16)(val)))
+#define SIVALS(buf,pos,val) SIVALX((buf),(pos),((int32_t)(val)))
+
+#else
+
+#define SVAL(buf,pos) (PVAL(buf,pos)|PVAL(buf,(pos)+1)<<8)
+#define IVAL(buf,pos) (SVAL(buf,pos)|SVAL(buf,(pos)+2)<<16)
+#define SSVALX(buf,pos,val) (CVAL_NC(buf,pos)=(unsigned char)((val)&0xFF),CVAL_NC(buf,pos+1)=(unsigned char)((val)>>8))
+#define SIVALX(buf,pos,val) (SSVALX(buf,pos,val&0xFFFF),SSVALX(buf,pos+2,val>>16))
+#define SVALS(buf,pos) ((int16)SVAL(buf,pos))
+#define IVALS(buf,pos) ((int32_t)IVAL(buf,pos))
+#define SSVAL(buf,pos,val) SSVALX((buf),(pos),((u_int16_t)(val)))
+#define SIVAL(buf,pos,val) SIVALX((buf),(pos),((u_int32_t)(val)))
+#define SSVALS(buf,pos,val) SSVALX((buf),(pos),((int16)(val)))
+#define SIVALS(buf,pos,val) SIVALX((buf),(pos),((int32_t)(val)))
+
+#endif
+
+#else /* CAREFUL_ALIGNMENT */
+
+/* this handles things for architectures like the 386 that can handle
+   alignment errors */
+/*
+   WARNING: This section is dependent on the length of int16 and int32
+   being correct 
+*/
+
+/* get single value from an SMB buffer */
+#define SVAL(buf,pos) (*(const u_int16_t *)((const char *)(buf) + (pos)))
+#define SVAL_NC(buf,pos) (*(u_int16_t *)((char *)(buf) + (pos))) /* Non const version of above. */
+#define IVAL(buf,pos) (*(const u_int32_t *)((const char *)(buf) + (pos)))
+#define IVAL_NC(buf,pos) (*(u_int32_t *)((char *)(buf) + (pos))) /* Non const version of above. */
+#define SVALS(buf,pos) (*(const int16_t *)((const char *)(buf) + (pos)))
+#define SVALS_NC(buf,pos) (*(int16 *)((char *)(buf) + (pos))) /* Non const version of above. */
+#define IVALS(buf,pos) (*(const int32_t *)((const char *)(buf) + (pos)))
+#define IVALS_NC(buf,pos) (*(int32_t *)((char *)(buf) + (pos))) /* Non const version of above. */
+
+/* store single value in an SMB buffer */
+#define SSVAL(buf,pos,val) SVAL_NC(buf,pos)=((u_int16_t)(val))
+#define SIVAL(buf,pos,val) IVAL_NC(buf,pos)=((u_int32_t)(val))
+#define SSVALS(buf,pos,val) SVALS_NC(buf,pos)=((int16)(val))
+#define SIVALS(buf,pos,val) IVALS_NC(buf,pos)=((int32_t)(val))
+
+#endif /* CAREFUL_ALIGNMENT */
+
+/* now the reverse routines - these are used in nmb packets (mostly) */
+#define SREV(x) ((((x)&0xFF)<<8) | (((x)>>8)&0xFF))
+#define IREV(x) ((SREV(x)<<16) | (SREV((x)>>16)))
+
+#define RSVAL(buf,pos) SREV(SVAL(buf,pos))
+#define RSVALS(buf,pos) SREV(SVALS(buf,pos))
+#define RIVAL(buf,pos) IREV(IVAL(buf,pos))
+#define RIVALS(buf,pos) IREV(IVALS(buf,pos))
+#define RSSVAL(buf,pos,val) SSVAL(buf,pos,SREV(val))
+#define RSSVALS(buf,pos,val) SSVALS(buf,pos,SREV(val))
+#define RSIVAL(buf,pos,val) SIVAL(buf,pos,IREV(val))
+#define RSIVALS(buf,pos,val) SIVALS(buf,pos,IREV(val))
+
+/* Alignment macros. */
+#define ALIGN4(p,base) ((p) + ((4 - (PTR_DIFF((p), (base)) & 3)) & 3))
+#define ALIGN2(p,base) ((p) + ((2 - (PTR_DIFF((p), (base)) & 1)) & 1))
+
+#endif /* _BYTEORDER_H */
diff --git a/libatalk/unicode/charcnv.c b/libatalk/unicode/charcnv.c
new file mode 100644 (file)
index 0000000..2e41a4c
--- /dev/null
@@ -0,0 +1,1079 @@
+/* 
+   Unix SMB/CIFS implementation.
+   Character set conversion Extensions
+   Copyright (C) Igor Vergeichik <iverg@mail.ru> 2001
+   Copyright (C) Andrew Tridgell 2001
+   Copyright (C) Simo Sorce 2001
+   Copyright (C) Martin Pool 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.
+
+*/
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#ifdef HAVE_USABLE_ICONV
+#include <iconv.h>
+#endif
+#if HAVE_LOCALE_H
+#include <locale.h>
+#endif
+#if HAVE_LANGINFO_H
+#include <langinfo.h>
+#endif
+
+#include <netatalk/endian.h>
+#include <atalk/logger.h>
+#include <atalk/unicode.h>
+#include <atalk/util.h>
+#include "byteorder.h"
+
+
+/**
+ * @file
+ *
+ * @brief Character-set conversion routines built on our iconv.
+ * 
+ * @note Samba's internal character set (at least in the 3.0 series)
+ * is always the same as the one for the Unix filesystem.  It is
+ * <b>not</b> necessarily UTF-8 and may be different on machines that
+ * need i18n filenames to be compatible with Unix software.  It does
+ * have to be a superset of ASCII.  All multibyte sequences must start
+ * with a byte with the high bit set.
+ *
+ * @sa lib/iconv.c
+ */
+
+
+#define MAX_CHARSETS 10
+
+#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];
+static struct charset_functions* charsets[MAX_CHARSETS];
+static char hexdig[] = "0123456789abcdef";
+#define hextoint( c )   ( isdigit( c ) ? c - '0' : c + 10 - 'a' )
+
+static char* read_charsets_from_env(charset_t ch) 
+{
+       char *name;
+
+       switch (ch) {
+           case CH_MAC:
+                if (( name = getenv( "ATALK_MAC_CHARSET" )) != NULL ) 
+                   return name;
+               else
+                   return "MAC_ROMAN";
+               break;
+            case CH_UNIX:
+                if (( name = getenv( "ATALK_UNIX_CHARSET" )) != NULL ) 
+                   return name;
+               else
+                   return "LOCALE";
+               break;
+           default:
+               break;
+        }
+        return "ASCII";
+} 
+           
+
+/**
+ * Return the name of a charset to give to iconv().
+ **/
+static const char *charset_name(charset_t ch)
+{
+       const char *ret = NULL;
+       static int first = 1;
+       static char macname[128];
+       static char unixname[128];
+
+       if (first) {
+               memset(macname, 0, sizeof(macname));
+               memset(unixname, 0, sizeof(unixname));
+               first = 0;
+       }
+
+       if (ch == CH_UCS2) ret = "UCS-2";
+       else if (ch == CH_UTF8) ret = "UTF8";
+       else if (ch == CH_UTF8_MAC) ret = "UTF8-MAC";
+       else if (ch == CH_UNIX) {
+               if (unixname[0] == '\0') {
+                       ret = read_charsets_from_env(CH_UNIX);
+                       strlcpy(unixname, ret, sizeof(unixname));
+               }
+               else
+                       ret = unixname;
+       }
+       else if (ch == CH_MAC) {
+               if (macname[0] == '\0') {
+                       ret = read_charsets_from_env(CH_MAC);
+                       strlcpy(macname, ret, sizeof(macname));
+               }
+               else
+                       ret = macname;
+       }
+
+       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-2");
+                       if (handle == (atalk_iconv_t) -1) {
+                               LOG(log_debug, logtype_default, "Locale charset '%s' unsupported, using ASCII instead", ln);
+                               ln = "ASCII";
+                       } else {
+                               atalk_iconv_close(handle);
+                       }
+                       if (ch==CH_UNIX)
+                               strlcpy(unixname, ln, sizeof(unixname));
+               }
+               ret = ln;
+       }
+#else /* system doesn't have LOCALE support */
+if (ch == CH_UNIX) ret = NULL;
+#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;
+
+       if (!initialized) {
+               initialized = 1;
+               init_iconv();
+       }
+}
+
+charset_t add_charset(char* name)
+{
+       static charset_t max_charset_t = NUM_CHARSETS-1;
+       charset_t cur_charset_t = max_charset_t+1;
+       unsigned int c1;
+
+       lazy_initialize_conv();
+
+       for (c1=0; c1<=max_charset_t;c1++) {
+               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 (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",
+                       name,  charset_name(CH_UCS2));
+               conv_handles[cur_charset_t][CH_UCS2] = NULL;
+               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",
+                       charset_name(CH_UCS2), name);
+               conv_handles[CH_UCS2][cur_charset_t] = NULL;
+               return (charset_t) -1;
+       }
+
+       /* register the new charset_t name */
+       charset_names[cur_charset_t] = strdup(name);
+
+       charsets[cur_charset_t] = get_charset_functions (cur_charset_t);
+       max_charset_t++;
+
+#ifdef DEBUG
+       LOG(log_debug, logtype_default, "Added charset %s with handle %u", name, cur_charset_t);
+#endif /* DEBUG */
+       return (cur_charset_t);
+}
+
+/**
+ * Initialize iconv conversion descriptors.
+ *
+ * This is called the first time it is needed, and also called again
+ * every time the configuration is reloaded, because the charset or
+ * codepage might have changed.
+ **/
+void init_iconv(void)
+{
+       int c1;
+
+       for (c1=0;c1<NUM_CHARSETS;c1++) {
+               const char *name = charset_name((charset_t)c1);
+
+               conv_handles[c1][CH_UCS2] = atalk_iconv_open( charset_name(CH_UCS2), name);
+               if (conv_handles[c1][CH_UCS2] == (atalk_iconv_t)-1) {
+                       LOG(log_error, logtype_default, "Required conversion from %s to %s not supported",
+                               name,  charset_name(CH_UCS2));
+                       conv_handles[c1][CH_UCS2] = NULL;
+               }
+
+               if (c1 != CH_UCS2) { /* avoid lost memory, make valgrind happy */
+                       conv_handles[CH_UCS2][c1] = atalk_iconv_open( name, charset_name(CH_UCS2));
+                       if (conv_handles[CH_UCS2][c1] == (atalk_iconv_t)-1) {
+                               LOG(log_error, logtype_default, "Required conversion from %s to %s not supported",
+                                       charset_name(CH_UCS2), name);
+                               conv_handles[CH_UCS2][c1] = NULL;
+                       }
+               }
+               
+               charsets[c1] = get_charset_functions (c1);
+       }
+}
+
+/**
+ * Convert string from one encoding to another, making error checking etc
+ *
+ * @param src pointer to source string (multibyte or singlebyte)
+ * @param srclen length of the source string in bytes
+ * @param dest pointer to destination string (multibyte or singlebyte)
+ * @param destlen maximal length allowed for string
+ * @returns the number of bytes occupied in the destination
+ **/
+static size_t convert_string_internal(charset_t from, charset_t to,
+                     void const *src, size_t srclen, 
+                     void *dest, size_t destlen)
+{
+       size_t i_len, o_len;
+       size_t retval;
+       const char* inbuf = (const char*)src;
+       char* outbuf = (char*)dest;
+       char* o_save = outbuf;
+       atalk_iconv_t descriptor;
+
+       /* Fixed based on Samba 3.0.6 */
+       if (srclen == (size_t)-1) {
+               if (from == CH_UCS2) {
+                       srclen = (strlen_w((const ucs2_t *)src)+1) * 2;
+               } else {
+                       srclen = strlen((const char *)src)+1;
+               }
+       }
+
+
+       lazy_initialize_conv();
+
+       descriptor = conv_handles[from][to];
+
+       if (descriptor == (atalk_iconv_t)-1 || descriptor == (atalk_iconv_t)0) {
+               return (size_t) -1;
+       }
+
+       i_len=srclen;
+       o_len=destlen;
+       retval = atalk_iconv(descriptor,  &inbuf, &i_len, &outbuf, &o_len);
+       if(retval==(size_t)-1) {
+               const char *reason="unknown error";
+               switch(errno) {
+                       case EINVAL:
+                               reason="Incomplete multibyte sequence";
+                               break;
+                       case E2BIG:
+                               reason="No more room"; 
+                              break;
+                       case EILSEQ:
+                              reason="Illegal multibyte sequence";
+                              break;
+               }
+               LOG(log_debug, logtype_default,"Conversion error: %s",reason);
+               return (size_t)-1;
+       }
+
+       /* Terminate the string */
+       if (to == CH_UCS2 && destlen-o_len >= 2) {
+               o_save[destlen-o_len]   = 0;
+               o_save[destlen-o_len+1] = 0;
+       }
+       else if ( to != CH_UCS2 && destlen-o_len > 0 )
+               o_save[destlen-o_len] = 0;
+       else {
+               /* FIXME: what should we do here, string *might* be unterminated. E2BIG? */
+       }
+
+       return destlen-o_len;
+}
+
+
+size_t convert_string(charset_t from, charset_t to,
+                     void const *src, size_t srclen, 
+                     void *dest, size_t destlen)
+{
+       size_t i_len, o_len;
+       ucs2_t *u;
+       ucs2_t buffer[MAXPATHLEN];
+       ucs2_t buffer2[MAXPATHLEN];
+       int composition = 0;
+
+       lazy_initialize_conv();
+
+       /* convert from_set to UCS2 */
+       if ((size_t)(-1) == ( o_len = convert_string_internal( from, CH_UCS2, src, srclen, 
+                                                               (char*) buffer, sizeof(buffer))) ) {
+               LOG(log_error, logtype_default, "Conversion failed ( %s to CH_UCS2 )", charset_name(from));
+               return (size_t) -1;
+       }
+
+       /* Do pre/decomposition */
+       if ( ((!(charsets[to])   || !(charsets[to]->flags & CHARSET_DECOMPOSED)) && 
+               (!(charsets[from]) || (charsets[from]->flags & CHARSET_DECOMPOSED))))
+           composition = 1;
+       if ((charsets[to] && charsets[to]->flags & CHARSET_DECOMPOSED) )
+           composition = 2;
+       i_len = sizeof(buffer2);
+       u = buffer2;
+
+       switch (composition) {
+       case 0:
+           u = buffer;
+           i_len = o_len;
+           break;
+       case 1:
+            if ( (size_t)-1 == (i_len = precompose_w(buffer, o_len, u, &i_len)) )
+               return (size_t)(-1);
+           break;
+       case 2:
+            if ( (size_t)-1 == (i_len = decompose_w(buffer, o_len, u, &i_len)) )
+               return (size_t)(-1);
+           break;
+       }
+               
+       /* Convert UCS2 to to_set */
+       if ((size_t)(-1) == ( o_len = convert_string_internal( CH_UCS2, to, (char*) u, i_len, dest, destlen)) ) {
+               LOG(log_error, logtype_default, "Conversion failed (CH_UCS2 to %s):%s", charset_name(to), strerror(errno));
+               return (size_t) -1;
+       }
+
+       return o_len;
+}      
+
+       
+
+/**
+ * Convert between character sets, allocating a new buffer for the result.
+ *
+ * @param srclen length of source buffer.
+ * @param dest always set at least to NULL
+ * @note -1 is not accepted for srclen.
+ *
+ * @returns Size in bytes of the converted string; or -1 in case of error.
+ **/
+
+static size_t convert_string_allocate_internal(charset_t from, charset_t to,
+                              void const *src, size_t srclen, char **dest)
+{
+       size_t i_len, o_len, destlen;
+       size_t retval;
+       const char *inbuf = (const char *)src;
+       char *outbuf = NULL, *ob = NULL;
+       atalk_iconv_t descriptor;
+
+       *dest = NULL;
+
+       if (src == NULL || srclen == (size_t)-1)
+               return (size_t)-1;
+
+       lazy_initialize_conv();
+
+       descriptor = conv_handles[from][to];
+
+       if (descriptor == (atalk_iconv_t)-1 || descriptor == (atalk_iconv_t)0) {
+               /* conversion not supported, return -1*/
+               LOG(log_debug, logtype_default, "convert_string_allocate: conversion not supported!");
+               return -1;
+       }
+
+       destlen = MAX(srclen, 512);
+convert:
+       destlen = destlen * 2;
+       outbuf = (char *)realloc(ob, destlen);
+       if (!outbuf) {
+               LOG(log_debug, logtype_default,"convert_string_allocate: realloc failed!");
+               SAFE_FREE(ob);
+               return (size_t)-1;
+       } else {
+               ob = outbuf;
+       }
+       inbuf = src;   /* this restarts the whole conversion if buffer needed to be increased */
+       i_len = srclen;
+       o_len = destlen;
+       retval = atalk_iconv(descriptor,
+                          &inbuf, &i_len,
+                          &outbuf, &o_len);
+       if(retval == (size_t)-1)                {
+               const char *reason="unknown error";
+               switch(errno) {
+                       case EINVAL:
+                               reason="Incomplete multibyte sequence";
+                               break;
+                       case E2BIG:
+                               goto convert;           
+                       case EILSEQ:
+                               reason="Illegal multibyte sequence";
+                               break;
+               }
+               LOG(log_debug, logtype_default,"Conversion error: %s(%s)",reason,inbuf);
+               SAFE_FREE(ob);
+               return (size_t)-1;
+       }
+
+       
+       destlen = destlen - o_len;
+
+       /* Terminate the string */
+       if (to == CH_UCS2 && o_len >= 2) {
+               ob[destlen] = 0;
+               ob[destlen+1] = 0;
+               *dest = (char *)realloc(ob,destlen+2);
+       }
+       else if ( to != CH_UCS2 && o_len > 0 ) {
+               ob[destlen] = 0;
+               *dest = (char *)realloc(ob,destlen+1);
+       }
+       else {
+               goto convert; /* realloc */
+       }
+
+       if (destlen && !*dest) {
+               LOG(log_debug, logtype_default, "convert_string_allocate: out of memory!");
+               SAFE_FREE(ob);
+               return (size_t)-1;
+       }
+
+       return destlen;
+}
+
+
+size_t convert_string_allocate(charset_t from, charset_t to,
+                     void const *src, size_t srclen, 
+                     char ** dest)
+{
+       size_t i_len, o_len;
+       ucs2_t *u;
+       ucs2_t buffer[MAXPATHLEN];
+       ucs2_t buffer2[MAXPATHLEN];
+       int composition = 0;
+
+       lazy_initialize_conv();
+
+       *dest = NULL;
+
+       /* convert from_set to UCS2 */
+       if ((size_t)(-1) == ( o_len = convert_string_internal( from, CH_UCS2, src, srclen, 
+                                                               buffer, sizeof(buffer))) ) {
+               LOG(log_error, logtype_default, "Conversion failed ( %s to CH_UCS2 )", charset_name(from));
+               return (size_t) -1;
+       }
+
+       /* Do pre/decomposition */
+       if ( ((!(charsets[to])   || !(charsets[to]->flags & CHARSET_DECOMPOSED)) && 
+               (!(charsets[from]) || (charsets[from]->flags & CHARSET_DECOMPOSED))))
+           composition = 1;
+       if ((charsets[to] && charsets[to]->flags & CHARSET_DECOMPOSED) )
+           composition = 2;
+       i_len = sizeof(buffer2);
+       u = buffer2;
+
+       switch (composition) {
+       case 0:
+           u = buffer;
+           i_len = o_len;
+           break;
+       case 1:
+            if ( (size_t)-1 == (i_len = precompose_w(buffer, o_len, u, &i_len)) )
+               return (size_t)(-1);
+           break;
+       case 2:
+            if ( (size_t)-1 == (i_len = decompose_w(buffer, o_len, u, &i_len)) )
+               return (size_t)(-1);
+           break;
+       }
+               
+       /* Convert UCS2 to to_set */
+       if ((size_t)(-1) == ( o_len = convert_string_allocate_internal( CH_UCS2, to, (char*)u, i_len, dest)) ) 
+               LOG(log_error, logtype_default, "Conversion failed (CH_UCS2 to %s):%s", charset_name(to), strerror(errno));
+               
+       return o_len;
+
+}
+
+size_t charset_strupper(charset_t ch, const char *src, size_t srclen, char *dest, size_t destlen)
+{
+       size_t size;
+       char *buffer;
+       
+       size = convert_string_allocate_internal(ch, CH_UCS2, src, srclen,
+                                      (char**) &buffer);
+       if (size == (size_t)-1) {
+               SAFE_FREE(buffer);
+               return size;
+       }
+       if (!strupper_w((ucs2_t *)buffer) && (dest == src)) {
+               free(buffer);
+               return srclen;
+       }
+       
+       size = convert_string_internal(CH_UCS2, ch, buffer, size, dest, destlen);
+       free(buffer);
+       return size;
+}
+
+size_t charset_strlower(charset_t ch, const char *src, size_t srclen, char *dest, size_t destlen)
+{
+       size_t size;
+       char *buffer;
+       
+       size = convert_string_allocate_internal(ch, CH_UCS2, src, srclen,
+                                      (char **) &buffer);
+       if (size == (size_t)-1) {
+               SAFE_FREE(buffer);
+               return size;
+       }
+       if (!strlower_w((ucs2_t *)buffer) && (dest == src)) {
+               free(buffer);
+               return srclen;
+       }
+       
+       size = convert_string_internal(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)
+{
+       return charset_strupper( CH_UTF8, src, srclen, dest, destlen);
+}
+
+size_t utf8_strlower(const char *src, size_t srclen, char *dest, size_t destlen)
+{
+       return charset_strlower( CH_UTF8, src, srclen, dest, destlen);
+}
+
+/**
+ * Copy a string from a charset_t char* src to a UCS2 destination, allocating a buffer
+ *
+ * @param dest always set at least to NULL 
+ *
+ * @returns The number of bytes occupied by the string in the destination
+ *         or -1 in case of error.
+ **/
+
+size_t charset_to_ucs2_allocate(charset_t ch, ucs2_t **dest, const char *src)
+{
+       size_t src_len = strlen(src);
+
+       *dest = NULL;
+       return convert_string_allocate(ch, CH_UCS2, src, src_len, (char**) dest);       
+}
+
+/** -----------------------------------
+ * Copy a string from a charset_t char* src to a UTF-8 destination, allocating a buffer
+ *
+ * @param dest always set at least to NULL 
+ *
+ * @returns The number of bytes occupied by the string in the destination
+ **/
+
+size_t charset_to_utf8_allocate(charset_t ch, char **dest, const char *src)
+{
+       size_t src_len = strlen(src);
+
+       *dest = NULL;
+       return convert_string_allocate(ch, CH_UTF8, src, src_len, dest);        
+}
+
+/** -----------------------------------
+ * Copy a string from a UCS2 src to a unix char * destination, allocating a buffer
+ *
+ * @param dest always set at least to NULL 
+ *
+ * @returns The number of bytes occupied by the string in the destination
+ **/
+
+size_t ucs2_to_charset(charset_t ch, const ucs2_t *src, char *dest, size_t destlen)
+{
+       size_t src_len = (strlen_w(src)) * sizeof(ucs2_t);
+       return convert_string(CH_UCS2, ch, src, src_len, dest, destlen);        
+}
+
+/* --------------------------------- */
+size_t ucs2_to_charset_allocate(charset_t ch, char **dest, const ucs2_t *src)
+{
+       size_t src_len = (strlen_w(src)) * sizeof(ucs2_t);
+       *dest = NULL;
+       return convert_string_allocate(CH_UCS2, ch, src, src_len, dest);        
+}
+
+/** ---------------------------------
+ * Copy a string from a UTF-8 src to a unix char * destination, allocating a buffer
+ *
+ * @param dest always set at least to NULL 
+ *
+ * @returns The number of bytes occupied by the string in the destination
+ **/
+
+size_t utf8_to_charset_allocate(charset_t ch, char **dest, const char *src)
+{
+       size_t src_len = strlen(src);
+       *dest = NULL;
+       return convert_string_allocate(CH_UTF8, ch, src, src_len, dest);        
+}
+
+size_t charset_precompose ( charset_t ch, char * src, size_t inlen, char * dst, size_t outlen)
+{
+       char *buffer;
+       ucs2_t u[MAXPATHLEN];
+       size_t len;
+       size_t ilen;
+
+        if ((size_t)(-1) == (len = convert_string_allocate_internal(ch, CH_UCS2, src, inlen, &buffer)) )
+            return len;
+
+       ilen=sizeof(u);
+
+       if ( (size_t)-1 == (ilen = precompose_w((ucs2_t *)buffer, len, u, &ilen)) ) {
+           free (buffer);
+           return (size_t)(-1);
+       }
+
+        if ((size_t)(-1) == (len = convert_string_internal( CH_UCS2, ch, (char*)u, ilen, dst, outlen)) ) {
+           free (buffer);
+           return (size_t)(-1);
+       }
+       
+       free(buffer);
+       dst[len] = 0;
+       return (len);
+}
+
+size_t charset_decompose ( charset_t ch, char * src, size_t inlen, char * dst, size_t outlen)
+{
+       char *buffer;
+       ucs2_t u[MAXPATHLEN];
+       size_t len;
+       size_t ilen;
+
+        if ((size_t)(-1) == (len = convert_string_allocate_internal(ch, CH_UCS2, src, inlen, &buffer)) )
+            return len;
+
+       ilen=sizeof(u);
+
+       if ( (size_t)-1 == (ilen = decompose_w((ucs2_t *)buffer, len, u, &ilen)) ) {
+           free (buffer);
+           return (size_t)(-1);
+       }
+
+        if ((size_t)(-1) == (len = convert_string_internal( CH_UCS2, ch, (char*)u, ilen, dst, outlen)) ) {
+           free (buffer);
+           return (size_t)(-1);
+       }
+
+       free(buffer);
+       dst[len] = 0;
+       return (len);
+}
+
+size_t utf8_precompose ( char * src, size_t inlen, char * dst, size_t outlen)
+{
+       return charset_precompose ( CH_UTF8, src, inlen, dst, outlen);
+}
+
+size_t utf8_decompose ( char * src, size_t inlen, char * dst, size_t outlen)
+{
+       return charset_decompose ( CH_UTF8, src, inlen, dst, outlen);
+}
+
+#if 0
+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;
+}
+#endif
+
+/* 
+ * Convert from MB to UCS2 charset 
+ * Flags:
+ *             CONV_UNESCAPEHEX:        ':XX' will be converted to an UCS2 character
+ *             CONV_IGNORE:             return the first convertable characters.
+ *             CONV_FORCE:      force convertion
+ * 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.
+ */
+
+static size_t pull_charset_flags (charset_t from_set, charset_t cap_set, char* src, size_t srclen, char* dest, size_t destlen, u_int16_t *flags)
+{
+  const u_int16_t option = (flags ? *flags : 0);
+  size_t i_len, o_len;
+  size_t j = 0;
+  const char* inbuf = (const char*)src;
+  char* outbuf = dest;
+  atalk_iconv_t descriptor;
+  atalk_iconv_t descriptor_cap;
+
+  if (srclen == (size_t)-1)
+    srclen = strlen(src) + 1;
+
+  lazy_initialize_conv();
+
+  descriptor = conv_handles[from_set][CH_UCS2];
+  descriptor_cap = conv_handles[cap_set][CH_UCS2];
+
+  if (descriptor == (atalk_iconv_t)-1 || descriptor == (atalk_iconv_t)0) {
+    errno = EINVAL;
+    return (size_t)-1;
+  }
+
+  i_len=srclen;
+  o_len=destlen;
+
+  while (i_len > 0) {
+    if ((option & CONV_UNESCAPEHEX)) {
+      for (j = 0; j < i_len; ++j) {
+       if (inbuf[j] == ':') break;
+      }
+      j = i_len - j;
+      i_len -= j;
+    }
+
+    if (i_len > 0 &&
+       atalk_iconv(descriptor, &inbuf, &i_len, &outbuf, &o_len) == (size_t)-1) {
+      if (errno == EILSEQ || errno == EINVAL) {
+       errno = EILSEQ;
+        if ((option & CONV_IGNORE)) {
+           *flags |= CONV_REQMANGLE;
+           return destlen - o_len;
+       }
+       if ((option & CONV__EILSEQ)) {
+           if (o_len < 2) {
+               errno = E2BIG;
+               goto end;
+           }
+           *((ucs2_t *)outbuf) = (ucs2_t) IGNORE_CHAR; /**inbuf */
+           inbuf++;
+           i_len--;
+           outbuf += 2;
+           o_len -= 2;
+           /* FIXME reset stat ? */
+           continue;
+       }
+      }
+      goto end;
+    }
+
+    if (j) {
+      /* we're at the start on an hex encoded ucs2 char */
+      char h[MAXPATHLEN];
+      size_t hlen = 0;
+
+      i_len = j, j = 0;
+      while (i_len >= 3 && inbuf[0] == ':' &&
+            isxdigit(inbuf[1]) && isxdigit(inbuf[2])) {
+       h[hlen++] = (hextoint(inbuf[1]) << 4) | hextoint(inbuf[2]);
+       inbuf += 3;
+       i_len -= 3;
+      }
+      if (hlen) {
+       const char *h_buf = h;
+       if (atalk_iconv(descriptor_cap, &h_buf, &hlen, &outbuf, &o_len) == (size_t)-1) {
+         i_len += hlen * 3;
+         inbuf -= hlen * 3;
+         if (errno == EILSEQ && (option & CONV_IGNORE)) {
+           *flags |= CONV_REQMANGLE;
+           return destlen - o_len;
+         }
+         goto end;
+       }
+      } else {
+       /* We have an invalid :xx sequence */
+       errno = EILSEQ;
+       if ((option & CONV_IGNORE)) {
+         *flags |= CONV_REQMANGLE;
+         return destlen - o_len;
+       }
+       goto end;
+      }
+    }
+  }
+ end:
+  return (i_len + j == 0 || (option & CONV_FORCE)) ? destlen - o_len : (size_t)-1;
+}
+
+/* 
+ * Convert from UCS2 to MB charset 
+ * Flags:
+ *             CONV_ESCAPEDOTS: escape leading dots
+ *             CONV_ESCAPEHEX:  unconvertable characters and '/' will be escaped to :XX
+ *             CONV_IGNORE:     return the first convertable characters.
+ *             CONV__EILSEQ:    unconvertable characters will be replaced with '_'
+ *             CONV_FORCE:      force convertion
+ * 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.
+ */
+
+
+static size_t push_charset_flags (charset_t to_set, charset_t cap_set, char* src, size_t srclen, char* dest, size_t destlen, u_int16_t *flags)
+{
+  const u_int16_t option = (flags ? *flags : 0);
+  size_t i_len, o_len, i;
+  size_t j = 0;
+  const char* inbuf = (const char*)src;
+  char* outbuf = (char*)dest;
+  atalk_iconv_t descriptor;
+  atalk_iconv_t descriptor_cap;
+
+  lazy_initialize_conv();
+
+  descriptor = conv_handles[CH_UCS2][to_set];
+  descriptor_cap = conv_handles[CH_UCS2][cap_set];
+
+  if (descriptor == (atalk_iconv_t)-1 || descriptor == (atalk_iconv_t)0) {
+    errno = EINVAL;
+    return (size_t) -1;
+  }
+
+  i_len=srclen;
+  o_len=destlen;
+
+  if ((option & CONV_ESCAPEDOTS) &&
+      i_len >= 2 && SVAL(inbuf, 0) == 0x002e) { /* 0x002e = . */
+    if (o_len < 3) {
+      errno = E2BIG;
+      goto end;
+    }
+    *outbuf++ = ':';
+    *outbuf++ = '2';
+    *outbuf++ = 'e';
+    o_len -= 3;
+    inbuf += 2;
+    i_len -= 2;
+    *flags |= CONV_REQESCAPE;
+  }
+
+  while (i_len >= 2) {
+    if ((option & CONV_ESCAPEHEX)) {
+      for (i = 0; i < i_len; i += 2) {
+       ucs2_t c = SVAL(inbuf, i);
+       if (c == 0x002f) { /* 0x002f = / */
+         j = i_len - i;
+         i_len = i;
+         break;
+       } else if (c == 0x003a) { /* 0x003a = : */
+         errno = EILSEQ;
+         goto end;
+       }
+      }
+    }
+    while (i_len > 0 &&
+          atalk_iconv(descriptor, &inbuf, &i_len, &outbuf, &o_len) == (size_t)-1) {
+      if (errno == EILSEQ) {
+       if ((option & CONV_IGNORE)) {
+         *flags |= CONV_REQMANGLE;
+         return destlen - o_len;
+       }
+       if ((option & CONV_ESCAPEHEX)) {
+         const size_t bufsiz = o_len / 3 + 1;
+         char *buf = malloc(bufsiz);
+         size_t buflen;
+
+         if (!buf) 
+             goto end;
+         i = i_len;
+         for (buflen = 1; buflen <= bufsiz; ++buflen) {
+           char *b = buf;
+           size_t o = buflen;
+           if (atalk_iconv(descriptor_cap, &inbuf, &i, &b, &o) != (size_t)-1) {
+             buflen -= o;
+             break;
+           } else if (errno != E2BIG) {
+             SAFE_FREE(buf);
+             goto end;
+           }
+         }
+         if (o_len < buflen * 3) {
+           SAFE_FREE(buf);
+           errno = E2BIG;
+           goto end;
+         }
+         o_len -= buflen * 3;
+         i_len = i;
+         for (i = 0; i < buflen; ++i) {
+           *outbuf++ = ':';
+           *outbuf++ = hexdig[(buf[i] >> 4) & 0x0f];
+           *outbuf++ = hexdig[buf[i] & 0x0f];
+         }
+         SAFE_FREE(buf);
+         *flags |= CONV_REQESCAPE;
+         continue;
+       }
+      }
+      goto end;
+    }
+
+    if (j) {
+      i_len = j, j = 0;
+      if (o_len < 3) {
+       errno = E2BIG;
+       goto end;
+      }
+      *outbuf++ = ':';
+      *outbuf++ = '2';
+      *outbuf++ = 'f';
+      o_len -= 3;
+      inbuf += 2;
+      i_len -= 2;
+    }
+  }
+  if (i_len > 0) errno = EINVAL;
+ end:
+  return (i_len + j == 0 || (option & CONV_FORCE)) ? destlen - o_len : (size_t)-1;
+}
+
+size_t convert_charset ( charset_t from_set, charset_t to_set, charset_t cap_charset, char* src, size_t src_len, char* dest, size_t dest_len, u_int16_t *flags)
+{
+       size_t i_len, o_len;
+       ucs2_t *u;
+       ucs2_t buffer[MAXPATHLEN];
+       ucs2_t buffer2[MAXPATHLEN];
+       int composition = 0;
+       
+       lazy_initialize_conv();
+
+       /* convert from_set to UCS2 */
+       if ((size_t)(-1) == ( o_len = pull_charset_flags( from_set, cap_charset, src, src_len, 
+                                                          (char *) buffer, sizeof(buffer), flags)) ) {
+               LOG(log_error, logtype_default, "Conversion failed ( %s to CH_UCS2 )", charset_name(from_set));
+               return (size_t) -1;
+       }
+
+       if ( o_len == 0)
+               return o_len;
+
+       /* 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 = sizeof(buffer2);
+       u = buffer2;
+
+       switch (composition) {
+       case 0:
+           u = buffer;
+           i_len = o_len;
+           break;
+       case 1:
+            if ( (size_t)-1 == (i_len = precompose_w(buffer, o_len, u, &i_len)) )
+               return (size_t)(-1);
+           break;
+       case 2:
+            if ( (size_t)-1 == (i_len = decompose_w(buffer, o_len, u, &i_len)) )
+               return (size_t)(-1);
+           break;
+       }
+               
+       /* Do case conversions */       
+       if (CHECK_FLAGS(flags, CONV_TOUPPER)) {
+           strupper_w(u);
+       }
+       if (CHECK_FLAGS(flags, CONV_TOLOWER)) {
+           strlower_w(u);
+       }
+
+       /* Convert UCS2 to to_set */
+       if ((size_t)(-1) == ( o_len = push_charset_flags( to_set, cap_charset, (char *)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;
+}
diff --git a/libatalk/unicode/charsets/.cvsignore b/libatalk/unicode/charsets/.cvsignore
new file mode 100644 (file)
index 0000000..0d0371d
--- /dev/null
@@ -0,0 +1,6 @@
+Makefile
+Makefile.in
+*.lo
+*.la
+.deps
+.libs
diff --git a/libatalk/unicode/charsets/Makefile.am b/libatalk/unicode/charsets/Makefile.am
new file mode 100644 (file)
index 0000000..e0a1ce5
--- /dev/null
@@ -0,0 +1,32 @@
+# Makefile.am for libatalk/unicode/charsets
+
+noinst_LTLIBRARIES = libcharsets.la
+
+CFLAGS = -I$(top_srcdir)/sys @CFLAGS@ @ICONV_CFLAGS@
+LIBS = 
+
+libcharsets_la_SOURCES = \
+       mac_roman.c     \
+       mac_hebrew.c    \
+       mac_centraleurope.c     \
+       mac_turkish.c \
+       mac_cyrillic.c \
+       mac_japanese.c \
+       mac_chinese_trad.c \
+       mac_chinese_simp.c \
+       mac_korean.c \
+       generic_cjk.c \
+       generic_mb.c
+
+noinst_HEADERS = \
+       mac_roman.h \
+       mac_centraleurope.h \
+       mac_hebrew.h \
+       mac_turkish.h \
+       mac_cyrillic.h \
+       mac_japanese.h \
+       mac_chinese_trad.h \
+       mac_chinese_simp.h \
+       mac_korean.h \
+       generic_cjk.h \
+       generic_mb.h
diff --git a/libatalk/unicode/charsets/generic_cjk.c b/libatalk/unicode/charsets/generic_cjk.c
new file mode 100644 (file)
index 0000000..29358a8
--- /dev/null
@@ -0,0 +1,215 @@
+/*
+ * generic_cjk
+ * Copyright (C) TSUBAKIMOTO Hiroya <zorac@4000do.co.jp> 2004
+ *
+ * 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 /* HAVE_CONFIG_H */
+
+#if HAVE_USABLE_ICONV
+
+#include "generic_cjk.h"
+#include <string.h>
+
+static size_t cjk_iconv(void *cd, char **inbuf, char *end,
+                       char **outbuf, size_t *outbytesleft)
+{
+  size_t n = end - *inbuf;
+  if (iconv(cd, (ICONV_CONST char**)inbuf, &n, outbuf, outbytesleft) == (size_t)-1) {
+    iconv(cd, NULL, NULL, NULL, NULL);
+  }
+  return n;
+}
+
+size_t cjk_generic_push(size_t (*char_func)(u_int8_t*, const ucs2_t*, size_t*),
+                       void *cd, char **inbuf, size_t *inbytesleft,
+                       char **outbuf, size_t *outbytesleft)
+{
+  char *in = *inbuf;
+
+  while (*inbytesleft >= sizeof(ucs2_t) && *outbytesleft > 0) {
+    u_int8_t buf[CJK_PUSH_BUFFER];
+    size_t size = *inbytesleft / sizeof(ucs2_t);
+    size_t n = (char_func)(buf, (const ucs2_t*)in, &size);
+    if (n == 0) {
+      in += size * sizeof(ucs2_t);
+      *inbytesleft -= size * sizeof(ucs2_t);
+      continue;
+    }
+    if (in != *inbuf) {
+      int err = errno;
+
+      *inbytesleft += cjk_iconv(cd, inbuf, in, outbuf, outbytesleft);
+      if (in != *inbuf) return -1;
+      errno = err;
+    }
+    if (n == (size_t)-1) return -1;
+    if (*outbytesleft < n) break;
+    memcpy(*outbuf, buf, n);
+    *outbuf += n;
+    *outbytesleft -= n;
+    in += size * sizeof(ucs2_t);
+    *inbytesleft -= size * sizeof(ucs2_t);
+    *inbuf = in;
+  }
+  if (in != *inbuf) {
+    *inbytesleft += cjk_iconv(cd, inbuf, in, outbuf, outbytesleft);
+    if (in != *inbuf) return -1;
+  }
+  if (*inbytesleft > 0) {
+    errno = (*inbytesleft < sizeof(ucs2_t) ? EINVAL : E2BIG);
+    return -1;
+  }
+  return 0;
+}
+
+size_t cjk_generic_pull(size_t (*char_func)(ucs2_t*, const u_int8_t*, size_t*),
+                       void *cd, char **inbuf, size_t *inbytesleft,
+                       char **outbuf, size_t *outbytesleft)
+{
+  char *in = *inbuf;
+
+  while (*inbytesleft > 0 && *outbytesleft >= sizeof(ucs2_t)) {
+    ucs2_t buf[CJK_PULL_BUFFER];
+    size_t size = *inbytesleft;
+    size_t n = (char_func)(buf, (const u_int8_t*)in, &size);
+    if (n == 0) {
+      in += size;
+      *inbytesleft -= size;
+      continue;
+    }
+    if (in != *inbuf) {
+      int err = errno;
+
+      *inbytesleft += cjk_iconv(cd, inbuf, in, outbuf, outbytesleft);
+      if (in != *inbuf) return -1;
+      errno = err;
+    }
+    if (n == (size_t)-1) return -1;
+    if (*outbytesleft < n * sizeof(ucs2_t)) break;
+    memcpy(*outbuf, buf, n * sizeof(ucs2_t));
+    *outbuf += n * sizeof(ucs2_t);
+    *outbytesleft -= n * sizeof(ucs2_t);
+    in += size;
+    *inbytesleft -= size;
+    *inbuf = in;
+  }
+  if (in != *inbuf) {
+    *inbytesleft += cjk_iconv(cd, inbuf, in, outbuf, outbytesleft);
+    if (in != *inbuf) return -1;
+  }
+  if (*inbytesleft > 0) {
+    errno = E2BIG;
+    return -1;
+  }
+  return 0;
+}
+
+size_t cjk_char_push(u_int16_t c, u_int8_t *out)
+{
+  if (!c) return 0;
+  if (c == (u_int16_t)-1) {
+    errno = EILSEQ;
+    return (size_t)-1;
+  }
+  if (c <= 0xff) {
+    out[0] = (u_int8_t)c;
+    return 1;
+  }
+  out[0] = (u_int8_t)(c >> 8);
+  out[1] = (u_int8_t)c;
+  return 2;
+}
+
+size_t cjk_char_pull(ucs2_t wc, ucs2_t* out, const u_int32_t* compose)
+{
+  if (!wc) return 0;
+  if ((wc & 0xf000) == 0xe000) {
+    ucs2_t buf[CJK_PULL_BUFFER];
+    size_t i = sizeof(buf) / sizeof(*buf) - 1;
+    do {
+      u_int32_t v = compose[wc & 0xfff];
+      buf[i] = (ucs2_t)v;
+      wc = (ucs2_t)(v >> 16);
+    } while (--i && (wc & 0xf000) == 0xe000);
+    buf[i] = wc;
+    memcpy(out, buf + i, sizeof(buf) - sizeof(*buf) * i);
+    return sizeof(buf) / sizeof(*buf) - i;
+  }
+  *out = wc;
+  return 1;
+}
+
+u_int16_t cjk_lookup(u_int16_t c, const cjk_index_t *index, const u_int16_t *charset)
+{
+  while (index->summary && c >= index->range[0]) {
+    if (c <= index->range[1]) {
+      const u_int16_t* summary = index->summary[(c - index->range[0]) >> 4];
+      u_int16_t used = 1 << (c & 15);
+
+      if (summary[0] & used) {
+       used = summary[0] & (used - 1);
+       charset += summary[1];
+       while (used) used &= used - 1, ++charset;
+       return *charset;
+      }
+      return 0;
+    }
+    ++index;
+  }
+  return 0;
+}
+
+ucs2_t cjk_compose(ucs2_t base, ucs2_t comb, const u_int32_t* table, size_t size)
+{
+  u_int32_t v = ((u_int32_t)base << 16) | comb;
+  size_t low = 0;
+  while (size > low) {
+    size_t n = (low + size) / 2;
+    if (table[n] == v) return 0xe000 + n;
+    if (table[n] < v) {
+      low = n + 1;
+    } else {
+      size = n;
+    }
+  }
+  return 0;
+}
+
+ucs2_t cjk_compose_seq(const ucs2_t* in, size_t* len, const u_int32_t* table, size_t size)
+{
+  static u_int8_t sz[] = { 3, 4, 5, 5, 5, 5, 5, 3 };
+  ucs2_t wc = in[0];
+  size_t n = sz[wc & 7];
+  size_t i = 0;
+
+  if (n > *len) {
+    errno = EINVAL;
+    return 0;
+  }
+  while (++i < n) {
+    wc = cjk_compose(wc, in[i], table, size);
+    if (!wc) {
+      errno = EILSEQ;
+      return 0;
+    }
+  }
+  *len = n;
+  return wc;
+}
+#endif
diff --git a/libatalk/unicode/charsets/generic_cjk.h b/libatalk/unicode/charsets/generic_cjk.h
new file mode 100644 (file)
index 0000000..1f9e208
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * generic_cjk
+ * Copyright (C) TSUBAKIMOTO Hiroya <zorac@4000do.co.jp> 2004
+ *
+ * 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.
+ */
+
+#include <atalk/unicode.h>
+#include <iconv.h>
+#include "../byteorder.h"
+
+#define CJK_PUSH_BUFFER 4
+#define CJK_PULL_BUFFER 8
+
+typedef struct {
+  u_int16_t range[2];
+  const u_int16_t (*summary)[2];
+} cjk_index_t;
+
+extern size_t cjk_generic_push __P((size_t (*)(u_int8_t*, const ucs2_t*, size_t*),
+                                  void*, char**, size_t*, char**, size_t*));
+extern size_t cjk_generic_pull __P((size_t (*)(ucs2_t*, const u_int8_t*, size_t*),
+                                  void*, char**, size_t*, char**, size_t*));
+
+extern size_t cjk_char_push __P((u_int16_t, u_int8_t*));
+extern size_t cjk_char_pull __P((ucs2_t, ucs2_t*, const u_int32_t*));
+
+extern u_int16_t cjk_lookup __P((u_int16_t, const cjk_index_t*, const u_int16_t*));
+extern ucs2_t cjk_compose __P((ucs2_t, ucs2_t, const u_int32_t*, size_t));
+extern ucs2_t cjk_compose_seq __P((const ucs2_t*, size_t*, const u_int32_t*, size_t));
diff --git a/libatalk/unicode/charsets/generic_mb.c b/libatalk/unicode/charsets/generic_mb.c
new file mode 100644 (file)
index 0000000..0fc36b7
--- /dev/null
@@ -0,0 +1,112 @@
+/* 
+   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 <errno.h>
+
+#include <netatalk/endian.h>
+#include <atalk/unicode.h>
+#include <atalk/logger.h>
+
+#include "generic_mb.h"
+#include "../byteorder.h"
+
+
+/* ------------------------ */
+
+size_t mb_generic_push( int (*char_func)(unsigned char *, ucs2_t), void *cd _U_, char **inbuf, 
+                       size_t *inbytesleft, char **outbuf, size_t *outbytesleft)
+{
+        int len = 0;
+       unsigned char *tmpptr = (unsigned char *) *outbuf;
+       ucs2_t inval;
+
+        while (*inbytesleft >= 2 && *outbytesleft >= 1) {
+
+               inval = SVAL((*inbuf),0);
+               if ( (char_func)( tmpptr, inval)) {
+                       (*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 _U_, 
+                       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;
+               if (char_func ( &temp, inptr)) {
+                       SSVAL((*outbuf), 0, temp);
+                       (*inbuf)        +=1;
+                       (*outbuf)       +=2;
+                       (*inbytesleft) -=1;
+                       (*outbytesleft)-=2;
+                       len++;
+                       
+               }
+               else    
+               {
+                       errno = EILSEQ;
+                       return (size_t) -1;     
+               }
+        }
+
+        if (*inbytesleft > 0) {
+                errno = E2BIG;
+                return (size_t) -1;
+        }
+
+        return len;
+
+}
diff --git a/libatalk/unicode/charsets/generic_mb.h b/libatalk/unicode/charsets/generic_mb.h
new file mode 100644 (file)
index 0000000..64a40a7
--- /dev/null
@@ -0,0 +1,2 @@
+size_t   mb_generic_pull(int (*charfunc)(ucs2_t *, const unsigned char *), void *,char **, size_t *, char **, size_t *);
+size_t   mb_generic_push(int (*charfunc)(unsigned char *, ucs2_t), void *,char **, size_t *, char **, size_t *);
diff --git a/libatalk/unicode/charsets/mac_centraleurope.c b/libatalk/unicode/charsets/mac_centraleurope.c
new file mode 100644 (file)
index 0000000..3effc68
--- /dev/null
@@ -0,0 +1,66 @@
+/* 
+   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,
+       NULL,
+       NULL, NULL
+};
+
+
+/* ------------------------ */
+
+static size_t mac_centraleurope_push( void *cd, char **inbuf, size_t *inbytesleft,
+                         char **outbuf, size_t *outbytesleft)
+{
+       return (size_t) mb_generic_push( char_ucs2_to_mac_centraleurope, cd, inbuf, inbytesleft, outbuf, outbytesleft);
+}
+
+/* ------------------------ */
+
+static size_t mac_centraleurope_pull ( void *cd, char **inbuf, size_t *inbytesleft,
+                         char **outbuf, size_t *outbytesleft)
+{
+       return (size_t) mb_generic_pull( char_mac_centraleurope_to_ucs2, cd, inbuf, inbytesleft, outbuf, outbytesleft);
+}
diff --git a/libatalk/unicode/charsets/mac_centraleurope.h b/libatalk/unicode/charsets/mac_centraleurope.h
new file mode 100644 (file)
index 0000000..dad99b0
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 1999-2001 Free Software Foundation, Inc.
+ * This file is part of the GNU LIBICONV Library.
+ *
+ * The GNU LIBICONV Library is free software; you can redistribute it
+ * and/or modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * The GNU LIBICONV Library is distributed in the hope that it will be
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with the GNU LIBICONV Library; see the file COPYING.LIB.
+ * If not, write to the Free Software Foundation, Inc., 59 Temple Place -
+ * Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * MacCentralEurope
+ */
+
+static const unsigned short mac_centraleurope_2uni[128] = {
+  /* 0x80 */
+  0x00c4, 0x0100, 0x0101, 0x00c9, 0x0104, 0x00d6, 0x00dc, 0x00e1,
+  0x0105, 0x010c, 0x00e4, 0x010d, 0x0106, 0x0107, 0x00e9, 0x0179,
+  /* 0x90 */
+  0x017a, 0x010e, 0x00ed, 0x010f, 0x0112, 0x0113, 0x0116, 0x00f3,
+  0x0117, 0x00f4, 0x00f6, 0x00f5, 0x00fa, 0x011a, 0x011b, 0x00fc,
+  /* 0xa0 */
+  0x2020, 0x00b0, 0x0118, 0x00a3, 0x00a7, 0x2022, 0x00b6, 0x00df,
+  0x00ae, 0x00a9, 0x2122, 0x0119, 0x00a8, 0x2260, 0x0123, 0x012e,
+  /* 0xb0 */
+  0x012f, 0x012a, 0x2264, 0x2265, 0x012b, 0x0136, 0x2202, 0x2211,
+  0x0142, 0x013b, 0x013c, 0x013d, 0x013e, 0x0139, 0x013a, 0x0145,
+  /* 0xc0 */
+  0x0146, 0x0143, 0x00ac, 0x221a, 0x0144, 0x0147, 0x2206, 0x00ab,
+  0x00bb, 0x2026, 0x00a0, 0x0148, 0x0150, 0x00d5, 0x0151, 0x014c,
+  /* 0xd0 */
+  0x2013, 0x2014, 0x201c, 0x201d, 0x2018, 0x2019, 0x00f7, 0x25ca,
+  0x014d, 0x0154, 0x0155, 0x0158, 0x2039, 0x203a, 0x0159, 0x0156,
+  /* 0xe0 */
+  0x0157, 0x0160, 0x201a, 0x201e, 0x0161, 0x015a, 0x015b, 0x00c1,
+  0x0164, 0x0165, 0x00cd, 0x017d, 0x017e, 0x016a, 0x00d3, 0x00d4,
+  /* 0xf0 */
+  0x016b, 0x016e, 0x00da, 0x016f, 0x0170, 0x0171, 0x0172, 0x0173,
+  0x00dd, 0x00fd, 0x0137, 0x017b, 0x0141, 0x017c, 0x0122, 0x02c7,
+};
+
+static int
+char_mac_centraleurope_to_ucs2 (ucs2_t *pwc, const unsigned char *s)
+{
+  unsigned char c = *s;
+  if (c < 0x80)
+    *pwc = (ucs2_t) c;
+  else
+    *pwc = (ucs2_t) mac_centraleurope_2uni[c-0x80];
+  return 1;
+}
+
+static const unsigned char mac_centraleurope_page00[224] = {
+  0xca, 0x00, 0x00, 0xa3, 0x00, 0x00, 0x00, 0xa4, /* 0xa0-0xa7 */
+  0xac, 0xa9, 0x00, 0xc7, 0xc2, 0x00, 0xa8, 0x00, /* 0xa8-0xaf */
+  0xa1, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa6, 0x00, /* 0xb0-0xb7 */
+  0x00, 0x00, 0x00, 0xc8, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+  0x00, 0xe7, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+  0x00, 0x83, 0x00, 0x00, 0x00, 0xea, 0x00, 0x00, /* 0xc8-0xcf */
+  0x00, 0x00, 0x00, 0xee, 0xef, 0xcd, 0x85, 0x00, /* 0xd0-0xd7 */
+  0x00, 0x00, 0xf2, 0x00, 0x86, 0xf8, 0x00, 0xa7, /* 0xd8-0xdf */
+  0x00, 0x87, 0x00, 0x00, 0x8a, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+  0x00, 0x8e, 0x00, 0x00, 0x00, 0x92, 0x00, 0x00, /* 0xe8-0xef */
+  0x00, 0x00, 0x00, 0x97, 0x99, 0x9b, 0x9a, 0xd6, /* 0xf0-0xf7 */
+  0x00, 0x00, 0x9c, 0x00, 0x9f, 0xf9, 0x00, 0x00, /* 0xf8-0xff */
+  /* 0x0100 */
+  0x81, 0x82, 0x00, 0x00, 0x84, 0x88, 0x8c, 0x8d, /* 0x00-0x07 */
+  0x00, 0x00, 0x00, 0x00, 0x89, 0x8b, 0x91, 0x93, /* 0x08-0x0f */
+  0x00, 0x00, 0x94, 0x95, 0x00, 0x00, 0x96, 0x98, /* 0x10-0x17 */
+  0xa2, 0xab, 0x9d, 0x9e, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+  0x00, 0x00, 0xfe, 0xae, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+  0x00, 0x00, 0xb1, 0xb4, 0x00, 0x00, 0xaf, 0xb0, /* 0x28-0x2f */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb5, 0xfa, /* 0x30-0x37 */
+  0x00, 0xbd, 0xbe, 0xb9, 0xba, 0xbb, 0xbc, 0x00, /* 0x38-0x3f */
+  0x00, 0xfc, 0xb8, 0xc1, 0xc4, 0xbf, 0xc0, 0xc5, /* 0x40-0x47 */
+  0xcb, 0x00, 0x00, 0x00, 0xcf, 0xd8, 0x00, 0x00, /* 0x48-0x4f */
+  0xcc, 0xce, 0x00, 0x00, 0xd9, 0xda, 0xdf, 0xe0, /* 0x50-0x57 */
+  0xdb, 0xde, 0xe5, 0xe6, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+  0xe1, 0xe4, 0x00, 0x00, 0xe8, 0xe9, 0x00, 0x00, /* 0x60-0x67 */
+  0x00, 0x00, 0xed, 0xf0, 0x00, 0x00, 0xf1, 0xf3, /* 0x68-0x6f */
+  0xf4, 0xf5, 0xf6, 0xf7, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+  0x00, 0x8f, 0x90, 0xfb, 0xfd, 0xeb, 0xec, 0x00, /* 0x78-0x7f */
+};
+static const unsigned char mac_centraleurope_page20[48] = {
+  0x00, 0x00, 0x00, 0xd0, 0xd1, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+  0xd4, 0xd5, 0xe2, 0x00, 0xd2, 0xd3, 0xe3, 0x00, /* 0x18-0x1f */
+  0xa0, 0x00, 0xa5, 0x00, 0x00, 0x00, 0xc9, 0x00, /* 0x20-0x27 */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+  0x00, 0xdc, 0xdd, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+};
+static const unsigned char mac_centraleurope_page22[32] = {
+  0x00, 0x00, 0xb6, 0x00, 0x00, 0x00, 0xc6, 0x00, /* 0x00-0x07 */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+  0x00, 0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+  0x00, 0x00, 0xc3, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+};
+static const unsigned char mac_centraleurope_page22_1[8] = {
+  0xad, 0x00, 0x00, 0x00, 0xb2, 0xb3, 0x00, 0x00, /* 0x60-0x67 */
+};
+
+static int
+char_ucs2_to_mac_centraleurope(unsigned char *r, ucs2_t wc)
+{
+  unsigned char c = 0;
+  if (wc < 0x0080) {
+    *r = wc;
+    return 1;
+  }
+  else if (wc >= 0x00a0 && wc < 0x0180)
+    c = mac_centraleurope_page00[wc-0x00a0];
+  else if (wc == 0x02c7)
+    c = 0xff;
+  else if (wc >= 0x2010 && wc < 0x2040)
+    c = mac_centraleurope_page20[wc-0x2010];
+  else if (wc == 0x2122)
+    c = 0xaa;
+  else if (wc >= 0x2200 && wc < 0x2220)
+    c = mac_centraleurope_page22[wc-0x2200];
+  else if (wc >= 0x2260 && wc < 0x2268)
+    c = mac_centraleurope_page22_1[wc-0x2260];
+  else if (wc == 0x25ca)
+    c = 0xd7;
+  if (c != 0) {
+    *r = c;
+    return 1;
+  }
+  return 0;
+}
diff --git a/libatalk/unicode/charsets/mac_chinese_simp.c b/libatalk/unicode/charsets/mac_chinese_simp.c
new file mode 100644 (file)
index 0000000..30f153f
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * MacChineseSimp
+ * Copyright (C) TSUBAKIMOTO Hiroya <zorac@4000do.co.jp> 2004
+ *
+ * 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.
+ *
+ * Reference
+ * http://www.unicode.org/Public/MAPPINGS/VENDORS/APPLE/
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#if HAVE_USABLE_ICONV
+
+#include "generic_cjk.h"
+#include "mac_chinese_simp.h"
+
+static size_t mac_chinese_simp_pull(void *,char **, size_t *, char **, size_t *);
+static size_t mac_chinese_simp_push(void *,char **, size_t *, char **, size_t *);
+
+struct charset_functions charset_mac_chinese_simp = {
+  "MAC_CHINESE_SIMP",
+  25,
+  mac_chinese_simp_pull,
+  mac_chinese_simp_push,
+  CHARSET_ICONV | CHARSET_MULTIBYTE | CHARSET_PRECOMPOSED | CHARSET_CLIENT,
+  "EUC-CN",
+  NULL, NULL
+};
+
+static size_t mac_chinese_simp_char_push(u_int8_t* out, const ucs2_t* in, size_t* size)
+{
+  ucs2_t wc = in[0];
+
+  if (wc <= 0x7f) {
+    *size = 1;
+    out[0] = (u_int8_t)wc;
+    return 1;
+  } else if ((wc & 0xf000) == 0xe000) {
+    *size = 1;
+    return 0;
+  } else if (*size >= 2 && (in[1] & ~15) == 0xf870) {
+    ucs2_t comp = cjk_compose(wc, in[1], mac_chinese_simp_compose,
+                             sizeof(mac_chinese_simp_compose) / sizeof(u_int32_t));
+    if (comp) {
+      wc = comp;
+      *size = 2;
+    } else {
+      *size = 1;
+    }
+  } else {
+    *size = 1;
+  }
+  return cjk_char_push(cjk_lookup(wc, mac_chinese_simp_uni2_index,
+                                 mac_chinese_simp_uni2_charset), out);
+}
+
+static size_t mac_chinese_simp_push(void *cd, char **inbuf, size_t *inbytesleft,
+                                   char **outbuf, size_t *outbytesleft)
+{
+  return cjk_generic_push(mac_chinese_simp_char_push,
+                         cd, inbuf, inbytesleft, outbuf, outbytesleft);
+}
+
+static size_t mac_chinese_simp_char_pull(ucs2_t* out, const u_int8_t* in, size_t* size)
+{
+  u_int16_t c = in[0];
+
+  if (c <= 0x7f) {
+    *size = 1;
+    *out = c;
+    return 1;
+  } else if (c >= 0xa1 && c <= 0xfc) {
+    if (*size >= 2) {
+      u_int8_t c2 = in[1];
+
+      if (c2 >= 0xa1 && c2 <= 0xfe) {
+       *size = 2;
+       c = (c << 8) + c2;
+      } else {
+       errno = EILSEQ;
+       return (size_t)-1;
+      }
+    } else {
+      errno = EINVAL;
+      return (size_t)-1;
+    }
+  } else {
+    *size = 1;
+  }
+  return cjk_char_pull(cjk_lookup(c, mac_chinese_simp_2uni_index,
+                                 mac_chinese_simp_2uni_charset),
+                      out, mac_chinese_simp_compose);
+}
+
+static size_t mac_chinese_simp_pull(void *cd, char **inbuf, size_t *inbytesleft,
+                                   char **outbuf, size_t *outbytesleft)
+{
+  return cjk_generic_pull(mac_chinese_simp_char_pull,
+                         cd, inbuf, inbytesleft, outbuf, outbytesleft);
+}
+#endif
diff --git a/libatalk/unicode/charsets/mac_chinese_simp.h b/libatalk/unicode/charsets/mac_chinese_simp.h
new file mode 100644 (file)
index 0000000..105f150
--- /dev/null
@@ -0,0 +1,146 @@
+/*
+ * MacChineseSimp
+ * Copyright (C) TSUBAKIMOTO Hiroya <zorac@4000do.co.jp> 2004
+ *
+ * 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.
+ *
+ * Reference
+ * http://www.unicode.org/Public/MAPPINGS/VENDORS/APPLE/
+ */
+
+static const u_int16_t mac_chinese_simp_uni2_page00[][2] = {
+  /* 0x00a */ { 0x022d,    0 }, { 0x0080,    5 },
+  /* 0x00c */ { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 },
+  /* 0x010 */ { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 },
+  /* 0x014 */ { 0x0110,    6 }, { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 },
+  /* 0x018 */ { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 },
+  /* 0x01c */ { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 }, { 0x0200,    8 },
+  /* 0x020 */ { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 },
+  /* 0x024 */ { 0x0000,    0 }, { 0x0002,    9 }, { 0x0002,   10 },
+};
+
+static const u_int16_t mac_chinese_simp_uni2_page1e[][2] = {
+  /* 0x1e3 */ { 0x8000,   11 },
+};
+
+static const u_int16_t mac_chinese_simp_uni2_page20[][2] = {
+  /* 0x201 */ { 0x0070,   12 }, { 0x0040,   15 }, { 0x4000,   16 },
+};
+
+static const u_int16_t mac_chinese_simp_uni2_page21[][2] = {
+  /* 0x212 */ { 0x0004,   17 },
+};
+
+static const u_int16_t mac_chinese_simp_uni2_page22[][2] = {
+  /* 0x22e */ { 0x8000,   18 },
+};
+
+static const u_int16_t mac_chinese_simp_uni2_page30[][2] = {
+  /* 0x301 */ { 0x1000,   19 }, { 0x0000,    0 }, { 0x0000,    0 },
+  /* 0x304 */ { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 },
+  /* 0x308 */ { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 },
+  /* 0x30c */ { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 }, { 0x0800,   20 },
+};
+
+static const u_int16_t mac_chinese_simp_uni2_pagee0[][2] = {
+  /* 0xe00 */ { 0x07ff,   21 },
+};
+
+static const u_int16_t mac_chinese_simp_uni2_pagef8[][2] = {
+  /* 0xf88 */ { 0x0003,   32 },
+};
+
+static const u_int16_t mac_chinese_simp_uni2_pagefe[][2] = {
+  /* 0xfe3 */ { 0xfffa,   34 }, { 0x001f,   48 },
+};
+
+static const u_int16_t mac_chinese_simp_uni2_pageff[][2] = {
+  /* 0xff5 */ { 0x4000,   53 }, { 0x0000,    0 }, { 0x0000,    0 },
+  /* 0xff8 */ { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 },
+  /* 0xffc */ { 0x0000,    0 }, { 0x0000,    0 }, { 0x002b,   54 },
+};
+
+static const cjk_index_t mac_chinese_simp_uni2_index[] = {
+  { { 0x00a0, 0x026f }, mac_chinese_simp_uni2_page00 },
+  { { 0x1e30, 0x1e3f }, mac_chinese_simp_uni2_page1e },
+  { { 0x2010, 0x203f }, mac_chinese_simp_uni2_page20 },
+  { { 0x2120, 0x212f }, mac_chinese_simp_uni2_page21 },
+  { { 0x22e0, 0x22ef }, mac_chinese_simp_uni2_page22 },
+  { { 0x3010, 0x30ff }, mac_chinese_simp_uni2_page30 },
+  { { 0xe000, 0xe00f }, mac_chinese_simp_uni2_pagee0 },
+  { { 0xf880, 0xf88f }, mac_chinese_simp_uni2_pagef8 },
+  { { 0xfe30, 0xfe4f }, mac_chinese_simp_uni2_pagefe },
+  { { 0xff50, 0xffef }, mac_chinese_simp_uni2_pageff },
+  { { 0, 0 }, 0 }
+};
+
+static const u_int16_t mac_chinese_simp_uni2_charset[] = {
+  0x00a0, 0xa1e9, 0xa1ea, 0xa3a4, 0x00fd, 0xa1a4, 0xa8bd, 0xa8be,
+  0xa8bf, 0xa8bb, 0xa8c0, 0xa8bc, 0xa1aa, 0xffff, 0xa1ac, 0x00ff,
+  0xa3fe, 0x00fe, 0xa1ad, 0xa1ab, 0xffff, 0x0080, 0xa6f3, 0xa6db,
+  0xa6da, 0xa6ec, 0xa6ed, 0xa6de, 0xa6d9, 0xa6dc, 0xa6dd, 0xa6df,
+  0x0081, 0x0082, 0xa6f2, 0xa6f4, 0xa6f5, 0xa6e0, 0xa6e1, 0xa6f0,
+  0xa6f1, 0xa6e2, 0xa6e3, 0xa6ee, 0xa6ef, 0xa6e6, 0xa6e7, 0xa6e4,
+  0xa6e5, 0xa6e8, 0xa6e9, 0xa6ea, 0xa6eb, 0xffff, 0xffff, 0xffff,
+  0xffff, 0xffff,
+};
+
+static const u_int16_t mac_chinese_simp_2uni_page00[][2] = {
+  /* 0x008 */ { 0x0007,    0 }, { 0x0000,    0 }, { 0x0001,    3 }, { 0x0000,    0 },
+  /* 0x00c */ { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 }, { 0xe000,    4 },
+};
+
+static const u_int16_t mac_chinese_simp_2uni_pagea1[][2] = {
+  /* 0xa1a */ { 0x3c10,    7 }, { 0x0000,    0 },
+  /* 0xa1c */ { 0x0000,    0 }, { 0x0000,    0 }, { 0x0600,   12 },
+};
+
+static const u_int16_t mac_chinese_simp_2uni_pagea3[][2] = {
+  /* 0xa3a */ { 0x0010,   14 }, { 0x0000,    0 },
+  /* 0xa3c */ { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 }, { 0x4000,   15 },
+};
+
+static const u_int16_t mac_chinese_simp_2uni_pagea6[][2] = {
+  /* 0xa6d */ { 0xfe00,   16 }, { 0xffff,   23 }, { 0x003f,   39 },
+};
+
+static const u_int16_t mac_chinese_simp_2uni_pagea8[][2] = {
+  /* 0xa8b */ { 0xf800,   45 }, { 0x0001,   50 },
+};
+
+static const cjk_index_t mac_chinese_simp_2uni_index[] = {
+  { { 0x0080, 0x00ff }, mac_chinese_simp_2uni_page00 },
+  { { 0xa1a0, 0xa1ef }, mac_chinese_simp_2uni_pagea1 },
+  { { 0xa3a0, 0xa3ff }, mac_chinese_simp_2uni_pagea3 },
+  { { 0xa6d0, 0xa6ff }, mac_chinese_simp_2uni_pagea6 },
+  { { 0xa8b0, 0xa8cf }, mac_chinese_simp_2uni_pagea8 },
+  { { 0, 0 }, 0 }
+};
+
+static const u_int16_t mac_chinese_simp_2uni_charset[] = {
+  0xe000, 0xf880, 0xf881, 0x00a0, 0x00a9, 0x2122, 0x2026, 0x00b7,
+  0x2014, 0x301c, 0x2016, 0x22ef, 0x00a2, 0x00a3, 0x00a5, 0x203e,
+  0xe007, 0xe003, 0xe002, 0xe008, 0xe009, 0xe006, 0xe00a, 0xfe35,
+  0xfe36, 0xfe39, 0xfe3a, 0xfe3f, 0xfe40, 0xfe3d, 0xfe3e, 0xfe41,
+  0xfe42, 0xfe43, 0xfe44, 0xe004, 0xe005, 0xfe3b, 0xfe3c, 0xfe37,
+  0xfe38, 0xfe31, 0xe001, 0xfe33, 0xfe34, 0x0251, 0x1e3f, 0x0144,
+  0x0148, 0x01f9, 0x0261,
+};
+
+static const u_int32_t mac_chinese_simp_compose[] = {
+  0x00fcf87f, 0x22eff87e, 0x3001f87e, 0x3002f87e,
+  0x3016f87e, 0x3017f87e, 0xff01f87e, 0xff0cf87e,
+  0xff1af87e, 0xff1bf87e, 0xff1ff87e,
+};
diff --git a/libatalk/unicode/charsets/mac_chinese_trad.c b/libatalk/unicode/charsets/mac_chinese_trad.c
new file mode 100644 (file)
index 0000000..f134ce8
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ * MacChineseTrad
+ * Copyright (C) TSUBAKIMOTO Hiroya <zorac@4000do.co.jp> 2004
+ *
+ * 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.
+ *
+ * Reference
+ * http://www.unicode.org/Public/MAPPINGS/VENDORS/APPLE/
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#if HAVE_USABLE_ICONV
+
+#include "generic_cjk.h"
+#include "mac_chinese_trad.h"
+
+static size_t mac_chinese_trad_pull(void *,char **, size_t *, char **, size_t *);
+static size_t mac_chinese_trad_push(void *,char **, size_t *, char **, size_t *);
+
+struct charset_functions charset_mac_chinese_trad = {
+  "MAC_CHINESE_TRAD",
+  2,
+  mac_chinese_trad_pull,
+  mac_chinese_trad_push,
+  CHARSET_ICONV | CHARSET_MULTIBYTE | CHARSET_PRECOMPOSED | CHARSET_CLIENT,
+  "BIG-5",
+  NULL, NULL
+};
+
+static size_t mac_chinese_trad_char_push(u_int8_t* out, const ucs2_t* in, size_t* size)
+{
+  ucs2_t wc = in[0];
+
+  if (wc <= 0x7f) {
+    if (wc == 0x5c && *size >= 2 && in[1] == 0xf87f) {
+      *size = 2;
+      out[0] = 0x80;
+    } else {
+      *size = 1;
+      out[0] = (u_int8_t)wc;
+    }
+    return 1;
+  } else if ((wc & 0xf000) == 0xe000) {
+    *size = 1;
+    return 0;
+  } else if (*size >= 2 && (in[1] & ~15) == 0xf870) {
+    ucs2_t comp = cjk_compose(wc, in[1], mac_chinese_trad_compose,
+                             sizeof(mac_chinese_trad_compose) / sizeof(u_int32_t));
+    if (comp) {
+      wc = comp;
+      *size = 2;
+    } else {
+      *size = 1;
+    }
+  } else {
+    *size = 1;
+  }
+  return cjk_char_push(cjk_lookup(wc, mac_chinese_trad_uni2_index,
+                                 mac_chinese_trad_uni2_charset), out);
+}
+
+static size_t mac_chinese_trad_push(void *cd, char **inbuf, size_t *inbytesleft,
+                                   char **outbuf, size_t *outbytesleft)
+{
+  return cjk_generic_push(mac_chinese_trad_char_push,
+                         cd, inbuf, inbytesleft, outbuf, outbytesleft);
+}
+
+static size_t mac_chinese_trad_char_pull(ucs2_t* out, const u_int8_t* in, size_t* size)
+{
+  u_int16_t c = in[0];
+
+  if (c <= 0x7f) {
+    *size = 1;
+    *out = c;
+    return 1;
+  } else if (c >= 0xa1 && c <= 0xfc) {
+    if (*size >= 2) {
+      u_int8_t c2 = in[1];
+
+      if ((c2 >= 0x40 && c2 <= 0x7e) || (c2 >= 0xa1 && c2 <= 0xfe)) {
+       *size = 2;
+       c = (c << 8) + c2;
+      } else {
+       errno = EILSEQ;
+       return (size_t)-1;
+      }
+    } else {
+      errno = EINVAL;
+      return (size_t)-1;
+    }
+  } else {
+    *size = 1;
+  }
+  return cjk_char_pull(cjk_lookup(c, mac_chinese_trad_2uni_index,
+                                 mac_chinese_trad_2uni_charset),
+                      out, mac_chinese_trad_compose);
+}
+
+static size_t mac_chinese_trad_pull(void *cd, char **inbuf, size_t *inbytesleft,
+                                   char **outbuf, size_t *outbytesleft)
+{
+  return cjk_generic_pull(mac_chinese_trad_char_pull,
+                         cd, inbuf, inbytesleft, outbuf, outbytesleft);
+}
+#endif
diff --git a/libatalk/unicode/charsets/mac_chinese_trad.h b/libatalk/unicode/charsets/mac_chinese_trad.h
new file mode 100644 (file)
index 0000000..2747f35
--- /dev/null
@@ -0,0 +1,124 @@
+/*
+ * MacChineseTrad
+ * Copyright (C) TSUBAKIMOTO Hiroya <zorac@4000do.co.jp> 2004
+ *
+ * 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.
+ *
+ * Reference
+ * http://www.unicode.org/Public/MAPPINGS/VENDORS/APPLE/
+ */
+
+static const u_int16_t mac_chinese_trad_uni2_page00[][2] = {
+  /* 0x00a */ { 0x0201,    0 }, { 0x0080,    2 },
+};
+
+static const u_int16_t mac_chinese_trad_uni2_page20[][2] = {
+  /* 0x202 */ { 0x0044,    3 },
+};
+
+static const u_int16_t mac_chinese_trad_uni2_page21[][2] = {
+  /* 0x212 */ { 0x0004,    5 },
+};
+
+static const u_int16_t mac_chinese_trad_uni2_page22[][2] = {
+  /* 0x229 */ { 0x0020,    6 }, { 0x0000,    0 }, { 0x0000,    0 },
+  /* 0x22c */ { 0x0000,    0 }, { 0x0000,    0 }, { 0x8000,    7 },
+};
+
+static const u_int16_t mac_chinese_trad_uni2_page25[][2] = {
+  /* 0x259 */ { 0x0020,    8 },
+};
+
+static const u_int16_t mac_chinese_trad_uni2_page26[][2] = {
+  /* 0x264 */ { 0x0002,    9 },
+};
+
+static const u_int16_t mac_chinese_trad_uni2_pagee0[][2] = {
+  /* 0xe00 */ { 0xffff,   10 }, { 0x00ff,   26 },
+};
+
+static const u_int16_t mac_chinese_trad_uni2_pagef8[][2] = {
+  /* 0xf88 */ { 0x0003,   34 },
+};
+
+static const u_int16_t mac_chinese_trad_uni2_pagefe[][2] = {
+  /* 0xfe4 */ { 0x1000,   36 }, { 0x7ef5,   37 },
+};
+
+static const u_int16_t mac_chinese_trad_uni2_pageff[][2] = {
+  /* 0xff6 */ { 0x0010,   49 },
+};
+
+static const cjk_index_t mac_chinese_trad_uni2_index[] = {
+  { { 0x00a0, 0x00bf }, mac_chinese_trad_uni2_page00 },
+  { { 0x2020, 0x202f }, mac_chinese_trad_uni2_page20 },
+  { { 0x2120, 0x212f }, mac_chinese_trad_uni2_page21 },
+  { { 0x2290, 0x22ef }, mac_chinese_trad_uni2_page22 },
+  { { 0x2590, 0x259f }, mac_chinese_trad_uni2_page25 },
+  { { 0x2640, 0x264f }, mac_chinese_trad_uni2_page26 },
+  { { 0xe000, 0xe01f }, mac_chinese_trad_uni2_pagee0 },
+  { { 0xf880, 0xf88f }, mac_chinese_trad_uni2_pagef8 },
+  { { 0xfe40, 0xfe5f }, mac_chinese_trad_uni2_pagefe },
+  { { 0xff60, 0xff6f }, mac_chinese_trad_uni2_pageff },
+  { { 0, 0 }, 0 }
+};
+
+static const u_int16_t mac_chinese_trad_uni2_charset[] = {
+  0x00a0, 0x00fd, 0xa145, 0xffff, 0x00ff, 0x00fe, 0xa1f2, 0xa14b,
+  0xffff, 0xffff, 0x0080, 0xa1c3, 0xa279, 0xa14e, 0xa1a3, 0xa1a4,
+  0xa2cc, 0xa2ce, 0xa1cb, 0xa154, 0xa17d, 0xa17e, 0xa14d, 0xa14f,
+  0xa150, 0xa1fe, 0xa152, 0xa151, 0xa153, 0xa240, 0xa1c5, 0xa15a,
+  0xa1a1, 0xa1a2, 0x0081, 0x0082, 0xffff, 0xffff, 0xffff, 0xffff,
+  0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
+  0xffff, 0xffff,
+};
+
+static const u_int16_t mac_chinese_trad_2uni_page00[][2] = {
+  /* 0x008 */ { 0x0007,    0 }, { 0x0000,    0 }, { 0x0001,    3 }, { 0x0000,    0 },
+  /* 0x00c */ { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 }, { 0xe000,    4 },
+};
+
+static const u_int16_t mac_chinese_trad_2uni_pagea1[][2] = {
+  /* 0xa14 */ { 0xe820,    7 }, { 0x041f,   12 }, { 0x0000,    0 }, { 0x6000,   18 },
+  /* 0xa18 */ { 0x0000,    0 }, { 0x0000,    0 }, { 0x001e,   20 }, { 0x0000,    0 },
+  /* 0xa1c */ { 0x0828,   24 }, { 0x0000,    0 }, { 0x0000,    0 }, { 0x4004,   27 },
+  /* 0xa20 */ { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 },
+  /* 0xa24 */ { 0x0001,   29 }, { 0x0000,    0 }, { 0x0000,    0 }, { 0x0200,   30 },
+  /* 0xa28 */ { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 },
+  /* 0xa2c */ { 0x5000,   31 },
+};
+
+static const cjk_index_t mac_chinese_trad_2uni_index[] = {
+  { { 0x0080, 0x00ff }, mac_chinese_trad_2uni_page00 },
+  { { 0xa140, 0xa2cf }, mac_chinese_trad_2uni_pagea1 },
+  { { 0, 0 }, 0 }
+};
+
+static const u_int16_t mac_chinese_trad_2uni_charset[] = {
+  0xe000, 0xf880, 0xf881, 0x00a0, 0x00a9, 0x2122, 0x2026, 0x00b7,
+  0x22ef, 0xe00c, 0xe003, 0xe00d, 0xe00e, 0xe011, 0xe010, 0xe012,
+  0xe009, 0xe015, 0xe00a, 0xe00b, 0xe016, 0xe017, 0xe004, 0xe005,
+  0xe001, 0xe014, 0xe008, 0x2295, 0xe00f, 0xe013, 0xe002, 0xe006,
+  0xe007,
+};
+
+static const u_int32_t mac_chinese_trad_compose[] = {
+  0x005cf87f, 0x203ef87c, 0x2502f87f, 0x3001f87d,
+  0x3014f87f, 0x3015f87f, 0x5341f87f, 0x5345f87f,
+  0xfe4bf87c, 0xff01f87d, 0xff08f87f, 0xff09f87f,
+  0xff0cf87d, 0xff0ef87d, 0xff0ef87e, 0xff0ff87f,
+  0xff1af87d, 0xff1bf87d, 0xff1ff87d, 0xff3cf87f,
+  0xff3ff87c, 0xff3ff87f, 0xff5bf87f, 0xff5df87f,
+};
diff --git a/libatalk/unicode/charsets/mac_cyrillic.c b/libatalk/unicode/charsets/mac_cyrillic.c
new file mode 100644 (file)
index 0000000..d20a8ce
--- /dev/null
@@ -0,0 +1,67 @@
+/* 
+   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,
+       NULL,
+       NULL, NULL
+};
+
+
+/* ------------------------ */
+
+static size_t mac_cyrillic_push( void *cd, char **inbuf, size_t *inbytesleft,
+                         char **outbuf, size_t *outbytesleft)
+{
+      return (size_t) mb_generic_push( char_ucs2_to_mac_cyrillic, cd, inbuf, inbytesleft, outbuf, outbytesleft);
+}
+
+/* ------------------------ */
+
+static size_t mac_cyrillic_pull ( void *cd, char **inbuf, size_t *inbytesleft,
+                         char **outbuf, size_t *outbytesleft)
+{
+      return (size_t) mb_generic_pull( char_mac_cyrillic_to_ucs2, cd, inbuf, inbytesleft, outbuf, outbytesleft);
+}
diff --git a/libatalk/unicode/charsets/mac_cyrillic.h b/libatalk/unicode/charsets/mac_cyrillic.h
new file mode 100644 (file)
index 0000000..4c6681a
--- /dev/null
@@ -0,0 +1,142 @@
+/*
+ * 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 == 0x0490)
+    c = 0xa2;
+  else if (wc == 0x0491)
+    c = 0xb6;
+  else if (wc >= 0x2010 && wc < 0x2028)
+    c = mac_cyrillic_page20[wc-0x2010];
+  else if (wc == 0x20ac)
+    c = 0xff;
+  else if (wc >= 0x2110 && wc < 0x2128)
+    c = mac_cyrillic_page21[wc-0x2110];
+  else if (wc >= 0x2200 && wc < 0x2268)
+    c = mac_cyrillic_page22[wc-0x2200];
+  if (c != 0) {
+    *r = c;
+    return 1;
+  }
+  return 0;
+}
diff --git a/libatalk/unicode/charsets/mac_hebrew.c b/libatalk/unicode/charsets/mac_hebrew.c
new file mode 100644 (file)
index 0000000..8b7bdca
--- /dev/null
@@ -0,0 +1,222 @@
+/* 
+   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 <errno.h>
+
+#include <netatalk/endian.h>
+#include <atalk/unicode.h>
+#include <atalk/logger.h>
+
+#include "../byteorder.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,
+       NULL,
+       NULL, NULL
+};
+
+
+/* ------------------------ 
+ * 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 _U_, 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 = SVAL((*inbuf),0);
+       if (inptr == 0x05b8) {
+           (*inbuf) += 2;
+           (*inbytesleft)  -= 2;
+           if (*inbytesleft >= 2 && SVAL((*inbuf),0) == 0xf87f ) {
+               (*inbuf) += 2;
+               (*inbytesleft)  -= 2;
+               c = 0xde;
+           }
+           else {
+               c = 0xcb;
+           }
+           *tmpptr = c; 
+       }
+       else if (inptr == 0x05f2 && *inbytesleft >= 4 && SVAL((*inbuf),2) == 0x05b7) {
+           (*inbuf) += 4;
+           (*inbytesleft)  -= 4;
+           *tmpptr = 0x81;
+       }
+       else if (inptr == 0xf86a && *inbytesleft >= 6 && SVAL((*inbuf),2) == 0x05dc && SVAL((*inbuf),4) == 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 _U_, 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;
+       if (char_mac_hebrew_to_ucs2 ( &temp, inptr)) {
+           if (temp == 1) {       /* 0x81 --> 0x05f2+0x05b7 */
+               if (*outbytesleft < 4) {
+                   errno = E2BIG;
+                   return (size_t) -1; 
+               }
+               SSVAL((*outbuf),0,0x05f2);
+               SSVAL((*outbuf),2,0x05b7);
+               (*outbuf)      +=4;
+               (*outbytesleft)-=4;
+               len += 2;
+           }
+           else if (temp == 2) { /* 0xc0 -> 0xf86a 0x05dc 0x05b9*/
+               if (*outbytesleft < 6) {
+                   errno = E2BIG;
+                   return (size_t) -1; 
+               }
+               SSVAL((*outbuf),0,0xf86a);
+               SSVAL((*outbuf),2,0x05dc);
+               SSVAL((*outbuf),4,0x05b9);
+               (*outbuf)      +=6;
+               (*outbytesleft)-=6;
+               len += 3;
+           }
+           else if (temp == 3) { /* 0xde --> 0x05b8 0xf87f */
+               if (*outbytesleft < 4) {
+                   errno = E2BIG;
+                   return (size_t) -1; 
+               }
+               SSVAL((*outbuf),0,0x05b8);
+               SSVAL((*outbuf),2,0xf87f);
+               (*outbuf)      +=4;
+               (*outbytesleft)-=4;
+               len += 2;
+           }
+           else {
+               SSVAL((*outbuf),0,temp);
+               (*outbuf)      +=2;
+               (*outbytesleft)-=2;
+               len++;
+           }
+           (*inbuf)        +=1;
+           (*inbytesleft) -=1;
+       }
+       else    
+       {
+           errno = EILSEQ;
+           return (size_t) -1; 
+       }
+    }
+
+    if (*inbytesleft > 0) {
+        errno = E2BIG;
+        return (size_t) -1;
+    }
+    return len;
+}
+
diff --git a/libatalk/unicode/charsets/mac_hebrew.h b/libatalk/unicode/charsets/mac_hebrew.h
new file mode 100644 (file)
index 0000000..dbb55fe
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 1999-2001 Free Software Foundation, Inc.
+ * This file is part of the GNU LIBICONV Library.
+ *
+ * The GNU LIBICONV Library is free software; you can redistribute it
+ * and/or modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * The GNU LIBICONV Library is distributed in the hope that it will be
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with the GNU LIBICONV Library; see the file COPYING.LIB.
+ * If not, write to the Free Software Foundation, Inc., 59 Temple Place -
+ * Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * from libiconv
+ * modified for round trip by didier gautheron
+ * Reference
+ * http://www.unicode.org/Public/MAPPINGS/VENDORS/APPLE/
+ */
+
+/*
+ * MacHebrew
+ */
+
+static const unsigned short mac_hebrew_2uni[128] = {
+  /* 0x80 0x81 -> 0x05f2+0x05b7 was 0xfb1f */
+  0x00c4,     01, 0x00c7, 0x00c9, 0x00d1, 0x00d6, 0x00dc, 0x00e1,
+  0x00e0, 0x00e2, 0x00e4, 0x00e3, 0x00e5, 0x00e7, 0x00e9, 0x00e8,
+
+  /* 0x90 */
+  0x00ea, 0x00eb, 0x00ed, 0x00ec, 0x00ee, 0x00ef, 0x00f1, 0x00f3,
+  0x00f2, 0x00f4, 0x00f6, 0x00f5, 0x00fa, 0x00f9, 0x00fb, 0x00fc,
+
+  /* 0xa0 */
+  /* 0xffd move to right to left (not 0x20aa) */
+  0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x20aa, 0x0027,
+  0x0029, 0x0028, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
+  
+  /* 0xb0 */
+  0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+  0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
+
+  /* 0xc0 -> 0xf86a 0x05dc 0x05b9*/
+      02, 0x201e, 0xf89b, 0xf89c, 0xf89d, 0xf89e, 0x05bc, 0xfb4b,
+  0xfb35, 0x2026, 0x00a0, 0x05b8, 0x05b7, 0x05b5, 0x05b6, 0x05b4,
+
+  /* 0xd0 
+     0xde --> 0x05b8 0xf87f 
+  */
+  0x2013, 0x2014, 0x201c, 0x201d, 0x2018, 0x2019, 0xfb2a, 0xfb2b,
+  0x05bf, 0x05b0, 0x05b2, 0x05b1, 0x05bb, 0x05b9,     03, 0x05b3,
+  /* 0xe0 */
+  0x05d0, 0x05d1, 0x05d2, 0x05d3, 0x05d4, 0x05d5, 0x05d6, 0x05d7,
+  0x05d8, 0x05d9, 0x05da, 0x05db, 0x05dc, 0x05dd, 0x05de, 0x05df,
+  /* 0xf0 */
+  0x05e0, 0x05e1, 0x05e2, 0x05e3, 0x05e4, 0x05e5, 0x05e6, 0x05e7,
+  0x05e8, 0x05e9, 0x05ea, 0x007d, 0x005d, 0x007b, 0x005b, 0x007c,
+};
+
+/* (wc >= 0x00a0 && wc < 0x0100) */
+
+static const unsigned char mac_hebrew_page00[96] = {
+  0xca, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+  0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x82, /* 0xc0-0xc7 */
+  0x00, 0x83, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+  0x00, 0x84, 0x00, 0x00, 0x00, 0x00, 0x85, 0x00, /* 0xd0-0xd7 */
+  0x00, 0x00, 0x00, 0x00, 0x86, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+  0x88, 0x87, 0x89, 0x8b, 0x8a, 0x8c, 0x00, 0x8d, /* 0xe0-0xe7 */
+  0x8f, 0x8e, 0x90, 0x91, 0x93, 0x92, 0x94, 0x95, /* 0xe8-0xef */
+  0x00, 0x96, 0x98, 0x97, 0x99, 0x9b, 0x9a, 0x00, /* 0xf0-0xf7 */
+  0x00, 0x9d, 0x9c, 0x9e, 0x9f, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+/*  (wc >= 0x05b0 && wc < 0x05f0) */
+static const unsigned char mac_hebrew_page05[64] = {
+  0xd9, 0xdb, 0xda, 0xdf, 0xcf, 0xcd, 0xce, 0xcc, /* 0xb0-0xb7 */
+  0xcb, 0xdd, 0x00, 0xdc, 0xc6, 0x00, 0x00, 0xd8, /* 0xb8-0xbf */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+  0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xd0-0xd7 */
+  0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xd8-0xdf */
+  0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xe0-0xe7 */
+  0xf8, 0xf9, 0xfa, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+};
+
+/* (wc >= 0x2010 && wc < 0x2028) */
+static const unsigned char mac_hebrew_page20[24] = {
+  0x00, 0x00, 0x00, 0xd0, 0xd1, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+  0xd4, 0xd5, 0x00, 0x00, 0xd2, 0xd3, 0xc1, 0x00, /* 0x18-0x1f */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc9, 0x00, /* 0x20-0x27 */
+};
+
+/* (wc >= 0xfb18 && wc < 0xfb50) */
+static const unsigned char mac_hebrew_pagefb[56] = {
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, /* 0x18-0x1f */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+  0x00, 0x00, 0xd6, 0xd7, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0x00, 0x00, /* 0x30-0x37 */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+  0x00, 0x00, 0x00, 0xc7, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+};
+
diff --git a/libatalk/unicode/charsets/mac_japanese.c b/libatalk/unicode/charsets/mac_japanese.c
new file mode 100644 (file)
index 0000000..6fe924f
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ * MacJapanese
+ * Copyright (C) TSUBAKIMOTO Hiroya <zorac@4000do.co.jp> 2004
+ *
+ * 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.
+ *
+ * Reference
+ * http://www.unicode.org/Public/MAPPINGS/VENDORS/APPLE/
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#if HAVE_USABLE_ICONV
+
+#include "generic_cjk.h"
+#include "mac_japanese.h"
+
+static size_t mac_japanese_pull(void *,char **, size_t *, char **, size_t *);
+static size_t mac_japanese_push(void *,char **, size_t *, char **, size_t *);
+
+struct charset_functions charset_mac_japanese = {
+  "MAC_JAPANESE",
+  1,
+  mac_japanese_pull,
+  mac_japanese_push,
+  CHARSET_ICONV | CHARSET_MULTIBYTE | CHARSET_PRECOMPOSED | CHARSET_CLIENT,
+  "SHIFT_JIS",
+  NULL, NULL
+};
+
+static size_t mac_japanese_char_push(u_int8_t* out, const ucs2_t* in, size_t* size)
+{
+  ucs2_t wc = in[0];
+
+  if (wc <= 0x7f) {
+    *size = 1;
+    out[0] = (u_int8_t)(wc == 0x5c ? 0x80 : wc);
+    return 1;
+  } else if ((wc & 0xf000) == 0xe000) { /* user defined */
+    *size = 1;
+    if (wc > 0xe98b) return 0;
+    wc -= 0xe000;
+    out[0] = (u_int8_t)(wc / 188 + 0xf0);
+    out[1] = (u_int8_t)(wc % 188 + 0x40);
+    if (out[1] >= 0x7f) ++out[1];
+    return 2;
+  } else if ((wc & ~7) == 0xf860) {
+    wc = cjk_compose_seq(in, size, mac_japanese_compose,
+                        sizeof(mac_japanese_compose) / sizeof(u_int32_t));
+    if (!wc) return (size_t)-1;
+  } else if (*size >= 2 && ((in[1] & ~15) == 0xf870 || in[1] == 0x20dd)) {
+    ucs2_t comp = cjk_compose(wc, in[1], mac_japanese_compose,
+                             sizeof(mac_japanese_compose) / sizeof(u_int32_t));
+    if (comp) {
+      wc = comp;
+      *size = 2;
+    } else {
+      *size = 1;
+    }
+  } else {
+    *size = 1;
+  }
+  return cjk_char_push(cjk_lookup(wc, mac_japanese_uni2_index,
+                                 mac_japanese_uni2_charset), out);
+}
+
+static size_t mac_japanese_push(void *cd, char **inbuf, size_t *inbytesleft,
+                               char **outbuf, size_t *outbytesleft)
+{
+  return cjk_generic_push(mac_japanese_char_push,
+                         cd, inbuf, inbytesleft, outbuf, outbytesleft);
+}
+
+static size_t mac_japanese_char_pull(ucs2_t* out, const u_int8_t* in, size_t* size)
+{
+  u_int16_t c = in[0];
+
+  if (c <= 0x7f) {
+    *size = 1;
+    *out = (c == 0x5c ? 0xa5 : c);
+    return 1;
+  } else if ((c >= 0x81 && c <= 0x9f) || (c >= 0xe0 && c <= 0xfc)) {
+    if (*size >= 2) {
+      u_int8_t c2 = in[1];
+
+      if ((c2 >= 0x40 && c2 <= 0x7e) || (c2 >= 0x80 && c2 <= 0xfc)) {
+       *size = 2;
+       if (c >= 0xf0) { /* user defined */
+         *out = 0xe000 + (c - 0xf0) * 188 + c2 - (c2 < 0x80 ? 0x40 : 0x41);
+         return 1;
+       }
+       c = (c << 8) + c2;
+      } else {
+       errno = EILSEQ;
+       return (size_t)-1;
+      }
+    } else {
+      errno = EINVAL;
+      return (size_t)-1;
+    }
+  } else {
+    *size = 1;
+  }
+  return cjk_char_pull(cjk_lookup(c, mac_japanese_2uni_index,
+                                 mac_japanese_2uni_charset),
+                      out, mac_japanese_compose);
+}
+
+static size_t mac_japanese_pull(void *cd, char **inbuf, size_t *inbytesleft,
+                               char **outbuf, size_t *outbytesleft)
+{
+  return cjk_generic_pull(mac_japanese_char_pull,
+                         cd, inbuf, inbytesleft, outbuf, outbytesleft);
+}
+#endif
diff --git a/libatalk/unicode/charsets/mac_japanese.h b/libatalk/unicode/charsets/mac_japanese.h
new file mode 100644 (file)
index 0000000..d032a83
--- /dev/null
@@ -0,0 +1,252 @@
+/*
+ * MacJapanese
+ * Copyright (C) TSUBAKIMOTO Hiroya <zorac@4000do.co.jp> 2004
+ *
+ * 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.
+ *
+ * Reference
+ * http://www.unicode.org/Public/MAPPINGS/VENDORS/APPLE/
+ */
+
+static const u_int16_t mac_japanese_uni2_page00[][2] = {
+  /* 0x00a */ { 0x0201,    1 },
+};
+
+static const u_int16_t mac_japanese_uni2_page20[][2] = {
+  /* 0x201 */ { 0x0030,    3 }, { 0x0000,    0 }, { 0x4000,    5 },
+  /* 0x204 */ { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 },
+  /* 0x208 */ { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 },
+  /* 0x20c */ { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 },
+  /* 0x210 */ { 0x0200,    6 }, { 0x0048,    7 }, { 0x0006,    9 }, { 0x0000,    0 },
+  /* 0x214 */ { 0x0000,    0 }, { 0x0000,    0 }, { 0x0fff,   11 }, { 0x0fff,   23 },
+  /* 0x218 */ { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 },
+  /* 0x21c */ { 0x0070,   35 }, { 0x0000,    0 }, { 0x03c0,   38 }, { 0x0000,    0 },
+  /* 0x220 */ { 0x0000,    0 }, { 0x8000,   42 }, { 0x4000,   43 }, { 0x0000,    0 },
+  /* 0x224 */ { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 },
+  /* 0x228 */ { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 }, { 0x8000,   44 },
+};
+
+static const u_int16_t mac_japanese_uni2_page24[][2] = {
+  /* 0x246 */ { 0xffff,   45 }, { 0xffff,   61 },
+  /* 0x248 */ { 0xffff,   77 }, { 0xf001,   93 }, { 0xffff,   98 }, { 0x003f,  114 },
+};
+
+static const u_int16_t mac_japanese_uni2_page26[][2] = {
+  /* 0x260 */ { 0x4000,  120 }, { 0xf000,  121 }, { 0x0000,    0 }, { 0x0000,    0 },
+  /* 0x264 */ { 0x0000,    0 }, { 0x0000,    0 }, { 0x00ff,  125 }, { 0x0000,    0 },
+  /* 0x268 */ { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 },
+  /* 0x26c */ { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 },
+  /* 0x270 */ { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 },
+  /* 0x274 */ { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 }, { 0x7fc0,  133 },
+};
+
+static const u_int16_t mac_japanese_uni2_page30[][2] = {
+  /* 0x300 */ { 0x0010,  142 }, { 0xa000,  143 }, { 0x0001,  145 }, { 0x0000,    0 },
+  /* 0x304 */ { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 },
+  /* 0x308 */ { 0x0000,    0 }, { 0x0010,  146 }, { 0x0000,    0 }, { 0x0000,    0 },
+  /* 0x30c */ { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 }, { 0x0780,  147 },
+};
+
+static const u_int16_t mac_japanese_uni2_page32[][2] = {
+  /* 0x322 */ { 0xfc00,  151 }, { 0xffff,  157 },
+  /* 0x324 */ { 0x000d,  173 }, { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 },
+  /* 0x328 */ { 0x0000,    0 }, { 0x6340,  176 }, { 0x03f0,  181 }, { 0x0000,    0 },
+  /* 0x32c */ { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 },
+  /* 0x330 */ { 0x2029,  187 }, { 0x4170,  191 }, { 0x0ccc,  196 }, { 0x0a4a,  202 },
+  /* 0x334 */ { 0x6684,  207 }, { 0x0082,  213 }, { 0x0000,    0 }, { 0xf800,  215 },
+  /* 0x338 */ { 0xc0e0,  220 }, { 0xf1c1,  225 }, { 0x0037,  233 }, { 0x000f,  238 },
+  /* 0x33c */ { 0x2810,  242 }, { 0x0010,  245 },
+};
+
+static const u_int16_t mac_japanese_uni2_pagee0[][2] = {
+  /* 0xe00 */ { 0xffff,  246 }, { 0xffff,  262 }, { 0x0fff,  278 }, { 0x001f,  290 },
+  /* 0xe04 */ { 0x7f00,  295 },
+};
+
+static const u_int16_t mac_japanese_uni2_pagefe[][2] = {
+  /* 0xfe3 */ { 0xffeb,  302 },
+  /* 0xfe4 */ { 0x001f,  316 }, { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 },
+  /* 0xfe8 */ { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 },
+  /* 0xfec */ { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 },
+  /* 0xff0 */ { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 }, { 0x1000,  321 },
+};
+
+static const cjk_index_t mac_japanese_uni2_index[] = {
+  { { 0x00a0, 0x00af }, mac_japanese_uni2_page00 },
+  { { 0x2010, 0x22bf }, mac_japanese_uni2_page20 },
+  { { 0x2460, 0x24bf }, mac_japanese_uni2_page24 },
+  { { 0x2600, 0x277f }, mac_japanese_uni2_page26 },
+  { { 0x3000, 0x30ff }, mac_japanese_uni2_page30 },
+  { { 0x3220, 0x33df }, mac_japanese_uni2_page32 },
+  { { 0xe000, 0xe04f }, mac_japanese_uni2_pagee0 },
+  { { 0xfe30, 0xff3f }, mac_japanese_uni2_pagefe },
+  { { 0, 0 }, 0 }
+};
+
+static const u_int16_t mac_japanese_uni2_charset[] = {
+  0x0080, 0x00a0, 0x00fd, 0x815c, 0xffff, 0xffff, 0x8656, 0x8650,
+  0x869b, 0x869d, 0x00fe, 0x859f, 0x85a0, 0x85a1, 0x85a2, 0x85a3,
+  0x85a4, 0x85a5, 0x85a6, 0x85a7, 0x85a8, 0x85a9, 0x85aa, 0x85b3,
+  0x85b4, 0x85b5, 0x85b6, 0x85b7, 0x85b8, 0x85b9, 0x85ba, 0x85bb,
+  0x85bc, 0x85bd, 0x85be, 0x86cc, 0x86cd, 0x86cb, 0x86d0, 0x86d1,
+  0x86cf, 0x86d2, 0x8841, 0x8840, 0x8842, 0x8540, 0x8541, 0x8542,
+  0x8543, 0x8544, 0x8545, 0x8546, 0x8547, 0x8548, 0x8549, 0x854a,
+  0x854b, 0x854c, 0x854d, 0x854e, 0x854f, 0x8550, 0x8551, 0x8552,
+  0x8553, 0x855e, 0x855f, 0x8560, 0x8561, 0x8562, 0x8563, 0x8564,
+  0x8565, 0x8566, 0x8567, 0x8568, 0x8569, 0x856a, 0x856b, 0x856c,
+  0x856d, 0x856e, 0x856f, 0x8570, 0x8571, 0x8592, 0x8593, 0x8594,
+  0x8595, 0x8596, 0x8597, 0x8598, 0x8599, 0x859a, 0x85db, 0x85dc,
+  0x85dd, 0x85de, 0x85df, 0x85e0, 0x85e1, 0x85e2, 0x85e3, 0x85e4,
+  0x85e5, 0x85e6, 0x85e7, 0x85e8, 0x85e9, 0x85ea, 0x85eb, 0x85ec,
+  0x85ed, 0x85ee, 0x85ef, 0x85f0, 0x85f1, 0x85f2, 0x85f3, 0x85f4,
+  0x86b4, 0x86c8, 0x86c9, 0x86c7, 0x86ca, 0x86a3, 0x86a1, 0x86a2,
+  0x86a4, 0x869f, 0x86a5, 0x86a6, 0x86a0, 0x857c, 0x857d, 0x857e,
+  0x8580, 0x8581, 0x8582, 0x8583, 0x8584, 0x8585, 0x86b5, 0x8854,
+  0x8855, 0x86b3, 0x8868, 0x886a, 0x886b, 0x886c, 0x886d, 0x8741,
+  0x8742, 0x8743, 0x8744, 0x8745, 0x8746, 0x8740, 0x874d, 0x8750,
+  0x8753, 0x874f, 0x8754, 0x8752, 0x8748, 0x8758, 0x874b, 0x874c,
+  0x8751, 0x8755, 0x8756, 0x874e, 0x8757, 0x8747, 0x8749, 0x874a,
+  0x8799, 0x879b, 0x879e, 0x879a, 0x879c, 0x8793, 0x8794, 0x8795,
+  0x8796, 0x8797, 0x8798, 0x87bd, 0x87a7, 0x87a4, 0x87b0, 0x87a2,
+  0x87aa, 0x87a3, 0x87a9, 0x87be, 0x87a0, 0x87b2, 0x87b3, 0x87ab,
+  0x87bf, 0x87b5, 0x87c0, 0x87a5, 0x87a8, 0x87ae, 0x87b4, 0x87b1,
+  0x87c1, 0x879f, 0x87ad, 0x87a1, 0x87a6, 0x87ac, 0x87af, 0x87e8,
+  0x87e7, 0x87e6, 0x87e5, 0x87fa, 0x865a, 0x865b, 0x865c, 0x864a,
+  0x864c, 0x8659, 0x864e, 0x864f, 0x8651, 0x8640, 0x8642, 0x8648,
+  0x8641, 0x8643, 0x8646, 0x8649, 0x8644, 0x8647, 0x8655, 0x8654,
+  0x8653, 0x8652, 0x864d, 0x8658, 0x869c, 0x8657, 0xeb5d, 0xeb61,
+  0xeb63, 0x00ff, 0x86d4, 0x86d5, 0x86d3, 0x86d6, 0xeb41, 0xeb42,
+  0xeb60, 0xec9f, 0xeca1, 0xeca3, 0xeca5, 0xeca7, 0xecc1, 0xece1,
+  0xece3, 0xece5, 0xecec, 0xed40, 0xed42, 0xed44, 0xed46, 0xed48,
+  0xed62, 0xed83, 0xed85, 0xed87, 0xed8e, 0xed95, 0xed96, 0xeb5b,
+  0x8791, 0x8792, 0x879d, 0x85ab, 0x85bf, 0x87fb, 0x87fc, 0x869e,
+  0x85ac, 0x85c0, 0x8591, 0x865d, 0x85ad, 0x85c1, 0x86ce, 0xeb81,
+  0xeb6d, 0xeb6e, 0x864b, 0x8645, 0xeb62, 0xeb50, 0xeb64, 0xeb5c,
+  0xeb51, 0xeb69, 0xeb6a, 0xeb6f, 0xeb70, 0xeb6b, 0xeb6c, 0xeb79,
+  0xeb7a, 0xeb73, 0xeb74, 0xeb71, 0xeb72, 0xeb75, 0xeb76, 0xeb77,
+  0xeb78, 0x815f,
+};
+
+static const u_int16_t mac_japanese_2uni_page00[][2] = {
+  /* 0x008 */ { 0x0001,    0 }, { 0x0000,    0 }, { 0x0001,    1 }, { 0x0000,    0 },
+  /* 0x00c */ { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 }, { 0xe000,    2 },
+};
+
+static const u_int16_t mac_japanese_2uni_page81[][2] = {
+  /* 0x815 */ { 0x9000,    5 },
+};
+
+static const u_int16_t mac_japanese_2uni_page85[][2] = {
+  /* 0x854 */ { 0xffff,    7 }, { 0xc00f,   23 }, { 0xffff,   29 }, { 0x7003,   45 },
+  /* 0x858 */ { 0x003f,   50 }, { 0x87fe,   56 }, { 0x3fff,   67 }, { 0xfff8,   81 },
+  /* 0x85c */ { 0x0003,   94 }, { 0xf800,   96 }, { 0xffff,  101 }, { 0x001f,  117 },
+  /* 0x860 */ { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 },
+  /* 0x864 */ { 0xffff,  122 }, { 0x3fff,  138 }, { 0x0000,    0 }, { 0x0000,    0 },
+  /* 0x868 */ { 0x0000,    0 }, { 0xf800,  152 }, { 0x007f,  157 }, { 0x0038,  164 },
+  /* 0x86c */ { 0xff80,  167 }, { 0x007f,  176 }, { 0x0000,    0 }, { 0x0000,    0 },
+  /* 0x870 */ { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 },
+  /* 0x874 */ { 0xffff,  183 }, { 0x01ff,  199 }, { 0x0000,    0 }, { 0x0000,    0 },
+  /* 0x878 */ { 0x0000,    0 }, { 0xfffe,  208 }, { 0xffff,  223 }, { 0xe03f,  239 },
+  /* 0x87c */ { 0x0003,  248 }, { 0x0000,    0 }, { 0x01e0,  250 }, { 0x1c00,  254 },
+  /* 0x880 */ { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 },
+  /* 0x884 */ { 0x0007,  257 }, { 0x0030,  260 }, { 0x3d00,  262 },
+};
+
+static const u_int16_t mac_japanese_2uni_pageeb[][2] = {
+  /* 0xeb4 */ { 0x0006,  267 }, { 0x3803,  269 }, { 0xfe1f,  274 }, { 0x07ff,  286 },
+  /* 0xeb8 */ { 0x0002,  297 }, { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 },
+  /* 0xebc */ { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 },
+  /* 0xec0 */ { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 },
+  /* 0xec4 */ { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 },
+  /* 0xec8 */ { 0x0000,    0 }, { 0x8000,  298 }, { 0x00aa,  299 }, { 0x0000,    0 },
+  /* 0xecc */ { 0x0002,  303 }, { 0x0000,    0 }, { 0x102a,  304 }, { 0x0000,    0 },
+  /* 0xed0 */ { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 },
+  /* 0xed4 */ { 0x0155,  308 }, { 0x0000,    0 }, { 0x0004,  313 }, { 0x0000,    0 },
+  /* 0xed8 */ { 0x40a8,  314 }, { 0x0060,  318 },
+};
+
+static const cjk_index_t mac_japanese_2uni_index[] = {
+  { { 0x0080, 0x00ff }, mac_japanese_2uni_page00 },
+  { { 0x8150, 0x815f }, mac_japanese_2uni_page81 },
+  { { 0x8540, 0x886f }, mac_japanese_2uni_page85 },
+  { { 0xeb40, 0xed9f }, mac_japanese_2uni_pageeb },
+  { { 0, 0 }, 0 }
+};
+
+static const u_int16_t mac_japanese_2uni_charset[] = {
+  0x005c, 0x00a0, 0x00a9, 0x2122, 0xe003, 0x2014, 0xff3c, 0x2460,
+  0x2461, 0x2462, 0x2463, 0x2464, 0x2465, 0x2466, 0x2467, 0x2468,
+  0x2469, 0x246a, 0x246b, 0x246c, 0x246d, 0x246e, 0x246f, 0x2470,
+  0x2471, 0x2472, 0x2473, 0x2474, 0x2475, 0x2476, 0x2477, 0x2478,
+  0x2479, 0x247a, 0x247b, 0x247c, 0x247d, 0x247e, 0x247f, 0x2480,
+  0x2481, 0x2482, 0x2483, 0x2484, 0x2485, 0x2486, 0x2487, 0x2776,
+  0x2777, 0x2778, 0x2779, 0x277a, 0x277b, 0x277c, 0x277d, 0x277e,
+  0xe030, 0x2488, 0x2489, 0x248a, 0x248b, 0x248c, 0x248d, 0x248e,
+  0x248f, 0x2490, 0x2160, 0x2161, 0x2162, 0x2163, 0x2164, 0x2165,
+  0x2166, 0x2167, 0x2168, 0x2169, 0x216a, 0x216b, 0xe025, 0xe02a,
+  0xe032, 0x2170, 0x2171, 0x2172, 0x2173, 0x2174, 0x2175, 0x2176,
+  0x2177, 0x2178, 0x2179, 0x217a, 0x217b, 0xe026, 0xe02b, 0xe033,
+  0x249c, 0x249d, 0x249e, 0x249f, 0x24a0, 0x24a1, 0x24a2, 0x24a3,
+  0x24a4, 0x24a5, 0x24a6, 0x24a7, 0x24a8, 0x24a9, 0x24aa, 0x24ab,
+  0x24ac, 0x24ad, 0x24ae, 0x24af, 0x24b0, 0x24b1, 0x24b2, 0x24b3,
+  0x24b4, 0x24b5, 0x339c, 0x339f, 0x339d, 0x33a0, 0x33a4, 0xe04c,
+  0x33a1, 0x33a5, 0x339e, 0x33a2, 0x338e, 0xe04b, 0x338f, 0x33c4,
+  0x3396, 0x3397, 0x2113, 0x3398, 0x33b3, 0x33b2, 0x33b1, 0x33b0,
+  0x2109, 0x33d4, 0x33cb, 0x3390, 0x3385, 0x3386, 0x3387, 0xe031,
+  0x2116, 0x33cd, 0x2121, 0xe029, 0x2664, 0x2667, 0x2661, 0x2662,
+  0x2660, 0x2663, 0x2665, 0x2666, 0x3020, 0x260e, 0x3004, 0x261e,
+  0x261c, 0x261d, 0x261f, 0x21c6, 0x21c4, 0x21c5, 0xe034, 0x21e8,
+  0x21e6, 0x21e7, 0x21e9, 0xe006, 0xe004, 0xe005, 0xe007, 0x3230,
+  0x322a, 0x322b, 0x322c, 0x322d, 0x322e, 0x322f, 0x3240, 0x3237,
+  0x3242, 0x3243, 0x3239, 0x323a, 0x3231, 0x323e, 0x3234, 0x3232,
+  0x323b, 0x3236, 0x3233, 0x3235, 0x323c, 0x323d, 0x323f, 0x3238,
+  0xe022, 0xe023, 0x32a4, 0x32a5, 0x32a6, 0x32a7, 0x32a8, 0x32a9,
+  0x3296, 0x329d, 0x3298, 0x329e, 0xe024, 0x3299, 0x3349, 0x3322,
+  0x334d, 0x3314, 0x3316, 0x3305, 0x3333, 0x334e, 0x3303, 0x3336,
+  0x3318, 0x3315, 0x3327, 0x3351, 0x334a, 0x3339, 0x3357, 0x330d,
+  0x3342, 0x3323, 0x3326, 0x333b, 0x332b, 0x3300, 0x331e, 0x332a,
+  0x3331, 0x3347, 0x337e, 0x337d, 0x337c, 0x337b, 0x337f, 0xe027,
+  0xe028, 0x222e, 0x221f, 0x22bf, 0x301d, 0x301f, 0x3094, 0x30f7,
+  0x30f8, 0x30f9, 0x30fa, 0xe008, 0xe009, 0xe04e, 0xfe33, 0xe021,
+  0xfe31, 0xe000, 0xe00a, 0xe001, 0xe04d, 0xe002, 0xfe30, 0xfe35,
+  0xfe36, 0xfe39, 0xfe3a, 0xe049, 0xe04a, 0xfe37, 0xfe38, 0xfe3f,
+  0xfe40, 0xfe3d, 0xfe3e, 0xfe41, 0xfe42, 0xfe43, 0xfe44, 0xfe3b,
+  0xfe3c, 0xe048, 0xe00b, 0xe00c, 0xe00d, 0xe00e, 0xe00f, 0xe010,
+  0xe011, 0xe012, 0xe013, 0xe014, 0xe015, 0xe016, 0xe017, 0xe018,
+  0xe019, 0xe01a, 0xe01b, 0xe01c, 0xe01d, 0xe01e, 0xe01f, 0xe020,
+};
+
+static const u_int32_t mac_japanese_compose[] = {
+  0x2010f87e, 0x2016f87e, 0x2026f87e, 0x2026f87f,
+  0x21e6f87a, 0x21e7f87a, 0x21e8f87a, 0x21e9f87a,
+  0x3001f87e, 0x3002f87e, 0x301cf87e, 0x3041f87e,
+  0x3043f87e, 0x3045f87e, 0x3047f87e, 0x3049f87e,
+  0x3063f87e, 0x3083f87e, 0x3085f87e, 0x3087f87e,
+  0x308ef87e, 0x30a1f87e, 0x30a3f87e, 0x30a5f87e,
+  0x30a7f87e, 0x30a9f87e, 0x30c3f87e, 0x30e3f87e,
+  0x30e5f87e, 0x30e7f87e, 0x30eef87e, 0x30f5f87e,
+  0x30f6f87e, 0x30fcf87e, 0x592720dd, 0x5c0f20dd,
+  0x63a720dd, 0xe02c0049, 0xe02d0069, 0xe02e793e,
+  0xe02f4eba, 0xe0350058, 0xe0360056, 0xe0370076,
+  0xe0380049, 0xe0390069, 0xe03a4f1a, 0xe03b6cd5,
+  0xe03c002e, 0xe03d0042, 0xe03e0056, 0xe03f0076,
+  0xe0402191, 0xe0410041, 0xe0420049, 0xe0430069,
+  0xe0440049, 0xe0450069, 0xe0469650, 0xe04756e3,
+  0xf8600030, 0xf8600054, 0xf8600058, 0xf8600078,
+  0xf8602193, 0xf8610046, 0xf8610058, 0xf8610078,
+  0xf8620058, 0xf8620078, 0xf8626709, 0xf8628ca1,
+  0xff1df87e, 0xff3bf87e, 0xff3df87e, 0xff47f87f,
+  0xff4df87f, 0xff5cf87e, 0xffe3f87e,
+};
diff --git a/libatalk/unicode/charsets/mac_korean.c b/libatalk/unicode/charsets/mac_korean.c
new file mode 100644 (file)
index 0000000..c0755cb
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ * MacKorean
+ * Copyright (C) TSUBAKIMOTO Hiroya <zorac@4000do.co.jp> 2004
+ *
+ * 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.
+ *
+ * Reference
+ * http://www.unicode.org/Public/MAPPINGS/VENDORS/APPLE/
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#if HAVE_USABLE_ICONV
+
+#include "generic_cjk.h"
+#include "mac_korean.h"
+
+static size_t mac_korean_pull(void *,char **, size_t *, char **, size_t *);
+static size_t mac_korean_push(void *,char **, size_t *, char **, size_t *);
+
+struct charset_functions charset_mac_korean = {
+  "MAC_KOREAN",
+  3,
+  mac_korean_pull,
+  mac_korean_push,
+  CHARSET_ICONV | CHARSET_MULTIBYTE | CHARSET_PRECOMPOSED | CHARSET_CLIENT,
+  "EUC-KR",
+  NULL, NULL
+};
+
+static size_t mac_korean_char_push(u_int8_t* out, const ucs2_t* in, size_t* size)
+{
+  ucs2_t wc = in[0];
+
+  if ((wc & ~7) == 0xf860) {
+    wc = cjk_compose_seq(in, size, mac_korean_compose,
+                        sizeof(mac_korean_compose) / sizeof(u_int32_t));
+    if (!wc) return (size_t)-1;
+  } else if ((wc & 0xf000) == 0xe000) {
+    *size = 1;
+    return 0;
+  } else if (*size >= 2) {
+    ucs2_t comb = in[1];
+    size_t n = 1;
+
+    while ((comb & ~15) == 0xf870 ||
+          (comb >= 0x0300 && comb <= 0x036f) ||
+          (comb >= 0x20d0 && comb <= 0x20ea)) {
+      ucs2_t comp = cjk_compose(wc, comb, mac_korean_compose,
+                               sizeof(mac_korean_compose) / sizeof(u_int32_t));
+      if (!comp) break;
+      wc = comp;
+      if (++n == *size) break;
+      comb = in[n];
+    }
+    *size = n;
+  } else {
+    *size = 1;
+  }
+  if (wc <= 0x7f) {
+    out[0] = (u_int8_t)wc;
+    return 1;
+  }
+  return cjk_char_push(cjk_lookup(wc, mac_korean_uni2_index,
+                                 mac_korean_uni2_charset), out);
+}
+
+static size_t mac_korean_push(void *cd, char **inbuf, size_t *inbytesleft,
+                                   char **outbuf, size_t *outbytesleft)
+{
+  return cjk_generic_push(mac_korean_char_push,
+                         cd, inbuf, inbytesleft, outbuf, outbytesleft);
+}
+
+static size_t mac_korean_char_pull(ucs2_t* out, const u_int8_t* in, size_t* size)
+{
+  u_int16_t c = in[0];
+
+  if (c <= 0x7f) {
+    *size = 1;
+    *out = c;
+    return 1;
+  } else if (c >= 0xa1 && c <= 0xfe) {
+    if (*size >= 2) {
+      u_int8_t c2 = in[1];
+      if ((c2 >= 0x41 && c2 <= 0x7d) || (c2 >= 0x81 && c2 <= 0xfe)) {
+       *size = 2;
+       c = (c << 8) + c2;
+      } else {
+       errno = EILSEQ;
+       return (size_t)-1;
+      }
+    } else {
+      errno = EINVAL;
+      return (size_t)-1;
+    }
+  } else {
+    *size = 1;
+  }
+  return cjk_char_pull(cjk_lookup(c, mac_korean_2uni_index,
+                                 mac_korean_2uni_charset),
+                      out, mac_korean_compose);
+}
+
+static size_t mac_korean_pull(void *cd, char **inbuf, size_t *inbytesleft,
+                                   char **outbuf, size_t *outbytesleft)
+{
+  return cjk_generic_pull(mac_korean_char_pull,
+                         cd, inbuf, inbytesleft, outbuf, outbytesleft);
+}
+#endif
diff --git a/libatalk/unicode/charsets/mac_korean.h b/libatalk/unicode/charsets/mac_korean.h
new file mode 100644 (file)
index 0000000..578ac51
--- /dev/null
@@ -0,0 +1,771 @@
+/*
+ * MacKorean
+ * Copyright (C) TSUBAKIMOTO Hiroya <zorac@4000do.co.jp> 2004
+ *
+ * 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.
+ *
+ * Reference
+ * http://www.unicode.org/Public/MAPPINGS/VENDORS/APPLE/
+ */
+
+static const u_int16_t mac_korean_uni2_page00[][2] = {
+  /* 0x00a */ { 0x7a2d,    0 }, { 0x0880,    9 },
+};
+
+static const u_int16_t mac_korean_uni2_page02[][2] = {
+  /* 0x02b */ { 0x1000,   11 },
+  /* 0x02c */ { 0x0000,    0 }, { 0x1001,   12 }, { 0x0000,    0 }, { 0x0000,    0 },
+  /* 0x030 */ { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 },
+  /* 0x034 */ { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 },
+  /* 0x038 */ { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 },
+  /* 0x03c */ { 0x0000,    0 }, { 0x0020,   14 },
+};
+
+static const u_int16_t mac_korean_uni2_page20[][2] = {
+  /* 0x201 */ { 0x8878,   15 }, { 0x0004,   21 }, { 0x5670,   22 },
+  /* 0x204 */ { 0x7284,   29 }, { 0x0002,   35 }, { 0x0000,    0 }, { 0x7c00,   36 },
+  /* 0x208 */ { 0x0000,    0 }, { 0x0000,    0 }, { 0x1200,   41 }, { 0x0000,    0 },
+  /* 0x20c */ { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 },
+  /* 0x210 */ { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 },
+  /* 0x214 */ { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 },
+  /* 0x218 */ { 0x0000,    0 }, { 0x3000,   43 }, { 0x0000,    0 }, { 0x10df,   45 },
+  /* 0x21c */ { 0xa031,   53 }, { 0x0001,   58 }, { 0x03cf,   59 }, { 0x0001,   67 },
+  /* 0x220 */ { 0x1240,   68 }, { 0x8008,   71 }, { 0x0064,   73 }, { 0x1080,   76 },
+  /* 0x224 */ { 0x0128,   78 }, { 0x040b,   81 }, { 0xccc4,   85 }, { 0x0ecf,   92 },
+  /* 0x228 */ { 0x0033,  101 }, { 0x02e0,  105 }, { 0x0018,  109 }, { 0x1800,  111 },
+  /* 0x22c */ { 0xc000,  113 }, { 0x0c00,  115 }, { 0x4000,  117 }, { 0x0000,    0 },
+  /* 0x230 */ { 0x0040,  118 }, { 0x0010,  119 },
+};
+
+static const u_int16_t mac_korean_uni2_page24[][2] = {
+  /* 0x246 */ { 0x8000,  120 }, { 0x000f,  121 },
+  /* 0x248 */ { 0x00f8,  125 }, { 0x0000,    0 }, { 0x0000,    0 }, { 0xffc0,  130 },
+  /* 0x24c */ { 0xffff,  140 }, { 0x0000,    0 }, { 0xf800,  156 }, { 0x001f,  161 },
+  /* 0x250 */ { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 },
+  /* 0x254 */ { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 },
+  /* 0x258 */ { 0x0100,  166 }, { 0x0000,    0 }, { 0x2004,  167 }, { 0x8222,  169 },
+  /* 0x25c */ { 0x3608,  173 }, { 0x0000,    0 }, { 0x8040,  178 }, { 0x1800,  180 },
+  /* 0x260 */ { 0x0000,    0 }, { 0xa001,  182 }, { 0x8000,  185 }, { 0x0000,    0 },
+  /* 0x264 */ { 0x0000,    0 }, { 0x0000,    0 }, { 0x8040,  186 }, { 0x0000,    0 },
+  /* 0x268 */ { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 },
+  /* 0x26c */ { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 },
+  /* 0x270 */ { 0x0000,    0 }, { 0x0440,  188 }, { 0x0009,  190 }, { 0xa002,  192 },
+  /* 0x274 */ { 0x2083,  195 }, { 0x0040,  199 }, { 0x0000,    0 }, { 0xffc0,  200 },
+  /* 0x278 */ { 0xfc00,  210 }, { 0x581f,  216 }, { 0x0012,  224 }, { 0x0024,  226 },
+};
+
+static const u_int16_t mac_korean_uni2_page29[][2] = {
+  /* 0x293 */ { 0x02f0,  228 },
+  /* 0x294 */ { 0x0000,    0 }, { 0x0000,    0 }, { 0x003c,  233 }, { 0x0000,    0 },
+  /* 0x298 */ { 0x0062,  237 }, { 0x0180,  240 }, { 0x0008,  242 }, { 0xc000,  243 },
+  /* 0x29c */ { 0x0100,  245 }, { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 },
+  /* 0x2a0 */ { 0x0000,    0 }, { 0x0000,    0 }, { 0x0040,  246 }, { 0x0100,  247 },
+  /* 0x2a4 */ { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 }, { 0x0004,  248 },
+  /* 0x2a8 */ { 0x1800,  249 }, { 0x0006,  251 }, { 0x0000,    0 }, { 0x0000,    0 },
+  /* 0x2ac */ { 0x1860,  253 }, { 0x0000,    0 }, { 0x0100,  257 },
+};
+
+static const u_int16_t mac_korean_uni2_page30[][2] = {
+  /* 0x301 */ { 0xd3c4,  258 }, { 0x0001,  266 }, { 0x0040,  267 },
+};
+
+static const u_int16_t mac_korean_uni2_page32[][2] = {
+  /* 0x323 */ { 0x0202,  268 },
+  /* 0x324 */ { 0x0000,    0 }, { 0x07fe,  270 }, { 0x0000,    0 }, { 0x0000,    0 },
+  /* 0x328 */ { 0xfc00,  280 }, { 0x4011,  286 }, { 0x0020,  289 },
+};
+
+static const u_int16_t mac_korean_uni2_page33[][2] = {
+  /* 0x33c */ { 0x0800,  290 },
+};
+
+static const u_int16_t mac_korean_uni2_pagee0[][2] = {
+  /* 0xe00 */ { 0xffff,  291 }, { 0xffff,  307 }, { 0xffff,  323 }, { 0xffff,  339 },
+  /* 0xe04 */ { 0xffff,  355 }, { 0xffff,  371 }, { 0xffff,  387 }, { 0xffff,  403 },
+  /* 0xe08 */ { 0xffff,  419 }, { 0xffff,  435 }, { 0xffff,  451 }, { 0xffff,  467 },
+  /* 0xe0c */ { 0xffff,  483 }, { 0xffff,  499 }, { 0xffff,  515 }, { 0xffff,  531 },
+  /* 0xe10 */ { 0xffff,  547 }, { 0xffff,  563 }, { 0xffff,  579 }, { 0xffff,  595 },
+  /* 0xe14 */ { 0xffff,  611 }, { 0xffff,  627 }, { 0xffff,  643 }, { 0xffff,  659 },
+  /* 0xe18 */ { 0xffff,  675 }, { 0xffff,  691 }, { 0xffde,  707 }, { 0xfff7,  721 },
+  /* 0xe1c */ { 0xdfff,  736 }, { 0xffbf,  751 }, { 0xffe7,  766 }, { 0xff9f,  780 },
+  /* 0xe20 */ { 0xffff,  794 }, { 0xffff,  810 }, { 0xffff,  826 }, { 0xffff,  842 },
+  /* 0xe24 */ { 0xffff,  858 }, { 0xffff,  874 }, { 0xffff,  890 }, { 0xffff,  906 },
+  /* 0xe28 */ { 0xffff,  922 }, { 0xffff,  938 }, { 0xffff,  954 }, { 0xffff,  970 },
+  /* 0xe2c */ { 0xffff,  986 }, { 0x07ff, 1002 }, { 0x0000,    0 }, { 0x0000,    0 },
+  /* 0xe30 */ { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 }, { 0xfffc, 1013 },
+  /* 0xe34 */ { 0xffff, 1027 }, { 0xffff, 1043 }, { 0xffff, 1059 }, { 0xffff, 1075 },
+  /* 0xe38 */ { 0xffff, 1091 }, { 0x1fff, 1107 }, { 0x0000,    0 }, { 0x0000,    0 },
+  /* 0xe3c */ { 0xfc00, 1120 }, { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 },
+  /* 0xe40 */ { 0x0000,    0 }, { 0x1ffc, 1126 },
+};
+
+static const u_int16_t mac_korean_uni2_pagef8[][2] = {
+  /* 0xf80 */ { 0x1fe0, 1137 }, { 0x0000,    0 }, { 0x0000,    0 }, { 0x2000, 1145 },
+  /* 0xf84 */ { 0xffff, 1146 },
+};
+
+static const u_int16_t mac_korean_uni2_pagefe[][2] = {
+  /* 0xfe5 */ { 0x0600, 1162 }, { 0x0000,    0 }, { 0x0000,    0 },
+  /* 0xfe8 */ { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 },
+  /* 0xfec */ { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 },
+  /* 0xff0 */ { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 },
+  /* 0xff4 */ { 0x0000,    0 }, { 0x4000, 1164 }, { 0x0000,    0 }, { 0x0000,    0 },
+  /* 0xff8 */ { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 },
+  /* 0xffc */ { 0x0000,    0 }, { 0x0000,    0 }, { 0x002f, 1165 },
+};
+
+static const cjk_index_t mac_korean_uni2_index[] = {
+  { { 0x00a0, 0x00bf }, mac_korean_uni2_page00 },
+  { { 0x02b0, 0x03df }, mac_korean_uni2_page02 },
+  { { 0x2010, 0x231f }, mac_korean_uni2_page20 },
+  { { 0x2460, 0x27bf }, mac_korean_uni2_page24 },
+  { { 0x2930, 0x2aef }, mac_korean_uni2_page29 },
+  { { 0x3010, 0x303f }, mac_korean_uni2_page30 },
+  { { 0x3230, 0x32af }, mac_korean_uni2_page32 },
+  { { 0x33c0, 0x33cf }, mac_korean_uni2_page33 },
+  { { 0xe000, 0xe41f }, mac_korean_uni2_pagee0 },
+  { { 0xf800, 0xf84f }, mac_korean_uni2_pagef8 },
+  { { 0xfe50, 0xffef }, mac_korean_uni2_pagefe },
+  { { 0, 0 }, 0 }
+};
+
+static const u_int16_t mac_korean_uni2_charset[] = {
+  0x0080, 0xa1cb, 0xa1cc, 0xa1cd, 0x0083, 0xa65c, 0xa1fe, 0xffff,
+  0xffff, 0xa1a4, 0xa65d, 0xa198, 0xa2b0, 0xa2a6, 0xa76a, 0xa1a9,
+  0xa1aa, 0xffff, 0xa1ab, 0xa170, 0xa16f, 0xa655, 0xa5de, 0xadad,
+  0xadab, 0xa65a, 0xa65b, 0xa784, 0xa3fe, 0xa64d, 0xa787, 0xa785,
+  0xa196, 0xa197, 0xa64e, 0xa16d, 0xa171, 0xa172, 0xa17a, 0xa17c,
+  0xa17d, 0x0081, 0xffff, 0xac53, 0xac52, 0xa882, 0xa87c, 0xa87b,
+  0xa883, 0xa881, 0xac50, 0xac51, 0xa892, 0xa893, 0xa89e, 0xa89f,
+  0xa84b, 0xa84a, 0xa849, 0xac6a, 0xac6c, 0xac6b, 0xac6d, 0xac72,
+  0xac74, 0xac73, 0xac75, 0xac41, 0xa751, 0xa773, 0xa774, 0xa75c,
+  0xa753, 0xa768, 0xa755, 0xa756, 0xa2fe, 0xffff, 0xa49a, 0xa499,
+  0xa49b, 0xa769, 0xa759, 0xa758, 0xa777, 0xa764, 0xa75a, 0xa75b,
+  0xa1ec, 0xa1ed, 0xa76f, 0xa770, 0xa487, 0xa488, 0xa489, 0xa48a,
+  0xa48f, 0xa490, 0xa491, 0xa481, 0xa482, 0xa485, 0xa486, 0xa772,
+  0xa771, 0xa75d, 0xa75e, 0xa75f, 0xffff, 0xa76c, 0xa49d, 0xa775,
+  0xa776, 0xa483, 0xa484, 0xa492, 0xa493, 0xa2fd, 0xa778, 0xa761,
+  0xa7f0, 0xa7f1, 0xa7f2, 0xa7f3, 0xa7f4, 0xaaf4, 0xaaf5, 0xaaf6,
+  0xaaf7, 0xaaf8, 0xa386, 0xa387, 0xa388, 0xa389, 0xa38a, 0xa38b,
+  0xa38c, 0xa38d, 0xa38e, 0xa38f, 0xa390, 0xa391, 0xa392, 0xa393,
+  0xa394, 0xa395, 0xa396, 0xa397, 0xa398, 0xa399, 0xa39a, 0xa39b,
+  0xa39c, 0xa39d, 0xa39e, 0xa39f, 0xa6ef, 0xa6f0, 0xa6f1, 0xa6f2,
+  0xa6f3, 0xa6f4, 0xa6f5, 0xa6f6, 0xa6f7, 0xa6f8, 0xa78f, 0xa678,
+  0xa74a, 0xa766, 0xa795, 0xa796, 0xa794, 0xa797, 0xa2c1, 0xa79c,
+  0xa675, 0xa684, 0xa790, 0xa66f, 0xa746, 0xa79a, 0xa677, 0xac8d,
+  0xac8e, 0xa693, 0xa798, 0xa648, 0xa66d, 0xa66c, 0xa688, 0xa672,
+  0xa653, 0xa652, 0xa67c, 0xa699, 0xa68d, 0xa654, 0xa683, 0xa673,
+  0xa6e5, 0xa6e6, 0xa6e7, 0xa6e8, 0xa6e9, 0xa6ea, 0xa6eb, 0xa6ec,
+  0xa6ed, 0xa6ee, 0xa355, 0xa356, 0xa357, 0xa358, 0xa359, 0xa35a,
+  0xa35b, 0xa35c, 0xa35d, 0xa35e, 0xac5e, 0xa86a, 0xa860, 0xa878,
+  0xa874, 0xac48, 0xa85c, 0xac43, 0xa88d, 0xa889, 0xa886, 0xa88b,
+  0xa88c, 0xa86f, 0xa871, 0xa870, 0xa872, 0xa799, 0xa159, 0xa15a,
+  0xa199, 0xa19a, 0xa49c, 0xa668, 0xa66e, 0xa664, 0xa47d, 0xa760,
+  0xa77b, 0xa494, 0xa495, 0xa496, 0xa497, 0xa48b, 0xa48d, 0xa48c,
+  0xa48e, 0xa76b, 0xa742, 0xa15d, 0xa15e, 0xa15f, 0xa160, 0xa1ad,
+  0xada9, 0xadaa, 0xa69e, 0xa743, 0xa79d, 0xa79e, 0xa7f5, 0xa7f6,
+  0xa7f7, 0xa7f8, 0xa7f9, 0xa7fa, 0xa7fb, 0xa7fc, 0xa7fd, 0xa7fe,
+  0xad71, 0xad72, 0xad73, 0xad74, 0xad75, 0xad76, 0xad70, 0xab5c,
+  0xa782, 0xab6c, 0xa79f, 0xa18a, 0xadb0, 0xa157, 0xa24b, 0xa158,
+  0xa24c, 0xa16c, 0xa767, 0xa541, 0xa542, 0xa543, 0xa544, 0xa545,
+  0xa546, 0xa547, 0xa548, 0xa549, 0xa54a, 0xa179, 0xa765, 0xa762,
+  0xa178, 0xa183, 0xa161, 0xa163, 0xa184, 0xa162, 0xa164, 0xa181,
+  0xa182, 0xa647, 0xa176, 0xa2fa, 0xa173, 0x0082, 0xa2fb, 0xa2fc,
+  0xa16b, 0xa169, 0xa643, 0xa167, 0xa16a, 0xa168, 0x00ff, 0xadae,
+  0xa5dc, 0xadac, 0xa5dd, 0xa786, 0xa651, 0xa64f, 0xa64b, 0xa1a0,
+  0xa19d, 0xa690, 0xac89, 0xa869, 0xa86b, 0xac5d, 0xac66, 0xa863,
+  0xac62, 0xa853, 0xac55, 0xa842, 0xa84e, 0xa85f, 0xac8b, 0xa86d,
+  0xac60, 0xac68, 0xa865, 0xac64, 0xa855, 0xac57, 0xa843, 0xa84f,
+  0xa861, 0xac8a, 0xa86c, 0xac67, 0xa864, 0xac63, 0xa854, 0xac56,
+  0xa841, 0xa84d, 0xac8c, 0xa86e, 0xac61, 0xac69, 0xa866, 0xac65,
+  0xa856, 0xac58, 0xa844, 0xa850, 0xa862, 0xa851, 0xa852, 0xa845,
+  0xa846, 0xa847, 0xa848, 0xac7a, 0xac85, 0xa88a, 0xac77, 0xac82,
+  0xa887, 0xac78, 0xa87d, 0xac83, 0xa888, 0xa899, 0xac4d, 0xa898,
+  0xac4c, 0xa89b, 0xa89a, 0xa895, 0xa84c, 0xa85b, 0xa857, 0xac47,
+  0xa897, 0xac6e, 0xada6, 0xa88e, 0xa873, 0xa877, 0xac59, 0xac4f,
+  0xa85d, 0xa859, 0xac70, 0xada7, 0xa890, 0xa875, 0xa879, 0xac5b,
+  0xadaf, 0xa858, 0xac46, 0xa896, 0xac6f, 0xada5, 0xa88f, 0xac5a,
+  0xac4e, 0xa85e, 0xa85a, 0xac71, 0xada8, 0xa891, 0xa876, 0xa87a,
+  0xac5c, 0xa752, 0xa188, 0xa189, 0xa177, 0xa174, 0xa498, 0xa49e,
+  0xa185, 0xa757, 0xa186, 0xa754, 0xa779, 0xa175, 0xa17b, 0xa76e,
+  0xa763, 0xa187, 0xa76d, 0xa77a, 0xa748, 0xa54c, 0xa54d, 0xa54e,
+  0xa54f, 0xa550, 0xa551, 0xa552, 0xa553, 0xa554, 0xa54b, 0xa473,
+  0xa35f, 0xa474, 0xa360, 0xa475, 0xa361, 0xa476, 0xa362, 0xa477,
+  0xa363, 0xa478, 0xa364, 0xa479, 0xa365, 0xa47a, 0xa366, 0xa47b,
+  0xa367, 0xa47c, 0xa368, 0xa656, 0xa659, 0xa78d, 0xa78e, 0xa78c,
+  0xa68a, 0xa749, 0xa66b, 0xa66a, 0xa745, 0xa79b, 0xa665, 0xa78b,
+  0xa662, 0xa657, 0xa789, 0xa78a, 0xa788, 0xa74e, 0xa689, 0xa682,
+  0xa791, 0xa792, 0xa744, 0xa669, 0xa793, 0xa670, 0xa671, 0xa676,
+  0xa65e, 0xac8f, 0xa65f, 0xac90, 0xa698, 0xa697, 0xa741, 0xa687,
+  0xa679, 0xa67b, 0xa69b, 0xa67a, 0xa68e, 0xa469, 0xa46a, 0xa46b,
+  0xa46c, 0xa46d, 0xa46e, 0xa46f, 0xa470, 0xa471, 0xa472, 0xa685,
+  0xac7d, 0xac88, 0xa885, 0xac79, 0xac84, 0xac76, 0xac81, 0xac7b,
+  0xac86, 0xac7c, 0xac87, 0xa884, 0xac45, 0xac44, 0xa243, 0xa241,
+  0xa153, 0xa165, 0xa155, 0xa151, 0xa244, 0xa242, 0xa154, 0xa166,
+  0xa156, 0xa152, 0xa667, 0xa49f, 0xa5db, 0xa18b, 0xa14b, 0xa14c,
+  0xa149, 0xa14a, 0xada1, 0xa143, 0xa145, 0xa141, 0xada2, 0xa144,
+  0xa146, 0xa142, 0xada3, 0xa147, 0xada4, 0xa148, 0xa249, 0xa15b,
+  0xa24a, 0xa15c, 0xa67d, 0xa247, 0xa248, 0xa6f9, 0xa6fa, 0xa6fb,
+  0xa6fc, 0xa6fd, 0xa6fe, 0xa5f9, 0xa5fa, 0xa5fb, 0xa5fc, 0xa783,
+  0xad55, 0xa18c, 0xad5b, 0xa192, 0xad57, 0xa18e, 0xad5d, 0xa194,
+  0xad56, 0xa18d, 0xad59, 0xa190, 0xab6d, 0xaa6e, 0xab5a, 0xaa5a,
+  0xaa66, 0xad5c, 0xa193, 0xad5a, 0xa191, 0xaa9f, 0xaa58, 0xa750,
+  0xa74f, 0xab60, 0xaa69, 0xab5e, 0xaa62, 0xab63, 0xaa6c, 0xab5b,
+  0xaa5c, 0xad5e, 0xa195, 0xa692, 0xab44, 0xaa54, 0xab65, 0xab5d,
+  0xaa5f, 0xaa5d, 0xad58, 0xa18f, 0xab6b, 0xad6f, 0xaa68, 0xaa63,
+  0xab69, 0xaa70, 0xaa65, 0xab58, 0xaa57, 0xab59, 0xaa6d, 0xab62,
+  0xaa6b, 0xab67, 0xad69, 0xad6a, 0xad6d, 0xab46, 0xab66, 0xaa61,
+  0xad6c, 0xab64, 0xaa6f, 0xaa67, 0xad6b, 0xab68, 0xaa5e, 0xaa59,
+  0xaa6a, 0xab5f, 0xab45, 0xaa60, 0xa77c, 0xaa55, 0xaa64, 0xad6e,
+  0xab6a, 0xab61, 0xaa5b, 0xab75, 0xab55, 0xab43, 0xaa50, 0xab56,
+  0xab47, 0xaa96, 0xaa9e, 0xab42, 0xab76, 0xaa8c, 0xaa8b, 0xab77,
+  0xac91, 0xab48, 0xaa42, 0xaa8e, 0xaa45, 0xaa94, 0xaa4b, 0xaa53,
+  0xaa81, 0xaa82, 0xaa8d, 0xaa44, 0xaa83, 0xaa97, 0xaa4d, 0xab49,
+  0xaa9a, 0xaa90, 0xaa47, 0xaa95, 0xaa4c, 0xab6e, 0xaa84, 0xab4a,
+  0xab4b, 0xac93, 0xaa98, 0xaa93, 0xaa4a, 0xaa9c, 0xab6f, 0xab4c,
+  0xab57, 0xaa85, 0xaa9b, 0xaa51, 0xab4d, 0xab4e, 0xaa56, 0xab53,
+  0xaa41, 0xab4f, 0xaa9d, 0xab71, 0xab72, 0xac96, 0xaa99, 0xaa52,
+  0xac95, 0xab70, 0xaa86, 0xaa4e, 0xab50, 0xaa91, 0xaa48, 0xaa92,
+  0xaa49, 0xab41, 0xaa71, 0xaa7d, 0xaa43, 0xab51, 0xac94, 0xab73,
+  0xaa87, 0xac92, 0xaa88, 0xab52, 0xaa89, 0xaa4f, 0xaa8a, 0xab74,
+  0xab78, 0xaa8f, 0xaa46, 0xab54, 0xac97, 0xacc2, 0xa455, 0xa341,
+  0xa2e6, 0xa441, 0xacc3, 0xa456, 0xa342, 0xa2e7, 0xa442, 0xacc4,
+  0xa457, 0xa343, 0xa2e8, 0xa443, 0xacc5, 0xa458, 0xa344, 0xa2e9,
+  0xa444, 0xacc6, 0xa459, 0xa345, 0xa2ea, 0xa445, 0xacc7, 0xa45a,
+  0xa346, 0xa2eb, 0xa446, 0xacc8, 0xa45b, 0xa347, 0xa2ec, 0xa447,
+  0xacc9, 0xa45c, 0xa348, 0xa2ed, 0xa448, 0xacca, 0xa45d, 0xa349,
+  0xa2ee, 0xa449, 0xa661, 0xad41, 0xad47, 0xad43, 0xad49, 0xad42,
+  0xad45, 0xad48, 0xad46, 0xad4a, 0xad44, 0xad7d, 0xad77, 0xad78,
+  0xad7b, 0xad7a, 0xad79, 0xaa76, 0xad7c, 0xab9b, 0xaa77, 0xab9c,
+  0xab99, 0xab98, 0xab97, 0xab9d, 0xab8a, 0xab87, 0xaa73, 0xaa75,
+  0xab9e, 0xab79, 0xaa72, 0xab7a, 0xab9a, 0xab89, 0xab86, 0xab88,
+  0xab7b, 0xab8b, 0xab8c, 0xab7c, 0xab8d, 0xaa78, 0xab8e, 0xaa7c,
+  0xab9f, 0xab8f, 0xab90, 0xaa79, 0xab91, 0xab7d, 0xaa7a, 0xab92,
+  0xab93, 0xaa74, 0xab94, 0xab81, 0xab82, 0xab83, 0xab84, 0xab95,
+  0xab85, 0xab96, 0xaa7b, 0xaaf9, 0xaafa, 0xaafb, 0xaafc, 0xaafd,
+  0xaafe, 0xabf7, 0xabf8, 0xabf9, 0xabfa, 0xa44a, 0xa44b, 0xa44c,
+  0xa44d, 0xa44e, 0xa44f, 0xa450, 0xa451, 0xa452, 0xa453, 0xa454,
+  0xad68, 0xad5f, 0xad65, 0xad61, 0xad67, 0xad60, 0xad63, 0xad66,
+  0xad64, 0xad62, 0xa77d, 0xa2ef, 0xa2f0, 0xa2f1, 0xa2f2, 0xa2f3,
+  0xa2f4, 0xa2f5, 0xa2f6, 0xa2f7, 0xa2f8, 0xa2f9, 0xad54, 0xad4b,
+  0xad51, 0xad4d, 0xad53, 0xad4c, 0xad4f, 0xad52, 0xad50, 0xad4e,
+  0xa781, 0xa34a, 0xa34b, 0xa34c, 0xa34d, 0xa34e, 0xa34f, 0xa350,
+  0xa351, 0xa352, 0xa353, 0xa354, 0xa45e, 0xa45f, 0xa460, 0xa461,
+  0xa462, 0xa463, 0xa464, 0xa465, 0xa466, 0xa467, 0xa468, 0xaccb,
+  0xaccc, 0xaccd, 0xacce, 0xaccf, 0xacd0, 0xacf2, 0xacf3, 0xacf4,
+  0xacf5, 0xacf6, 0xa369, 0xa36a, 0xa36b, 0xa36c, 0xa36d, 0xa36e,
+  0xa36f, 0xa370, 0xa371, 0xa372, 0xa373, 0xa374, 0xa375, 0xa376,
+  0xa377, 0xa378, 0xa379, 0xa37a, 0xa37b, 0xa37c, 0xa37d, 0xa381,
+  0xa382, 0xa383, 0xa384, 0xa385, 0xa646, 0xa64c, 0xa555, 0xa941,
+  0xa556, 0xa942, 0xa557, 0xa943, 0xa558, 0xa944, 0xa559, 0xa945,
+  0xa55a, 0xa946, 0xa55b, 0xa947, 0xa55c, 0xa948, 0xa55d, 0xa949,
+  0xa55e, 0xa94a, 0xa55f, 0xa94b, 0xa560, 0xa94c, 0xa561, 0xa94d,
+  0xa562, 0xa94e, 0xa563, 0xa94f, 0xa564, 0xa950, 0xa565, 0xa951,
+  0xa566, 0xa952, 0xa567, 0xa953, 0xa568, 0xa954, 0xa569, 0xa955,
+  0xa56a, 0xa956, 0xa56b, 0xa957, 0xa56c, 0xa958, 0xa56d, 0xa959,
+  0xa56e, 0xa95a, 0xa56f, 0xa95b, 0xa570, 0xa95c, 0xa571, 0xa95d,
+  0xa572, 0xa95e, 0xa573, 0xa95f, 0xa574, 0xa960, 0xa575, 0xa961,
+  0xa576, 0xa962, 0xa577, 0xa963, 0xa578, 0xa964, 0xa579, 0xa965,
+  0xa57a, 0xa966, 0xa57b, 0xa967, 0xa57c, 0xa968, 0xa57d, 0xa969,
+  0xa581, 0xa96a, 0xa582, 0xa96b, 0xa583, 0xa96c, 0xa584, 0xa96d,
+  0xa585, 0xa96e, 0xa586, 0xa96f, 0xa587, 0xa970, 0xa588, 0xa971,
+  0xa589, 0xa972, 0xa58a, 0xa973, 0xa58b, 0xa974, 0xa644, 0xa645,
+  0xa650, 0xa666, 0xa660, 0xa691, 0xa686, 0xa641, 0xa245, 0xa14f,
+  0xa246, 0xa150, 0xa5da, 0xa19f, 0xa64a, 0xa19c, 0xa19e, 0xa649,
+  0x0084, 0xa658, 0xa663, 0xa69f, 0xa68f, 0xa681, 0xa674, 0xa696,
+  0xa69a, 0xa642, 0xa16e, 0xa894, 0xac54, 0xac42, 0xac49, 0xac5f,
+  0xa867, 0xa868, 0xa89d, 0xa89c, 0xac4b, 0xac4a, 0xa747, 0xa74b,
+  0xa74c, 0xa74d, 0xa14d, 0xa14e, 0xffff, 0xffff, 0xffff, 0xffff,
+  0xffff, 0xffff,
+};
+
+static const u_int16_t mac_korean_2uni_page00[][2] = {
+  /* 0x008 */ { 0x001f,    0 }, { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 },
+  /* 0x00c */ { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 }, { 0x8000,    5 },
+};
+
+static const u_int16_t mac_korean_2uni_pagea1[][2] = {
+  /* 0xa14 */ { 0xfffe,    6 }, { 0xffff,   21 }, { 0xffff,   37 }, { 0x3fff,   53 },
+  /* 0xa18 */ { 0xfffe,   67 }, { 0xf7ff,   82 }, { 0x2e11,   97 }, { 0x0000,    0 },
+  /* 0xa1c */ { 0x3800,  103 }, { 0x0000,    0 }, { 0x3000,  106 }, { 0x4000,  108 },
+  /* 0xa20 */ { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 },
+  /* 0xa24 */ { 0x1ffe,  109 }, { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 },
+  /* 0xa28 */ { 0x0000,    0 }, { 0x0000,    0 }, { 0x0040,  121 }, { 0x0001,  122 },
+  /* 0xa2c */ { 0x0002,  123 }, { 0x0000,    0 }, { 0xffc0,  124 }, { 0x7fff,  134 },
+  /* 0xa30 */ { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 },
+  /* 0xa34 */ { 0xfffe,  149 }, { 0xffff,  164 }, { 0xffff,  180 }, { 0x3fff,  196 },
+  /* 0xa38 */ { 0xfffe,  210 }, { 0xffff,  225 }, { 0x0000,    0 }, { 0x0000,    0 },
+  /* 0xa3c */ { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 }, { 0x4000,  241 },
+  /* 0xa40 */ { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 },
+  /* 0xa44 */ { 0xfffe,  242 }, { 0xffff,  257 }, { 0xffff,  273 }, { 0x3fff,  289 },
+  /* 0xa48 */ { 0xfffe,  303 }, { 0xffff,  318 }, { 0x0000,    0 }, { 0x0000,    0 },
+  /* 0xa4c */ { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 },
+  /* 0xa50 */ { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 },
+  /* 0xa54 */ { 0xfffe,  334 }, { 0xffff,  349 }, { 0xffff,  365 }, { 0x3fff,  381 },
+  /* 0xa58 */ { 0x0ffe,  395 }, { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 },
+  /* 0xa5c */ { 0x0000,    0 }, { 0x7c00,  406 }, { 0x0000,    0 }, { 0x1e00,  411 },
+  /* 0xa60 */ { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 },
+  /* 0xa64 */ { 0xfffe,  415 }, { 0xffff,  430 }, { 0xffff,  446 }, { 0x3fff,  462 },
+  /* 0xa68 */ { 0xe7fe,  476 }, { 0xcfcf,  489 }, { 0x0000,    0 }, { 0x0000,    0 },
+  /* 0xa6c */ { 0x0000,    0 }, { 0x0000,    0 }, { 0xffe0,  501 }, { 0x7fff,  512 },
+  /* 0xa70 */ { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 },
+  /* 0xa74 */ { 0xfffe,  527 }, { 0xffff,  542 }, { 0xffff,  558 }, { 0x3fff,  574 },
+  /* 0xa78 */ { 0xfffe,  588 }, { 0xffff,  603 }, { 0x0000,    0 }, { 0x0000,    0 },
+  /* 0xa7c */ { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 }, { 0x7fff,  619 },
+  /* 0xa80 */ { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 },
+  /* 0xa84 */ { 0xfffe,  634 }, { 0xffff,  649 }, { 0xffff,  665 }, { 0x3fff,  681 },
+  /* 0xa88 */ { 0xfffe,  695 }, { 0xffff,  710 }, { 0x0000,    0 }, { 0x0000,    0 },
+  /* 0xa8c */ { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 },
+  /* 0xa90 */ { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 },
+  /* 0xa94 */ { 0xfffe,  726 }, { 0xffff,  741 }, { 0xffff,  757 }, { 0x001f,  773 },
+  /* 0xa98 */ { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 },
+  /* 0xa9c */ { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 },
+  /* 0xaa0 */ { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 },
+  /* 0xaa4 */ { 0xfffe,  778 }, { 0xffff,  793 }, { 0xffff,  809 }, { 0x3fff,  825 },
+  /* 0xaa8 */ { 0xfffe,  839 }, { 0xffff,  854 }, { 0x0000,    0 }, { 0x0000,    0 },
+  /* 0xaac */ { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 }, { 0x7ff0,  870 },
+  /* 0xab0 */ { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 },
+  /* 0xab4 */ { 0xfffe,  881 }, { 0xffff,  896 }, { 0xffff,  912 }, { 0x3fff,  928 },
+  /* 0xab8 */ { 0xfffe,  942 }, { 0xffff,  957 }, { 0x0000,    0 }, { 0x0000,    0 },
+  /* 0xabc */ { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 }, { 0x0780,  973 },
+  /* 0xac0 */ { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 },
+  /* 0xac4 */ { 0xfffe,  977 }, { 0xffff,  992 }, { 0xffff, 1008 }, { 0x3fff, 1024 },
+  /* 0xac8 */ { 0xfffe, 1038 }, { 0x00ff, 1053 }, { 0x0000,    0 }, { 0x0000,    0 },
+  /* 0xacc */ { 0xfffc, 1061 }, { 0x0001, 1075 }, { 0x0000,    0 }, { 0x007c, 1076 },
+  /* 0xad0 */ { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 }, { 0x0000,    0 },
+  /* 0xad4 */ { 0xfffe, 1081 }, { 0xffff, 1096 }, { 0xffff, 1112 }, { 0x3fff, 1128 },
+  /* 0xad8 */ { 0x0000,    0 }, { 0x0000,    0 }, { 0xfffe, 1142 }, { 0x0001, 1157 },
+};
+
+static const cjk_index_t mac_korean_2uni_index[] = {
+  { { 0x0080, 0x00ff }, mac_korean_2uni_page00 },
+  { { 0xa140, 0xadbf }, mac_korean_2uni_pagea1 },
+  { { 0, 0 }, 0 }
+};
+
+static const u_int16_t mac_korean_2uni_charset[] = {
+  0x00a0, 0x20a9, 0xe022, 0x00a9, 0xe41c, 0xe02b, 0xe12a, 0xe12e,
+  0xe128, 0xe12c, 0xe129, 0xe12d, 0xe130, 0xe132, 0xe125, 0xe126,
+  0xe123, 0xe124, 0xfe59, 0xfe5a, 0xe413, 0xe415, 0xe118, 0xe11e,
+  0xe115, 0xe11b, 0xe117, 0xe11d, 0xe002, 0xe004, 0x2985, 0x2986,
+  0xe134, 0xe136, 0x3016, 0x3017, 0x3018, 0x3019, 0xe017, 0xe01a,
+  0xe018, 0xe01b, 0xe116, 0xe11c, 0xe028, 0xe02a, 0xe026, 0xe029,
+  0xe025, 0xe006, 0x2051, 0xf840, 0x201f, 0x201b, 0x207a, 0x207b,
+  0xe021, 0xe0a2, 0xe0aa, 0xe01f, 0xe0a1, 0xe015, 0xe012, 0x207c,
+  0xe0ab, 0x207d, 0x207e, 0xe01c, 0xe01d, 0xe016, 0xe019, 0xe0a5,
+  0xe0a7, 0xe0ae, 0xe09f, 0xe0a0, 0xe000, 0xe122, 0xe146, 0xe14e,
+  0xe14a, 0xe170, 0xe150, 0xe159, 0xe148, 0xe157, 0xe14c, 0xe167,
+  0x204c, 0x204d, 0x02bc, 0x2997, 0x2998, 0xe419, 0xe035, 0xe41a,
+  0xe417, 0xe034, 0x00b7, 0x2013, 0x2014, 0x2016, 0x301c, 0x00a2,
+  0x00a3, 0x00a5, 0x226a, 0x226b, 0x00ac, 0xe114, 0xe11a, 0xe113,
+  0xe119, 0xe412, 0xe414, 0xe138, 0xe139, 0xe133, 0xe135, 0xe003,
+  0xe005, 0x02dc, 0x02d0, 0x25c9, 0xe1fe, 0xe203, 0xe208, 0xe20d,
+  0xe212, 0xe217, 0xe21c, 0xe221, 0xe226, 0xe289, 0xe28a, 0xe28b,
+  0xe28c, 0xe28d, 0xe28e, 0xe28f, 0xe290, 0xe291, 0xe292, 0xe293,
+  0xe020, 0xe023, 0xe024, 0x22ee, 0x2237, 0xe1fd, 0xe202, 0xe207,
+  0xe20c, 0xe211, 0xe216, 0xe21b, 0xe220, 0xe225, 0xe29f, 0xe2a0,
+  0xe2a1, 0xe2a2, 0xe2a3, 0xe2a4, 0xe2a5, 0xe2a6, 0xe2a7, 0xe2a8,
+  0xe2a9, 0x278a, 0x278b, 0x278c, 0x278d, 0x278e, 0x278f, 0x2790,
+  0x2791, 0x2792, 0x2793, 0xe0bd, 0xe0bf, 0xe0c1, 0xe0c3, 0xe0c5,
+  0xe0c7, 0xe0c9, 0xe0cb, 0xe0cd, 0xe0cf, 0xe2c0, 0xe2c1, 0xe2c2,
+  0xe2c3, 0xe2c4, 0xe2c5, 0xe2c6, 0xe2c7, 0xe2c8, 0xe2c9, 0xe2ca,
+  0xe2cb, 0xe2cc, 0xe2cd, 0xe2ce, 0xe2cf, 0xe2d0, 0xe2d1, 0xe2d2,
+  0xe2d3, 0xe2d4, 0xe2d5, 0xe2d6, 0xe2d7, 0xe2d8, 0xe2d9, 0x24b6,
+  0x24b7, 0x24b8, 0x24b9, 0x24ba, 0x24bb, 0x24bc, 0x24bd, 0x24be,
+  0x24bf, 0x24c0, 0x24c1, 0x24c2, 0x24c3, 0x24c4, 0x24c5, 0x24c6,
+  0x24c7, 0x24c8, 0x24c9, 0x24ca, 0x24cb, 0x24cc, 0x24cd, 0x24ce,
+  0x24cf, 0x203e, 0xe1ff, 0xe204, 0xe209, 0xe20e, 0xe213, 0xe218,
+  0xe21d, 0xe222, 0xe227, 0xe273, 0xe274, 0xe275, 0xe276, 0xe277,
+  0xe278, 0xe279, 0xe27a, 0xe27b, 0xe27c, 0xe27d, 0xe1fc, 0xe201,
+  0xe206, 0xe20b, 0xe210, 0xe215, 0xe21a, 0xe21f, 0xe224, 0xe2aa,
+  0xe2ab, 0xe2ac, 0xe2ad, 0xe2ae, 0xe2af, 0xe2b0, 0xe2b1, 0xe2b2,
+  0xe2b3, 0xe2b4, 0xe0fa, 0xe0fb, 0xe0fc, 0xe0fd, 0xe0fe, 0xe0ff,
+  0xe100, 0xe101, 0xe102, 0xe103, 0xe0bc, 0xe0be, 0xe0c0, 0xe0c2,
+  0xe0c4, 0xe0c6, 0xe0c8, 0xe0ca, 0xe0cc, 0xe0ce, 0x2a26, 0x227a,
+  0x227b, 0x22ce, 0x22cf, 0x2280, 0x2281, 0x2270, 0x2271, 0x2272,
+  0x2273, 0x2ac5, 0x2acb, 0x2ac6, 0x2acc, 0x2276, 0x2277, 0x2279,
+  0x22da, 0x22db, 0x2a8b, 0x2a8c, 0x2a91, 0x2a92, 0xe0a3, 0x2245,
+  0x2243, 0x2248, 0x29a3, 0x22a4, 0xe0a4, 0xe120, 0xe008, 0xe009,
+  0xe00a, 0xe00b, 0xe00c, 0xe00d, 0xe00e, 0xe00f, 0xe010, 0xe011,
+  0xe0bb, 0xe0b2, 0xe0b3, 0xe0b4, 0xe0b5, 0xe0b6, 0xe0b7, 0xe0b8,
+  0xe0b9, 0xe0ba, 0xe333, 0xe335, 0xe337, 0xe339, 0xe33b, 0xe33d,
+  0xe33f, 0xe341, 0xe343, 0xe345, 0xe347, 0xe349, 0xe34b, 0xe34d,
+  0xe34f, 0xe351, 0xe353, 0xe355, 0xe357, 0xe359, 0xe35b, 0xe35d,
+  0xe35f, 0xe361, 0xe363, 0xe365, 0xe367, 0xe369, 0xe36b, 0xe36d,
+  0xe36f, 0xe371, 0xe373, 0xe375, 0xe377, 0xe379, 0xe37b, 0xe37d,
+  0xe37f, 0xe381, 0xe383, 0xe385, 0xe387, 0xe389, 0xe38b, 0xe38d,
+  0xe38f, 0xe391, 0xe393, 0xe395, 0xe397, 0xe399, 0xe416, 0xe121,
+  0xe02d, 0xe02f, 0x2034, 0xe140, 0xe141, 0xe142, 0xe143, 0xe3cf,
+  0xf83d, 0xe027, 0xe39b, 0xe39c, 0xe2da, 0xe01e, 0x266f, 0xe41b,
+  0xe418, 0xe033, 0xe332, 0x2042, 0x204e, 0xe032, 0xe3ca, 0xe031,
+  0x273d, 0x2731, 0x2747, 0x2022, 0xe0d0, 0xe0de, 0xf805, 0xe0d1,
+  0x2039, 0x203a, 0x00ab, 0x00bb, 0xe0ed, 0xe0ef, 0xe3cc, 0xe228,
+  0xe0dd, 0xf806, 0x29c8, 0xe0db, 0xe3cb, 0xe11f, 0x29be, 0xe0e8,
+  0xe0d8, 0xe0d7, 0x271a, 0x2716, 0x29bf, 0x25ef, 0xe0ea, 0xe0eb,
+  0x2723, 0x2756, 0xf80a, 0x25cc, 0xe0ec, 0x2610, 0x25a2, 0xe0f5,
+  0xe0f8, 0xe0f6, 0x273f, 0xe137, 0xf809, 0xe0e4, 0x274d, 0x25cd,
+  0xe104, 0xe3ce, 0xe0f4, 0x2720, 0xe0e3, 0xe0d5, 0x2741, 0xe0f9,
+  0xf808, 0xe036, 0xe3cd, 0xe168, 0x262f, 0xf80b, 0xe0f2, 0xe0f1,
+  0x2740, 0xf80c, 0xe0f7, 0x3020, 0xf807, 0x2776, 0x2777, 0x2778,
+  0x2779, 0x277a, 0x277b, 0x277c, 0x277d, 0x277e, 0x277f, 0x24eb,
+  0x24ec, 0x24ed, 0x24ee, 0x24ef, 0x24f0, 0x24f1, 0x24f2, 0x24f3,
+  0x24f4, 0xe13a, 0xe13b, 0xe13c, 0xe13d, 0xe13e, 0xe13f, 0xe0f3,
+  0x3012, 0x3036, 0xe0e7, 0xe0d9, 0x25fb, 0xf84c, 0xe0b1, 0xe0d6,
+  0x25ad, 0xf84d, 0xf84e, 0xf84f, 0xe0e2, 0xe15d, 0xe15c, 0x2206,
+  0xe09e, 0x221f, 0xe0a8, 0x2225, 0x2226, 0xe0a6, 0x2253, 0x2251,
+  0x2266, 0x2267, 0x2213, 0x2295, 0x2296, 0x2297, 0x2a38, 0x2314,
+  0xe014, 0xe0ad, 0x2262, 0xe013, 0x25b1, 0xe007, 0x2222, 0x2250,
+  0x03d5, 0x2ae8, 0x22a3, 0xe0af, 0xe0ac, 0x226e, 0x226f, 0x2285,
+  0x2284, 0x2209, 0x220c, 0x22bb, 0x22bc, 0x225a, 0x2306, 0xe0a9,
+  0xe0b0, 0x2a72, 0xe191, 0xe288, 0xe29e, 0x329e, 0xe144, 0x203c,
+  0x2049, 0xe030, 0x2047, 0xe0e1, 0xe0df, 0xe0e0, 0xe0dc, 0xe0d4,
+  0xe0d2, 0xe0d3, 0x2588, 0x25e6, 0xe0e5, 0xe0e6, 0xe0e9, 0x25bf,
+  0x25b5, 0x25b9, 0x25c3, 0x2666, 0x2981, 0x25fc, 0xe0da, 0x25ca,
+  0x3231, 0x3239, 0x33cb, 0x246f, 0x2470, 0x2471, 0x2472, 0x2473,
+  0x3251, 0x3252, 0x3253, 0x3254, 0x3255, 0x3256, 0x3257, 0x3258,
+  0x3259, 0x325a, 0xe055, 0xe040, 0xe04b, 0xe05f, 0xe064, 0xe065,
+  0xe066, 0xe067, 0x21d0, 0x21cf, 0x21cd, 0xe079, 0xe056, 0xe041,
+  0xe04c, 0xe060, 0xe062, 0xe063, 0xe03e, 0xe053, 0xe049, 0xe05d,
+  0xe07b, 0xe08e, 0xe086, 0xe097, 0xe07a, 0x27b2, 0xe085, 0xe096,
+  0xe042, 0x279c, 0xe04d, 0xe061, 0xe03c, 0xe051, 0xe047, 0xe05b,
+  0xf846, 0xf847, 0xe038, 0x279b, 0xe039, 0xe04f, 0xe044, 0xe058,
+  0x2962, 0x2964, 0x2963, 0x2965, 0xe081, 0x27a1, 0xe08a, 0xe09b,
+  0xe082, 0x279e, 0xe08b, 0xe09c, 0x21b2, 0x21b1, 0xe06f, 0x21b4,
+  0x21b0, 0x21b3, 0xe110, 0xe107, 0x2936, 0xe06d, 0xe071, 0x2935,
+  0xe06a, 0x2937, 0x2939, 0x2934, 0xe080, 0xe093, 0xe089, 0xe09a,
+  0x21bc, 0x21c0, 0xf841, 0xe078, 0xe090, 0xe07d, 0xe074, 0xe072,
+  0xe077, 0xe076, 0xf849, 0xf848, 0x21c4, 0x21c5, 0xe334, 0xe336,
+  0xe338, 0xe33a, 0xe33c, 0xe33e, 0xe340, 0xe342, 0xe344, 0xe346,
+  0xe348, 0xe34a, 0xe34c, 0xe34e, 0xe350, 0xe352, 0xe354, 0xe356,
+  0xe358, 0xe35a, 0xe35c, 0xe35e, 0xe360, 0xe362, 0xe364, 0xe366,
+  0xe368, 0xe36a, 0xe36c, 0xe36e, 0xe370, 0xe372, 0xe374, 0xe376,
+  0xe378, 0xe37a, 0xe37c, 0xe37e, 0xe380, 0xe382, 0xe384, 0xe386,
+  0xe388, 0xe38a, 0xe38c, 0xe38e, 0xe390, 0xe392, 0xe394, 0xe396,
+  0xe398, 0xe39a, 0xe1d1, 0xe1a9, 0xe1e8, 0xe1b2, 0xe1ab, 0xe1f8,
+  0xe1ba, 0xe1e0, 0xe1e2, 0xe1c4, 0xe1ad, 0xe1bc, 0xe1b6, 0xe1dd,
+  0xe1f1, 0xe19b, 0xe1cb, 0xe1d9, 0xe1ae, 0xe16a, 0xe192, 0xe1cf,
+  0xe179, 0xe15b, 0xe18c, 0xe154, 0xe197, 0xe165, 0xe16e, 0xe18b,
+  0xe16d, 0xe190, 0xe184, 0xe161, 0xe174, 0xe193, 0xe177, 0xe155,
+  0xe188, 0xe173, 0xe15f, 0xe18d, 0xe17d, 0xe163, 0xe17b, 0xe152,
+  0xe187, 0xe176, 0xe1e6, 0xe248, 0xe244, 0xe25f, 0xe245, 0xe239,
+  0xe23c, 0xe253, 0xe259, 0xe25c, 0xe268, 0xe255, 0xe1e7, 0xe1af,
+  0xe1b0, 0xe1b4, 0xe1be, 0xe1c9, 0xe1dc, 0xe1ec, 0xe1ee, 0xe1f0,
+  0xe1f2, 0xe1a4, 0xe1a3, 0xe1b1, 0xe1aa, 0xe1f7, 0xe1b9, 0xe1df,
+  0xe1e1, 0xe1c3, 0xe1ac, 0xe1bb, 0xe19e, 0xe1b5, 0xe1c2, 0xe1d8,
+  0xe1b8, 0xe1ca, 0xe1c5, 0xe1d3, 0xe19f, 0xe15a, 0x2483, 0x2484,
+  0x2485, 0x2486, 0x2487, 0xe269, 0xe26a, 0xe26b, 0xe26c, 0xe26d,
+  0xe26e, 0xe1e5, 0xe1a1, 0xe19a, 0xe169, 0xe18f, 0xe182, 0xe19d,
+  0xe1a8, 0xe1b7, 0xe1bf, 0xe1c0, 0xe1c7, 0xe1cc, 0xe1ce, 0xe1d2,
+  0xe1de, 0xe1e9, 0xe1ef, 0xe1d0, 0xe1f9, 0xe199, 0xe19c, 0xe1c8,
+  0xe178, 0xe17a, 0xe153, 0xe164, 0x3294, 0xe16c, 0xe160, 0xe18e,
+  0xe15e, 0xe196, 0xe17c, 0xe162, 0xe186, 0xe16b, 0xe183, 0xe17e,
+  0xe18a, 0xe175, 0xe195, 0xe171, 0x32a5, 0xe151, 0xe1bd, 0xe1c6,
+  0xe1db, 0xe1d4, 0xe1d5, 0xe1eb, 0xe1f3, 0xe198, 0xe1a2, 0xe1a6,
+  0xe1f4, 0xe247, 0xe249, 0xe24e, 0xe251, 0xe25b, 0xe261, 0xe262,
+  0xe263, 0xe264, 0xe266, 0xe24c, 0xe243, 0xe24d, 0xe24b, 0xe242,
+  0xe24f, 0xe250, 0xe252, 0xe254, 0xe257, 0xe258, 0xe25a, 0xe25d,
+  0xe25e, 0xe260, 0xe265, 0xe267, 0xe240, 0xe23f, 0xe23e, 0xe24a,
+  0xe23b, 0xe23d, 0xe241, 0xe246, 0xe256, 0xe26f, 0xe270, 0xe271,
+  0xe272, 0x21f0, 0xf843, 0x27b5, 0xe112, 0xe111, 0xe08f, 0xe07c,
+  0x27a4, 0xf844, 0xf84b, 0xf84a, 0xe075, 0xe073, 0xe095, 0xe084,
+  0x21b6, 0x21b7, 0x219d, 0x219c, 0xf842, 0xe03f, 0xe054, 0xe04a,
+  0xe05e, 0xe083, 0xe094, 0xe08c, 0xe09d, 0xe03a, 0x2794, 0xf845,
+  0xe045, 0xe059, 0xe03d, 0xe052, 0xe048, 0xe05c, 0xe03b, 0xe050,
+  0xe046, 0xe05a, 0x21e0, 0x21e2, 0x21e1, 0x21e3, 0xe07e, 0xe091,
+  0xe087, 0xe098, 0x21e6, 0x21e8, 0x21e7, 0x21e9, 0xe10a, 0xe06b,
+  0xe06e, 0xe108, 0xe068, 0xe10c, 0xe10e, 0xe105, 0xe10b, 0xe06c,
+  0xe070, 0xe109, 0xe069, 0xe10d, 0xe10f, 0xe106, 0xe037, 0xe04e,
+  0xe043, 0xe057, 0x261d, 0x261f, 0xe0ee, 0xe0f0, 0xe1a7, 0xe1ed,
+  0xe1c1, 0xe1ea, 0xe1da, 0xe1d7, 0xe1fa, 0xe1fb, 0xe200, 0xe205,
+  0xe20a, 0xe20f, 0xe214, 0xe219, 0xe21e, 0xe223, 0xe2b5, 0xe2b6,
+  0xe2b7, 0xe2b8, 0xe2b9, 0xe2ba, 0xe2bb, 0xe2bc, 0xe2bd, 0xe2be,
+  0xe2bf, 0xe229, 0xe22d, 0xe22b, 0xe232, 0xe22e, 0xe230, 0xe22a,
+  0xe22f, 0xe22c, 0xe231, 0xe295, 0xe299, 0xe297, 0xe29d, 0xe29a,
+  0xe29c, 0xe296, 0xe29b, 0xe298, 0xe294, 0xe145, 0xe14d, 0xe149,
+  0xe16f, 0xe14f, 0xe158, 0xe147, 0xe156, 0xe14b, 0xe166, 0xe27f,
+  0xe283, 0xe281, 0xe287, 0xe284, 0xe286, 0xe280, 0xe285, 0xe282,
+  0xe27e, 0xe17f, 0xe180, 0xe189, 0xe185, 0xe181, 0xe194, 0xe172,
+  0x3290, 0x328a, 0x328b, 0x328c, 0x328d, 0x328e, 0x328f, 0xe234,
+  0xe235, 0xe238, 0xe237, 0xe236, 0xe23a, 0xe233, 0xe127, 0xe12b,
+  0xe12f, 0xe131, 0xe092, 0xe07f, 0xe088, 0xe099, 0x301e, 0x301f,
+  0x2036, 0xe02e, 0x2035, 0xe02c, 0xe08d, 0xe001,
+};
+
+static const u_int32_t mac_korean_compose[] = {
+  0x0021f877, 0x0021f87f, 0x0028f87c, 0x0028f87f,
+  0x0029f87c, 0x0029f87f, 0x002af877, 0x002d0308,
+  0x003020de, 0x003120de, 0x003220de, 0x003320de,
+  0x003420de, 0x003520de, 0x003620de, 0x003720de,
+  0x003820de, 0x003920de, 0x003cf877, 0x003d20d2,
+  0x003d20e5, 0x003ef877, 0x005bf877, 0x005bf87b,
+  0x005bf87c, 0x005df877, 0x005df87b, 0x005df87c,
+  0x007bf877, 0x007df877, 0x00a7f87c, 0x00b1f877,
+  0x00b6f87f, 0x00d7f877, 0x2013f87f, 0x2016f87b,
+  0x2016f87c, 0x2020f877, 0x2020f87b, 0x2020f87c,
+  0x2020f87f, 0x2021f87c, 0x2021f87f, 0x2026f87f,
+  0x2032f873, 0x2032f87f, 0x2033f873, 0x2033f87f,
+  0x203cf87f, 0x2042f879, 0x2051f871, 0x2051f874,
+  0x2051f879, 0x2051f87c, 0x20a9f87f, 0x2190f870,
+  0x2190f871, 0x2190f872, 0x2190f873, 0x2190f874,
+  0x2190f875, 0x2190f878, 0x2190f879, 0x2190f87a,
+  0x2190f87b, 0x2190f87c, 0x2190f87f, 0x2191f870,
+  0x2191f872, 0x2191f873, 0x2191f874, 0x2191f875,
+  0x2191f878, 0x2191f879, 0x2191f87a, 0x2191f87b,
+  0x2191f87c, 0x2191f87f, 0x2192f870, 0x2192f872,
+  0x2192f874, 0x2192f875, 0x2192f878, 0x2192f879,
+  0x2192f87a, 0x2192f87b, 0x2192f87c, 0x2193f870,
+  0x2193f872, 0x2193f873, 0x2193f874, 0x2193f875,
+  0x2193f878, 0x2193f879, 0x2193f87a, 0x2193f87b,
+  0x2193f87c, 0x2193f87f, 0x2194f87c, 0x2195f87c,
+  0x2196f87b, 0x2197f87b, 0x2198f87b, 0x2199f87b,
+  0x21b0f87a, 0x21b0f87c, 0x21b0f87f, 0x21b1f87a,
+  0x21b1f87c, 0x21b1f87f, 0x21bbf87a, 0x21bbf87b,
+  0x21bbf87c, 0x21bbf87f, 0x21bcf879, 0x21bcf87f,
+  0x21c0f879, 0x21c0f87f, 0x21d0f87c, 0x21d2f87c,
+  0x21d4f879, 0x21d4f87f, 0x21e620dd, 0x21e620de,
+  0x21e6f870, 0x21e6f874, 0x21e6f875, 0x21e6f878,
+  0x21e6f879, 0x21e6f87a, 0x21e6f87b, 0x21e6f87c,
+  0x21e6f87f, 0x21e720dd, 0x21e720de, 0x21e7f875,
+  0x21e7f878, 0x21e7f879, 0x21e7f87a, 0x21e7f87b,
+  0x21e7f87c, 0x21e7f87f, 0x21e820de, 0x21e8f870,
+  0x21e8f874, 0x21e8f875, 0x21e8f878, 0x21e8f879,
+  0x21e8f87c, 0x21e8f87f, 0x21e920dd, 0x21e920de,
+  0x21e9f875, 0x21e9f878, 0x21e9f879, 0x21e9f87a,
+  0x21e9f87b, 0x21e9f87c, 0x2206f87f, 0x2208f877,
+  0x2211f877, 0x2213f877, 0x221ef877, 0x2222f87f,
+  0x22250347, 0x2229f877, 0x2229f87f, 0x222af877,
+  0x222af87f, 0x223d0336, 0x223df877, 0x2260f877,
+  0x226120d2, 0x226120e5, 0x2282f877, 0x22a50338,
+  0x2314f87f, 0x2394f876, 0x2460f87f, 0x2461f87f,
+  0x2462f87f, 0x2463f87f, 0x2464f87f, 0x2465f87f,
+  0x2466f87f, 0x2467f87f, 0x2468f87f, 0x24eaf87f,
+  0x24ebf878, 0x24ebf87f, 0x24ecf878, 0x24ecf87f,
+  0x24edf878, 0x24edf87f, 0x24eef878, 0x24eef87f,
+  0x24eff878, 0x24eff87f, 0x24f0f878, 0x24f0f87f,
+  0x24f1f878, 0x24f1f87f, 0x24f2f878, 0x24f2f87f,
+  0x24f3f878, 0x24f3f87f, 0x24f4f878, 0x24f4f87f,
+  0x25a020df, 0x25a120df, 0x25a1f879, 0x25a1f87b,
+  0x25a1f87c, 0x25a8f87f, 0x25adf878, 0x25b220dd,
+  0x25b320dd, 0x25b3f87f, 0x25b420e4, 0x25c620de,
+  0x25c6f879, 0x25c720de, 0x25c720df, 0x25c7f879,
+  0x25c7f87b, 0x25c7f87c, 0x25c7f87f, 0x25c8f87f,
+  0x25c920dd, 0x25cbf879, 0x25cbf87b, 0x25cbf87f,
+  0x25ce20dd, 0x25cff879, 0x25eff87c, 0x2610f87c,
+  0x2610f87f, 0x261cf87f, 0x261df87f, 0x261ef87f,
+  0x261ff87f, 0x262ff876, 0x262ff87a, 0x2642f87f,
+  0x2720f87a, 0x2723f87a, 0x273ff87a, 0x274820d8,
+  0x2756f87a, 0x2756f87f, 0x278af87f, 0x278bf87f,
+  0x278cf87f, 0x278df87f, 0x278ef87f, 0x278ff87f,
+  0x2790f87f, 0x2791f87f, 0x2792f87f, 0x2793f87f,
+  0x27e120dd, 0x2934f87a, 0x2934f87c, 0x2934f87f,
+  0x2935f87a, 0x2935f87c, 0x2936f87a, 0x2936f87c,
+  0x2937f87a, 0x2937f87c, 0x2939f87a, 0x2939f87c,
+  0x2939f87f, 0x2962f87f, 0x2964f87f, 0x2985f873,
+  0x2985f878, 0x2985f879, 0x2985f87b, 0x2985f87c,
+  0x2985f87f, 0x2986f873, 0x2986f878, 0x2986f879,
+  0x2986f87b, 0x2986f87c, 0x2986f87f, 0x29c820de,
+  0x2afd0347, 0x3002f87d, 0x3007f876, 0x3008f878,
+  0x3009f878, 0x300af878, 0x300bf878, 0x300cf879,
+  0x300cf87b, 0x300cf87c, 0x300cf87f, 0x300df879,
+  0x300df87b, 0x300df87c, 0x300df87f, 0x300ef879,
+  0x300ef87c, 0x300ff879, 0x300ff87c, 0x3010f878,
+  0x3010f87f, 0x3011f878, 0x3011f87f, 0x3013f87c,
+  0x3016f878, 0x3017f878, 0x3251f87a, 0x3252f87a,
+  0x3253f87a, 0x3254f87a, 0x3255f87a, 0x3256f87a,
+  0x3257f87a, 0x3258f87a, 0x3259f87a, 0x325af87a,
+  0x329ef87f, 0x4e0020de, 0x4e00f876, 0x4e0320de,
+  0x4e03f876, 0x4e0920de, 0x4e09f876, 0x4e5d20de,
+  0x4e5df876, 0x4e8c20de, 0x4e8cf876, 0x4e9420de,
+  0x4e94f876, 0x4ed620dd, 0x4ed620de, 0x4ee320dd,
+  0x4ee320de, 0x4f8b20de, 0x516b20de, 0x516bf876,
+  0x516d20de, 0x516df876, 0x51a020dd, 0x51a020de,
+  0x51f8f87f, 0x51f9f87f, 0x524d20dd, 0x524d20de,
+  0x526f20dd, 0x526f20de, 0x52a920dd, 0x52a920de,
+  0x52d520dd, 0x52d520de, 0x534120de, 0x5341f876,
+  0x534df87f, 0x537020dd, 0x537020de, 0x53c320dd,
+  0x53cd20dd, 0x53cd20de, 0x540d20de, 0x56db20de,
+  0x56dbf876, 0x570b20dd, 0x571f20de, 0x5b5020de,
+  0x5e8f20de, 0x5f6220dd, 0x5f6220de, 0x5f7120de,
+  0x611f20dd, 0x611f20de, 0x616320dd, 0x630720de,
+  0x63a520dd, 0x63a520de, 0x65b020dd, 0x65e520de,
+  0x670820de, 0x672820de, 0x672b20dd, 0x672c20dd,
+  0x672c20de, 0x6c3420de, 0x6ce820dd, 0x6d3e20de,
+  0x6e9020de, 0x706b20de, 0x73fe20dd, 0x76ee20de,
+  0x7b5420de, 0x7bc020de, 0x81ea20dd, 0x886320dd,
+  0x88dc20de, 0x88dc20e4, 0x8a3b20de, 0x902320de,
+  0x91d120de, 0x959320dd, 0x96fb20dd, 0x982d20de,
+  0xac0020dd, 0xac0420dd, 0xac1020dd, 0xac1020de,
+  0xac1920dd, 0xac7020dd, 0xac8c20dd, 0xad0020dd,
+  0xad5020de, 0xad6d20dd, 0xb09820dd, 0xb0ae20dd,
+  0xb19220dd, 0xb29020dd, 0xb2e420dd, 0xb2e820dd,
+  0xb2f520dd, 0xb2f520de, 0xb30020dd, 0xb30020de,
+  0xb3d920dd, 0xb3d920de, 0xb73b20de, 0xb77c20dd,
+  0xb9c820dd, 0xba8520dd, 0xba8520de, 0xbb3820de,
+  0xbc1420dd, 0xbc1820dd, 0xbc1820de, 0xbcc020dd,
+  0xbcf820dd, 0xbd8020dd, 0xbd8020de, 0xbe4420dd,
+  0xbe4420de, 0xbe6020dd, 0xc0ac20dd, 0xc0c120dd,
+  0xc13c20dd, 0xc18c20dd, 0xc18d20dd, 0xc21820dd,
+  0xc21820de, 0xc21920dd, 0xc2dc20dd, 0xc2e020dd,
+  0xc2e420dd, 0xc54420dd, 0xc57d20dd, 0xc57d20de,
+  0xc5ec20dd, 0xc5ed20de, 0xc60820dd, 0xc60820de,
+  0xc67820dd, 0xc6b420de, 0xc6d020dd, 0xc72020dd,
+  0xc73c20dd, 0xc74c20dd, 0xc74c20de, 0xc77420dd,
+  0xc77820dd, 0xc77820de, 0xc77c20dd, 0xc78520dd,
+  0xc79020dd, 0xc79020de, 0xc79120dd, 0xc80420dd,
+  0xc80420de, 0xc81120dd, 0xc81120de, 0xc81520de,
+  0xc81c20dd, 0xc87020dd, 0xc87020de, 0xc87420dd,
+  0xc8fc20de, 0xc90020dd, 0xc91120dd, 0xc9c120dd,
+  0xcc2820dd, 0xcc3820dd, 0xce7420dd, 0xd0b920dd,
+  0xd0c020dd, 0xd0c020de, 0xd30c20dd, 0xd45c20dd,
+  0xd55820dd, 0xd57420dd, 0xd57420de, 0xd61520dd,
+  0xd61520de, 0xd65c20dd, 0xd73420dd, 0xe009f875,
+  0xe009f87a, 0xe009f87b, 0xe009f87c, 0xe009f87f,
+  0xe00af875, 0xe00af87a, 0xe00af87b, 0xe00af87c,
+  0xe00af87f, 0xe00bf875, 0xe00bf87a, 0xe00bf87b,
+  0xe00bf87c, 0xe00bf87f, 0xe00cf875, 0xe00cf87a,
+  0xe00cf87b, 0xe00cf87c, 0xe00cf87f, 0xe00df875,
+  0xe00df87a, 0xe00df87b, 0xe00df87c, 0xe00df87f,
+  0xe00ef875, 0xe00ef87a, 0xe00ef87b, 0xe00ef87c,
+  0xe00ef87f, 0xe00ff875, 0xe00ff87a, 0xe00ff87b,
+  0xe00ff87c, 0xe00ff87f, 0xe010f875, 0xe010f87a,
+  0xe010f87b, 0xe010f87c, 0xe010f87f, 0xe011f875,
+  0xe011f87a, 0xe011f87b, 0xe011f87c, 0xe011f87f,
+  0xe0de20df, 0xe145f87a, 0xe147f87a, 0xe149f87a,
+  0xe14bf87a, 0xe14df87a, 0xe14ff87a, 0xe156f87a,
+  0xe158f87a, 0xe166f87a, 0xe16ff87a, 0xe172f87c,
+  0xe17ff87c, 0xe180f87c, 0xe181f87c, 0xe185f87c,
+  0xe189f87c, 0xe192f87a, 0xe194f87c, 0xe198f87a,
+  0xe1a0f87a, 0xe1a2f87a, 0xe1a3f87a, 0xe1a4f87a,
+  0xe1a5f87a, 0xe1a6f87a, 0xe1a7f87a, 0xe1a8f87a,
+  0xe1a9f87a, 0xe1aef87a, 0xe1aff87a, 0xe1b0f87a,
+  0xe1b3f87a, 0xe1b4f87a, 0xe1b5f87a, 0xe1b8f87a,
+  0xe1bbf87a, 0xe1bdf87a, 0xe1bef87a, 0xe1c0f87a,
+  0xe1c6f87a, 0xe1c9f87a, 0xe1ccf87a, 0xe1cdf87a,
+  0xe1cef87a, 0xe1cff87a, 0xe1d0f87a, 0xe1d4f87a,
+  0xe1d5f87a, 0xe1d6f87a, 0xe1dbf87a, 0xe1dcf87a,
+  0xe1e3f87a, 0xe1e4f87a, 0xe1e7f87a, 0xe1e8f87a,
+  0xe1e9f87a, 0xe1ecf87a, 0xe1eef87a, 0xe1f0f87a,
+  0xe1f2f87a, 0xe1f3f87a, 0xe1f4f87a, 0xe1f5f87a,
+  0xe1f6f87a, 0xe2db0029, 0xe2dc0029, 0xe2dd0029,
+  0xe2de0029, 0xe2df0029, 0xe2e00029, 0xe2e10029,
+  0xe2e20029, 0xe2e30029, 0xe2e40029, 0xe2e5005d,
+  0xe2e6005d, 0xe2e7005d, 0xe2e8005d, 0xe2e9005d,
+  0xe2ea005d, 0xe2eb005d, 0xe2ec005d, 0xe2ed005d,
+  0xe2ee005d, 0xe2ef005d, 0xe2f0005d, 0xe2f1005d,
+  0xe2f2005d, 0xe2f3005d, 0xe2f4005d, 0xe2f5005d,
+  0xe2f6005d, 0xe2f7005d, 0xe2f8005d, 0xe2f9005d,
+  0xe2fac0ac, 0xe2fb005d, 0xe2fc005d, 0xe2fd005d,
+  0xe2fe005d, 0xe2ff005d, 0xe300005d, 0xe301005d,
+  0xe302005d, 0xe303005d, 0xe304005d, 0xe305005d,
+  0xe306005d, 0xe307005d, 0xe308005d, 0xe309005d,
+  0xe30a005d, 0xe30b005d, 0xe30c005d, 0xe30d005d,
+  0xe30e005d, 0xe30f005d, 0xe310c0ac, 0xe311005d,
+  0xe312005d, 0xe313005d, 0xe314005d, 0xe315005d,
+  0xe316005d, 0xe317005d, 0xe318005d, 0xe319005d,
+  0xe31a005d, 0xe31b005d, 0xe31c005d, 0xe31d005d,
+  0xe31e005d, 0xe31f005d, 0xe320005d, 0xe321005d,
+  0xe322005d, 0xe323005d, 0xe324005d, 0xe325005d,
+  0xe326005d, 0xe327005d, 0xe328005d, 0xe329005d,
+  0xe32a005d, 0xe32b005d, 0xe32c005d, 0xe32d005d,
+  0xe32e005d, 0xe32f005d, 0xe330005d, 0xe331005d,
+  0xe39d0029, 0xe39e0029, 0xe39f0029, 0xe3a00029,
+  0xe3a10029, 0xe3a20029, 0xe3a30029, 0xe3a40029,
+  0xe3a50029, 0xe3a60029, 0xe3a70029, 0xe3a80029,
+  0xe3a90029, 0xe3aa0029, 0xe3ab0029, 0xe3ac0029,
+  0xe3ad0029, 0xe3ae0029, 0xe3af0029, 0xe3b00029,
+  0xe3b10029, 0xe3b20029, 0xe3b30029, 0xe3b40029,
+  0xe3b50029, 0xe3b60029, 0xe3b72020, 0xe3b80031,
+  0xe3b80032, 0xe3b80033, 0xe3b80034, 0xe3b80035,
+  0xe3b80036, 0xe3b80037, 0xe3b80038, 0xe3b80039,
+  0xe3b90030, 0xe3ba0030, 0xe3ba0031, 0xe3ba0032,
+  0xe3ba0033, 0xe3ba0034, 0xe3ba0035, 0xe3ba0036,
+  0xe3ba0037, 0xe3ba0038, 0xe3ba0039, 0xe3bb0030,
+  0xe3bc5341, 0xe3bd4e00, 0xe3bd4e03, 0xe3bd4e09,
+  0xe3bd4e5d, 0xe3bd4e8c, 0xe3bd4e94, 0xe3bd516b,
+  0xe3bd516d, 0xe3bd56db, 0xe3bed68c, 0xe3bf0030,
+  0xe3bf0031, 0xe3bf0032, 0xe3bf0033, 0xe3bf0034,
+  0xe3bf0035, 0xe3bf0036, 0xe3bf0037, 0xe3bf0038,
+  0xe3bf0039, 0xe3c00030, 0xe3c15341, 0xe3c24e00,
+  0xe3c24e03, 0xe3c24e09, 0xe3c24e5d, 0xe3c24e8c,
+  0xe3c24e94, 0xe3c2516b, 0xe3c2516d, 0xe3c256db,
+  0xe3c3d68c, 0xe3c40030, 0xe3c40031, 0xe3c40032,
+  0xe3c40033, 0xe3c40034, 0xe3c40035, 0xe3c40036,
+  0xe3c40037, 0xe3c40038, 0xe3c40039, 0xe3c50030,
+  0xe3c60030, 0xe3c60031, 0xe3c60032, 0xe3c60033,
+  0xe3c60034, 0xe3c60035, 0xe3c60036, 0xe3c60037,
+  0xe3c60038, 0xe3c60039, 0xe3c70030, 0xe3c80030,
+  0xe3c80031, 0xe3c80032, 0xe3c80033, 0xe3c80034,
+  0xe3c80035, 0xe3c80036, 0xe3c80037, 0xe3c80038,
+  0xe3c80039, 0xe3c90030, 0xe3d0002a, 0xe3d10029,
+  0xe3d1002e, 0xe3d20029, 0xe3d2002e, 0xe3d30029,
+  0xe3d3002e, 0xe3d40029, 0xe3d4002e, 0xe3d50029,
+  0xe3d5002e, 0xe3d60029, 0xe3d6002e, 0xe3d70029,
+  0xe3d7002e, 0xe3d80029, 0xe3d8002e, 0xe3d90029,
+  0xe3d9002e, 0xe3da0029, 0xe3da002e, 0xe3db0029,
+  0xe3db002e, 0xe3dc0029, 0xe3dc002e, 0xe3dd0029,
+  0xe3dd002e, 0xe3de0029, 0xe3de002e, 0xe3df0029,
+  0xe3df002e, 0xe3e00029, 0xe3e0002e, 0xe3e10029,
+  0xe3e1002e, 0xe3e20029, 0xe3e2002e, 0xe3e30029,
+  0xe3e3002e, 0xe3e40029, 0xe3e4002e, 0xe3e50029,
+  0xe3e5002e, 0xe3e60029, 0xe3e6002e, 0xe3e70029,
+  0xe3e7002e, 0xe3e80029, 0xe3e8002e, 0xe3e90029,
+  0xe3e9002e, 0xe3ea0029, 0xe3ea002e, 0xe3eb0029,
+  0xe3eb002e, 0xe3ec0029, 0xe3ec002e, 0xe3ed0029,
+  0xe3ed002e, 0xe3ee0029, 0xe3ee002e, 0xe3ef0029,
+  0xe3ef002e, 0xe3f00029, 0xe3f0002e, 0xe3f10029,
+  0xe3f1002e, 0xe3f20029, 0xe3f2002e, 0xe3f30029,
+  0xe3f3002e, 0xe3f40029, 0xe3f4002e, 0xe3f50029,
+  0xe3f5002e, 0xe3f60029, 0xe3f6002e, 0xe3f70029,
+  0xe3f7002e, 0xe3f80029, 0xe3f8002e, 0xe3f90029,
+  0xe3f9002e, 0xe3fa0029, 0xe3fa002e, 0xe3fb0029,
+  0xe3fb002e, 0xe3fc0029, 0xe3fc002e, 0xe3fd0029,
+  0xe3fd002e, 0xe3fe0029, 0xe3fe002e, 0xe3ff0029,
+  0xe3ff002e, 0xe4000029, 0xe400002e, 0xe4010029,
+  0xe401002e, 0xe4020029, 0xe402002e, 0xe4030029,
+  0xe403002e, 0xe4040029, 0xe404002e, 0xe4052020,
+  0xe4062021, 0xe4070041, 0xe4070042, 0xe4070043,
+  0xe4070044, 0xe4070045, 0xe4070046, 0xe4070047,
+  0xe4070048, 0xe4070049, 0xe407004a, 0xe407004b,
+  0xe407004c, 0xe407004d, 0xe407004e, 0xe407004f,
+  0xe4070050, 0xe4070051, 0xe4070052, 0xe4070053,
+  0xe4070054, 0xe4070055, 0xe4070056, 0xe4070057,
+  0xe4070058, 0xe4070059, 0xe407005a, 0xe4082020,
+  0xe4090032, 0xe4090033, 0xe40a0031, 0xe40a0032,
+  0xe40a4e8c, 0xe40a5341, 0xe40bc2dd, 0xe40c0031,
+  0xe40c0032, 0xe40c4e8c, 0xe40c5341, 0xe40dc2dd,
+  0xe40e0031, 0xe40e0032, 0xe40f0031, 0xe40f0032,
+  0xe4100031, 0xe4100032, 0xe411002a, 0xf80520de,
+  0xf80620df, 0xf809f87a, 0xf80bf87f, 0xf83df87f,
+  0xf860002a, 0xf8600041, 0xf8600042, 0xf8600043,
+  0xf8600044, 0xf8600045, 0xf8600046, 0xf8600047,
+  0xf8600048, 0xf8600049, 0xf860004a, 0xf860004b,
+  0xf860004c, 0xf860004d, 0xf860004e, 0xf860004f,
+  0xf8600050, 0xf8600051, 0xf8600052, 0xf8600053,
+  0xf8600054, 0xf8600055, 0xf8600056, 0xf8600057,
+  0xf8600058, 0xf8600059, 0xf860005a, 0xf8600061,
+  0xf8600062, 0xf8600063, 0xf8600064, 0xf8600065,
+  0xf8600066, 0xf8600067, 0xf8600068, 0xf8600069,
+  0xf860006a, 0xf860006b, 0xf860006c, 0xf860006d,
+  0xf860006e, 0xf860006f, 0xf8600070, 0xf8600071,
+  0xf8600072, 0xf8600073, 0xf8600074, 0xf8600075,
+  0xf8600076, 0xf8600077, 0xf8600078, 0xf8600079,
+  0xf860007a, 0xf8602020, 0xf8602021, 0xf8610028,
+  0xf8612020, 0xf8620028, 0xf862005b, 0xf862c8fc,
+  0xf863005b, 0xf863c8fc, 0xf864005b, 0xf865005b,
+  0xf866005b, 0xf867002a, 0xfe59f87c, 0xfe59f87f,
+  0xfe5af87c, 0xfe5af87f, 0xff01f874, 0xff0af871,
+  0xff0af873, 0xff0af874, 0xff0af875, 0xff0af87f,
+  0xff3ff87f,
+};
diff --git a/libatalk/unicode/charsets/mac_roman.c b/libatalk/unicode/charsets/mac_roman.c
new file mode 100644 (file)
index 0000000..e703d21
--- /dev/null
@@ -0,0 +1,117 @@
+/* 
+   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,
+       NULL,
+       NULL, NULL
+};
+
+/* ------------------------ */
+static int
+char_ucs2_to_mac_roman ( unsigned char *r, ucs2_t wc)
+{
+       unsigned char c = 0;
+       if (wc < 0x0080) {
+               *r = wc;
+               return 1;
+       }
+       else if (wc >= 0x00a0 && wc < 0x0100)
+               c = mac_roman_page00[wc-0x00a0];
+       else if (wc >= 0x0130 && wc < 0x0198)
+               c = mac_roman_page01[wc-0x0130];
+       else if (wc >= 0x02c0 && wc < 0x02e0)
+               c = mac_roman_page02[wc-0x02c0];
+       else if (wc == 0x03c0)
+               c = 0xb9;
+       else if (wc >= 0x2010 && wc < 0x2048)
+               c = mac_roman_page20[wc-0x2010];
+       else if (wc >= 0x2120 && wc < 0x2128)
+               c = mac_roman_page21[wc-0x2120];
+       else if (wc >= 0x2200 && wc < 0x2268)
+               c = mac_roman_page22[wc-0x2200];
+       else if (wc == 0x25ca)
+               c = 0xd7;
+       else if (wc >= 0xfb00 && wc < 0xfb08)
+               c = mac_roman_pagefb[wc-0xfb00];
+       else if (wc == 0xf8ff)
+               c = 0xf0;
+
+       if (c != 0) {
+               *r = c;
+               return 1;
+       }
+       return 0;
+}
+
+static size_t mac_roman_push( void *cd, char **inbuf, size_t *inbytesleft,
+                         char **outbuf, size_t *outbytesleft)
+{
+       /* No special handling required */
+       return (size_t) mb_generic_push( char_ucs2_to_mac_roman, cd, inbuf, inbytesleft, outbuf, outbytesleft);
+}
+
+/* ------------------------ */
+static int
+char_mac_roman_to_ucs2 (ucs2_t *pwc, const unsigned char *s)
+{
+       unsigned char c = *s;
+       if (c < 0x80) {
+               *pwc = (ucs2_t) c;
+               return 1;
+       }
+       else {
+               unsigned short wc = mac_roman_2uni[c-0x80];
+               *pwc = (ucs2_t) wc;
+               return 1;
+       }
+       return 0;
+}
+
+static size_t mac_roman_pull ( void *cd, char **inbuf, size_t *inbytesleft,
+                         char **outbuf, size_t *outbytesleft)
+{
+       return (size_t) mb_generic_pull( char_mac_roman_to_ucs2, cd, inbuf, inbytesleft, outbuf, outbytesleft);
+}
diff --git a/libatalk/unicode/charsets/mac_roman.h b/libatalk/unicode/charsets/mac_roman.h
new file mode 100644 (file)
index 0000000..bf3a5bc
--- /dev/null
@@ -0,0 +1,118 @@
+
+/*
+ * $Id: mac_roman.h,v 1.2 2005-04-28 20:50:04 bfernhomberg Exp $
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * from GNU libiconv
+ * modified by Bjorn (Apple Logo 0xf0 to Apple unicode 0xf8ff )
+ */
+
+
+static const unsigned char mac_roman_page00[96] = {
+  0xca, 0xc1, 0xa2, 0xa3, 0xdb, 0xb4, 0x00, 0xa4, /* 0xa0-0xa7 */
+  0xac, 0xa9, 0xbb, 0xc7, 0xc2, 0x00, 0xa8, 0xf8, /* 0xa8-0xaf */
+  0xa1, 0xb1, 0x00, 0x00, 0xab, 0xb5, 0xa6, 0xe1, /* 0xb0-0xb7 */
+  0xfc, 0x00, 0xbc, 0xc8, 0x00, 0x00, 0x00, 0xc0, /* 0xb8-0xbf */
+  0xcb, 0xe7, 0xe5, 0xcc, 0x80, 0x81, 0xae, 0x82, /* 0xc0-0xc7 */
+  0xe9, 0x83, 0xe6, 0xe8, 0xed, 0xea, 0xeb, 0xec, /* 0xc8-0xcf */
+  0x00, 0x84, 0xf1, 0xee, 0xef, 0xcd, 0x85, 0x00, /* 0xd0-0xd7 */
+  0xaf, 0xf4, 0xf2, 0xf3, 0x86, 0x00, 0x00, 0xa7, /* 0xd8-0xdf */
+  0x88, 0x87, 0x89, 0x8b, 0x8a, 0x8c, 0xbe, 0x8d, /* 0xe0-0xe7 */
+  0x8f, 0x8e, 0x90, 0x91, 0x93, 0x92, 0x94, 0x95, /* 0xe8-0xef */
+  0x00, 0x96, 0x98, 0x97, 0x99, 0x9b, 0x9a, 0xd6, /* 0xf0-0xf7 */
+  0xbf, 0x9d, 0x9c, 0x9e, 0x9f, 0x00, 0x00, 0xd8, /* 0xf8-0xff */
+};
+static const unsigned char mac_roman_page01[104] = {
+  0x00, 0xf5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+  0x00, 0x00, 0xce, 0xcf, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+  0xd9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+  0x00, 0x00, 0xc4, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+};
+static const unsigned char mac_roman_page02[32] = {
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf6, 0xff, /* 0xc0-0xc7 */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+  0xf9, 0xfa, 0xfb, 0xfe, 0xf7, 0xfd, 0x00, 0x00, /* 0xd8-0xdf */
+};
+static const unsigned char mac_roman_page20[56] = {
+  0x00, 0x00, 0x00, 0xd0, 0xd1, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+  0xd4, 0xd5, 0xe2, 0x00, 0xd2, 0xd3, 0xe3, 0x00, /* 0x18-0x1f */
+  0xa0, 0xe0, 0xa5, 0x00, 0x00, 0x00, 0xc9, 0x00, /* 0x20-0x27 */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+  0xe4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+  0x00, 0xdc, 0xdd, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+  0x00, 0x00, 0x00, 0x00, 0xda, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+};
+static const unsigned char mac_roman_page21[8] = {
+  0x00, 0x00, 0xaa, 0x00, 0x00, 0x00, 0xbd, 0x00, /* 0x20-0x27 */
+};
+static const unsigned char mac_roman_page22[104] = {
+  0x00, 0x00, 0xb6, 0x00, 0x00, 0x00, 0xc6, 0x00, /* 0x00-0x07 */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, /* 0x08-0x0f */
+  0x00, 0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+  0x00, 0x00, 0xc3, 0x00, 0x00, 0x00, 0xb0, 0x00, /* 0x18-0x1f */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+  0x00, 0x00, 0x00, 0xba, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+  0xc5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+  0xad, 0x00, 0x00, 0x00, 0xb2, 0xb3, 0x00, 0x00, /* 0x60-0x67 */
+};
+static const unsigned char mac_roman_pagefb[8] = {
+  0x00, 0xde, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+};
+
+
+
+
+static const unsigned short mac_roman_2uni[128] = {
+  /* 0x80 */
+  0x00c4, 0x00c5, 0x00c7, 0x00c9, 0x00d1, 0x00d6, 0x00dc, 0x00e1,
+  0x00e0, 0x00e2, 0x00e4, 0x00e3, 0x00e5, 0x00e7, 0x00e9, 0x00e8,
+  /* 0x90 */
+  0x00ea, 0x00eb, 0x00ed, 0x00ec, 0x00ee, 0x00ef, 0x00f1, 0x00f3,
+  0x00f2, 0x00f4, 0x00f6, 0x00f5, 0x00fa, 0x00f9, 0x00fb, 0x00fc,
+  /* 0xa0 */
+  0x2020, 0x00b0, 0x00a2, 0x00a3, 0x00a7, 0x2022, 0x00b6, 0x00df,
+  0x00ae, 0x00a9, 0x2122, 0x00b4, 0x00a8, 0x2260, 0x00c6, 0x00d8,
+  /* 0xb0 */
+  0x221e, 0x00b1, 0x2264, 0x2265, 0x00a5, 0x00b5, 0x2202, 0x2211,
+  0x220f, 0x03c0, 0x222b, 0x00aa, 0x00ba, 0x2126, 0x00e6, 0x00f8,
+  /* 0xc0 */
+  0x00bf, 0x00a1, 0x00ac, 0x221a, 0x0192, 0x2248, 0x2206, 0x00ab,
+  0x00bb, 0x2026, 0x00a0, 0x00c0, 0x00c3, 0x00d5, 0x0152, 0x0153,
+  /* 0xd0 */
+  0x2013, 0x2014, 0x201c, 0x201d, 0x2018, 0x2019, 0x00f7, 0x25ca,
+  0x00ff, 0x0178, 0x2044, 0x00a4, 0x2039, 0x203a, 0xfb01, 0xfb02,
+  /* 0xe0 */
+  0x2021, 0x00b7, 0x201a, 0x201e, 0x2030, 0x00c2, 0x00ca, 0x00c1,
+  0x00cb, 0x00c8, 0x00cd, 0x00ce, 0x00cf, 0x00cc, 0x00d3, 0x00d4,
+  /* 0xf0 */
+  0xf8ff, 0x00d2, 0x00da, 0x00db, 0x00d9, 0x0131, 0x02c6, 0x02dc,
+  0x00af, 0x02d8, 0x02d9, 0x02da, 0x00b8, 0x02dd, 0x02db, 0x02c7,
+};
diff --git a/libatalk/unicode/charsets/mac_turkish.c b/libatalk/unicode/charsets/mac_turkish.c
new file mode 100644 (file)
index 0000000..44b18a1
--- /dev/null
@@ -0,0 +1,64 @@
+/* 
+   Unix SMB/CIFS implementation.
+   minimal iconv implementation
+   Copyright (C) Andrew Tridgell 2001
+   Copyright (C) Jelmer Vernooij 2002,2003
+   
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+   
+   From samba 3.0 beta and GNU libiconv-1.8
+   It's bad but most of the time we can't use libc iconv service:
+   - it doesn't round trip for most encoding
+   - it doesn't know about Apple extension
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+#include <stdlib.h>
+#include <netatalk/endian.h>
+#include <atalk/unicode.h>
+
+#include "mac_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,
+       NULL,
+       NULL, NULL
+};
+
+static size_t mac_turkish_push( void *cd, char **inbuf, size_t *inbytesleft,
+                         char **outbuf, size_t *outbytesleft)
+{
+       return (size_t) mb_generic_push( char_ucs2_to_mac_turkish, cd, inbuf, inbytesleft, outbuf, outbytesleft);
+}
+
+/* ------------------------ */
+
+static size_t mac_turkish_pull ( void *cd, char **inbuf, size_t *inbytesleft,
+                         char **outbuf, size_t *outbytesleft)
+{
+       return (size_t) mb_generic_pull( char_mac_turkish_to_ucs2, cd, inbuf, inbytesleft, outbuf, outbytesleft);
+
+}
diff --git a/libatalk/unicode/charsets/mac_turkish.h b/libatalk/unicode/charsets/mac_turkish.h
new file mode 100644 (file)
index 0000000..66d22f8
--- /dev/null
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 1999-2001 Free Software Foundation, Inc.
+ * This file is part of the GNU LIBICONV Library.
+ *
+ * The GNU LIBICONV Library is free software; you can redistribute it
+ * and/or modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * The GNU LIBICONV Library is distributed in the hope that it will be
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with the GNU LIBICONV Library; see the file COPYING.LIB.
+ * If not, write to the Free Software Foundation, Inc., 59 Temple Place -
+ * Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * MacTurkish
+ */
+
+static const unsigned short mac_turkish_2uni[128] = {
+  /* 0x80 */
+  0x00c4, 0x00c5, 0x00c7, 0x00c9, 0x00d1, 0x00d6, 0x00dc, 0x00e1,
+  0x00e0, 0x00e2, 0x00e4, 0x00e3, 0x00e5, 0x00e7, 0x00e9, 0x00e8,
+  /* 0x90 */
+  0x00ea, 0x00eb, 0x00ed, 0x00ec, 0x00ee, 0x00ef, 0x00f1, 0x00f3,
+  0x00f2, 0x00f4, 0x00f6, 0x00f5, 0x00fa, 0x00f9, 0x00fb, 0x00fc,
+  /* 0xa0 */
+  0x2020, 0x00b0, 0x00a2, 0x00a3, 0x00a7, 0x2022, 0x00b6, 0x00df,
+  0x00ae, 0x00a9, 0x2122, 0x00b4, 0x00a8, 0x2260, 0x00c6, 0x00d8,
+  /* 0xb0 */
+  0x221e, 0x00b1, 0x2264, 0x2265, 0x00a5, 0x00b5, 0x2202, 0x2211,
+  0x220f, 0x03c0, 0x222b, 0x00aa, 0x00ba, 0x2126, 0x00e6, 0x00f8,
+  /* 0xc0 */
+  0x00bf, 0x00a1, 0x00ac, 0x221a, 0x0192, 0x2248, 0x2206, 0x00ab,
+  0x00bb, 0x2026, 0x00a0, 0x00c0, 0x00c3, 0x00d5, 0x0152, 0x0153,
+  /* 0xd0 */
+  0x2013, 0x2014, 0x201c, 0x201d, 0x2018, 0x2019, 0x00f7, 0x25ca,
+  0x00ff, 0x0178, 0x011e, 0x011f, 0x0130, 0x0131, 0x015e, 0x015f,
+  /* 0xe0 */
+  0x2021, 0x00b7, 0x201a, 0x201e, 0x2030, 0x00c2, 0x00ca, 0x00c1,
+  0x00cb, 0x00c8, 0x00cd, 0x00ce, 0x00cf, 0x00cc, 0x00d3, 0x00d4,
+  /* 0xf0 */
+  0xf8ff, 0x00d2, 0x00da, 0x00db, 0x00d9, 0xf8a0, 0x02c6, 0x02dc,
+  0x00af, 0x02d8, 0x02d9, 0x02da, 0x00b8, 0x02dd, 0x02db, 0x02c7,
+};
+
+static int
+char_mac_turkish_to_ucs2 (ucs2_t *pwc, const unsigned char *s)
+{
+  unsigned char c = *s;
+  if (c < 0x80) {
+    *pwc = (ucs2_t) c;
+    return 1;
+  }
+  else {
+    unsigned short wc = mac_turkish_2uni[c-0x80];
+    if (wc != 0xfffd) {
+      *pwc = (ucs2_t) wc;
+      return 1;
+    }
+  }
+  return 0;
+}
+
+static const unsigned char mac_turkish_page00[96] = {
+  0xca, 0xc1, 0xa2, 0xa3, 0x00, 0xb4, 0x00, 0xa4, /* 0xa0-0xa7 */
+  0xac, 0xa9, 0xbb, 0xc7, 0xc2, 0x00, 0xa8, 0xf8, /* 0xa8-0xaf */
+  0xa1, 0xb1, 0x00, 0x00, 0xab, 0xb5, 0xa6, 0xe1, /* 0xb0-0xb7 */
+  0xfc, 0x00, 0xbc, 0xc8, 0x00, 0x00, 0x00, 0xc0, /* 0xb8-0xbf */
+  0xcb, 0xe7, 0xe5, 0xcc, 0x80, 0x81, 0xae, 0x82, /* 0xc0-0xc7 */
+  0xe9, 0x83, 0xe6, 0xe8, 0xed, 0xea, 0xeb, 0xec, /* 0xc8-0xcf */
+  0x00, 0x84, 0xf1, 0xee, 0xef, 0xcd, 0x85, 0x00, /* 0xd0-0xd7 */
+  0xaf, 0xf4, 0xf2, 0xf3, 0x86, 0x00, 0x00, 0xa7, /* 0xd8-0xdf */
+  0x88, 0x87, 0x89, 0x8b, 0x8a, 0x8c, 0xbe, 0x8d, /* 0xe0-0xe7 */
+  0x8f, 0x8e, 0x90, 0x91, 0x93, 0x92, 0x94, 0x95, /* 0xe8-0xef */
+  0x00, 0x96, 0x98, 0x97, 0x99, 0x9b, 0x9a, 0xd6, /* 0xf0-0xf7 */
+  0xbf, 0x9d, 0x9c, 0x9e, 0x9f, 0x00, 0x00, 0xd8, /* 0xf8-0xff */
+};
+static const unsigned char mac_turkish_page01[128] = {
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xda, 0xdb, /* 0x18-0x1f */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+  0xdc, 0xdd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+  0x00, 0x00, 0xce, 0xcf, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xde, 0xdf, /* 0x58-0x5f */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+  0xd9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+  0x00, 0x00, 0xc4, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+};
+static const unsigned char mac_turkish_page02[32] = {
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf6, 0xff, /* 0xc0-0xc7 */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+  0xf9, 0xfa, 0xfb, 0xfe, 0xf7, 0xfd, 0x00, 0x00, /* 0xd8-0xdf */
+};
+static const unsigned char mac_turkish_page20[40] = {
+  0x00, 0x00, 0x00, 0xd0, 0xd1, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+  0xd4, 0xd5, 0xe2, 0x00, 0xd2, 0xd3, 0xe3, 0x00, /* 0x18-0x1f */
+  0xa0, 0xe0, 0xa5, 0x00, 0x00, 0x00, 0xc9, 0x00, /* 0x20-0x27 */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+  0xe4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+};
+static const unsigned char mac_turkish_page21[8] = {
+  0x00, 0x00, 0xaa, 0x00, 0x00, 0x00, 0xbd, 0x00, /* 0x20-0x27 */
+};
+static const unsigned char mac_turkish_page22[104] = {
+  0x00, 0x00, 0xb6, 0x00, 0x00, 0x00, 0xc6, 0x00, /* 0x00-0x07 */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, /* 0x08-0x0f */
+  0x00, 0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+  0x00, 0x00, 0xc3, 0x00, 0x00, 0x00, 0xb0, 0x00, /* 0x18-0x1f */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+  0x00, 0x00, 0x00, 0xba, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+  0xc5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+  0xad, 0x00, 0x00, 0x00, 0xb2, 0xb3, 0x00, 0x00, /* 0x60-0x67 */
+};
+
+static int
+char_ucs2_to_mac_turkish (unsigned char *r, ucs2_t wc)
+{
+  unsigned char c = 0;
+  if (wc < 0x0080) {
+    *r = wc;
+    return 1;
+  }
+  else if (wc >= 0x00a0 && wc < 0x0100)
+    c = mac_turkish_page00[wc-0x00a0];
+  else if (wc >= 0x0118 && wc < 0x0198)
+    c = mac_turkish_page01[wc-0x0118];
+  else if (wc >= 0x02c0 && wc < 0x02e0)
+    c = mac_turkish_page02[wc-0x02c0];
+  else if (wc == 0x03c0)
+    c = 0xb9;
+  else if (wc >= 0x2010 && wc < 0x2038)
+    c = mac_turkish_page20[wc-0x2010];
+  else if (wc >= 0x2120 && wc < 0x2128)
+    c = mac_turkish_page21[wc-0x2120];
+  else if (wc >= 0x2200 && wc < 0x2268)
+    c = mac_turkish_page22[wc-0x2200];
+  else if (wc == 0x25ca)
+    c = 0xd7;
+  else if (wc == 0xf8ff) /* Apple Logo */
+    c = 0xf0;
+  else if (wc == 0xf8a0) /* undefinded1, roundtrip only */
+    c = 0xf5;
+  if (c != 0) {
+    *r = c;
+    return 1;
+  }
+  return 0;
+}
diff --git a/libatalk/unicode/iconv.c b/libatalk/unicode/iconv.c
new file mode 100644 (file)
index 0000000..de38e13
--- /dev/null
@@ -0,0 +1,436 @@
+/* 
+   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 <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#ifdef HAVE_USABLE_ICONV
+#include <iconv.h>
+#endif
+
+#include <netatalk/endian.h>
+#include <atalk/unicode.h>
+#include <atalk/logger.h>
+#include "byteorder.h"
+
+
+/**
+ * @file
+ *
+ * @brief Samba wrapper/stub for iconv character set conversion.
+ *
+ * iconv is the XPG2 interface for converting between character
+ * encodings.  This file provides a Samba wrapper around it, and also
+ * a simple reimplementation that is used if the system does not
+ * implement iconv.
+ *
+ * Samba only works with encodings that are supersets of ASCII: ascii
+ * characters like whitespace can be tested for directly, multibyte
+ * sequences start with a byte with the high bit set, and strings are
+ * terminated by a nul byte.
+ *
+ * Note that the only function provided by iconv is conversion between
+ * characters.  It doesn't directly support operations like
+ * uppercasing or comparison.  We have to convert to UCS-2 and compare
+ * there.
+ *
+ * @sa Samba Developers Guide
+ **/
+#define CHARSET_WIDECHAR    32
+
+#ifdef HAVE_USABLE_ICONV
+#ifdef HAVE_UCS2INTERNAL
+#define UCS2ICONV "UCS-2-INTERNAL"
+#else /* !HAVE_UCS2INTERNAL */
+#if BYTE_ORDER==LITTLE_ENDIAN
+#define UCS2ICONV "UCS-2LE"
+#else /* !LITTLE_ENDIAN */
+#define UCS2ICONV "UCS-2BE"
+#endif /* BYTE_ORDER */
+#endif /* HAVE_UCS2INTERNAL */
+#else /* !HAVE_USABLE_ICONV */
+#define UCS2ICONV "UCS-2"
+#endif /* HAVE_USABLE_ICONV */
+
+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 iconv_copy(void *,char **, size_t *, char **, size_t *);
+
+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;
+#ifdef HAVE_USABLE_ICONV
+extern  struct charset_functions charset_mac_japanese;
+extern  struct charset_functions charset_mac_chinese_trad;
+extern  struct charset_functions charset_mac_korean;
+extern  struct charset_functions charset_mac_chinese_simp;
+#endif
+
+
+static struct charset_functions builtin_functions[] = {
+       {"UCS-2",   0, iconv_copy, iconv_copy, CHARSET_WIDECHAR | CHARSET_PRECOMPOSED, NULL, NULL, NULL},
+       {"ASCII",     0, ascii_pull, ascii_push, CHARSET_MULTIBYTE | CHARSET_PRECOMPOSED, NULL, NULL, NULL},
+       {"SHIFT_JIS", 1568, NULL, NULL, CHARSET_ICONV | CHARSET_PRECOMPOSED | CHARSET_CLIENT, NULL, NULL, NULL},
+       {NULL, 0, NULL, NULL, 0, NULL, NULL, NULL}
+};
+
+
+#define DLIST_ADD(list, p) \
+{ \
+        if (!(list)) { \
+                (list) = (p); \
+                (p)->next = (p)->prev = NULL; \
+        } else { \
+                (list)->prev = (p); \
+                (p)->next = (list); \
+                (p)->prev = NULL; \
+                (list) = (p); \
+        }\
+}
+
+static struct charset_functions *charsets = NULL;
+
+struct charset_functions *find_charset_functions(const char *name) 
+{
+       struct charset_functions *c = charsets;
+
+       while(c) {
+               if (strcasecmp(name, c->name) == 0) {
+                       return c;
+               }
+               c = c->next;
+       }
+
+       return NULL;
+}
+
+int atalk_register_charset(struct charset_functions *funcs) 
+{
+       if (!funcs) {
+               return -1;
+       }
+
+       /* 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);
+               return -2;
+       }
+
+       funcs->next = funcs->prev = NULL;
+       DLIST_ADD(charsets, funcs);
+       return 0;
+}
+
+void lazy_initialize_iconv(void)
+{
+       static int initialized = 0;
+       int i;
+
+       if (!initialized) {
+               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);
+#ifdef HAVE_USABLE_ICONV
+               atalk_register_charset(&charset_mac_japanese);
+               atalk_register_charset(&charset_mac_chinese_trad);
+               atalk_register_charset(&charset_mac_korean);
+               atalk_register_charset(&charset_mac_chinese_simp);
+#endif
+       }
+}
+
+/* if there was an error then reset the internal state,
+   this ensures that we don't have a shift state remaining for
+   character sets like SJIS */
+static size_t sys_iconv(void *cd, 
+                       char **inbuf, size_t *inbytesleft,
+                       char **outbuf, size_t *outbytesleft)
+{
+#ifdef HAVE_USABLE_ICONV
+       size_t ret = iconv((iconv_t)cd, 
+                          (ICONV_CONST char**)inbuf, inbytesleft, 
+                          outbuf, outbytesleft);
+       if (ret == (size_t)-1) iconv(cd, NULL, NULL, NULL, NULL);
+       return ret;
+#else
+       errno = EINVAL;
+       return -1;
+#endif
+}
+
+/**
+ * This is a simple portable iconv() implementaion.
+ *
+ * It only knows about a very small number of character sets - just
+ * enough that netatalk works on systems that don't have iconv.
+ **/
+size_t atalk_iconv(atalk_iconv_t cd, 
+                const char **inbuf, size_t *inbytesleft,
+                char **outbuf, size_t *outbytesleft)
+{
+       char cvtbuf[2048];
+       char *bufp = cvtbuf;
+       size_t bufsize;
+
+       /* in many cases we can go direct */
+       if (cd->direct) {
+               return cd->direct(cd->cd_direct, 
+                                 (char **)inbuf, inbytesleft, outbuf, outbytesleft);
+       }
+
+
+       /* otherwise we have to do it chunks at a time */
+       while (*inbytesleft > 0) {
+               bufp = cvtbuf;
+               bufsize = sizeof(cvtbuf);
+               
+               if (cd->pull(cd->cd_pull, (char **)inbuf, inbytesleft, &bufp, &bufsize) == (size_t)-1
+                      && errno != E2BIG) {
+                   return -1;
+               }
+
+               bufp = cvtbuf;
+               bufsize = sizeof(cvtbuf) - bufsize;
+
+               if (cd->push(cd->cd_push, &bufp, &bufsize, outbuf, outbytesleft) == (size_t)-1) {
+                   return -1;
+               }
+       }
+
+       return 0;
+}
+
+
+/*
+  simple iconv_open() wrapper
+ */
+atalk_iconv_t atalk_iconv_open(const char *tocode, const char *fromcode)
+{
+       atalk_iconv_t ret;
+       struct charset_functions *from, *to;
+
+
+       lazy_initialize_iconv();
+       from = charsets;
+       to = charsets;
+
+       ret = (atalk_iconv_t)malloc(sizeof(*ret));
+       if (!ret) {
+               errno = ENOMEM;
+               return (atalk_iconv_t)-1;
+       }
+       memset(ret, 0, sizeof(*ret));
+
+       ret->from_name = strdup(fromcode);
+       ret->to_name = strdup(tocode);
+
+       /* check for the simplest null conversion */
+       if (strcasecmp(fromcode, tocode) == 0) {
+               ret->direct = iconv_copy;
+               return ret;
+       }
+
+       /* check if we have a builtin function for this conversion */
+       from = find_charset_functions(fromcode);
+       if (from) ret->pull = from->pull;
+       
+       to = find_charset_functions(tocode);
+       if (to) ret->push = to->push;
+
+       /* check if we can use iconv for this conversion */
+#ifdef HAVE_USABLE_ICONV
+       if (!from || (from->flags & CHARSET_ICONV)) {
+         ret->cd_pull = iconv_open(UCS2ICONV, from && from->iname ? from->iname : fromcode);
+         if (ret->cd_pull != (iconv_t)-1) {
+           if (!ret->pull) ret->pull = sys_iconv;
+         } else ret->pull = NULL;
+       }
+       if (ret->pull) {
+         if (!to || (to->flags & CHARSET_ICONV)) {
+           ret->cd_push = iconv_open(to && to->iname ? to->iname : tocode, UCS2ICONV);
+           if (ret->cd_push != (iconv_t)-1) {
+             if (!ret->push) ret->push = sys_iconv;
+           } else ret->push = NULL;
+         }
+         if (!ret->push && ret->cd_pull) iconv_close((iconv_t)ret->cd_pull);
+       }
+#endif
+       
+       if (!ret->push || !ret->pull) {
+               SAFE_FREE(ret->from_name);
+               SAFE_FREE(ret->to_name);
+               SAFE_FREE(ret);
+               errno = EINVAL;
+               return (atalk_iconv_t)-1;
+       }
+
+       /* check for conversion to/from ucs2 */
+       if (strcasecmp(fromcode, "UCS-2") == 0) {
+         ret->direct = ret->push;
+         ret->cd_direct = ret->cd_push;
+         ret->cd_push = NULL;
+       }
+       if (strcasecmp(tocode, "UCS-2") == 0) {
+         ret->direct = ret->pull;
+         ret->cd_direct = ret->cd_pull;
+         ret->cd_pull = NULL;
+       }
+
+       return ret;
+}
+
+/*
+  simple iconv_close() wrapper
+*/
+int atalk_iconv_close (atalk_iconv_t cd)
+{
+#ifdef HAVE_USABLE_ICONV
+       if (cd->cd_direct) iconv_close((iconv_t)cd->cd_direct);
+       if (cd->cd_pull) iconv_close((iconv_t)cd->cd_pull);
+       if (cd->cd_push) iconv_close((iconv_t)cd->cd_push);
+#endif
+
+       SAFE_FREE(cd->from_name);
+       SAFE_FREE(cd->to_name);
+
+       memset(cd, 0, sizeof(*cd));
+       SAFE_FREE(cd);
+       return 0;
+}
+
+
+/************************************************************************
+ the following functions implement the builtin character sets in Netatalk
+*************************************************************************/
+
+static size_t ascii_pull(void *cd _U_, char **inbuf, size_t *inbytesleft,
+                        char **outbuf, size_t *outbytesleft)
+{
+       ucs2_t curchar;
+
+       while (*inbytesleft >= 1 && *outbytesleft >= 2) {
+               if ((unsigned char)(*inbuf)[0] < 0x80) {
+                       curchar = (ucs2_t) (*inbuf)[0];
+                       SSVAL((*outbuf),0,curchar);
+               }
+               else {
+                       errno = EILSEQ;
+                       return -1;
+               }
+               (*inbytesleft)  -= 1;
+               (*outbytesleft) -= 2;
+               (*inbuf)  += 1;
+               (*outbuf) += 2;
+       }
+
+       if (*inbytesleft > 0) {
+               errno = E2BIG;
+               return -1;
+       }
+       
+       return 0;
+}
+
+static size_t ascii_push(void *cd _U_, char **inbuf, size_t *inbytesleft,
+                        char **outbuf, size_t *outbytesleft)
+{
+       int ir_count=0;
+       ucs2_t curchar;
+
+       while (*inbytesleft >= 2 && *outbytesleft >= 1) {
+               curchar = SVAL((*inbuf), 0);
+               if (curchar < 0x0080) {
+                       (*outbuf)[0] = curchar;
+               }
+               else {
+                       errno = EILSEQ;
+                       return -1;
+               }       
+               (*inbytesleft)  -= 2;
+               (*outbytesleft) -= 1;
+               (*inbuf)  += 2;
+               (*outbuf) += 1;
+       }
+
+       if (*inbytesleft == 1) {
+               errno = EINVAL;
+               return -1;
+       }
+
+       if (*inbytesleft > 1) {
+               errno = E2BIG;
+               return -1;
+       }
+       
+       return ir_count;
+}
+
+
+static size_t iconv_copy(void *cd _U_, char **inbuf, size_t *inbytesleft,
+                        char **outbuf, size_t *outbytesleft)
+{
+       int n;
+
+       n = MIN(*inbytesleft, *outbytesleft);
+
+       memmove(*outbuf, *inbuf, n);
+
+       (*inbytesleft) -= n;
+       (*outbytesleft) -= n;
+       (*inbuf) += n;
+       (*outbuf) += n;
+
+       if (*inbytesleft > 0) {
+               errno = E2BIG;
+               return -1;
+       }
+
+       return 0;
+}
+
+/* ------------------------ */
diff --git a/libatalk/unicode/precompose.h b/libatalk/unicode/precompose.h
new file mode 100644 (file)
index 0000000..bd578bf
--- /dev/null
@@ -0,0 +1,1995 @@
+/*
+ * Canonical Compositions
+ * from xfree86 project
+ */
+/* $XFree86: xc/programs/xterm/precompose.c,v 1.2 2000/11/01 01:12:41 dawes Exp $ */
+
+static const struct {
+  unsigned int replacement;
+  unsigned int base;
+  unsigned int comb; 
+} precompositions[] = {
+{ 0x226E, 0x003C, 0x0338},
+{ 0x2260, 0x003D, 0x0338},
+{ 0x226F, 0x003E, 0x0338},
+{ 0x00C0, 0x0041, 0x0300},
+{ 0x00C1, 0x0041, 0x0301},
+{ 0x00C2, 0x0041, 0x0302},
+{ 0x00C3, 0x0041, 0x0303},
+{ 0x0100, 0x0041, 0x0304},
+{ 0x0102, 0x0041, 0x0306},
+{ 0x0226, 0x0041, 0x0307},
+{ 0x00C4, 0x0041, 0x0308},
+{ 0x1EA2, 0x0041, 0x0309},
+{ 0x00C5, 0x0041, 0x030A},
+{ 0x01CD, 0x0041, 0x030C},
+{ 0x0200, 0x0041, 0x030F},
+{ 0x0202, 0x0041, 0x0311},
+{ 0x1EA0, 0x0041, 0x0323},
+{ 0x1E00, 0x0041, 0x0325},
+{ 0x0104, 0x0041, 0x0328},
+{ 0x1E02, 0x0042, 0x0307},
+{ 0x1E04, 0x0042, 0x0323},
+{ 0x1E06, 0x0042, 0x0331},
+{ 0x0106, 0x0043, 0x0301},
+{ 0x0108, 0x0043, 0x0302},
+{ 0x010A, 0x0043, 0x0307},
+{ 0x010C, 0x0043, 0x030C},
+{ 0x00C7, 0x0043, 0x0327},
+{ 0x1E0A, 0x0044, 0x0307},
+{ 0x010E, 0x0044, 0x030C},
+{ 0x1E0C, 0x0044, 0x0323},
+{ 0x1E10, 0x0044, 0x0327},
+{ 0x1E12, 0x0044, 0x032D},
+{ 0x1E0E, 0x0044, 0x0331},
+{ 0x00C8, 0x0045, 0x0300},
+{ 0x00C9, 0x0045, 0x0301},
+{ 0x00CA, 0x0045, 0x0302},
+{ 0x1EBC, 0x0045, 0x0303},
+{ 0x0112, 0x0045, 0x0304},
+{ 0x0114, 0x0045, 0x0306},
+{ 0x0116, 0x0045, 0x0307},
+{ 0x00CB, 0x0045, 0x0308},
+{ 0x1EBA, 0x0045, 0x0309},
+{ 0x011A, 0x0045, 0x030C},
+{ 0x0204, 0x0045, 0x030F},
+{ 0x0206, 0x0045, 0x0311},
+{ 0x1EB8, 0x0045, 0x0323},
+{ 0x0228, 0x0045, 0x0327},
+{ 0x0118, 0x0045, 0x0328},
+{ 0x1E18, 0x0045, 0x032D},
+{ 0x1E1A, 0x0045, 0x0330},
+{ 0x1E1E, 0x0046, 0x0307},
+{ 0x01F4, 0x0047, 0x0301},
+{ 0x011C, 0x0047, 0x0302},
+{ 0x1E20, 0x0047, 0x0304},
+{ 0x011E, 0x0047, 0x0306},
+{ 0x0120, 0x0047, 0x0307},
+{ 0x01E6, 0x0047, 0x030C},
+{ 0x0122, 0x0047, 0x0327},
+{ 0x0124, 0x0048, 0x0302},
+{ 0x1E22, 0x0048, 0x0307},
+{ 0x1E26, 0x0048, 0x0308},
+{ 0x021E, 0x0048, 0x030C},
+{ 0x1E24, 0x0048, 0x0323},
+{ 0x1E28, 0x0048, 0x0327},
+{ 0x1E2A, 0x0048, 0x032E},
+{ 0x00CC, 0x0049, 0x0300},
+{ 0x00CD, 0x0049, 0x0301},
+{ 0x00CE, 0x0049, 0x0302},
+{ 0x0128, 0x0049, 0x0303},
+{ 0x012A, 0x0049, 0x0304},
+{ 0x012C, 0x0049, 0x0306},
+{ 0x0130, 0x0049, 0x0307},
+{ 0x00CF, 0x0049, 0x0308},
+{ 0x1EC8, 0x0049, 0x0309},
+{ 0x01CF, 0x0049, 0x030C},
+{ 0x0208, 0x0049, 0x030F},
+{ 0x020A, 0x0049, 0x0311},
+{ 0x1ECA, 0x0049, 0x0323},
+{ 0x012E, 0x0049, 0x0328},
+{ 0x1E2C, 0x0049, 0x0330},
+{ 0x0134, 0x004A, 0x0302},
+{ 0x1E30, 0x004B, 0x0301},
+{ 0x01E8, 0x004B, 0x030C},
+{ 0x1E32, 0x004B, 0x0323},
+{ 0x0136, 0x004B, 0x0327},
+{ 0x1E34, 0x004B, 0x0331},
+{ 0x0139, 0x004C, 0x0301},
+{ 0x013D, 0x004C, 0x030C},
+{ 0x1E36, 0x004C, 0x0323},
+{ 0x013B, 0x004C, 0x0327},
+{ 0x1E3C, 0x004C, 0x032D},
+{ 0x1E3A, 0x004C, 0x0331},
+{ 0x1E3E, 0x004D, 0x0301},
+{ 0x1E40, 0x004D, 0x0307},
+{ 0x1E42, 0x004D, 0x0323},
+{ 0x01F8, 0x004E, 0x0300},
+{ 0x0143, 0x004E, 0x0301},
+{ 0x00D1, 0x004E, 0x0303},
+{ 0x1E44, 0x004E, 0x0307},
+{ 0x0147, 0x004E, 0x030C},
+{ 0x1E46, 0x004E, 0x0323},
+{ 0x0145, 0x004E, 0x0327},
+{ 0x1E4A, 0x004E, 0x032D},
+{ 0x1E48, 0x004E, 0x0331},
+{ 0x00D2, 0x004F, 0x0300},
+{ 0x00D3, 0x004F, 0x0301},
+{ 0x00D4, 0x004F, 0x0302},
+{ 0x00D5, 0x004F, 0x0303},
+{ 0x014C, 0x004F, 0x0304},
+{ 0x014E, 0x004F, 0x0306},
+{ 0x022E, 0x004F, 0x0307},
+{ 0x00D6, 0x004F, 0x0308},
+{ 0x1ECE, 0x004F, 0x0309},
+{ 0x0150, 0x004F, 0x030B},
+{ 0x01D1, 0x004F, 0x030C},
+{ 0x020C, 0x004F, 0x030F},
+{ 0x020E, 0x004F, 0x0311},
+{ 0x01A0, 0x004F, 0x031B},
+{ 0x1ECC, 0x004F, 0x0323},
+{ 0x01EA, 0x004F, 0x0328},
+{ 0x1E54, 0x0050, 0x0301},
+{ 0x1E56, 0x0050, 0x0307},
+{ 0x0154, 0x0052, 0x0301},
+{ 0x1E58, 0x0052, 0x0307},
+{ 0x0158, 0x0052, 0x030C},
+{ 0x0210, 0x0052, 0x030F},
+{ 0x0212, 0x0052, 0x0311},
+{ 0x1E5A, 0x0052, 0x0323},
+{ 0x0156, 0x0052, 0x0327},
+{ 0x1E5E, 0x0052, 0x0331},
+{ 0x015A, 0x0053, 0x0301},
+{ 0x015C, 0x0053, 0x0302},
+{ 0x1E60, 0x0053, 0x0307},
+{ 0x0160, 0x0053, 0x030C},
+{ 0x1E62, 0x0053, 0x0323},
+{ 0x0218, 0x0053, 0x0326},
+{ 0x015E, 0x0053, 0x0327},
+{ 0x1E6A, 0x0054, 0x0307},
+{ 0x0164, 0x0054, 0x030C},
+{ 0x1E6C, 0x0054, 0x0323},
+{ 0x021A, 0x0054, 0x0326},
+{ 0x0162, 0x0054, 0x0327},
+{ 0x1E70, 0x0054, 0x032D},
+{ 0x1E6E, 0x0054, 0x0331},
+{ 0x00D9, 0x0055, 0x0300},
+{ 0x00DA, 0x0055, 0x0301},
+{ 0x00DB, 0x0055, 0x0302},
+{ 0x0168, 0x0055, 0x0303},
+{ 0x016A, 0x0055, 0x0304},
+{ 0x016C, 0x0055, 0x0306},
+{ 0x00DC, 0x0055, 0x0308},
+{ 0x1EE6, 0x0055, 0x0309},
+{ 0x016E, 0x0055, 0x030A},
+{ 0x0170, 0x0055, 0x030B},
+{ 0x01D3, 0x0055, 0x030C},
+{ 0x0214, 0x0055, 0x030F},
+{ 0x0216, 0x0055, 0x0311},
+{ 0x01AF, 0x0055, 0x031B},
+{ 0x1EE4, 0x0055, 0x0323},
+{ 0x1E72, 0x0055, 0x0324},
+{ 0x0172, 0x0055, 0x0328},
+{ 0x1E76, 0x0055, 0x032D},
+{ 0x1E74, 0x0055, 0x0330},
+{ 0x1E7C, 0x0056, 0x0303},
+{ 0x1E7E, 0x0056, 0x0323},
+{ 0x1E80, 0x0057, 0x0300},
+{ 0x1E82, 0x0057, 0x0301},
+{ 0x0174, 0x0057, 0x0302},
+{ 0x1E86, 0x0057, 0x0307},
+{ 0x1E84, 0x0057, 0x0308},
+{ 0x1E88, 0x0057, 0x0323},
+{ 0x1E8A, 0x0058, 0x0307},
+{ 0x1E8C, 0x0058, 0x0308},
+{ 0x1EF2, 0x0059, 0x0300},
+{ 0x00DD, 0x0059, 0x0301},
+{ 0x0176, 0x0059, 0x0302},
+{ 0x1EF8, 0x0059, 0x0303},
+{ 0x0232, 0x0059, 0x0304},
+{ 0x1E8E, 0x0059, 0x0307},
+{ 0x0178, 0x0059, 0x0308},
+{ 0x1EF6, 0x0059, 0x0309},
+{ 0x1EF4, 0x0059, 0x0323},
+{ 0x0179, 0x005A, 0x0301},
+{ 0x1E90, 0x005A, 0x0302},
+{ 0x017B, 0x005A, 0x0307},
+{ 0x017D, 0x005A, 0x030C},
+{ 0x1E92, 0x005A, 0x0323},
+{ 0x1E94, 0x005A, 0x0331},
+{ 0x00E0, 0x0061, 0x0300},
+{ 0x00E1, 0x0061, 0x0301},
+{ 0x00E2, 0x0061, 0x0302},
+{ 0x00E3, 0x0061, 0x0303},
+{ 0x0101, 0x0061, 0x0304},
+{ 0x0103, 0x0061, 0x0306},
+{ 0x0227, 0x0061, 0x0307},
+{ 0x00E4, 0x0061, 0x0308},
+{ 0x1EA3, 0x0061, 0x0309},
+{ 0x00E5, 0x0061, 0x030A},
+{ 0x01CE, 0x0061, 0x030C},
+{ 0x0201, 0x0061, 0x030F},
+{ 0x0203, 0x0061, 0x0311},
+{ 0x1EA1, 0x0061, 0x0323},
+{ 0x1E01, 0x0061, 0x0325},
+{ 0x0105, 0x0061, 0x0328},
+{ 0x1E03, 0x0062, 0x0307},
+{ 0x1E05, 0x0062, 0x0323},
+{ 0x1E07, 0x0062, 0x0331},
+{ 0x0107, 0x0063, 0x0301},
+{ 0x0109, 0x0063, 0x0302},
+{ 0x010B, 0x0063, 0x0307},
+{ 0x010D, 0x0063, 0x030C},
+{ 0x00E7, 0x0063, 0x0327},
+{ 0x1E0B, 0x0064, 0x0307},
+{ 0x010F, 0x0064, 0x030C},
+{ 0x1E0D, 0x0064, 0x0323},
+{ 0x1E11, 0x0064, 0x0327},
+{ 0x1E13, 0x0064, 0x032D},
+{ 0x1E0F, 0x0064, 0x0331},
+{ 0x00E8, 0x0065, 0x0300},
+{ 0x00E9, 0x0065, 0x0301},
+{ 0x00EA, 0x0065, 0x0302},
+{ 0x1EBD, 0x0065, 0x0303},
+{ 0x0113, 0x0065, 0x0304},
+{ 0x0115, 0x0065, 0x0306},
+{ 0x0117, 0x0065, 0x0307},
+{ 0x00EB, 0x0065, 0x0308},
+{ 0x1EBB, 0x0065, 0x0309},
+{ 0x011B, 0x0065, 0x030C},
+{ 0x0205, 0x0065, 0x030F},
+{ 0x0207, 0x0065, 0x0311},
+{ 0x1EB9, 0x0065, 0x0323},
+{ 0x0229, 0x0065, 0x0327},
+{ 0x0119, 0x0065, 0x0328},
+{ 0x1E19, 0x0065, 0x032D},
+{ 0x1E1B, 0x0065, 0x0330},
+{ 0x1E1F, 0x0066, 0x0307},
+{ 0x01F5, 0x0067, 0x0301},
+{ 0x011D, 0x0067, 0x0302},
+{ 0x1E21, 0x0067, 0x0304},
+{ 0x011F, 0x0067, 0x0306},
+{ 0x0121, 0x0067, 0x0307},
+{ 0x01E7, 0x0067, 0x030C},
+{ 0x0123, 0x0067, 0x0327},
+{ 0x0125, 0x0068, 0x0302},
+{ 0x1E23, 0x0068, 0x0307},
+{ 0x1E27, 0x0068, 0x0308},
+{ 0x021F, 0x0068, 0x030C},
+{ 0x1E25, 0x0068, 0x0323},
+{ 0x1E29, 0x0068, 0x0327},
+{ 0x1E2B, 0x0068, 0x032E},
+{ 0x1E96, 0x0068, 0x0331},
+{ 0x00EC, 0x0069, 0x0300},
+{ 0x00ED, 0x0069, 0x0301},
+{ 0x00EE, 0x0069, 0x0302},
+{ 0x0129, 0x0069, 0x0303},
+{ 0x012B, 0x0069, 0x0304},
+{ 0x012D, 0x0069, 0x0306},
+{ 0x00EF, 0x0069, 0x0308},
+{ 0x1EC9, 0x0069, 0x0309},
+{ 0x01D0, 0x0069, 0x030C},
+{ 0x0209, 0x0069, 0x030F},
+{ 0x020B, 0x0069, 0x0311},
+{ 0x1ECB, 0x0069, 0x0323},
+{ 0x012F, 0x0069, 0x0328},
+{ 0x1E2D, 0x0069, 0x0330},
+{ 0x0135, 0x006A, 0x0302},
+{ 0x01F0, 0x006A, 0x030C},
+{ 0x1E31, 0x006B, 0x0301},
+{ 0x01E9, 0x006B, 0x030C},
+{ 0x1E33, 0x006B, 0x0323},
+{ 0x0137, 0x006B, 0x0327},
+{ 0x1E35, 0x006B, 0x0331},
+{ 0x013A, 0x006C, 0x0301},
+{ 0x013E, 0x006C, 0x030C},
+{ 0x1E37, 0x006C, 0x0323},
+{ 0x013C, 0x006C, 0x0327},
+{ 0x1E3D, 0x006C, 0x032D},
+{ 0x1E3B, 0x006C, 0x0331},
+{ 0x1E3F, 0x006D, 0x0301},
+{ 0x1E41, 0x006D, 0x0307},
+{ 0x1E43, 0x006D, 0x0323},
+{ 0x01F9, 0x006E, 0x0300},
+{ 0x0144, 0x006E, 0x0301},
+{ 0x00F1, 0x006E, 0x0303},
+{ 0x1E45, 0x006E, 0x0307},
+{ 0x0148, 0x006E, 0x030C},
+{ 0x1E47, 0x006E, 0x0323},
+{ 0x0146, 0x006E, 0x0327},
+{ 0x1E4B, 0x006E, 0x032D},
+{ 0x1E49, 0x006E, 0x0331},
+{ 0x00F2, 0x006F, 0x0300},
+{ 0x00F3, 0x006F, 0x0301},
+{ 0x00F4, 0x006F, 0x0302},
+{ 0x00F5, 0x006F, 0x0303},
+{ 0x014D, 0x006F, 0x0304},
+{ 0x014F, 0x006F, 0x0306},
+{ 0x022F, 0x006F, 0x0307},
+{ 0x00F6, 0x006F, 0x0308},
+{ 0x1ECF, 0x006F, 0x0309},
+{ 0x0151, 0x006F, 0x030B},
+{ 0x01D2, 0x006F, 0x030C},
+{ 0x020D, 0x006F, 0x030F},
+{ 0x020F, 0x006F, 0x0311},
+{ 0x01A1, 0x006F, 0x031B},
+{ 0x1ECD, 0x006F, 0x0323},
+{ 0x01EB, 0x006F, 0x0328},
+{ 0x1E55, 0x0070, 0x0301},
+{ 0x1E57, 0x0070, 0x0307},
+{ 0x0155, 0x0072, 0x0301},
+{ 0x1E59, 0x0072, 0x0307},
+{ 0x0159, 0x0072, 0x030C},
+{ 0x0211, 0x0072, 0x030F},
+{ 0x0213, 0x0072, 0x0311},
+{ 0x1E5B, 0x0072, 0x0323},
+{ 0x0157, 0x0072, 0x0327},
+{ 0x1E5F, 0x0072, 0x0331},
+{ 0x015B, 0x0073, 0x0301},
+{ 0x015D, 0x0073, 0x0302},
+{ 0x1E61, 0x0073, 0x0307},
+{ 0x0161, 0x0073, 0x030C},
+{ 0x1E63, 0x0073, 0x0323},
+{ 0x0219, 0x0073, 0x0326},
+{ 0x015F, 0x0073, 0x0327},
+{ 0x1E6B, 0x0074, 0x0307},
+{ 0x1E97, 0x0074, 0x0308},
+{ 0x0165, 0x0074, 0x030C},
+{ 0x1E6D, 0x0074, 0x0323},
+{ 0x021B, 0x0074, 0x0326},
+{ 0x0163, 0x0074, 0x0327},
+{ 0x1E71, 0x0074, 0x032D},
+{ 0x1E6F, 0x0074, 0x0331},
+{ 0x00F9, 0x0075, 0x0300},
+{ 0x00FA, 0x0075, 0x0301},
+{ 0x00FB, 0x0075, 0x0302},
+{ 0x0169, 0x0075, 0x0303},
+{ 0x016B, 0x0075, 0x0304},
+{ 0x016D, 0x0075, 0x0306},
+{ 0x00FC, 0x0075, 0x0308},
+{ 0x1EE7, 0x0075, 0x0309},
+{ 0x016F, 0x0075, 0x030A},
+{ 0x0171, 0x0075, 0x030B},
+{ 0x01D4, 0x0075, 0x030C},
+{ 0x0215, 0x0075, 0x030F},
+{ 0x0217, 0x0075, 0x0311},
+{ 0x01B0, 0x0075, 0x031B},
+{ 0x1EE5, 0x0075, 0x0323},
+{ 0x1E73, 0x0075, 0x0324},
+{ 0x0173, 0x0075, 0x0328},
+{ 0x1E77, 0x0075, 0x032D},
+{ 0x1E75, 0x0075, 0x0330},
+{ 0x1E7D, 0x0076, 0x0303},
+{ 0x1E7F, 0x0076, 0x0323},
+{ 0x1E81, 0x0077, 0x0300},
+{ 0x1E83, 0x0077, 0x0301},
+{ 0x0175, 0x0077, 0x0302},
+{ 0x1E87, 0x0077, 0x0307},
+{ 0x1E85, 0x0077, 0x0308},
+{ 0x1E98, 0x0077, 0x030A},
+{ 0x1E89, 0x0077, 0x0323},
+{ 0x1E8B, 0x0078, 0x0307},
+{ 0x1E8D, 0x0078, 0x0308},
+{ 0x1EF3, 0x0079, 0x0300},
+{ 0x00FD, 0x0079, 0x0301},
+{ 0x0177, 0x0079, 0x0302},
+{ 0x1EF9, 0x0079, 0x0303},
+{ 0x0233, 0x0079, 0x0304},
+{ 0x1E8F, 0x0079, 0x0307},
+{ 0x00FF, 0x0079, 0x0308},
+{ 0x1EF7, 0x0079, 0x0309},
+{ 0x1E99, 0x0079, 0x030A},
+{ 0x1EF5, 0x0079, 0x0323},
+{ 0x017A, 0x007A, 0x0301},
+{ 0x1E91, 0x007A, 0x0302},
+{ 0x017C, 0x007A, 0x0307},
+{ 0x017E, 0x007A, 0x030C},
+{ 0x1E93, 0x007A, 0x0323},
+{ 0x1E95, 0x007A, 0x0331},
+{ 0x1FED, 0x00A8, 0x0300},
+{ 0x0385, 0x00A8, 0x0301},
+{ 0x1FC1, 0x00A8, 0x0342},
+{ 0x1EA6, 0x00C2, 0x0300},
+{ 0x1EA4, 0x00C2, 0x0301},
+{ 0x1EAA, 0x00C2, 0x0303},
+{ 0x1EA8, 0x00C2, 0x0309},
+{ 0x01DE, 0x00C4, 0x0304},
+{ 0x01FA, 0x00C5, 0x0301},
+{ 0x01FC, 0x00C6, 0x0301},
+{ 0x01E2, 0x00C6, 0x0304},
+{ 0x1E08, 0x00C7, 0x0301},
+{ 0x1EC0, 0x00CA, 0x0300},
+{ 0x1EBE, 0x00CA, 0x0301},
+{ 0x1EC4, 0x00CA, 0x0303},
+{ 0x1EC2, 0x00CA, 0x0309},
+{ 0x1E2E, 0x00CF, 0x0301},
+{ 0x1ED2, 0x00D4, 0x0300},
+{ 0x1ED0, 0x00D4, 0x0301},
+{ 0x1ED6, 0x00D4, 0x0303},
+{ 0x1ED4, 0x00D4, 0x0309},
+{ 0x1E4C, 0x00D5, 0x0301},
+{ 0x022C, 0x00D5, 0x0304},
+{ 0x1E4E, 0x00D5, 0x0308},
+{ 0x022A, 0x00D6, 0x0304},
+{ 0x01FE, 0x00D8, 0x0301},
+{ 0x01DB, 0x00DC, 0x0300},
+{ 0x01D7, 0x00DC, 0x0301},
+{ 0x01D5, 0x00DC, 0x0304},
+{ 0x01D9, 0x00DC, 0x030C},
+{ 0x1EA7, 0x00E2, 0x0300},
+{ 0x1EA5, 0x00E2, 0x0301},
+{ 0x1EAB, 0x00E2, 0x0303},
+{ 0x1EA9, 0x00E2, 0x0309},
+{ 0x01DF, 0x00E4, 0x0304},
+{ 0x01FB, 0x00E5, 0x0301},
+{ 0x01FD, 0x00E6, 0x0301},
+{ 0x01E3, 0x00E6, 0x0304},
+{ 0x1E09, 0x00E7, 0x0301},
+{ 0x1EC1, 0x00EA, 0x0300},
+{ 0x1EBF, 0x00EA, 0x0301},
+{ 0x1EC5, 0x00EA, 0x0303},
+{ 0x1EC3, 0x00EA, 0x0309},
+{ 0x1E2F, 0x00EF, 0x0301},
+{ 0x1ED3, 0x00F4, 0x0300},
+{ 0x1ED1, 0x00F4, 0x0301},
+{ 0x1ED7, 0x00F4, 0x0303},
+{ 0x1ED5, 0x00F4, 0x0309},
+{ 0x1E4D, 0x00F5, 0x0301},
+{ 0x022D, 0x00F5, 0x0304},
+{ 0x1E4F, 0x00F5, 0x0308},
+{ 0x022B, 0x00F6, 0x0304},
+{ 0x01FF, 0x00F8, 0x0301},
+{ 0x01DC, 0x00FC, 0x0300},
+{ 0x01D8, 0x00FC, 0x0301},
+{ 0x01D6, 0x00FC, 0x0304},
+{ 0x01DA, 0x00FC, 0x030C},
+{ 0x1EB0, 0x0102, 0x0300},
+{ 0x1EAE, 0x0102, 0x0301},
+{ 0x1EB4, 0x0102, 0x0303},
+{ 0x1EB2, 0x0102, 0x0309},
+{ 0x1EB1, 0x0103, 0x0300},
+{ 0x1EAF, 0x0103, 0x0301},
+{ 0x1EB5, 0x0103, 0x0303},
+{ 0x1EB3, 0x0103, 0x0309},
+{ 0x1E14, 0x0112, 0x0300},
+{ 0x1E16, 0x0112, 0x0301},
+{ 0x1E15, 0x0113, 0x0300},
+{ 0x1E17, 0x0113, 0x0301},
+{ 0x1E50, 0x014C, 0x0300},
+{ 0x1E52, 0x014C, 0x0301},
+{ 0x1E51, 0x014D, 0x0300},
+{ 0x1E53, 0x014D, 0x0301},
+{ 0x1E64, 0x015A, 0x0307},
+{ 0x1E65, 0x015B, 0x0307},
+{ 0x1E66, 0x0160, 0x0307},
+{ 0x1E67, 0x0161, 0x0307},
+{ 0x1E78, 0x0168, 0x0301},
+{ 0x1E79, 0x0169, 0x0301},
+{ 0x1E7A, 0x016A, 0x0308},
+{ 0x1E7B, 0x016B, 0x0308},
+{ 0x1E9B, 0x017F, 0x0307},
+{ 0x1EDC, 0x01A0, 0x0300},
+{ 0x1EDA, 0x01A0, 0x0301},
+{ 0x1EE0, 0x01A0, 0x0303},
+{ 0x1EDE, 0x01A0, 0x0309},
+{ 0x1EE2, 0x01A0, 0x0323},
+{ 0x1EDD, 0x01A1, 0x0300},
+{ 0x1EDB, 0x01A1, 0x0301},
+{ 0x1EE1, 0x01A1, 0x0303},
+{ 0x1EDF, 0x01A1, 0x0309},
+{ 0x1EE3, 0x01A1, 0x0323},
+{ 0x1EEA, 0x01AF, 0x0300},
+{ 0x1EE8, 0x01AF, 0x0301},
+{ 0x1EEE, 0x01AF, 0x0303},
+{ 0x1EEC, 0x01AF, 0x0309},
+{ 0x1EF0, 0x01AF, 0x0323},
+{ 0x1EEB, 0x01B0, 0x0300},
+{ 0x1EE9, 0x01B0, 0x0301},
+{ 0x1EEF, 0x01B0, 0x0303},
+{ 0x1EED, 0x01B0, 0x0309},
+{ 0x1EF1, 0x01B0, 0x0323},
+{ 0x01EE, 0x01B7, 0x030C},
+{ 0x01EC, 0x01EA, 0x0304},
+{ 0x01ED, 0x01EB, 0x0304},
+{ 0x01E0, 0x0226, 0x0304},
+{ 0x01E1, 0x0227, 0x0304},
+{ 0x1E1C, 0x0228, 0x0306},
+{ 0x1E1D, 0x0229, 0x0306},
+{ 0x0230, 0x022E, 0x0304},
+{ 0x0231, 0x022F, 0x0304},
+{ 0x01EF, 0x0292, 0x030C},
+{ 0x0344, 0x0308, 0x0301},
+{ 0x1FBA, 0x0391, 0x0300},
+{ 0x0386, 0x0391, 0x0301},
+{ 0x1FB9, 0x0391, 0x0304},
+{ 0x1FB8, 0x0391, 0x0306},
+{ 0x1F08, 0x0391, 0x0313},
+{ 0x1F09, 0x0391, 0x0314},
+{ 0x1FBC, 0x0391, 0x0345},
+{ 0x1FC8, 0x0395, 0x0300},
+{ 0x0388, 0x0395, 0x0301},
+{ 0x1F18, 0x0395, 0x0313},
+{ 0x1F19, 0x0395, 0x0314},
+{ 0x1FCA, 0x0397, 0x0300},
+{ 0x0389, 0x0397, 0x0301},
+{ 0x1F28, 0x0397, 0x0313},
+{ 0x1F29, 0x0397, 0x0314},
+{ 0x1FCC, 0x0397, 0x0345},
+{ 0x1FDA, 0x0399, 0x0300},
+{ 0x038A, 0x0399, 0x0301},
+{ 0x1FD9, 0x0399, 0x0304},
+{ 0x1FD8, 0x0399, 0x0306},
+{ 0x03AA, 0x0399, 0x0308},
+{ 0x1F38, 0x0399, 0x0313},
+{ 0x1F39, 0x0399, 0x0314},
+{ 0x1FF8, 0x039F, 0x0300},
+{ 0x038C, 0x039F, 0x0301},
+{ 0x1F48, 0x039F, 0x0313},
+{ 0x1F49, 0x039F, 0x0314},
+{ 0x1FEC, 0x03A1, 0x0314},
+{ 0x1FEA, 0x03A5, 0x0300},
+{ 0x038E, 0x03A5, 0x0301},
+{ 0x1FE9, 0x03A5, 0x0304},
+{ 0x1FE8, 0x03A5, 0x0306},
+{ 0x03AB, 0x03A5, 0x0308},
+{ 0x1F59, 0x03A5, 0x0314},
+{ 0x1FFA, 0x03A9, 0x0300},
+{ 0x038F, 0x03A9, 0x0301},
+{ 0x1F68, 0x03A9, 0x0313},
+{ 0x1F69, 0x03A9, 0x0314},
+{ 0x1FFC, 0x03A9, 0x0345},
+{ 0x1FB4, 0x03AC, 0x0345},
+{ 0x1FC4, 0x03AE, 0x0345},
+{ 0x1F70, 0x03B1, 0x0300},
+{ 0x03AC, 0x03B1, 0x0301},
+{ 0x1FB1, 0x03B1, 0x0304},
+{ 0x1FB0, 0x03B1, 0x0306},
+{ 0x1F00, 0x03B1, 0x0313},
+{ 0x1F01, 0x03B1, 0x0314},
+{ 0x1FB6, 0x03B1, 0x0342},
+{ 0x1FB3, 0x03B1, 0x0345},
+{ 0x1F72, 0x03B5, 0x0300},
+{ 0x03AD, 0x03B5, 0x0301},
+{ 0x1F10, 0x03B5, 0x0313},
+{ 0x1F11, 0x03B5, 0x0314},
+{ 0x1F74, 0x03B7, 0x0300},
+{ 0x03AE, 0x03B7, 0x0301},
+{ 0x1F20, 0x03B7, 0x0313},
+{ 0x1F21, 0x03B7, 0x0314},
+{ 0x1FC6, 0x03B7, 0x0342},
+{ 0x1FC3, 0x03B7, 0x0345},
+{ 0x1F76, 0x03B9, 0x0300},
+{ 0x03AF, 0x03B9, 0x0301},
+{ 0x1FD1, 0x03B9, 0x0304},
+{ 0x1FD0, 0x03B9, 0x0306},
+{ 0x03CA, 0x03B9, 0x0308},
+{ 0x1F30, 0x03B9, 0x0313},
+{ 0x1F31, 0x03B9, 0x0314},
+{ 0x1FD6, 0x03B9, 0x0342},
+{ 0x1F78, 0x03BF, 0x0300},
+{ 0x03CC, 0x03BF, 0x0301},
+{ 0x1F40, 0x03BF, 0x0313},
+{ 0x1F41, 0x03BF, 0x0314},
+{ 0x1FE4, 0x03C1, 0x0313},
+{ 0x1FE5, 0x03C1, 0x0314},
+{ 0x1F7A, 0x03C5, 0x0300},
+{ 0x03CD, 0x03C5, 0x0301},
+{ 0x1FE1, 0x03C5, 0x0304},
+{ 0x1FE0, 0x03C5, 0x0306},
+{ 0x03CB, 0x03C5, 0x0308},
+{ 0x1F50, 0x03C5, 0x0313},
+{ 0x1F51, 0x03C5, 0x0314},
+{ 0x1FE6, 0x03C5, 0x0342},
+{ 0x1F7C, 0x03C9, 0x0300},
+{ 0x03CE, 0x03C9, 0x0301},
+{ 0x1F60, 0x03C9, 0x0313},
+{ 0x1F61, 0x03C9, 0x0314},
+{ 0x1FF6, 0x03C9, 0x0342},
+{ 0x1FF3, 0x03C9, 0x0345},
+{ 0x1FD2, 0x03CA, 0x0300},
+{ 0x0390, 0x03CA, 0x0301},
+{ 0x1FD7, 0x03CA, 0x0342},
+{ 0x1FE2, 0x03CB, 0x0300},
+{ 0x03B0, 0x03CB, 0x0301},
+{ 0x1FE7, 0x03CB, 0x0342},
+{ 0x1FF4, 0x03CE, 0x0345},
+{ 0x03D3, 0x03D2, 0x0301},
+{ 0x03D4, 0x03D2, 0x0308},
+{ 0x0407, 0x0406, 0x0308},
+{ 0x04D0, 0x0410, 0x0306},
+{ 0x04D2, 0x0410, 0x0308},
+{ 0x0403, 0x0413, 0x0301},
+{ 0x0400, 0x0415, 0x0300},
+{ 0x04D6, 0x0415, 0x0306},
+{ 0x0401, 0x0415, 0x0308},
+{ 0x04C1, 0x0416, 0x0306},
+{ 0x04DC, 0x0416, 0x0308},
+{ 0x04DE, 0x0417, 0x0308},
+{ 0x040D, 0x0418, 0x0300},
+{ 0x04E2, 0x0418, 0x0304},
+{ 0x0419, 0x0418, 0x0306},
+{ 0x04E4, 0x0418, 0x0308},
+{ 0x040C, 0x041A, 0x0301},
+{ 0x04E6, 0x041E, 0x0308},
+{ 0x04EE, 0x0423, 0x0304},
+{ 0x040E, 0x0423, 0x0306},
+{ 0x04F0, 0x0423, 0x0308},
+{ 0x04F2, 0x0423, 0x030B},
+{ 0x04F4, 0x0427, 0x0308},
+{ 0x04F8, 0x042B, 0x0308},
+{ 0x04EC, 0x042D, 0x0308},
+{ 0x04D1, 0x0430, 0x0306},
+{ 0x04D3, 0x0430, 0x0308},
+{ 0x0453, 0x0433, 0x0301},
+{ 0x0450, 0x0435, 0x0300},
+{ 0x04D7, 0x0435, 0x0306},
+{ 0x0451, 0x0435, 0x0308},
+{ 0x04C2, 0x0436, 0x0306},
+{ 0x04DD, 0x0436, 0x0308},
+{ 0x04DF, 0x0437, 0x0308},
+{ 0x045D, 0x0438, 0x0300},
+{ 0x04E3, 0x0438, 0x0304},
+{ 0x0439, 0x0438, 0x0306},
+{ 0x04E5, 0x0438, 0x0308},
+{ 0x045C, 0x043A, 0x0301},
+{ 0x04E7, 0x043E, 0x0308},
+{ 0x04EF, 0x0443, 0x0304},
+{ 0x045E, 0x0443, 0x0306},
+{ 0x04F1, 0x0443, 0x0308},
+{ 0x04F3, 0x0443, 0x030B},
+{ 0x04F5, 0x0447, 0x0308},
+{ 0x04F9, 0x044B, 0x0308},
+{ 0x04ED, 0x044D, 0x0308},
+{ 0x0457, 0x0456, 0x0308},
+{ 0x0476, 0x0474, 0x030F},
+{ 0x0477, 0x0475, 0x030F},
+{ 0x04DA, 0x04D8, 0x0308},
+{ 0x04DB, 0x04D9, 0x0308},
+{ 0x04EA, 0x04E8, 0x0308},
+{ 0x04EB, 0x04E9, 0x0308},
+{ 0xFB2E, 0x05D0, 0x05B7},
+{ 0xFB2F, 0x05D0, 0x05B8},
+{ 0xFB30, 0x05D0, 0x05BC},
+{ 0xFB31, 0x05D1, 0x05BC},
+{ 0xFB4C, 0x05D1, 0x05BF},
+{ 0xFB32, 0x05D2, 0x05BC},
+{ 0xFB33, 0x05D3, 0x05BC},
+{ 0xFB34, 0x05D4, 0x05BC},
+{ 0xFB4B, 0x05D5, 0x05B9},
+{ 0xFB35, 0x05D5, 0x05BC},
+{ 0xFB36, 0x05D6, 0x05BC},
+{ 0xFB38, 0x05D8, 0x05BC},
+{ 0xFB1D, 0x05D9, 0x05B4},
+{ 0xFB39, 0x05D9, 0x05BC},
+{ 0xFB3A, 0x05DA, 0x05BC},
+{ 0xFB3B, 0x05DB, 0x05BC},
+{ 0xFB4D, 0x05DB, 0x05BF},
+{ 0xFB3C, 0x05DC, 0x05BC},
+{ 0xFB3E, 0x05DE, 0x05BC},
+{ 0xFB40, 0x05E0, 0x05BC},
+{ 0xFB41, 0x05E1, 0x05BC},
+{ 0xFB43, 0x05E3, 0x05BC},
+{ 0xFB44, 0x05E4, 0x05BC},
+{ 0xFB4E, 0x05E4, 0x05BF},
+{ 0xFB46, 0x05E6, 0x05BC},
+{ 0xFB47, 0x05E7, 0x05BC},
+{ 0xFB48, 0x05E8, 0x05BC},
+{ 0xFB49, 0x05E9, 0x05BC},
+{ 0xFB2A, 0x05E9, 0x05C1},
+{ 0xFB2B, 0x05E9, 0x05C2},
+{ 0xFB4A, 0x05EA, 0x05BC},
+{ 0xFB1F, 0x05F2, 0x05B7},
+{ 0x0622, 0x0627, 0x0653},
+{ 0x0623, 0x0627, 0x0654},
+{ 0x0625, 0x0627, 0x0655},
+{ 0x0624, 0x0648, 0x0654},
+{ 0x0626, 0x064A, 0x0654},
+{ 0x06C2, 0x06C1, 0x0654},
+{ 0x06D3, 0x06D2, 0x0654},
+{ 0x06C0, 0x06D5, 0x0654},
+{ 0x0958, 0x0915, 0x093C},
+{ 0x0959, 0x0916, 0x093C},
+{ 0x095A, 0x0917, 0x093C},
+{ 0x095B, 0x091C, 0x093C},
+{ 0x095C, 0x0921, 0x093C},
+{ 0x095D, 0x0922, 0x093C},
+{ 0x0929, 0x0928, 0x093C},
+{ 0x095E, 0x092B, 0x093C},
+{ 0x095F, 0x092F, 0x093C},
+{ 0x0931, 0x0930, 0x093C},
+{ 0x0934, 0x0933, 0x093C},
+{ 0x09DC, 0x09A1, 0x09BC},
+{ 0x09DD, 0x09A2, 0x09BC},
+{ 0x09DF, 0x09AF, 0x09BC},
+{ 0x09CB, 0x09C7, 0x09BE},
+{ 0x09CC, 0x09C7, 0x09D7},
+{ 0x0A59, 0x0A16, 0x0A3C},
+{ 0x0A5A, 0x0A17, 0x0A3C},
+{ 0x0A5B, 0x0A1C, 0x0A3C},
+{ 0x0A5E, 0x0A2B, 0x0A3C},
+{ 0x0A33, 0x0A32, 0x0A3C},
+{ 0x0A36, 0x0A38, 0x0A3C},
+{ 0x0B5C, 0x0B21, 0x0B3C},
+{ 0x0B5D, 0x0B22, 0x0B3C},
+{ 0x0B4B, 0x0B47, 0x0B3E},
+{ 0x0B48, 0x0B47, 0x0B56},
+{ 0x0B4C, 0x0B47, 0x0B57},
+{ 0x0B94, 0x0B92, 0x0BD7},
+{ 0x0BCA, 0x0BC6, 0x0BBE},
+{ 0x0BCC, 0x0BC6, 0x0BD7},
+{ 0x0BCB, 0x0BC7, 0x0BBE},
+{ 0x0C48, 0x0C46, 0x0C56},
+{ 0x0CC0, 0x0CBF, 0x0CD5},
+{ 0x0CCA, 0x0CC6, 0x0CC2},
+{ 0x0CC7, 0x0CC6, 0x0CD5},
+{ 0x0CC8, 0x0CC6, 0x0CD6},
+{ 0x0CCB, 0x0CCA, 0x0CD5},
+{ 0x0D4A, 0x0D46, 0x0D3E},
+{ 0x0D4C, 0x0D46, 0x0D57},
+{ 0x0D4B, 0x0D47, 0x0D3E},
+{ 0x0DDA, 0x0DD9, 0x0DCA},
+{ 0x0DDC, 0x0DD9, 0x0DCF},
+{ 0x0DDE, 0x0DD9, 0x0DDF},
+{ 0x0DDD, 0x0DDC, 0x0DCA},
+{ 0x0F69, 0x0F40, 0x0FB5},
+{ 0x0F43, 0x0F42, 0x0FB7},
+{ 0x0F4D, 0x0F4C, 0x0FB7},
+{ 0x0F52, 0x0F51, 0x0FB7},
+{ 0x0F57, 0x0F56, 0x0FB7},
+{ 0x0F5C, 0x0F5B, 0x0FB7},
+{ 0x0F73, 0x0F71, 0x0F72},
+{ 0x0F75, 0x0F71, 0x0F74},
+{ 0x0F81, 0x0F71, 0x0F80},
+{ 0x0FB9, 0x0F90, 0x0FB5},
+{ 0x0F93, 0x0F92, 0x0FB7},
+{ 0x0F9D, 0x0F9C, 0x0FB7},
+{ 0x0FA2, 0x0FA1, 0x0FB7},
+{ 0x0FA7, 0x0FA6, 0x0FB7},
+{ 0x0FAC, 0x0FAB, 0x0FB7},
+{ 0x0F76, 0x0FB2, 0x0F80},
+{ 0x0F78, 0x0FB3, 0x0F80},
+{ 0x1026, 0x1025, 0x102E},
+{ 0x1E38, 0x1E36, 0x0304},
+{ 0x1E39, 0x1E37, 0x0304},
+{ 0x1E5C, 0x1E5A, 0x0304},
+{ 0x1E5D, 0x1E5B, 0x0304},
+{ 0x1E68, 0x1E62, 0x0307},
+{ 0x1E69, 0x1E63, 0x0307},
+{ 0x1EAC, 0x1EA0, 0x0302},
+{ 0x1EB6, 0x1EA0, 0x0306},
+{ 0x1EAD, 0x1EA1, 0x0302},
+{ 0x1EB7, 0x1EA1, 0x0306},
+{ 0x1EC6, 0x1EB8, 0x0302},
+{ 0x1EC7, 0x1EB9, 0x0302},
+{ 0x1ED8, 0x1ECC, 0x0302},
+{ 0x1ED9, 0x1ECD, 0x0302},
+{ 0x1F02, 0x1F00, 0x0300},
+{ 0x1F04, 0x1F00, 0x0301},
+{ 0x1F06, 0x1F00, 0x0342},
+{ 0x1F80, 0x1F00, 0x0345},
+{ 0x1F03, 0x1F01, 0x0300},
+{ 0x1F05, 0x1F01, 0x0301},
+{ 0x1F07, 0x1F01, 0x0342},
+{ 0x1F81, 0x1F01, 0x0345},
+{ 0x1F82, 0x1F02, 0x0345},
+{ 0x1F83, 0x1F03, 0x0345},
+{ 0x1F84, 0x1F04, 0x0345},
+{ 0x1F85, 0x1F05, 0x0345},
+{ 0x1F86, 0x1F06, 0x0345},
+{ 0x1F87, 0x1F07, 0x0345},
+{ 0x1F0A, 0x1F08, 0x0300},
+{ 0x1F0C, 0x1F08, 0x0301},
+{ 0x1F0E, 0x1F08, 0x0342},
+{ 0x1F88, 0x1F08, 0x0345},
+{ 0x1F0B, 0x1F09, 0x0300},
+{ 0x1F0D, 0x1F09, 0x0301},
+{ 0x1F0F, 0x1F09, 0x0342},
+{ 0x1F89, 0x1F09, 0x0345},
+{ 0x1F8A, 0x1F0A, 0x0345},
+{ 0x1F8B, 0x1F0B, 0x0345},
+{ 0x1F8C, 0x1F0C, 0x0345},
+{ 0x1F8D, 0x1F0D, 0x0345},
+{ 0x1F8E, 0x1F0E, 0x0345},
+{ 0x1F8F, 0x1F0F, 0x0345},
+{ 0x1F12, 0x1F10, 0x0300},
+{ 0x1F14, 0x1F10, 0x0301},
+{ 0x1F13, 0x1F11, 0x0300},
+{ 0x1F15, 0x1F11, 0x0301},
+{ 0x1F1A, 0x1F18, 0x0300},
+{ 0x1F1C, 0x1F18, 0x0301},
+{ 0x1F1B, 0x1F19, 0x0300},
+{ 0x1F1D, 0x1F19, 0x0301},
+{ 0x1F22, 0x1F20, 0x0300},
+{ 0x1F24, 0x1F20, 0x0301},
+{ 0x1F26, 0x1F20, 0x0342},
+{ 0x1F90, 0x1F20, 0x0345},
+{ 0x1F23, 0x1F21, 0x0300},
+{ 0x1F25, 0x1F21, 0x0301},
+{ 0x1F27, 0x1F21, 0x0342},
+{ 0x1F91, 0x1F21, 0x0345},
+{ 0x1F92, 0x1F22, 0x0345},
+{ 0x1F93, 0x1F23, 0x0345},
+{ 0x1F94, 0x1F24, 0x0345},
+{ 0x1F95, 0x1F25, 0x0345},
+{ 0x1F96, 0x1F26, 0x0345},
+{ 0x1F97, 0x1F27, 0x0345},
+{ 0x1F2A, 0x1F28, 0x0300},
+{ 0x1F2C, 0x1F28, 0x0301},
+{ 0x1F2E, 0x1F28, 0x0342},
+{ 0x1F98, 0x1F28, 0x0345},
+{ 0x1F2B, 0x1F29, 0x0300},
+{ 0x1F2D, 0x1F29, 0x0301},
+{ 0x1F2F, 0x1F29, 0x0342},
+{ 0x1F99, 0x1F29, 0x0345},
+{ 0x1F9A, 0x1F2A, 0x0345},
+{ 0x1F9B, 0x1F2B, 0x0345},
+{ 0x1F9C, 0x1F2C, 0x0345},
+{ 0x1F9D, 0x1F2D, 0x0345},
+{ 0x1F9E, 0x1F2E, 0x0345},
+{ 0x1F9F, 0x1F2F, 0x0345},
+{ 0x1F32, 0x1F30, 0x0300},
+{ 0x1F34, 0x1F30, 0x0301},
+{ 0x1F36, 0x1F30, 0x0342},
+{ 0x1F33, 0x1F31, 0x0300},
+{ 0x1F35, 0x1F31, 0x0301},
+{ 0x1F37, 0x1F31, 0x0342},
+{ 0x1F3A, 0x1F38, 0x0300},
+{ 0x1F3C, 0x1F38, 0x0301},
+{ 0x1F3E, 0x1F38, 0x0342},
+{ 0x1F3B, 0x1F39, 0x0300},
+{ 0x1F3D, 0x1F39, 0x0301},
+{ 0x1F3F, 0x1F39, 0x0342},
+{ 0x1F42, 0x1F40, 0x0300},
+{ 0x1F44, 0x1F40, 0x0301},
+{ 0x1F43, 0x1F41, 0x0300},
+{ 0x1F45, 0x1F41, 0x0301},
+{ 0x1F4A, 0x1F48, 0x0300},
+{ 0x1F4C, 0x1F48, 0x0301},
+{ 0x1F4B, 0x1F49, 0x0300},
+{ 0x1F4D, 0x1F49, 0x0301},
+{ 0x1F52, 0x1F50, 0x0300},
+{ 0x1F54, 0x1F50, 0x0301},
+{ 0x1F56, 0x1F50, 0x0342},
+{ 0x1F53, 0x1F51, 0x0300},
+{ 0x1F55, 0x1F51, 0x0301},
+{ 0x1F57, 0x1F51, 0x0342},
+{ 0x1F5B, 0x1F59, 0x0300},
+{ 0x1F5D, 0x1F59, 0x0301},
+{ 0x1F5F, 0x1F59, 0x0342},
+{ 0x1F62, 0x1F60, 0x0300},
+{ 0x1F64, 0x1F60, 0x0301},
+{ 0x1F66, 0x1F60, 0x0342},
+{ 0x1FA0, 0x1F60, 0x0345},
+{ 0x1F63, 0x1F61, 0x0300},
+{ 0x1F65, 0x1F61, 0x0301},
+{ 0x1F67, 0x1F61, 0x0342},
+{ 0x1FA1, 0x1F61, 0x0345},
+{ 0x1FA2, 0x1F62, 0x0345},
+{ 0x1FA3, 0x1F63, 0x0345},
+{ 0x1FA4, 0x1F64, 0x0345},
+{ 0x1FA5, 0x1F65, 0x0345},
+{ 0x1FA6, 0x1F66, 0x0345},
+{ 0x1FA7, 0x1F67, 0x0345},
+{ 0x1F6A, 0x1F68, 0x0300},
+{ 0x1F6C, 0x1F68, 0x0301},
+{ 0x1F6E, 0x1F68, 0x0342},
+{ 0x1FA8, 0x1F68, 0x0345},
+{ 0x1F6B, 0x1F69, 0x0300},
+{ 0x1F6D, 0x1F69, 0x0301},
+{ 0x1F6F, 0x1F69, 0x0342},
+{ 0x1FA9, 0x1F69, 0x0345},
+{ 0x1FAA, 0x1F6A, 0x0345},
+{ 0x1FAB, 0x1F6B, 0x0345},
+{ 0x1FAC, 0x1F6C, 0x0345},
+{ 0x1FAD, 0x1F6D, 0x0345},
+{ 0x1FAE, 0x1F6E, 0x0345},
+{ 0x1FAF, 0x1F6F, 0x0345},
+{ 0x1FB2, 0x1F70, 0x0345},
+{ 0x1FC2, 0x1F74, 0x0345},
+{ 0x1FF2, 0x1F7C, 0x0345},
+{ 0x1FB7, 0x1FB6, 0x0345},
+{ 0x1FCD, 0x1FBF, 0x0300},
+{ 0x1FCE, 0x1FBF, 0x0301},
+{ 0x1FCF, 0x1FBF, 0x0342},
+{ 0x1FC7, 0x1FC6, 0x0345},
+{ 0x1FF7, 0x1FF6, 0x0345},
+{ 0x1FDD, 0x1FFE, 0x0300},
+{ 0x1FDE, 0x1FFE, 0x0301},
+{ 0x1FDF, 0x1FFE, 0x0342},
+{ 0x219A, 0x2190, 0x0338},
+{ 0x219B, 0x2192, 0x0338},
+{ 0x21AE, 0x2194, 0x0338},
+{ 0x21CD, 0x21D0, 0x0338},
+{ 0x21CF, 0x21D2, 0x0338},
+{ 0x21CE, 0x21D4, 0x0338},
+{ 0x2204, 0x2203, 0x0338},
+{ 0x2209, 0x2208, 0x0338},
+{ 0x220C, 0x220B, 0x0338},
+{ 0x2224, 0x2223, 0x0338},
+{ 0x2226, 0x2225, 0x0338},
+{ 0x2241, 0x223C, 0x0338},
+{ 0x2244, 0x2243, 0x0338},
+{ 0x2247, 0x2245, 0x0338},
+{ 0x2249, 0x2248, 0x0338},
+{ 0x226D, 0x224D, 0x0338},
+{ 0x2262, 0x2261, 0x0338},
+{ 0x2270, 0x2264, 0x0338},
+{ 0x2271, 0x2265, 0x0338},
+{ 0x2274, 0x2272, 0x0338},
+{ 0x2275, 0x2273, 0x0338},
+{ 0x2278, 0x2276, 0x0338},
+{ 0x2279, 0x2277, 0x0338},
+{ 0x2280, 0x227A, 0x0338},
+{ 0x2281, 0x227B, 0x0338},
+{ 0x22E0, 0x227C, 0x0338},
+{ 0x22E1, 0x227D, 0x0338},
+{ 0x2284, 0x2282, 0x0338},
+{ 0x2285, 0x2283, 0x0338},
+{ 0x2288, 0x2286, 0x0338},
+{ 0x2289, 0x2287, 0x0338},
+{ 0x22E2, 0x2291, 0x0338},
+{ 0x22E3, 0x2292, 0x0338},
+{ 0x22AC, 0x22A2, 0x0338},
+{ 0x22AD, 0x22A8, 0x0338},
+{ 0x22AE, 0x22A9, 0x0338},
+{ 0x22AF, 0x22AB, 0x0338},
+{ 0x22EA, 0x22B2, 0x0338},
+{ 0x22EB, 0x22B3, 0x0338},
+{ 0x22EC, 0x22B4, 0x0338},
+{ 0x22ED, 0x22B5, 0x0338},
+{ 0x3094, 0x3046, 0x3099},
+{ 0x304C, 0x304B, 0x3099},
+{ 0x304E, 0x304D, 0x3099},
+{ 0x3050, 0x304F, 0x3099},
+{ 0x3052, 0x3051, 0x3099},
+{ 0x3054, 0x3053, 0x3099},
+{ 0x3056, 0x3055, 0x3099},
+{ 0x3058, 0x3057, 0x3099},
+{ 0x305A, 0x3059, 0x3099},
+{ 0x305C, 0x305B, 0x3099},
+{ 0x305E, 0x305D, 0x3099},
+{ 0x3060, 0x305F, 0x3099},
+{ 0x3062, 0x3061, 0x3099},
+{ 0x3065, 0x3064, 0x3099},
+{ 0x3067, 0x3066, 0x3099},
+{ 0x3069, 0x3068, 0x3099},
+{ 0x3070, 0x306F, 0x3099},
+{ 0x3071, 0x306F, 0x309A},
+{ 0x3073, 0x3072, 0x3099},
+{ 0x3074, 0x3072, 0x309A},
+{ 0x3076, 0x3075, 0x3099},
+{ 0x3077, 0x3075, 0x309A},
+{ 0x3079, 0x3078, 0x3099},
+{ 0x307A, 0x3078, 0x309A},
+{ 0x307C, 0x307B, 0x3099},
+{ 0x307D, 0x307B, 0x309A},
+{ 0x309E, 0x309D, 0x3099},
+{ 0x30F4, 0x30A6, 0x3099},
+{ 0x30AC, 0x30AB, 0x3099},
+{ 0x30AE, 0x30AD, 0x3099},
+{ 0x30B0, 0x30AF, 0x3099},
+{ 0x30B2, 0x30B1, 0x3099},
+{ 0x30B4, 0x30B3, 0x3099},
+{ 0x30B6, 0x30B5, 0x3099},
+{ 0x30B8, 0x30B7, 0x3099},
+{ 0x30BA, 0x30B9, 0x3099},
+{ 0x30BC, 0x30BB, 0x3099},
+{ 0x30BE, 0x30BD, 0x3099},
+{ 0x30C0, 0x30BF, 0x3099},
+{ 0x30C2, 0x30C1, 0x3099},
+{ 0x30C5, 0x30C4, 0x3099},
+{ 0x30C7, 0x30C6, 0x3099},
+{ 0x30C9, 0x30C8, 0x3099},
+{ 0x30D0, 0x30CF, 0x3099},
+{ 0x30D1, 0x30CF, 0x309A},
+{ 0x30D3, 0x30D2, 0x3099},
+{ 0x30D4, 0x30D2, 0x309A},
+{ 0x30D6, 0x30D5, 0x3099},
+{ 0x30D7, 0x30D5, 0x309A},
+{ 0x30D9, 0x30D8, 0x3099},
+{ 0x30DA, 0x30D8, 0x309A},
+{ 0x30DC, 0x30DB, 0x3099},
+{ 0x30DD, 0x30DB, 0x309A},
+{ 0x30F7, 0x30EF, 0x3099},
+{ 0x30F8, 0x30F0, 0x3099},
+{ 0x30F9, 0x30F1, 0x3099},
+{ 0x30FA, 0x30F2, 0x3099},
+{ 0x30FE, 0x30FD, 0x3099},
+{ 0xFB2C, 0xFB49, 0x05C1},
+{ 0xFB2D, 0xFB49, 0x05C2},
+};
+
+static const struct {
+  unsigned int replacement;
+  unsigned int base;
+  unsigned int comb; 
+} decompositions[] = {
+{ 0x00C0, 0x0041, 0x0300},
+{ 0x00C1, 0x0041, 0x0301},
+{ 0x00C2, 0x0041, 0x0302},
+{ 0x00C3, 0x0041, 0x0303},
+{ 0x00C4, 0x0041, 0x0308},
+{ 0x00C5, 0x0041, 0x030A},
+{ 0x00C7, 0x0043, 0x0327},
+{ 0x00C8, 0x0045, 0x0300},
+{ 0x00C9, 0x0045, 0x0301},
+{ 0x00CA, 0x0045, 0x0302},
+{ 0x00CB, 0x0045, 0x0308},
+{ 0x00CC, 0x0049, 0x0300},
+{ 0x00CD, 0x0049, 0x0301},
+{ 0x00CE, 0x0049, 0x0302},
+{ 0x00CF, 0x0049, 0x0308},
+{ 0x00D1, 0x004E, 0x0303},
+{ 0x00D2, 0x004F, 0x0300},
+{ 0x00D3, 0x004F, 0x0301},
+{ 0x00D4, 0x004F, 0x0302},
+{ 0x00D5, 0x004F, 0x0303},
+{ 0x00D6, 0x004F, 0x0308},
+{ 0x00D9, 0x0055, 0x0300},
+{ 0x00DA, 0x0055, 0x0301},
+{ 0x00DB, 0x0055, 0x0302},
+{ 0x00DC, 0x0055, 0x0308},
+{ 0x00DD, 0x0059, 0x0301},
+{ 0x00E0, 0x0061, 0x0300},
+{ 0x00E1, 0x0061, 0x0301},
+{ 0x00E2, 0x0061, 0x0302},
+{ 0x00E3, 0x0061, 0x0303},
+{ 0x00E4, 0x0061, 0x0308},
+{ 0x00E5, 0x0061, 0x030A},
+{ 0x00E7, 0x0063, 0x0327},
+{ 0x00E8, 0x0065, 0x0300},
+{ 0x00E9, 0x0065, 0x0301},
+{ 0x00EA, 0x0065, 0x0302},
+{ 0x00EB, 0x0065, 0x0308},
+{ 0x00EC, 0x0069, 0x0300},
+{ 0x00ED, 0x0069, 0x0301},
+{ 0x00EE, 0x0069, 0x0302},
+{ 0x00EF, 0x0069, 0x0308},
+{ 0x00F1, 0x006E, 0x0303},
+{ 0x00F2, 0x006F, 0x0300},
+{ 0x00F3, 0x006F, 0x0301},
+{ 0x00F4, 0x006F, 0x0302},
+{ 0x00F5, 0x006F, 0x0303},
+{ 0x00F6, 0x006F, 0x0308},
+{ 0x00F9, 0x0075, 0x0300},
+{ 0x00FA, 0x0075, 0x0301},
+{ 0x00FB, 0x0075, 0x0302},
+{ 0x00FC, 0x0075, 0x0308},
+{ 0x00FD, 0x0079, 0x0301},
+{ 0x00FF, 0x0079, 0x0308},
+{ 0x0100, 0x0041, 0x0304},
+{ 0x0101, 0x0061, 0x0304},
+{ 0x0102, 0x0041, 0x0306},
+{ 0x0103, 0x0061, 0x0306},
+{ 0x0104, 0x0041, 0x0328},
+{ 0x0105, 0x0061, 0x0328},
+{ 0x0106, 0x0043, 0x0301},
+{ 0x0107, 0x0063, 0x0301},
+{ 0x0108, 0x0043, 0x0302},
+{ 0x0109, 0x0063, 0x0302},
+{ 0x010A, 0x0043, 0x0307},
+{ 0x010B, 0x0063, 0x0307},
+{ 0x010C, 0x0043, 0x030C},
+{ 0x010D, 0x0063, 0x030C},
+{ 0x010E, 0x0044, 0x030C},
+{ 0x010F, 0x0064, 0x030C},
+{ 0x0112, 0x0045, 0x0304},
+{ 0x0113, 0x0065, 0x0304},
+{ 0x0114, 0x0045, 0x0306},
+{ 0x0115, 0x0065, 0x0306},
+{ 0x0116, 0x0045, 0x0307},
+{ 0x0117, 0x0065, 0x0307},
+{ 0x0118, 0x0045, 0x0328},
+{ 0x0119, 0x0065, 0x0328},
+{ 0x011A, 0x0045, 0x030C},
+{ 0x011B, 0x0065, 0x030C},
+{ 0x011C, 0x0047, 0x0302},
+{ 0x011D, 0x0067, 0x0302},
+{ 0x011E, 0x0047, 0x0306},
+{ 0x011F, 0x0067, 0x0306},
+{ 0x0120, 0x0047, 0x0307},
+{ 0x0121, 0x0067, 0x0307},
+{ 0x0122, 0x0047, 0x0327},
+{ 0x0123, 0x0067, 0x0327},
+{ 0x0124, 0x0048, 0x0302},
+{ 0x0125, 0x0068, 0x0302},
+{ 0x0128, 0x0049, 0x0303},
+{ 0x0129, 0x0069, 0x0303},
+{ 0x012A, 0x0049, 0x0304},
+{ 0x012B, 0x0069, 0x0304},
+{ 0x012C, 0x0049, 0x0306},
+{ 0x012D, 0x0069, 0x0306},
+{ 0x012E, 0x0049, 0x0328},
+{ 0x012F, 0x0069, 0x0328},
+{ 0x0130, 0x0049, 0x0307},
+{ 0x0134, 0x004A, 0x0302},
+{ 0x0135, 0x006A, 0x0302},
+{ 0x0136, 0x004B, 0x0327},
+{ 0x0137, 0x006B, 0x0327},
+{ 0x0139, 0x004C, 0x0301},
+{ 0x013A, 0x006C, 0x0301},
+{ 0x013B, 0x004C, 0x0327},
+{ 0x013C, 0x006C, 0x0327},
+{ 0x013D, 0x004C, 0x030C},
+{ 0x013E, 0x006C, 0x030C},
+{ 0x0143, 0x004E, 0x0301},
+{ 0x0144, 0x006E, 0x0301},
+{ 0x0145, 0x004E, 0x0327},
+{ 0x0146, 0x006E, 0x0327},
+{ 0x0147, 0x004E, 0x030C},
+{ 0x0148, 0x006E, 0x030C},
+{ 0x014C, 0x004F, 0x0304},
+{ 0x014D, 0x006F, 0x0304},
+{ 0x014E, 0x004F, 0x0306},
+{ 0x014F, 0x006F, 0x0306},
+{ 0x0150, 0x004F, 0x030B},
+{ 0x0151, 0x006F, 0x030B},
+{ 0x0154, 0x0052, 0x0301},
+{ 0x0155, 0x0072, 0x0301},
+{ 0x0156, 0x0052, 0x0327},
+{ 0x0157, 0x0072, 0x0327},
+{ 0x0158, 0x0052, 0x030C},
+{ 0x0159, 0x0072, 0x030C},
+{ 0x015A, 0x0053, 0x0301},
+{ 0x015B, 0x0073, 0x0301},
+{ 0x015C, 0x0053, 0x0302},
+{ 0x015D, 0x0073, 0x0302},
+{ 0x015E, 0x0053, 0x0327},
+{ 0x015F, 0x0073, 0x0327},
+{ 0x0160, 0x0053, 0x030C},
+{ 0x0161, 0x0073, 0x030C},
+{ 0x0162, 0x0054, 0x0327},
+{ 0x0163, 0x0074, 0x0327},
+{ 0x0164, 0x0054, 0x030C},
+{ 0x0165, 0x0074, 0x030C},
+{ 0x0168, 0x0055, 0x0303},
+{ 0x0169, 0x0075, 0x0303},
+{ 0x016A, 0x0055, 0x0304},
+{ 0x016B, 0x0075, 0x0304},
+{ 0x016C, 0x0055, 0x0306},
+{ 0x016D, 0x0075, 0x0306},
+{ 0x016E, 0x0055, 0x030A},
+{ 0x016F, 0x0075, 0x030A},
+{ 0x0170, 0x0055, 0x030B},
+{ 0x0171, 0x0075, 0x030B},
+{ 0x0172, 0x0055, 0x0328},
+{ 0x0173, 0x0075, 0x0328},
+{ 0x0174, 0x0057, 0x0302},
+{ 0x0175, 0x0077, 0x0302},
+{ 0x0176, 0x0059, 0x0302},
+{ 0x0177, 0x0079, 0x0302},
+{ 0x0178, 0x0059, 0x0308},
+{ 0x0179, 0x005A, 0x0301},
+{ 0x017A, 0x007A, 0x0301},
+{ 0x017B, 0x005A, 0x0307},
+{ 0x017C, 0x007A, 0x0307},
+{ 0x017D, 0x005A, 0x030C},
+{ 0x017E, 0x007A, 0x030C},
+{ 0x01A0, 0x004F, 0x031B},
+{ 0x01A1, 0x006F, 0x031B},
+{ 0x01AF, 0x0055, 0x031B},
+{ 0x01B0, 0x0075, 0x031B},
+{ 0x01CD, 0x0041, 0x030C},
+{ 0x01CE, 0x0061, 0x030C},
+{ 0x01CF, 0x0049, 0x030C},
+{ 0x01D0, 0x0069, 0x030C},
+{ 0x01D1, 0x004F, 0x030C},
+{ 0x01D2, 0x006F, 0x030C},
+{ 0x01D3, 0x0055, 0x030C},
+{ 0x01D4, 0x0075, 0x030C},
+{ 0x01D5, 0x00DC, 0x0304},
+{ 0x01D6, 0x00FC, 0x0304},
+{ 0x01D7, 0x00DC, 0x0301},
+{ 0x01D8, 0x00FC, 0x0301},
+{ 0x01D9, 0x00DC, 0x030C},
+{ 0x01DA, 0x00FC, 0x030C},
+{ 0x01DB, 0x00DC, 0x0300},
+{ 0x01DC, 0x00FC, 0x0300},
+{ 0x01DE, 0x00C4, 0x0304},
+{ 0x01DF, 0x00E4, 0x0304},
+{ 0x01E0, 0x0226, 0x0304},
+{ 0x01E1, 0x0227, 0x0304},
+{ 0x01E2, 0x00C6, 0x0304},
+{ 0x01E3, 0x00E6, 0x0304},
+{ 0x01E6, 0x0047, 0x030C},
+{ 0x01E7, 0x0067, 0x030C},
+{ 0x01E8, 0x004B, 0x030C},
+{ 0x01E9, 0x006B, 0x030C},
+{ 0x01EA, 0x004F, 0x0328},
+{ 0x01EB, 0x006F, 0x0328},
+{ 0x01EC, 0x01EA, 0x0304},
+{ 0x01ED, 0x01EB, 0x0304},
+{ 0x01EE, 0x01B7, 0x030C},
+{ 0x01EF, 0x0292, 0x030C},
+{ 0x01F0, 0x006A, 0x030C},
+{ 0x01F4, 0x0047, 0x0301},
+{ 0x01F5, 0x0067, 0x0301},
+{ 0x01F8, 0x004E, 0x0300},
+{ 0x01F9, 0x006E, 0x0300},
+{ 0x01FA, 0x00C5, 0x0301},
+{ 0x01FB, 0x00E5, 0x0301},
+{ 0x01FC, 0x00C6, 0x0301},
+{ 0x01FD, 0x00E6, 0x0301},
+{ 0x01FE, 0x00D8, 0x0301},
+{ 0x01FF, 0x00F8, 0x0301},
+{ 0x0200, 0x0041, 0x030F},
+{ 0x0201, 0x0061, 0x030F},
+{ 0x0202, 0x0041, 0x0311},
+{ 0x0203, 0x0061, 0x0311},
+{ 0x0204, 0x0045, 0x030F},
+{ 0x0205, 0x0065, 0x030F},
+{ 0x0206, 0x0045, 0x0311},
+{ 0x0207, 0x0065, 0x0311},
+{ 0x0208, 0x0049, 0x030F},
+{ 0x0209, 0x0069, 0x030F},
+{ 0x020A, 0x0049, 0x0311},
+{ 0x020B, 0x0069, 0x0311},
+{ 0x020C, 0x004F, 0x030F},
+{ 0x020D, 0x006F, 0x030F},
+{ 0x020E, 0x004F, 0x0311},
+{ 0x020F, 0x006F, 0x0311},
+{ 0x0210, 0x0052, 0x030F},
+{ 0x0211, 0x0072, 0x030F},
+{ 0x0212, 0x0052, 0x0311},
+{ 0x0213, 0x0072, 0x0311},
+{ 0x0214, 0x0055, 0x030F},
+{ 0x0215, 0x0075, 0x030F},
+{ 0x0216, 0x0055, 0x0311},
+{ 0x0217, 0x0075, 0x0311},
+{ 0x0218, 0x0053, 0x0326},
+{ 0x0219, 0x0073, 0x0326},
+{ 0x021A, 0x0054, 0x0326},
+{ 0x021B, 0x0074, 0x0326},
+{ 0x021E, 0x0048, 0x030C},
+{ 0x021F, 0x0068, 0x030C},
+{ 0x0226, 0x0041, 0x0307},
+{ 0x0227, 0x0061, 0x0307},
+{ 0x0228, 0x0045, 0x0327},
+{ 0x0229, 0x0065, 0x0327},
+{ 0x022A, 0x00D6, 0x0304},
+{ 0x022B, 0x00F6, 0x0304},
+{ 0x022C, 0x00D5, 0x0304},
+{ 0x022D, 0x00F5, 0x0304},
+{ 0x022E, 0x004F, 0x0307},
+{ 0x022F, 0x006F, 0x0307},
+{ 0x0230, 0x022E, 0x0304},
+{ 0x0231, 0x022F, 0x0304},
+{ 0x0232, 0x0059, 0x0304},
+{ 0x0233, 0x0079, 0x0304},
+{ 0x0344, 0x0308, 0x0301},
+{ 0x0385, 0x00A8, 0x0301},
+{ 0x0386, 0x0391, 0x0301},
+{ 0x0388, 0x0395, 0x0301},
+{ 0x0389, 0x0397, 0x0301},
+{ 0x038A, 0x0399, 0x0301},
+{ 0x038C, 0x039F, 0x0301},
+{ 0x038E, 0x03A5, 0x0301},
+{ 0x038F, 0x03A9, 0x0301},
+{ 0x0390, 0x03CA, 0x0301},
+{ 0x03AA, 0x0399, 0x0308},
+{ 0x03AB, 0x03A5, 0x0308},
+{ 0x03AC, 0x03B1, 0x0301},
+{ 0x03AD, 0x03B5, 0x0301},
+{ 0x03AE, 0x03B7, 0x0301},
+{ 0x03AF, 0x03B9, 0x0301},
+{ 0x03B0, 0x03CB, 0x0301},
+{ 0x03CA, 0x03B9, 0x0308},
+{ 0x03CB, 0x03C5, 0x0308},
+{ 0x03CC, 0x03BF, 0x0301},
+{ 0x03CD, 0x03C5, 0x0301},
+{ 0x03CE, 0x03C9, 0x0301},
+{ 0x03D3, 0x03D2, 0x0301},
+{ 0x03D4, 0x03D2, 0x0308},
+{ 0x0400, 0x0415, 0x0300},
+{ 0x0401, 0x0415, 0x0308},
+{ 0x0403, 0x0413, 0x0301},
+{ 0x0407, 0x0406, 0x0308},
+{ 0x040C, 0x041A, 0x0301},
+{ 0x040D, 0x0418, 0x0300},
+{ 0x040E, 0x0423, 0x0306},
+{ 0x0419, 0x0418, 0x0306},
+{ 0x0439, 0x0438, 0x0306},
+{ 0x0450, 0x0435, 0x0300},
+{ 0x0451, 0x0435, 0x0308},
+{ 0x0453, 0x0433, 0x0301},
+{ 0x0457, 0x0456, 0x0308},
+{ 0x045C, 0x043A, 0x0301},
+{ 0x045D, 0x0438, 0x0300},
+{ 0x045E, 0x0443, 0x0306},
+{ 0x0476, 0x0474, 0x030F},
+{ 0x0477, 0x0475, 0x030F},
+{ 0x04C1, 0x0416, 0x0306},
+{ 0x04C2, 0x0436, 0x0306},
+{ 0x04D0, 0x0410, 0x0306},
+{ 0x04D1, 0x0430, 0x0306},
+{ 0x04D2, 0x0410, 0x0308},
+{ 0x04D3, 0x0430, 0x0308},
+{ 0x04D6, 0x0415, 0x0306},
+{ 0x04D7, 0x0435, 0x0306},
+{ 0x04DA, 0x04D8, 0x0308},
+{ 0x04DB, 0x04D9, 0x0308},
+{ 0x04DC, 0x0416, 0x0308},
+{ 0x04DD, 0x0436, 0x0308},
+{ 0x04DE, 0x0417, 0x0308},
+{ 0x04DF, 0x0437, 0x0308},
+{ 0x04E2, 0x0418, 0x0304},
+{ 0x04E3, 0x0438, 0x0304},
+{ 0x04E4, 0x0418, 0x0308},
+{ 0x04E5, 0x0438, 0x0308},
+{ 0x04E6, 0x041E, 0x0308},
+{ 0x04E7, 0x043E, 0x0308},
+{ 0x04EA, 0x04E8, 0x0308},
+{ 0x04EB, 0x04E9, 0x0308},
+{ 0x04EC, 0x042D, 0x0308},
+{ 0x04ED, 0x044D, 0x0308},
+{ 0x04EE, 0x0423, 0x0304},
+{ 0x04EF, 0x0443, 0x0304},
+{ 0x04F0, 0x0423, 0x0308},
+{ 0x04F1, 0x0443, 0x0308},
+{ 0x04F2, 0x0423, 0x030B},
+{ 0x04F3, 0x0443, 0x030B},
+{ 0x04F4, 0x0427, 0x0308},
+{ 0x04F5, 0x0447, 0x0308},
+{ 0x04F8, 0x042B, 0x0308},
+{ 0x04F9, 0x044B, 0x0308},
+{ 0x0622, 0x0627, 0x0653},
+{ 0x0623, 0x0627, 0x0654},
+{ 0x0624, 0x0648, 0x0654},
+{ 0x0625, 0x0627, 0x0655},
+{ 0x0626, 0x064A, 0x0654},
+{ 0x06C0, 0x06D5, 0x0654},
+{ 0x06C2, 0x06C1, 0x0654},
+{ 0x06D3, 0x06D2, 0x0654},
+{ 0x0929, 0x0928, 0x093C},
+{ 0x0931, 0x0930, 0x093C},
+{ 0x0934, 0x0933, 0x093C},
+{ 0x0958, 0x0915, 0x093C},
+{ 0x0959, 0x0916, 0x093C},
+{ 0x095A, 0x0917, 0x093C},
+{ 0x095B, 0x091C, 0x093C},
+{ 0x095C, 0x0921, 0x093C},
+{ 0x095D, 0x0922, 0x093C},
+{ 0x095E, 0x092B, 0x093C},
+{ 0x095F, 0x092F, 0x093C},
+{ 0x09CB, 0x09C7, 0x09BE},
+{ 0x09CC, 0x09C7, 0x09D7},
+{ 0x09DC, 0x09A1, 0x09BC},
+{ 0x09DD, 0x09A2, 0x09BC},
+{ 0x09DF, 0x09AF, 0x09BC},
+{ 0x0A33, 0x0A32, 0x0A3C},
+{ 0x0A36, 0x0A38, 0x0A3C},
+{ 0x0A59, 0x0A16, 0x0A3C},
+{ 0x0A5A, 0x0A17, 0x0A3C},
+{ 0x0A5B, 0x0A1C, 0x0A3C},
+{ 0x0A5E, 0x0A2B, 0x0A3C},
+{ 0x0B48, 0x0B47, 0x0B56},
+{ 0x0B4B, 0x0B47, 0x0B3E},
+{ 0x0B4C, 0x0B47, 0x0B57},
+{ 0x0B5C, 0x0B21, 0x0B3C},
+{ 0x0B5D, 0x0B22, 0x0B3C},
+{ 0x0B94, 0x0B92, 0x0BD7},
+{ 0x0BCA, 0x0BC6, 0x0BBE},
+{ 0x0BCB, 0x0BC7, 0x0BBE},
+{ 0x0BCC, 0x0BC6, 0x0BD7},
+{ 0x0C48, 0x0C46, 0x0C56},
+{ 0x0CC0, 0x0CBF, 0x0CD5},
+{ 0x0CC7, 0x0CC6, 0x0CD5},
+{ 0x0CC8, 0x0CC6, 0x0CD6},
+{ 0x0CCA, 0x0CC6, 0x0CC2},
+{ 0x0CCB, 0x0CCA, 0x0CD5},
+{ 0x0D4A, 0x0D46, 0x0D3E},
+{ 0x0D4B, 0x0D47, 0x0D3E},
+{ 0x0D4C, 0x0D46, 0x0D57},
+{ 0x0DDA, 0x0DD9, 0x0DCA},
+{ 0x0DDC, 0x0DD9, 0x0DCF},
+{ 0x0DDD, 0x0DDC, 0x0DCA},
+{ 0x0DDE, 0x0DD9, 0x0DDF},
+{ 0x0F43, 0x0F42, 0x0FB7},
+{ 0x0F4D, 0x0F4C, 0x0FB7},
+{ 0x0F52, 0x0F51, 0x0FB7},
+{ 0x0F57, 0x0F56, 0x0FB7},
+{ 0x0F5C, 0x0F5B, 0x0FB7},
+{ 0x0F69, 0x0F40, 0x0FB5},
+{ 0x0F73, 0x0F71, 0x0F72},
+{ 0x0F75, 0x0F71, 0x0F74},
+{ 0x0F76, 0x0FB2, 0x0F80},
+{ 0x0F78, 0x0FB3, 0x0F80},
+{ 0x0F81, 0x0F71, 0x0F80},
+{ 0x0F93, 0x0F92, 0x0FB7},
+{ 0x0F9D, 0x0F9C, 0x0FB7},
+{ 0x0FA2, 0x0FA1, 0x0FB7},
+{ 0x0FA7, 0x0FA6, 0x0FB7},
+{ 0x0FAC, 0x0FAB, 0x0FB7},
+{ 0x0FB9, 0x0F90, 0x0FB5},
+{ 0x1026, 0x1025, 0x102E},
+{ 0x1E00, 0x0041, 0x0325},
+{ 0x1E01, 0x0061, 0x0325},
+{ 0x1E02, 0x0042, 0x0307},
+{ 0x1E03, 0x0062, 0x0307},
+{ 0x1E04, 0x0042, 0x0323},
+{ 0x1E05, 0x0062, 0x0323},
+{ 0x1E06, 0x0042, 0x0331},
+{ 0x1E07, 0x0062, 0x0331},
+{ 0x1E08, 0x00C7, 0x0301},
+{ 0x1E09, 0x00E7, 0x0301},
+{ 0x1E0A, 0x0044, 0x0307},
+{ 0x1E0B, 0x0064, 0x0307},
+{ 0x1E0C, 0x0044, 0x0323},
+{ 0x1E0D, 0x0064, 0x0323},
+{ 0x1E0E, 0x0044, 0x0331},
+{ 0x1E0F, 0x0064, 0x0331},
+{ 0x1E10, 0x0044, 0x0327},
+{ 0x1E11, 0x0064, 0x0327},
+{ 0x1E12, 0x0044, 0x032D},
+{ 0x1E13, 0x0064, 0x032D},
+{ 0x1E14, 0x0112, 0x0300},
+{ 0x1E15, 0x0113, 0x0300},
+{ 0x1E16, 0x0112, 0x0301},
+{ 0x1E17, 0x0113, 0x0301},
+{ 0x1E18, 0x0045, 0x032D},
+{ 0x1E19, 0x0065, 0x032D},
+{ 0x1E1A, 0x0045, 0x0330},
+{ 0x1E1B, 0x0065, 0x0330},
+{ 0x1E1C, 0x0228, 0x0306},
+{ 0x1E1D, 0x0229, 0x0306},
+{ 0x1E1E, 0x0046, 0x0307},
+{ 0x1E1F, 0x0066, 0x0307},
+{ 0x1E20, 0x0047, 0x0304},
+{ 0x1E21, 0x0067, 0x0304},
+{ 0x1E22, 0x0048, 0x0307},
+{ 0x1E23, 0x0068, 0x0307},
+{ 0x1E24, 0x0048, 0x0323},
+{ 0x1E25, 0x0068, 0x0323},
+{ 0x1E26, 0x0048, 0x0308},
+{ 0x1E27, 0x0068, 0x0308},
+{ 0x1E28, 0x0048, 0x0327},
+{ 0x1E29, 0x0068, 0x0327},
+{ 0x1E2A, 0x0048, 0x032E},
+{ 0x1E2B, 0x0068, 0x032E},
+{ 0x1E2C, 0x0049, 0x0330},
+{ 0x1E2D, 0x0069, 0x0330},
+{ 0x1E2E, 0x00CF, 0x0301},
+{ 0x1E2F, 0x00EF, 0x0301},
+{ 0x1E30, 0x004B, 0x0301},
+{ 0x1E31, 0x006B, 0x0301},
+{ 0x1E32, 0x004B, 0x0323},
+{ 0x1E33, 0x006B, 0x0323},
+{ 0x1E34, 0x004B, 0x0331},
+{ 0x1E35, 0x006B, 0x0331},
+{ 0x1E36, 0x004C, 0x0323},
+{ 0x1E37, 0x006C, 0x0323},
+{ 0x1E38, 0x1E36, 0x0304},
+{ 0x1E39, 0x1E37, 0x0304},
+{ 0x1E3A, 0x004C, 0x0331},
+{ 0x1E3B, 0x006C, 0x0331},
+{ 0x1E3C, 0x004C, 0x032D},
+{ 0x1E3D, 0x006C, 0x032D},
+{ 0x1E3E, 0x004D, 0x0301},
+{ 0x1E3F, 0x006D, 0x0301},
+{ 0x1E40, 0x004D, 0x0307},
+{ 0x1E41, 0x006D, 0x0307},
+{ 0x1E42, 0x004D, 0x0323},
+{ 0x1E43, 0x006D, 0x0323},
+{ 0x1E44, 0x004E, 0x0307},
+{ 0x1E45, 0x006E, 0x0307},
+{ 0x1E46, 0x004E, 0x0323},
+{ 0x1E47, 0x006E, 0x0323},
+{ 0x1E48, 0x004E, 0x0331},
+{ 0x1E49, 0x006E, 0x0331},
+{ 0x1E4A, 0x004E, 0x032D},
+{ 0x1E4B, 0x006E, 0x032D},
+{ 0x1E4C, 0x00D5, 0x0301},
+{ 0x1E4D, 0x00F5, 0x0301},
+{ 0x1E4E, 0x00D5, 0x0308},
+{ 0x1E4F, 0x00F5, 0x0308},
+{ 0x1E50, 0x014C, 0x0300},
+{ 0x1E51, 0x014D, 0x0300},
+{ 0x1E52, 0x014C, 0x0301},
+{ 0x1E53, 0x014D, 0x0301},
+{ 0x1E54, 0x0050, 0x0301},
+{ 0x1E55, 0x0070, 0x0301},
+{ 0x1E56, 0x0050, 0x0307},
+{ 0x1E57, 0x0070, 0x0307},
+{ 0x1E58, 0x0052, 0x0307},
+{ 0x1E59, 0x0072, 0x0307},
+{ 0x1E5A, 0x0052, 0x0323},
+{ 0x1E5B, 0x0072, 0x0323},
+{ 0x1E5C, 0x1E5A, 0x0304},
+{ 0x1E5D, 0x1E5B, 0x0304},
+{ 0x1E5E, 0x0052, 0x0331},
+{ 0x1E5F, 0x0072, 0x0331},
+{ 0x1E60, 0x0053, 0x0307},
+{ 0x1E61, 0x0073, 0x0307},
+{ 0x1E62, 0x0053, 0x0323},
+{ 0x1E63, 0x0073, 0x0323},
+{ 0x1E64, 0x015A, 0x0307},
+{ 0x1E65, 0x015B, 0x0307},
+{ 0x1E66, 0x0160, 0x0307},
+{ 0x1E67, 0x0161, 0x0307},
+{ 0x1E68, 0x1E62, 0x0307},
+{ 0x1E69, 0x1E63, 0x0307},
+{ 0x1E6A, 0x0054, 0x0307},
+{ 0x1E6B, 0x0074, 0x0307},
+{ 0x1E6C, 0x0054, 0x0323},
+{ 0x1E6D, 0x0074, 0x0323},
+{ 0x1E6E, 0x0054, 0x0331},
+{ 0x1E6F, 0x0074, 0x0331},
+{ 0x1E70, 0x0054, 0x032D},
+{ 0x1E71, 0x0074, 0x032D},
+{ 0x1E72, 0x0055, 0x0324},
+{ 0x1E73, 0x0075, 0x0324},
+{ 0x1E74, 0x0055, 0x0330},
+{ 0x1E75, 0x0075, 0x0330},
+{ 0x1E76, 0x0055, 0x032D},
+{ 0x1E77, 0x0075, 0x032D},
+{ 0x1E78, 0x0168, 0x0301},
+{ 0x1E79, 0x0169, 0x0301},
+{ 0x1E7A, 0x016A, 0x0308},
+{ 0x1E7B, 0x016B, 0x0308},
+{ 0x1E7C, 0x0056, 0x0303},
+{ 0x1E7D, 0x0076, 0x0303},
+{ 0x1E7E, 0x0056, 0x0323},
+{ 0x1E7F, 0x0076, 0x0323},
+{ 0x1E80, 0x0057, 0x0300},
+{ 0x1E81, 0x0077, 0x0300},
+{ 0x1E82, 0x0057, 0x0301},
+{ 0x1E83, 0x0077, 0x0301},
+{ 0x1E84, 0x0057, 0x0308},
+{ 0x1E85, 0x0077, 0x0308},
+{ 0x1E86, 0x0057, 0x0307},
+{ 0x1E87, 0x0077, 0x0307},
+{ 0x1E88, 0x0057, 0x0323},
+{ 0x1E89, 0x0077, 0x0323},
+{ 0x1E8A, 0x0058, 0x0307},
+{ 0x1E8B, 0x0078, 0x0307},
+{ 0x1E8C, 0x0058, 0x0308},
+{ 0x1E8D, 0x0078, 0x0308},
+{ 0x1E8E, 0x0059, 0x0307},
+{ 0x1E8F, 0x0079, 0x0307},
+{ 0x1E90, 0x005A, 0x0302},
+{ 0x1E91, 0x007A, 0x0302},
+{ 0x1E92, 0x005A, 0x0323},
+{ 0x1E93, 0x007A, 0x0323},
+{ 0x1E94, 0x005A, 0x0331},
+{ 0x1E95, 0x007A, 0x0331},
+{ 0x1E96, 0x0068, 0x0331},
+{ 0x1E97, 0x0074, 0x0308},
+{ 0x1E98, 0x0077, 0x030A},
+{ 0x1E99, 0x0079, 0x030A},
+{ 0x1E9B, 0x017F, 0x0307},
+{ 0x1EA0, 0x0041, 0x0323},
+{ 0x1EA1, 0x0061, 0x0323},
+{ 0x1EA2, 0x0041, 0x0309},
+{ 0x1EA3, 0x0061, 0x0309},
+{ 0x1EA4, 0x00C2, 0x0301},
+{ 0x1EA5, 0x00E2, 0x0301},
+{ 0x1EA6, 0x00C2, 0x0300},
+{ 0x1EA7, 0x00E2, 0x0300},
+{ 0x1EA8, 0x00C2, 0x0309},
+{ 0x1EA9, 0x00E2, 0x0309},
+{ 0x1EAA, 0x00C2, 0x0303},
+{ 0x1EAB, 0x00E2, 0x0303},
+{ 0x1EAC, 0x1EA0, 0x0302},
+{ 0x1EAD, 0x1EA1, 0x0302},
+{ 0x1EAE, 0x0102, 0x0301},
+{ 0x1EAF, 0x0103, 0x0301},
+{ 0x1EB0, 0x0102, 0x0300},
+{ 0x1EB1, 0x0103, 0x0300},
+{ 0x1EB2, 0x0102, 0x0309},
+{ 0x1EB3, 0x0103, 0x0309},
+{ 0x1EB4, 0x0102, 0x0303},
+{ 0x1EB5, 0x0103, 0x0303},
+{ 0x1EB6, 0x1EA0, 0x0306},
+{ 0x1EB7, 0x1EA1, 0x0306},
+{ 0x1EB8, 0x0045, 0x0323},
+{ 0x1EB9, 0x0065, 0x0323},
+{ 0x1EBA, 0x0045, 0x0309},
+{ 0x1EBB, 0x0065, 0x0309},
+{ 0x1EBC, 0x0045, 0x0303},
+{ 0x1EBD, 0x0065, 0x0303},
+{ 0x1EBE, 0x00CA, 0x0301},
+{ 0x1EBF, 0x00EA, 0x0301},
+{ 0x1EC0, 0x00CA, 0x0300},
+{ 0x1EC1, 0x00EA, 0x0300},
+{ 0x1EC2, 0x00CA, 0x0309},
+{ 0x1EC3, 0x00EA, 0x0309},
+{ 0x1EC4, 0x00CA, 0x0303},
+{ 0x1EC5, 0x00EA, 0x0303},
+{ 0x1EC6, 0x1EB8, 0x0302},
+{ 0x1EC7, 0x1EB9, 0x0302},
+{ 0x1EC8, 0x0049, 0x0309},
+{ 0x1EC9, 0x0069, 0x0309},
+{ 0x1ECA, 0x0049, 0x0323},
+{ 0x1ECB, 0x0069, 0x0323},
+{ 0x1ECC, 0x004F, 0x0323},
+{ 0x1ECD, 0x006F, 0x0323},
+{ 0x1ECE, 0x004F, 0x0309},
+{ 0x1ECF, 0x006F, 0x0309},
+{ 0x1ED0, 0x00D4, 0x0301},
+{ 0x1ED1, 0x00F4, 0x0301},
+{ 0x1ED2, 0x00D4, 0x0300},
+{ 0x1ED3, 0x00F4, 0x0300},
+{ 0x1ED4, 0x00D4, 0x0309},
+{ 0x1ED5, 0x00F4, 0x0309},
+{ 0x1ED6, 0x00D4, 0x0303},
+{ 0x1ED7, 0x00F4, 0x0303},
+{ 0x1ED8, 0x1ECC, 0x0302},
+{ 0x1ED9, 0x1ECD, 0x0302},
+{ 0x1EDA, 0x01A0, 0x0301},
+{ 0x1EDB, 0x01A1, 0x0301},
+{ 0x1EDC, 0x01A0, 0x0300},
+{ 0x1EDD, 0x01A1, 0x0300},
+{ 0x1EDE, 0x01A0, 0x0309},
+{ 0x1EDF, 0x01A1, 0x0309},
+{ 0x1EE0, 0x01A0, 0x0303},
+{ 0x1EE1, 0x01A1, 0x0303},
+{ 0x1EE2, 0x01A0, 0x0323},
+{ 0x1EE3, 0x01A1, 0x0323},
+{ 0x1EE4, 0x0055, 0x0323},
+{ 0x1EE5, 0x0075, 0x0323},
+{ 0x1EE6, 0x0055, 0x0309},
+{ 0x1EE7, 0x0075, 0x0309},
+{ 0x1EE8, 0x01AF, 0x0301},
+{ 0x1EE9, 0x01B0, 0x0301},
+{ 0x1EEA, 0x01AF, 0x0300},
+{ 0x1EEB, 0x01B0, 0x0300},
+{ 0x1EEC, 0x01AF, 0x0309},
+{ 0x1EED, 0x01B0, 0x0309},
+{ 0x1EEE, 0x01AF, 0x0303},
+{ 0x1EEF, 0x01B0, 0x0303},
+{ 0x1EF0, 0x01AF, 0x0323},
+{ 0x1EF1, 0x01B0, 0x0323},
+{ 0x1EF2, 0x0059, 0x0300},
+{ 0x1EF3, 0x0079, 0x0300},
+{ 0x1EF4, 0x0059, 0x0323},
+{ 0x1EF5, 0x0079, 0x0323},
+{ 0x1EF6, 0x0059, 0x0309},
+{ 0x1EF7, 0x0079, 0x0309},
+{ 0x1EF8, 0x0059, 0x0303},
+{ 0x1EF9, 0x0079, 0x0303},
+{ 0x1F00, 0x03B1, 0x0313},
+{ 0x1F01, 0x03B1, 0x0314},
+{ 0x1F02, 0x1F00, 0x0300},
+{ 0x1F03, 0x1F01, 0x0300},
+{ 0x1F04, 0x1F00, 0x0301},
+{ 0x1F05, 0x1F01, 0x0301},
+{ 0x1F06, 0x1F00, 0x0342},
+{ 0x1F07, 0x1F01, 0x0342},
+{ 0x1F08, 0x0391, 0x0313},
+{ 0x1F09, 0x0391, 0x0314},
+{ 0x1F0A, 0x1F08, 0x0300},
+{ 0x1F0B, 0x1F09, 0x0300},
+{ 0x1F0C, 0x1F08, 0x0301},
+{ 0x1F0D, 0x1F09, 0x0301},
+{ 0x1F0E, 0x1F08, 0x0342},
+{ 0x1F0F, 0x1F09, 0x0342},
+{ 0x1F10, 0x03B5, 0x0313},
+{ 0x1F11, 0x03B5, 0x0314},
+{ 0x1F12, 0x1F10, 0x0300},
+{ 0x1F13, 0x1F11, 0x0300},
+{ 0x1F14, 0x1F10, 0x0301},
+{ 0x1F15, 0x1F11, 0x0301},
+{ 0x1F18, 0x0395, 0x0313},
+{ 0x1F19, 0x0395, 0x0314},
+{ 0x1F1A, 0x1F18, 0x0300},
+{ 0x1F1B, 0x1F19, 0x0300},
+{ 0x1F1C, 0x1F18, 0x0301},
+{ 0x1F1D, 0x1F19, 0x0301},
+{ 0x1F20, 0x03B7, 0x0313},
+{ 0x1F21, 0x03B7, 0x0314},
+{ 0x1F22, 0x1F20, 0x0300},
+{ 0x1F23, 0x1F21, 0x0300},
+{ 0x1F24, 0x1F20, 0x0301},
+{ 0x1F25, 0x1F21, 0x0301},
+{ 0x1F26, 0x1F20, 0x0342},
+{ 0x1F27, 0x1F21, 0x0342},
+{ 0x1F28, 0x0397, 0x0313},
+{ 0x1F29, 0x0397, 0x0314},
+{ 0x1F2A, 0x1F28, 0x0300},
+{ 0x1F2B, 0x1F29, 0x0300},
+{ 0x1F2C, 0x1F28, 0x0301},
+{ 0x1F2D, 0x1F29, 0x0301},
+{ 0x1F2E, 0x1F28, 0x0342},
+{ 0x1F2F, 0x1F29, 0x0342},
+{ 0x1F30, 0x03B9, 0x0313},
+{ 0x1F31, 0x03B9, 0x0314},
+{ 0x1F32, 0x1F30, 0x0300},
+{ 0x1F33, 0x1F31, 0x0300},
+{ 0x1F34, 0x1F30, 0x0301},
+{ 0x1F35, 0x1F31, 0x0301},
+{ 0x1F36, 0x1F30, 0x0342},
+{ 0x1F37, 0x1F31, 0x0342},
+{ 0x1F38, 0x0399, 0x0313},
+{ 0x1F39, 0x0399, 0x0314},
+{ 0x1F3A, 0x1F38, 0x0300},
+{ 0x1F3B, 0x1F39, 0x0300},
+{ 0x1F3C, 0x1F38, 0x0301},
+{ 0x1F3D, 0x1F39, 0x0301},
+{ 0x1F3E, 0x1F38, 0x0342},
+{ 0x1F3F, 0x1F39, 0x0342},
+{ 0x1F40, 0x03BF, 0x0313},
+{ 0x1F41, 0x03BF, 0x0314},
+{ 0x1F42, 0x1F40, 0x0300},
+{ 0x1F43, 0x1F41, 0x0300},
+{ 0x1F44, 0x1F40, 0x0301},
+{ 0x1F45, 0x1F41, 0x0301},
+{ 0x1F48, 0x039F, 0x0313},
+{ 0x1F49, 0x039F, 0x0314},
+{ 0x1F4A, 0x1F48, 0x0300},
+{ 0x1F4B, 0x1F49, 0x0300},
+{ 0x1F4C, 0x1F48, 0x0301},
+{ 0x1F4D, 0x1F49, 0x0301},
+{ 0x1F50, 0x03C5, 0x0313},
+{ 0x1F51, 0x03C5, 0x0314},
+{ 0x1F52, 0x1F50, 0x0300},
+{ 0x1F53, 0x1F51, 0x0300},
+{ 0x1F54, 0x1F50, 0x0301},
+{ 0x1F55, 0x1F51, 0x0301},
+{ 0x1F56, 0x1F50, 0x0342},
+{ 0x1F57, 0x1F51, 0x0342},
+{ 0x1F59, 0x03A5, 0x0314},
+{ 0x1F5B, 0x1F59, 0x0300},
+{ 0x1F5D, 0x1F59, 0x0301},
+{ 0x1F5F, 0x1F59, 0x0342},
+{ 0x1F60, 0x03C9, 0x0313},
+{ 0x1F61, 0x03C9, 0x0314},
+{ 0x1F62, 0x1F60, 0x0300},
+{ 0x1F63, 0x1F61, 0x0300},
+{ 0x1F64, 0x1F60, 0x0301},
+{ 0x1F65, 0x1F61, 0x0301},
+{ 0x1F66, 0x1F60, 0x0342},
+{ 0x1F67, 0x1F61, 0x0342},
+{ 0x1F68, 0x03A9, 0x0313},
+{ 0x1F69, 0x03A9, 0x0314},
+{ 0x1F6A, 0x1F68, 0x0300},
+{ 0x1F6B, 0x1F69, 0x0300},
+{ 0x1F6C, 0x1F68, 0x0301},
+{ 0x1F6D, 0x1F69, 0x0301},
+{ 0x1F6E, 0x1F68, 0x0342},
+{ 0x1F6F, 0x1F69, 0x0342},
+{ 0x1F70, 0x03B1, 0x0300},
+{ 0x1F72, 0x03B5, 0x0300},
+{ 0x1F74, 0x03B7, 0x0300},
+{ 0x1F76, 0x03B9, 0x0300},
+{ 0x1F78, 0x03BF, 0x0300},
+{ 0x1F7A, 0x03C5, 0x0300},
+{ 0x1F7C, 0x03C9, 0x0300},
+{ 0x1F80, 0x1F00, 0x0345},
+{ 0x1F81, 0x1F01, 0x0345},
+{ 0x1F82, 0x1F02, 0x0345},
+{ 0x1F83, 0x1F03, 0x0345},
+{ 0x1F84, 0x1F04, 0x0345},
+{ 0x1F85, 0x1F05, 0x0345},
+{ 0x1F86, 0x1F06, 0x0345},
+{ 0x1F87, 0x1F07, 0x0345},
+{ 0x1F88, 0x1F08, 0x0345},
+{ 0x1F89, 0x1F09, 0x0345},
+{ 0x1F8A, 0x1F0A, 0x0345},
+{ 0x1F8B, 0x1F0B, 0x0345},
+{ 0x1F8C, 0x1F0C, 0x0345},
+{ 0x1F8D, 0x1F0D, 0x0345},
+{ 0x1F8E, 0x1F0E, 0x0345},
+{ 0x1F8F, 0x1F0F, 0x0345},
+{ 0x1F90, 0x1F20, 0x0345},
+{ 0x1F91, 0x1F21, 0x0345},
+{ 0x1F92, 0x1F22, 0x0345},
+{ 0x1F93, 0x1F23, 0x0345},
+{ 0x1F94, 0x1F24, 0x0345},
+{ 0x1F95, 0x1F25, 0x0345},
+{ 0x1F96, 0x1F26, 0x0345},
+{ 0x1F97, 0x1F27, 0x0345},
+{ 0x1F98, 0x1F28, 0x0345},
+{ 0x1F99, 0x1F29, 0x0345},
+{ 0x1F9A, 0x1F2A, 0x0345},
+{ 0x1F9B, 0x1F2B, 0x0345},
+{ 0x1F9C, 0x1F2C, 0x0345},
+{ 0x1F9D, 0x1F2D, 0x0345},
+{ 0x1F9E, 0x1F2E, 0x0345},
+{ 0x1F9F, 0x1F2F, 0x0345},
+{ 0x1FA0, 0x1F60, 0x0345},
+{ 0x1FA1, 0x1F61, 0x0345},
+{ 0x1FA2, 0x1F62, 0x0345},
+{ 0x1FA3, 0x1F63, 0x0345},
+{ 0x1FA4, 0x1F64, 0x0345},
+{ 0x1FA5, 0x1F65, 0x0345},
+{ 0x1FA6, 0x1F66, 0x0345},
+{ 0x1FA7, 0x1F67, 0x0345},
+{ 0x1FA8, 0x1F68, 0x0345},
+{ 0x1FA9, 0x1F69, 0x0345},
+{ 0x1FAA, 0x1F6A, 0x0345},
+{ 0x1FAB, 0x1F6B, 0x0345},
+{ 0x1FAC, 0x1F6C, 0x0345},
+{ 0x1FAD, 0x1F6D, 0x0345},
+{ 0x1FAE, 0x1F6E, 0x0345},
+{ 0x1FAF, 0x1F6F, 0x0345},
+{ 0x1FB0, 0x03B1, 0x0306},
+{ 0x1FB1, 0x03B1, 0x0304},
+{ 0x1FB2, 0x1F70, 0x0345},
+{ 0x1FB3, 0x03B1, 0x0345},
+{ 0x1FB4, 0x03AC, 0x0345},
+{ 0x1FB6, 0x03B1, 0x0342},
+{ 0x1FB7, 0x1FB6, 0x0345},
+{ 0x1FB8, 0x0391, 0x0306},
+{ 0x1FB9, 0x0391, 0x0304},
+{ 0x1FBA, 0x0391, 0x0300},
+{ 0x1FBC, 0x0391, 0x0345},
+{ 0x1FC1, 0x00A8, 0x0342},
+{ 0x1FC2, 0x1F74, 0x0345},
+{ 0x1FC3, 0x03B7, 0x0345},
+{ 0x1FC4, 0x03AE, 0x0345},
+{ 0x1FC6, 0x03B7, 0x0342},
+{ 0x1FC7, 0x1FC6, 0x0345},
+{ 0x1FC8, 0x0395, 0x0300},
+{ 0x1FCA, 0x0397, 0x0300},
+{ 0x1FCC, 0x0397, 0x0345},
+{ 0x1FCD, 0x1FBF, 0x0300},
+{ 0x1FCE, 0x1FBF, 0x0301},
+{ 0x1FCF, 0x1FBF, 0x0342},
+{ 0x1FD0, 0x03B9, 0x0306},
+{ 0x1FD1, 0x03B9, 0x0304},
+{ 0x1FD2, 0x03CA, 0x0300},
+{ 0x1FD6, 0x03B9, 0x0342},
+{ 0x1FD7, 0x03CA, 0x0342},
+{ 0x1FD8, 0x0399, 0x0306},
+{ 0x1FD9, 0x0399, 0x0304},
+{ 0x1FDA, 0x0399, 0x0300},
+{ 0x1FDD, 0x1FFE, 0x0300},
+{ 0x1FDE, 0x1FFE, 0x0301},
+{ 0x1FDF, 0x1FFE, 0x0342},
+{ 0x1FE0, 0x03C5, 0x0306},
+{ 0x1FE1, 0x03C5, 0x0304},
+{ 0x1FE2, 0x03CB, 0x0300},
+{ 0x1FE4, 0x03C1, 0x0313},
+{ 0x1FE5, 0x03C1, 0x0314},
+{ 0x1FE6, 0x03C5, 0x0342},
+{ 0x1FE7, 0x03CB, 0x0342},
+{ 0x1FE8, 0x03A5, 0x0306},
+{ 0x1FE9, 0x03A5, 0x0304},
+{ 0x1FEA, 0x03A5, 0x0300},
+{ 0x1FEC, 0x03A1, 0x0314},
+{ 0x1FED, 0x00A8, 0x0300},
+{ 0x1FF2, 0x1F7C, 0x0345},
+{ 0x1FF3, 0x03C9, 0x0345},
+{ 0x1FF4, 0x03CE, 0x0345},
+{ 0x1FF6, 0x03C9, 0x0342},
+{ 0x1FF7, 0x1FF6, 0x0345},
+{ 0x1FF8, 0x039F, 0x0300},
+{ 0x1FFA, 0x03A9, 0x0300},
+{ 0x1FFC, 0x03A9, 0x0345},
+{ 0x219A, 0x2190, 0x0338},
+{ 0x219B, 0x2192, 0x0338},
+{ 0x21AE, 0x2194, 0x0338},
+{ 0x21CD, 0x21D0, 0x0338},
+{ 0x21CE, 0x21D4, 0x0338},
+{ 0x21CF, 0x21D2, 0x0338},
+{ 0x2204, 0x2203, 0x0338},
+{ 0x2209, 0x2208, 0x0338},
+{ 0x220C, 0x220B, 0x0338},
+{ 0x2224, 0x2223, 0x0338},
+{ 0x2226, 0x2225, 0x0338},
+{ 0x2241, 0x223C, 0x0338},
+{ 0x2244, 0x2243, 0x0338},
+{ 0x2247, 0x2245, 0x0338},
+{ 0x2249, 0x2248, 0x0338},
+{ 0x2260, 0x003D, 0x0338},
+{ 0x2262, 0x2261, 0x0338},
+{ 0x226D, 0x224D, 0x0338},
+{ 0x226E, 0x003C, 0x0338},
+{ 0x226F, 0x003E, 0x0338},
+{ 0x2270, 0x2264, 0x0338},
+{ 0x2271, 0x2265, 0x0338},
+{ 0x2274, 0x2272, 0x0338},
+{ 0x2275, 0x2273, 0x0338},
+{ 0x2278, 0x2276, 0x0338},
+{ 0x2279, 0x2277, 0x0338},
+{ 0x2280, 0x227A, 0x0338},
+{ 0x2281, 0x227B, 0x0338},
+{ 0x2284, 0x2282, 0x0338},
+{ 0x2285, 0x2283, 0x0338},
+{ 0x2288, 0x2286, 0x0338},
+{ 0x2289, 0x2287, 0x0338},
+{ 0x22AC, 0x22A2, 0x0338},
+{ 0x22AD, 0x22A8, 0x0338},
+{ 0x22AE, 0x22A9, 0x0338},
+{ 0x22AF, 0x22AB, 0x0338},
+{ 0x22E0, 0x227C, 0x0338},
+{ 0x22E1, 0x227D, 0x0338},
+{ 0x22E2, 0x2291, 0x0338},
+{ 0x22E3, 0x2292, 0x0338},
+{ 0x22EA, 0x22B2, 0x0338},
+{ 0x22EB, 0x22B3, 0x0338},
+{ 0x22EC, 0x22B4, 0x0338},
+{ 0x22ED, 0x22B5, 0x0338},
+{ 0x304C, 0x304B, 0x3099},
+{ 0x304E, 0x304D, 0x3099},
+{ 0x3050, 0x304F, 0x3099},
+{ 0x3052, 0x3051, 0x3099},
+{ 0x3054, 0x3053, 0x3099},
+{ 0x3056, 0x3055, 0x3099},
+{ 0x3058, 0x3057, 0x3099},
+{ 0x305A, 0x3059, 0x3099},
+{ 0x305C, 0x305B, 0x3099},
+{ 0x305E, 0x305D, 0x3099},
+{ 0x3060, 0x305F, 0x3099},
+{ 0x3062, 0x3061, 0x3099},
+{ 0x3065, 0x3064, 0x3099},
+{ 0x3067, 0x3066, 0x3099},
+{ 0x3069, 0x3068, 0x3099},
+{ 0x3070, 0x306F, 0x3099},
+{ 0x3071, 0x306F, 0x309A},
+{ 0x3073, 0x3072, 0x3099},
+{ 0x3074, 0x3072, 0x309A},
+{ 0x3076, 0x3075, 0x3099},
+{ 0x3077, 0x3075, 0x309A},
+{ 0x3079, 0x3078, 0x3099},
+{ 0x307A, 0x3078, 0x309A},
+{ 0x307C, 0x307B, 0x3099},
+{ 0x307D, 0x307B, 0x309A},
+{ 0x3094, 0x3046, 0x3099},
+{ 0x309E, 0x309D, 0x3099},
+{ 0x30AC, 0x30AB, 0x3099},
+{ 0x30AE, 0x30AD, 0x3099},
+{ 0x30B0, 0x30AF, 0x3099},
+{ 0x30B2, 0x30B1, 0x3099},
+{ 0x30B4, 0x30B3, 0x3099},
+{ 0x30B6, 0x30B5, 0x3099},
+{ 0x30B8, 0x30B7, 0x3099},
+{ 0x30BA, 0x30B9, 0x3099},
+{ 0x30BC, 0x30BB, 0x3099},
+{ 0x30BE, 0x30BD, 0x3099},
+{ 0x30C0, 0x30BF, 0x3099},
+{ 0x30C2, 0x30C1, 0x3099},
+{ 0x30C5, 0x30C4, 0x3099},
+{ 0x30C7, 0x30C6, 0x3099},
+{ 0x30C9, 0x30C8, 0x3099},
+{ 0x30D0, 0x30CF, 0x3099},
+{ 0x30D1, 0x30CF, 0x309A},
+{ 0x30D3, 0x30D2, 0x3099},
+{ 0x30D4, 0x30D2, 0x309A},
+{ 0x30D6, 0x30D5, 0x3099},
+{ 0x30D7, 0x30D5, 0x309A},
+{ 0x30D9, 0x30D8, 0x3099},
+{ 0x30DA, 0x30D8, 0x309A},
+{ 0x30DC, 0x30DB, 0x3099},
+{ 0x30DD, 0x30DB, 0x309A},
+{ 0x30F4, 0x30A6, 0x3099},
+{ 0x30F7, 0x30EF, 0x3099},
+{ 0x30F8, 0x30F0, 0x3099},
+{ 0x30F9, 0x30F1, 0x3099},
+{ 0x30FA, 0x30F2, 0x3099},
+{ 0x30FE, 0x30FD, 0x3099},
+{ 0xFB1D, 0x05D9, 0x05B4},
+{ 0xFB1F, 0x05F2, 0x05B7},
+{ 0xFB2A, 0x05E9, 0x05C1},
+{ 0xFB2B, 0x05E9, 0x05C2},
+{ 0xFB2C, 0xFB49, 0x05C1},
+{ 0xFB2D, 0xFB49, 0x05C2},
+{ 0xFB2E, 0x05D0, 0x05B7},
+{ 0xFB2F, 0x05D0, 0x05B8},
+{ 0xFB30, 0x05D0, 0x05BC},
+{ 0xFB31, 0x05D1, 0x05BC},
+{ 0xFB32, 0x05D2, 0x05BC},
+{ 0xFB33, 0x05D3, 0x05BC},
+{ 0xFB34, 0x05D4, 0x05BC},
+{ 0xFB35, 0x05D5, 0x05BC},
+{ 0xFB36, 0x05D6, 0x05BC},
+{ 0xFB38, 0x05D8, 0x05BC},
+{ 0xFB39, 0x05D9, 0x05BC},
+{ 0xFB3A, 0x05DA, 0x05BC},
+{ 0xFB3B, 0x05DB, 0x05BC},
+{ 0xFB3C, 0x05DC, 0x05BC},
+{ 0xFB3E, 0x05DE, 0x05BC},
+{ 0xFB40, 0x05E0, 0x05BC},
+{ 0xFB41, 0x05E1, 0x05BC},
+{ 0xFB43, 0x05E3, 0x05BC},
+{ 0xFB44, 0x05E4, 0x05BC},
+{ 0xFB46, 0x05E6, 0x05BC},
+{ 0xFB47, 0x05E7, 0x05BC},
+{ 0xFB48, 0x05E8, 0x05BC},
+{ 0xFB49, 0x05E9, 0x05BC},
+{ 0xFB4A, 0x05EA, 0x05BC},
+{ 0xFB4B, 0x05D5, 0x05B9},
+{ 0xFB4C, 0x05D1, 0x05BF},
+{ 0xFB4D, 0x05DB, 0x05BF},
+{ 0xFB4E, 0x05E4, 0x05BF},
+};
diff --git a/libatalk/unicode/ucs2_casetable.h b/libatalk/unicode/ucs2_casetable.h
new file mode 100644 (file)
index 0000000..8ac86da
--- /dev/null
@@ -0,0 +1,472 @@
+static const u_int16_t upcase_table_1[64] = {
+0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,   /* 0x0040-0x0047 */ 
+0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,   /* 0x0048-0x004F */ 
+0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,   /* 0x0050-0x0057 */ 
+0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,   /* 0x0058-0x005F */ 
+0x0060, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,   /* 0x0060-0x0067 */ 
+0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,   /* 0x0068-0x006F */ 
+0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,   /* 0x0070-0x0077 */ 
+0x0058, 0x0059, 0x005A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F }; /* 0x0078-0x007F */
+
+static const u_int16_t upcase_table_2[512] = {
+0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7,   /* 0x00C0-0x00C7 */ 
+0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF,   /* 0x00C8-0x00CF */ 
+0x00D0, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7,   /* 0x00D0-0x00D7 */ 
+0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00DE, 0x00DF,   /* 0x00D8-0x00DF */ 
+0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7,   /* 0x00E0-0x00E7 */ 
+0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF,   /* 0x00E8-0x00EF */ 
+0x00D0, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00F7,   /* 0x00F0-0x00F7 */ 
+0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00DE, 0x0178,   /* 0x00F8-0x00FF */ 
+0x0100, 0x0100, 0x0102, 0x0102, 0x0104, 0x0104, 0x0106, 0x0106,   /* 0x0100-0x0107 */ 
+0x0108, 0x0108, 0x010A, 0x010A, 0x010C, 0x010C, 0x010E, 0x010E,   /* 0x0108-0x010F */ 
+0x0110, 0x0110, 0x0112, 0x0112, 0x0114, 0x0114, 0x0116, 0x0116,   /* 0x0110-0x0117 */ 
+0x0118, 0x0118, 0x011A, 0x011A, 0x011C, 0x011C, 0x011E, 0x011E,   /* 0x0118-0x011F */ 
+0x0120, 0x0120, 0x0122, 0x0122, 0x0124, 0x0124, 0x0126, 0x0126,   /* 0x0120-0x0127 */ 
+0x0128, 0x0128, 0x012A, 0x012A, 0x012C, 0x012C, 0x012E, 0x012E,   /* 0x0128-0x012F */ 
+0x0130, 0x0131, 0x0132, 0x0132, 0x0134, 0x0134, 0x0136, 0x0136,   /* 0x0130-0x0137 */ 
+0x0138, 0x0139, 0x0139, 0x013B, 0x013B, 0x013D, 0x013D, 0x013F,   /* 0x0138-0x013F */ 
+0x013F, 0x0141, 0x0141, 0x0143, 0x0143, 0x0145, 0x0145, 0x0147,   /* 0x0140-0x0147 */ 
+0x0147, 0x0149, 0x014A, 0x014A, 0x014C, 0x014C, 0x014E, 0x014E,   /* 0x0148-0x014F */ 
+0x0150, 0x0150, 0x0152, 0x0152, 0x0154, 0x0154, 0x0156, 0x0156,   /* 0x0150-0x0157 */ 
+0x0158, 0x0158, 0x015A, 0x015A, 0x015C, 0x015C, 0x015E, 0x015E,   /* 0x0158-0x015F */ 
+0x0160, 0x0160, 0x0162, 0x0162, 0x0164, 0x0164, 0x0166, 0x0166,   /* 0x0160-0x0167 */ 
+0x0168, 0x0168, 0x016A, 0x016A, 0x016C, 0x016C, 0x016E, 0x016E,   /* 0x0168-0x016F */ 
+0x0170, 0x0170, 0x0172, 0x0172, 0x0174, 0x0174, 0x0176, 0x0176,   /* 0x0170-0x0177 */ 
+0x0178, 0x0179, 0x0179, 0x017B, 0x017B, 0x017D, 0x017D, 0x017F,   /* 0x0178-0x017F */ 
+0x0180, 0x0181, 0x0182, 0x0182, 0x0184, 0x0184, 0x0186, 0x0187,   /* 0x0180-0x0187 */ 
+0x0187, 0x0189, 0x018A, 0x018B, 0x018B, 0x018D, 0x018E, 0x018F,   /* 0x0188-0x018F */ 
+0x0190, 0x0191, 0x0191, 0x0193, 0x0194, 0x0195, 0x0196, 0x0197,   /* 0x0190-0x0197 */ 
+0x0198, 0x0198, 0x019A, 0x019B, 0x019C, 0x019D, 0x019E, 0x019F,   /* 0x0198-0x019F */ 
+0x01A0, 0x01A0, 0x01A2, 0x01A2, 0x01A4, 0x01A4, 0x01A6, 0x01A7,   /* 0x01A0-0x01A7 */ 
+0x01A7, 0x01A9, 0x01AA, 0x01AB, 0x01AC, 0x01AC, 0x01AE, 0x01AF,   /* 0x01A8-0x01AF */ 
+0x01AF, 0x01B1, 0x01B2, 0x01B3, 0x01B3, 0x01B5, 0x01B5, 0x01B7,   /* 0x01B0-0x01B7 */ 
+0x01B8, 0x01B8, 0x01BA, 0x01BB, 0x01BC, 0x01BC, 0x01BE, 0x01BF,   /* 0x01B8-0x01BF */ 
+0x01C0, 0x01C1, 0x01C2, 0x01C3, 0x01C4, 0x01C5, 0x01C4, 0x01C7,   /* 0x01C0-0x01C7 */ 
+0x01C8, 0x01C7, 0x01CA, 0x01CB, 0x01CA, 0x01CD, 0x01CD, 0x01CF,   /* 0x01C8-0x01CF */ 
+0x01CF, 0x01D1, 0x01D1, 0x01D3, 0x01D3, 0x01D5, 0x01D5, 0x01D7,   /* 0x01D0-0x01D7 */ 
+0x01D7, 0x01D9, 0x01D9, 0x01DB, 0x01DB, 0x018E, 0x01DE, 0x01DE,   /* 0x01D8-0x01DF */ 
+0x01E0, 0x01E0, 0x01E2, 0x01E2, 0x01E4, 0x01E4, 0x01E6, 0x01E6,   /* 0x01E0-0x01E7 */ 
+0x01E8, 0x01E8, 0x01EA, 0x01EA, 0x01EC, 0x01EC, 0x01EE, 0x01EE,   /* 0x01E8-0x01EF */ 
+0x01F0, 0x01F1, 0x01F2, 0x01F1, 0x01F4, 0x01F4, 0x01F6, 0x01F7,   /* 0x01F0-0x01F7 */ 
+0x01F8, 0x01F9, 0x01FA, 0x01FA, 0x01FC, 0x01FC, 0x01FE, 0x01FE,   /* 0x01F8-0x01FF */ 
+0x0200, 0x0200, 0x0202, 0x0202, 0x0204, 0x0204, 0x0206, 0x0206,   /* 0x0200-0x0207 */ 
+0x0208, 0x0208, 0x020A, 0x020A, 0x020C, 0x020C, 0x020E, 0x020E,   /* 0x0208-0x020F */ 
+0x0210, 0x0210, 0x0212, 0x0212, 0x0214, 0x0214, 0x0216, 0x0216,   /* 0x0210-0x0217 */ 
+0x0218, 0x0219, 0x021A, 0x021B, 0x021C, 0x021D, 0x021E, 0x021F,   /* 0x0218-0x021F */ 
+0x0220, 0x0221, 0x0222, 0x0223, 0x0224, 0x0225, 0x0226, 0x0227,   /* 0x0220-0x0227 */ 
+0x0228, 0x0229, 0x022A, 0x022B, 0x022C, 0x022D, 0x022E, 0x022F,   /* 0x0228-0x022F */ 
+0x0230, 0x0231, 0x0232, 0x0233, 0x0234, 0x0235, 0x0236, 0x0237,   /* 0x0230-0x0237 */ 
+0x0238, 0x0239, 0x023A, 0x023B, 0x023C, 0x023D, 0x023E, 0x023F,   /* 0x0238-0x023F */ 
+0x0240, 0x0241, 0x0242, 0x0243, 0x0244, 0x0245, 0x0246, 0x0247,   /* 0x0240-0x0247 */ 
+0x0248, 0x0249, 0x024A, 0x024B, 0x024C, 0x024D, 0x024E, 0x024F,   /* 0x0248-0x024F */ 
+0x0250, 0x0251, 0x0252, 0x0181, 0x0186, 0x0255, 0x0189, 0x018A,   /* 0x0250-0x0257 */ 
+0x0258, 0x018F, 0x025A, 0x0190, 0x025C, 0x025D, 0x025E, 0x025F,   /* 0x0258-0x025F */ 
+0x0193, 0x0261, 0x0262, 0x0194, 0x0264, 0x0265, 0x0266, 0x0267,   /* 0x0260-0x0267 */ 
+0x0197, 0x0196, 0x026A, 0x026B, 0x026C, 0x026D, 0x026E, 0x019C,   /* 0x0268-0x026F */ 
+0x0270, 0x0271, 0x019D, 0x0273, 0x0274, 0x019F, 0x0276, 0x0277,   /* 0x0270-0x0277 */ 
+0x0278, 0x0279, 0x027A, 0x027B, 0x027C, 0x027D, 0x027E, 0x027F,   /* 0x0278-0x027F */ 
+0x0280, 0x0281, 0x0282, 0x01A9, 0x0284, 0x0285, 0x0286, 0x0287,   /* 0x0280-0x0287 */ 
+0x01AE, 0x0289, 0x01B1, 0x01B2, 0x028C, 0x028D, 0x028E, 0x028F,   /* 0x0288-0x028F */ 
+0x0290, 0x0291, 0x01B7, 0x0293, 0x0294, 0x0295, 0x0296, 0x0297,   /* 0x0290-0x0297 */ 
+0x0298, 0x0299, 0x029A, 0x029B, 0x029C, 0x029D, 0x029E, 0x029F,   /* 0x0298-0x029F */ 
+0x02A0, 0x02A1, 0x02A2, 0x02A3, 0x02A4, 0x02A5, 0x02A6, 0x02A7,   /* 0x02A0-0x02A7 */ 
+0x02A8, 0x02A9, 0x02AA, 0x02AB, 0x02AC, 0x02AD, 0x02AE, 0x02AF,   /* 0x02A8-0x02AF */ 
+0x02B0, 0x02B1, 0x02B2, 0x02B3, 0x02B4, 0x02B5, 0x02B6, 0x02B7,   /* 0x02B0-0x02B7 */ 
+0x02B8, 0x02B9, 0x02BA, 0x02BB, 0x02BC, 0x02BD, 0x02BE, 0x02BF }; /* 0x02B8-0x02BF */
+
+static const u_int16_t upcase_table_3[384] = {
+0x0380, 0x0381, 0x0382, 0x0383, 0x0384, 0x0385, 0x0386, 0x0387,   /* 0x0380-0x0387 */ 
+0x0388, 0x0389, 0x038A, 0x038B, 0x038C, 0x038D, 0x038E, 0x038F,   /* 0x0388-0x038F */ 
+0x0390, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397,   /* 0x0390-0x0397 */ 
+0x0398, 0x0399, 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F,   /* 0x0398-0x039F */ 
+0x03A0, 0x03A1, 0x03A2, 0x03A3, 0x03A4, 0x03A5, 0x03A6, 0x03A7,   /* 0x03A0-0x03A7 */ 
+0x03A8, 0x03A9, 0x03AA, 0x03AB, 0x0386, 0x0388, 0x0389, 0x038A,   /* 0x03A8-0x03AF */ 
+0x03B0, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397,   /* 0x03B0-0x03B7 */ 
+0x0398, 0x0399, 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F,   /* 0x03B8-0x03BF */ 
+0x03A0, 0x03A1, 0x03A3, 0x03A3, 0x03A4, 0x03A5, 0x03A6, 0x03A7,   /* 0x03C0-0x03C7 */ 
+0x03A8, 0x03A9, 0x03AA, 0x03AB, 0x038C, 0x038E, 0x038F, 0x03CF,   /* 0x03C8-0x03CF */ 
+0x03D0, 0x03D1, 0x03D2, 0x03D3, 0x03D4, 0x03D5, 0x03D6, 0x03D7,   /* 0x03D0-0x03D7 */ 
+0x03D8, 0x03D9, 0x03DA, 0x03DB, 0x03DC, 0x03DD, 0x03DE, 0x03DF,   /* 0x03D8-0x03DF */ 
+0x03E0, 0x03E1, 0x03E2, 0x03E2, 0x03E4, 0x03E4, 0x03E6, 0x03E6,   /* 0x03E0-0x03E7 */ 
+0x03E8, 0x03E8, 0x03EA, 0x03EA, 0x03EC, 0x03EC, 0x03EE, 0x03EE,   /* 0x03E8-0x03EF */ 
+0x03F0, 0x03F1, 0x03F2, 0x03F3, 0x03F4, 0x03F5, 0x03F6, 0x03F7,   /* 0x03F0-0x03F7 */ 
+0x03F8, 0x03F9, 0x03FA, 0x03FB, 0x03FC, 0x03FD, 0x03FE, 0x03FF,   /* 0x03F8-0x03FF */ 
+0x0400, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0406, 0x0407,   /* 0x0400-0x0407 */ 
+0x0408, 0x0409, 0x040A, 0x040B, 0x040C, 0x040D, 0x040E, 0x040F,   /* 0x0408-0x040F */ 
+0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417,   /* 0x0410-0x0417 */ 
+0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F,   /* 0x0418-0x041F */ 
+0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427,   /* 0x0420-0x0427 */ 
+0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F,   /* 0x0428-0x042F */ 
+0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417,   /* 0x0430-0x0437 */ 
+0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F,   /* 0x0438-0x043F */ 
+0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427,   /* 0x0440-0x0447 */ 
+0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F,   /* 0x0448-0x044F */ 
+0x0450, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0406, 0x0407,   /* 0x0450-0x0457 */ 
+0x0408, 0x0409, 0x040A, 0x040B, 0x040C, 0x045D, 0x040E, 0x040F,   /* 0x0458-0x045F */ 
+0x0460, 0x0460, 0x0462, 0x0462, 0x0464, 0x0464, 0x0466, 0x0466,   /* 0x0460-0x0467 */ 
+0x0468, 0x0468, 0x046A, 0x046A, 0x046C, 0x046C, 0x046E, 0x046E,   /* 0x0468-0x046F */ 
+0x0470, 0x0470, 0x0472, 0x0472, 0x0474, 0x0474, 0x0476, 0x0476,   /* 0x0470-0x0477 */ 
+0x0478, 0x0478, 0x047A, 0x047A, 0x047C, 0x047C, 0x047E, 0x047E,   /* 0x0478-0x047F */ 
+0x0480, 0x0480, 0x0482, 0x0483, 0x0484, 0x0485, 0x0486, 0x0487,   /* 0x0480-0x0487 */ 
+0x0488, 0x0489, 0x048A, 0x048B, 0x048C, 0x048D, 0x048E, 0x048F,   /* 0x0488-0x048F */ 
+0x0490, 0x0490, 0x0492, 0x0492, 0x0494, 0x0494, 0x0496, 0x0496,   /* 0x0490-0x0497 */ 
+0x0498, 0x0498, 0x049A, 0x049A, 0x049C, 0x049C, 0x049E, 0x049E,   /* 0x0498-0x049F */ 
+0x04A0, 0x04A0, 0x04A2, 0x04A2, 0x04A4, 0x04A4, 0x04A6, 0x04A6,   /* 0x04A0-0x04A7 */ 
+0x04A8, 0x04A8, 0x04AA, 0x04AA, 0x04AC, 0x04AC, 0x04AE, 0x04AE,   /* 0x04A8-0x04AF */ 
+0x04B0, 0x04B0, 0x04B2, 0x04B2, 0x04B4, 0x04B4, 0x04B6, 0x04B6,   /* 0x04B0-0x04B7 */ 
+0x04B8, 0x04B8, 0x04BA, 0x04BA, 0x04BC, 0x04BC, 0x04BE, 0x04BE,   /* 0x04B8-0x04BF */ 
+0x04C0, 0x04C1, 0x04C1, 0x04C3, 0x04C3, 0x04C5, 0x04C6, 0x04C7,   /* 0x04C0-0x04C7 */ 
+0x04C7, 0x04C9, 0x04CA, 0x04CB, 0x04CB, 0x04CD, 0x04CE, 0x04CF,   /* 0x04C8-0x04CF */ 
+0x04D0, 0x04D0, 0x04D2, 0x04D2, 0x04D4, 0x04D4, 0x04D6, 0x04D6,   /* 0x04D0-0x04D7 */ 
+0x04D8, 0x04D8, 0x04DA, 0x04DA, 0x04DC, 0x04DC, 0x04DE, 0x04DE,   /* 0x04D8-0x04DF */ 
+0x04E0, 0x04E0, 0x04E2, 0x04E2, 0x04E4, 0x04E4, 0x04E6, 0x04E6,   /* 0x04E0-0x04E7 */ 
+0x04E8, 0x04E8, 0x04EA, 0x04EA, 0x04EC, 0x04ED, 0x04EE, 0x04EE,   /* 0x04E8-0x04EF */ 
+0x04F0, 0x04F0, 0x04F2, 0x04F2, 0x04F4, 0x04F4, 0x04F6, 0x04F7,   /* 0x04F0-0x04F7 */ 
+0x04F8, 0x04F8, 0x04FA, 0x04FB, 0x04FC, 0x04FD, 0x04FE, 0x04FF }; /* 0x04F8-0x04FF */
+
+static const u_int16_t upcase_table_4[128] = {
+0x0540, 0x0541, 0x0542, 0x0543, 0x0544, 0x0545, 0x0546, 0x0547,   /* 0x0540-0x0547 */ 
+0x0548, 0x0549, 0x054A, 0x054B, 0x054C, 0x054D, 0x054E, 0x054F,   /* 0x0548-0x054F */ 
+0x0550, 0x0551, 0x0552, 0x0553, 0x0554, 0x0555, 0x0556, 0x0557,   /* 0x0550-0x0557 */ 
+0x0558, 0x0559, 0x055A, 0x055B, 0x055C, 0x055D, 0x055E, 0x055F,   /* 0x0558-0x055F */ 
+0x0560, 0x0531, 0x0532, 0x0533, 0x0534, 0x0535, 0x0536, 0x0537,   /* 0x0560-0x0567 */ 
+0x0538, 0x0539, 0x053A, 0x053B, 0x053C, 0x053D, 0x053E, 0x053F,   /* 0x0568-0x056F */ 
+0x0540, 0x0541, 0x0542, 0x0543, 0x0544, 0x0545, 0x0546, 0x0547,   /* 0x0570-0x0577 */ 
+0x0548, 0x0549, 0x054A, 0x054B, 0x054C, 0x054D, 0x054E, 0x054F,   /* 0x0578-0x057F */ 
+0x0550, 0x0551, 0x0552, 0x0553, 0x0554, 0x0555, 0x0556, 0x0587,   /* 0x0580-0x0587 */ 
+0x0588, 0x0589, 0x058A, 0x058B, 0x058C, 0x058D, 0x058E, 0x058F,   /* 0x0588-0x058F */ 
+0x0590, 0x0591, 0x0592, 0x0593, 0x0594, 0x0595, 0x0596, 0x0597,   /* 0x0590-0x0597 */ 
+0x0598, 0x0599, 0x059A, 0x059B, 0x059C, 0x059D, 0x059E, 0x059F,   /* 0x0598-0x059F */ 
+0x05A0, 0x05A1, 0x05A2, 0x05A3, 0x05A4, 0x05A5, 0x05A6, 0x05A7,   /* 0x05A0-0x05A7 */ 
+0x05A8, 0x05A9, 0x05AA, 0x05AB, 0x05AC, 0x05AD, 0x05AE, 0x05AF,   /* 0x05A8-0x05AF */ 
+0x05B0, 0x05B1, 0x05B2, 0x05B3, 0x05B4, 0x05B5, 0x05B6, 0x05B7,   /* 0x05B0-0x05B7 */ 
+0x05B8, 0x05B9, 0x05BA, 0x05BB, 0x05BC, 0x05BD, 0x05BE, 0x05BF }; /* 0x05B8-0x05BF */
+
+static const u_int16_t upcase_table_5[512] = {
+0x1E00, 0x1E00, 0x1E02, 0x1E02, 0x1E04, 0x1E04, 0x1E06, 0x1E06,   /* 0x1E00-0x1E07 */ 
+0x1E08, 0x1E08, 0x1E0A, 0x1E0A, 0x1E0C, 0x1E0C, 0x1E0E, 0x1E0E,   /* 0x1E08-0x1E0F */ 
+0x1E10, 0x1E10, 0x1E12, 0x1E12, 0x1E14, 0x1E14, 0x1E16, 0x1E16,   /* 0x1E10-0x1E17 */ 
+0x1E18, 0x1E18, 0x1E1A, 0x1E1A, 0x1E1C, 0x1E1C, 0x1E1E, 0x1E1E,   /* 0x1E18-0x1E1F */ 
+0x1E20, 0x1E20, 0x1E22, 0x1E22, 0x1E24, 0x1E24, 0x1E26, 0x1E26,   /* 0x1E20-0x1E27 */ 
+0x1E28, 0x1E28, 0x1E2A, 0x1E2A, 0x1E2C, 0x1E2C, 0x1E2E, 0x1E2E,   /* 0x1E28-0x1E2F */ 
+0x1E30, 0x1E30, 0x1E32, 0x1E32, 0x1E34, 0x1E34, 0x1E36, 0x1E36,   /* 0x1E30-0x1E37 */ 
+0x1E38, 0x1E38, 0x1E3A, 0x1E3A, 0x1E3C, 0x1E3C, 0x1E3E, 0x1E3E,   /* 0x1E38-0x1E3F */ 
+0x1E40, 0x1E40, 0x1E42, 0x1E42, 0x1E44, 0x1E44, 0x1E46, 0x1E46,   /* 0x1E40-0x1E47 */ 
+0x1E48, 0x1E48, 0x1E4A, 0x1E4A, 0x1E4C, 0x1E4C, 0x1E4E, 0x1E4E,   /* 0x1E48-0x1E4F */ 
+0x1E50, 0x1E50, 0x1E52, 0x1E52, 0x1E54, 0x1E54, 0x1E56, 0x1E56,   /* 0x1E50-0x1E57 */ 
+0x1E58, 0x1E58, 0x1E5A, 0x1E5A, 0x1E5C, 0x1E5C, 0x1E5E, 0x1E5E,   /* 0x1E58-0x1E5F */ 
+0x1E60, 0x1E60, 0x1E62, 0x1E62, 0x1E64, 0x1E64, 0x1E66, 0x1E66,   /* 0x1E60-0x1E67 */ 
+0x1E68, 0x1E68, 0x1E6A, 0x1E6A, 0x1E6C, 0x1E6C, 0x1E6E, 0x1E6E,   /* 0x1E68-0x1E6F */ 
+0x1E70, 0x1E70, 0x1E72, 0x1E72, 0x1E74, 0x1E74, 0x1E76, 0x1E76,   /* 0x1E70-0x1E77 */ 
+0x1E78, 0x1E78, 0x1E7A, 0x1E7A, 0x1E7C, 0x1E7C, 0x1E7E, 0x1E7E,   /* 0x1E78-0x1E7F */ 
+0x1E80, 0x1E80, 0x1E82, 0x1E82, 0x1E84, 0x1E84, 0x1E86, 0x1E86,   /* 0x1E80-0x1E87 */ 
+0x1E88, 0x1E88, 0x1E8A, 0x1E8A, 0x1E8C, 0x1E8C, 0x1E8E, 0x1E8E,   /* 0x1E88-0x1E8F */ 
+0x1E90, 0x1E90, 0x1E92, 0x1E92, 0x1E94, 0x1E94, 0x1E96, 0x1E97,   /* 0x1E90-0x1E97 */ 
+0x1E98, 0x1E99, 0x1E9A, 0x1E9B, 0x1E9C, 0x1E9D, 0x1E9E, 0x1E9F,   /* 0x1E98-0x1E9F */ 
+0x1EA0, 0x1EA0, 0x1EA2, 0x1EA2, 0x1EA4, 0x1EA4, 0x1EA6, 0x1EA6,   /* 0x1EA0-0x1EA7 */ 
+0x1EA8, 0x1EA8, 0x1EAA, 0x1EAA, 0x1EAC, 0x1EAC, 0x1EAE, 0x1EAE,   /* 0x1EA8-0x1EAF */ 
+0x1EB0, 0x1EB0, 0x1EB2, 0x1EB2, 0x1EB4, 0x1EB4, 0x1EB6, 0x1EB6,   /* 0x1EB0-0x1EB7 */ 
+0x1EB8, 0x1EB8, 0x1EBA, 0x1EBA, 0x1EBC, 0x1EBC, 0x1EBE, 0x1EBE,   /* 0x1EB8-0x1EBF */ 
+0x1EC0, 0x1EC0, 0x1EC2, 0x1EC2, 0x1EC4, 0x1EC4, 0x1EC6, 0x1EC6,   /* 0x1EC0-0x1EC7 */ 
+0x1EC8, 0x1EC8, 0x1ECA, 0x1ECA, 0x1ECC, 0x1ECC, 0x1ECE, 0x1ECE,   /* 0x1EC8-0x1ECF */ 
+0x1ED0, 0x1ED0, 0x1ED2, 0x1ED2, 0x1ED4, 0x1ED4, 0x1ED6, 0x1ED6,   /* 0x1ED0-0x1ED7 */ 
+0x1ED8, 0x1ED8, 0x1EDA, 0x1EDA, 0x1EDC, 0x1EDC, 0x1EDE, 0x1EDE,   /* 0x1ED8-0x1EDF */ 
+0x1EE0, 0x1EE0, 0x1EE2, 0x1EE2, 0x1EE4, 0x1EE4, 0x1EE6, 0x1EE6,   /* 0x1EE0-0x1EE7 */ 
+0x1EE8, 0x1EE8, 0x1EEA, 0x1EEA, 0x1EEC, 0x1EEC, 0x1EEE, 0x1EEE,   /* 0x1EE8-0x1EEF */ 
+0x1EF0, 0x1EF0, 0x1EF2, 0x1EF2, 0x1EF4, 0x1EF4, 0x1EF6, 0x1EF6,   /* 0x1EF0-0x1EF7 */ 
+0x1EF8, 0x1EF8, 0x1EFA, 0x1EFB, 0x1EFC, 0x1EFD, 0x1EFE, 0x1EFF,   /* 0x1EF8-0x1EFF */ 
+0x1F08, 0x1F09, 0x1F0A, 0x1F0B, 0x1F0C, 0x1F0D, 0x1F0E, 0x1F0F,   /* 0x1F00-0x1F07 */ 
+0x1F08, 0x1F09, 0x1F0A, 0x1F0B, 0x1F0C, 0x1F0D, 0x1F0E, 0x1F0F,   /* 0x1F08-0x1F0F */ 
+0x1F18, 0x1F19, 0x1F1A, 0x1F1B, 0x1F1C, 0x1F1D, 0x1F16, 0x1F17,   /* 0x1F10-0x1F17 */ 
+0x1F18, 0x1F19, 0x1F1A, 0x1F1B, 0x1F1C, 0x1F1D, 0x1F1E, 0x1F1F,   /* 0x1F18-0x1F1F */ 
+0x1F28, 0x1F29, 0x1F2A, 0x1F2B, 0x1F2C, 0x1F2D, 0x1F2E, 0x1F2F,   /* 0x1F20-0x1F27 */ 
+0x1F28, 0x1F29, 0x1F2A, 0x1F2B, 0x1F2C, 0x1F2D, 0x1F2E, 0x1F2F,   /* 0x1F28-0x1F2F */ 
+0x1F38, 0x1F39, 0x1F3A, 0x1F3B, 0x1F3C, 0x1F3D, 0x1F3E, 0x1F3F,   /* 0x1F30-0x1F37 */ 
+0x1F38, 0x1F39, 0x1F3A, 0x1F3B, 0x1F3C, 0x1F3D, 0x1F3E, 0x1F3F,   /* 0x1F38-0x1F3F */ 
+0x1F48, 0x1F49, 0x1F4A, 0x1F4B, 0x1F4C, 0x1F4D, 0x1F46, 0x1F47,   /* 0x1F40-0x1F47 */ 
+0x1F48, 0x1F49, 0x1F4A, 0x1F4B, 0x1F4C, 0x1F4D, 0x1F4E, 0x1F4F,   /* 0x1F48-0x1F4F */ 
+0x1F50, 0x1F59, 0x1F52, 0x1F5B, 0x1F54, 0x1F5D, 0x1F56, 0x1F5F,   /* 0x1F50-0x1F57 */ 
+0x1F58, 0x1F59, 0x1F5A, 0x1F5B, 0x1F5C, 0x1F5D, 0x1F5E, 0x1F5F,   /* 0x1F58-0x1F5F */ 
+0x1F68, 0x1F69, 0x1F6A, 0x1F6B, 0x1F6C, 0x1F6D, 0x1F6E, 0x1F6F,   /* 0x1F60-0x1F67 */ 
+0x1F68, 0x1F69, 0x1F6A, 0x1F6B, 0x1F6C, 0x1F6D, 0x1F6E, 0x1F6F,   /* 0x1F68-0x1F6F */ 
+0x1FBA, 0x1FBB, 0x1FC8, 0x1FC9, 0x1FCA, 0x1FCB, 0x1FDA, 0x1FDB,   /* 0x1F70-0x1F77 */ 
+0x1FF8, 0x1FF9, 0x1FEA, 0x1FEB, 0x1FFA, 0x1FFB, 0x1F7E, 0x1F7F,   /* 0x1F78-0x1F7F */ 
+0x1F80, 0x1F81, 0x1F82, 0x1F83, 0x1F84, 0x1F85, 0x1F86, 0x1F87,   /* 0x1F80-0x1F87 */ 
+0x1F88, 0x1F89, 0x1F8A, 0x1F8B, 0x1F8C, 0x1F8D, 0x1F8E, 0x1F8F,   /* 0x1F88-0x1F8F */ 
+0x1F90, 0x1F91, 0x1F92, 0x1F93, 0x1F94, 0x1F95, 0x1F96, 0x1F97,   /* 0x1F90-0x1F97 */ 
+0x1F98, 0x1F99, 0x1F9A, 0x1F9B, 0x1F9C, 0x1F9D, 0x1F9E, 0x1F9F,   /* 0x1F98-0x1F9F */ 
+0x1FA0, 0x1FA1, 0x1FA2, 0x1FA3, 0x1FA4, 0x1FA5, 0x1FA6, 0x1FA7,   /* 0x1FA0-0x1FA7 */ 
+0x1FA8, 0x1FA9, 0x1FAA, 0x1FAB, 0x1FAC, 0x1FAD, 0x1FAE, 0x1FAF,   /* 0x1FA8-0x1FAF */ 
+0x1FB8, 0x1FB9, 0x1FB2, 0x1FB3, 0x1FB4, 0x1FB5, 0x1FB6, 0x1FB7,   /* 0x1FB0-0x1FB7 */ 
+0x1FB8, 0x1FB9, 0x1FBA, 0x1FBB, 0x1FBC, 0x1FBD, 0x1FBE, 0x1FBF,   /* 0x1FB8-0x1FBF */ 
+0x1FC0, 0x1FC1, 0x1FC2, 0x1FC3, 0x1FC4, 0x1FC5, 0x1FC6, 0x1FC7,   /* 0x1FC0-0x1FC7 */ 
+0x1FC8, 0x1FC9, 0x1FCA, 0x1FCB, 0x1FCC, 0x1FCD, 0x1FCE, 0x1FCF,   /* 0x1FC8-0x1FCF */ 
+0x1FD8, 0x1FD9, 0x1FD2, 0x1FD3, 0x1FD4, 0x1FD5, 0x1FD6, 0x1FD7,   /* 0x1FD0-0x1FD7 */ 
+0x1FD8, 0x1FD9, 0x1FDA, 0x1FDB, 0x1FDC, 0x1FDD, 0x1FDE, 0x1FDF,   /* 0x1FD8-0x1FDF */ 
+0x1FE8, 0x1FE9, 0x1FE2, 0x1FE3, 0x1FE4, 0x1FEC, 0x1FE6, 0x1FE7,   /* 0x1FE0-0x1FE7 */ 
+0x1FE8, 0x1FE9, 0x1FEA, 0x1FEB, 0x1FEC, 0x1FED, 0x1FEE, 0x1FEF,   /* 0x1FE8-0x1FEF */ 
+0x1FF0, 0x1FF1, 0x1FF2, 0x1FF3, 0x1FF4, 0x1FF5, 0x1FF6, 0x1FF7,   /* 0x1FF0-0x1FF7 */ 
+0x1FF8, 0x1FF9, 0x1FFA, 0x1FFB, 0x1FFC, 0x1FFD, 0x1FFE, 0x1FFF }; /* 0x1FF8-0x1FFF */
+
+static const u_int16_t upcase_table_6[64] = {
+0x2140, 0x2141, 0x2142, 0x2143, 0x2144, 0x2145, 0x2146, 0x2147,   /* 0x2140-0x2147 */ 
+0x2148, 0x2149, 0x214A, 0x214B, 0x214C, 0x214D, 0x214E, 0x214F,   /* 0x2148-0x214F */ 
+0x2150, 0x2151, 0x2152, 0x2153, 0x2154, 0x2155, 0x2156, 0x2157,   /* 0x2150-0x2157 */ 
+0x2158, 0x2159, 0x215A, 0x215B, 0x215C, 0x215D, 0x215E, 0x215F,   /* 0x2158-0x215F */ 
+0x2160, 0x2161, 0x2162, 0x2163, 0x2164, 0x2165, 0x2166, 0x2167,   /* 0x2160-0x2167 */ 
+0x2168, 0x2169, 0x216A, 0x216B, 0x216C, 0x216D, 0x216E, 0x216F,   /* 0x2168-0x216F */ 
+0x2160, 0x2161, 0x2162, 0x2163, 0x2164, 0x2165, 0x2166, 0x2167,   /* 0x2170-0x2177 */ 
+0x2168, 0x2169, 0x216A, 0x216B, 0x216C, 0x216D, 0x216E, 0x216F }; /* 0x2178-0x217F */
+
+static const u_int16_t upcase_table_7[64] = {
+0x24C0, 0x24C1, 0x24C2, 0x24C3, 0x24C4, 0x24C5, 0x24C6, 0x24C7,   /* 0x24C0-0x24C7 */ 
+0x24C8, 0x24C9, 0x24CA, 0x24CB, 0x24CC, 0x24CD, 0x24CE, 0x24CF,   /* 0x24C8-0x24CF */ 
+0x24B6, 0x24B7, 0x24B8, 0x24B9, 0x24BA, 0x24BB, 0x24BC, 0x24BD,   /* 0x24D0-0x24D7 */ 
+0x24BE, 0x24BF, 0x24C0, 0x24C1, 0x24C2, 0x24C3, 0x24C4, 0x24C5,   /* 0x24D8-0x24DF */ 
+0x24C6, 0x24C7, 0x24C8, 0x24C9, 0x24CA, 0x24CB, 0x24CC, 0x24CD,   /* 0x24E0-0x24E7 */ 
+0x24CE, 0x24CF, 0x24EA, 0x24EB, 0x24EC, 0x24ED, 0x24EE, 0x24EF,   /* 0x24E8-0x24EF */ 
+0x24F0, 0x24F1, 0x24F2, 0x24F3, 0x24F4, 0x24F5, 0x24F6, 0x24F7,   /* 0x24F0-0x24F7 */ 
+0x24F8, 0x24F9, 0x24FA, 0x24FB, 0x24FC, 0x24FD, 0x24FE, 0x24FF }; /* 0x24F8-0x24FF */
+
+static const u_int16_t upcase_table_8[64] = {
+0xFF40, 0xFF21, 0xFF22, 0xFF23, 0xFF24, 0xFF25, 0xFF26, 0xFF27,   /* 0xFF40-0xFF47 */ 
+0xFF28, 0xFF29, 0xFF2A, 0xFF2B, 0xFF2C, 0xFF2D, 0xFF2E, 0xFF2F,   /* 0xFF48-0xFF4F */ 
+0xFF30, 0xFF31, 0xFF32, 0xFF33, 0xFF34, 0xFF35, 0xFF36, 0xFF37,   /* 0xFF50-0xFF57 */ 
+0xFF38, 0xFF39, 0xFF3A, 0xFF5B, 0xFF5C, 0xFF5D, 0xFF5E, 0xFF5F,   /* 0xFF58-0xFF5F */ 
+0xFF60, 0xFF61, 0xFF62, 0xFF63, 0xFF64, 0xFF65, 0xFF66, 0xFF67,   /* 0xFF60-0xFF67 */ 
+0xFF68, 0xFF69, 0xFF6A, 0xFF6B, 0xFF6C, 0xFF6D, 0xFF6E, 0xFF6F,   /* 0xFF68-0xFF6F */ 
+0xFF70, 0xFF71, 0xFF72, 0xFF73, 0xFF74, 0xFF75, 0xFF76, 0xFF77,   /* 0xFF70-0xFF77 */ 
+0xFF78, 0xFF79, 0xFF7A, 0xFF7B, 0xFF7C, 0xFF7D, 0xFF7E, 0xFF7F }; /* 0xFF78-0xFF7F */
+
+
+
+static const u_int16_t lowcase_table_1[64] = {
+0x0040, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,   /* 0x0040-0x0047 */ 
+0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,   /* 0x0048-0x004F */ 
+0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,   /* 0x0050-0x0057 */ 
+0x0078, 0x0079, 0x007A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,   /* 0x0058-0x005F */ 
+0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,   /* 0x0060-0x0067 */ 
+0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,   /* 0x0068-0x006F */ 
+0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,   /* 0x0070-0x0077 */ 
+0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F }; /* 0x0078-0x007F */
+
+static const u_int16_t lowcase_table_2[384] = {
+0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7,   /* 0x00C0-0x00C7 */ 
+0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF,   /* 0x00C8-0x00CF */ 
+0x00F0, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00D7,   /* 0x00D0-0x00D7 */ 
+0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x00DF,   /* 0x00D8-0x00DF */ 
+0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7,   /* 0x00E0-0x00E7 */ 
+0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF,   /* 0x00E8-0x00EF */ 
+0x00F0, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7,   /* 0x00F0-0x00F7 */ 
+0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x00FF,   /* 0x00F8-0x00FF */ 
+0x0101, 0x0101, 0x0103, 0x0103, 0x0105, 0x0105, 0x0107, 0x0107,   /* 0x0100-0x0107 */ 
+0x0109, 0x0109, 0x010B, 0x010B, 0x010D, 0x010D, 0x010F, 0x010F,   /* 0x0108-0x010F */ 
+0x0111, 0x0111, 0x0113, 0x0113, 0x0115, 0x0115, 0x0117, 0x0117,   /* 0x0110-0x0117 */ 
+0x0119, 0x0119, 0x011B, 0x011B, 0x011D, 0x011D, 0x011F, 0x011F,   /* 0x0118-0x011F */ 
+0x0121, 0x0121, 0x0123, 0x0123, 0x0125, 0x0125, 0x0127, 0x0127,   /* 0x0120-0x0127 */ 
+0x0129, 0x0129, 0x012B, 0x012B, 0x012D, 0x012D, 0x012F, 0x012F,   /* 0x0128-0x012F */ 
+0x0130, 0x0131, 0x0133, 0x0133, 0x0135, 0x0135, 0x0137, 0x0137,   /* 0x0130-0x0137 */ 
+0x0138, 0x013A, 0x013A, 0x013C, 0x013C, 0x013E, 0x013E, 0x0140,   /* 0x0138-0x013F */ 
+0x0140, 0x0142, 0x0142, 0x0144, 0x0144, 0x0146, 0x0146, 0x0148,   /* 0x0140-0x0147 */ 
+0x0148, 0x0149, 0x014B, 0x014B, 0x014D, 0x014D, 0x014F, 0x014F,   /* 0x0148-0x014F */ 
+0x0151, 0x0151, 0x0153, 0x0153, 0x0155, 0x0155, 0x0157, 0x0157,   /* 0x0150-0x0157 */ 
+0x0159, 0x0159, 0x015B, 0x015B, 0x015D, 0x015D, 0x015F, 0x015F,   /* 0x0158-0x015F */ 
+0x0161, 0x0161, 0x0163, 0x0163, 0x0165, 0x0165, 0x0167, 0x0167,   /* 0x0160-0x0167 */ 
+0x0169, 0x0169, 0x016B, 0x016B, 0x016D, 0x016D, 0x016F, 0x016F,   /* 0x0168-0x016F */ 
+0x0171, 0x0171, 0x0173, 0x0173, 0x0175, 0x0175, 0x0177, 0x0177,   /* 0x0170-0x0177 */ 
+0x00FF, 0x017A, 0x017A, 0x017C, 0x017C, 0x017E, 0x017E, 0x017F,   /* 0x0178-0x017F */ 
+0x0180, 0x0253, 0x0183, 0x0183, 0x0185, 0x0185, 0x0254, 0x0188,   /* 0x0180-0x0187 */ 
+0x0188, 0x0256, 0x0257, 0x018C, 0x018C, 0x018D, 0x01DD, 0x0259,   /* 0x0188-0x018F */ 
+0x025B, 0x0192, 0x0192, 0x0260, 0x0263, 0x0195, 0x0269, 0x0268,   /* 0x0190-0x0197 */ 
+0x0199, 0x0199, 0x019A, 0x019B, 0x026F, 0x0272, 0x019E, 0x0275,   /* 0x0198-0x019F */ 
+0x01A1, 0x01A1, 0x01A3, 0x01A3, 0x01A5, 0x01A5, 0x01A6, 0x01A8,   /* 0x01A0-0x01A7 */ 
+0x01A8, 0x0283, 0x01AA, 0x01AB, 0x01AD, 0x01AD, 0x0288, 0x01B0,   /* 0x01A8-0x01AF */ 
+0x01B0, 0x028A, 0x028B, 0x01B4, 0x01B4, 0x01B6, 0x01B6, 0x0292,   /* 0x01B0-0x01B7 */ 
+0x01B9, 0x01B9, 0x01BA, 0x01BB, 0x01BD, 0x01BD, 0x01BE, 0x01BF,   /* 0x01B8-0x01BF */ 
+0x01C0, 0x01C1, 0x01C2, 0x01C3, 0x01C6, 0x01C5, 0x01C6, 0x01C9,   /* 0x01C0-0x01C7 */ 
+0x01C8, 0x01C9, 0x01CC, 0x01CB, 0x01CC, 0x01CE, 0x01CE, 0x01D0,   /* 0x01C8-0x01CF */ 
+0x01D0, 0x01D2, 0x01D2, 0x01D4, 0x01D4, 0x01D6, 0x01D6, 0x01D8,   /* 0x01D0-0x01D7 */ 
+0x01D8, 0x01DA, 0x01DA, 0x01DC, 0x01DC, 0x01DD, 0x01DF, 0x01DF,   /* 0x01D8-0x01DF */ 
+0x01E1, 0x01E1, 0x01E3, 0x01E3, 0x01E5, 0x01E5, 0x01E7, 0x01E7,   /* 0x01E0-0x01E7 */ 
+0x01E9, 0x01E9, 0x01EB, 0x01EB, 0x01ED, 0x01ED, 0x01EF, 0x01EF,   /* 0x01E8-0x01EF */ 
+0x01F0, 0x01F3, 0x01F2, 0x01F3, 0x01F5, 0x01F5, 0x01F6, 0x01F7,   /* 0x01F0-0x01F7 */ 
+0x01F8, 0x01F9, 0x01FB, 0x01FB, 0x01FD, 0x01FD, 0x01FF, 0x01FF,   /* 0x01F8-0x01FF */ 
+0x0201, 0x0201, 0x0203, 0x0203, 0x0205, 0x0205, 0x0207, 0x0207,   /* 0x0200-0x0207 */ 
+0x0209, 0x0209, 0x020B, 0x020B, 0x020D, 0x020D, 0x020F, 0x020F,   /* 0x0208-0x020F */ 
+0x0211, 0x0211, 0x0213, 0x0213, 0x0215, 0x0215, 0x0217, 0x0217,   /* 0x0210-0x0217 */ 
+0x0218, 0x0219, 0x021A, 0x021B, 0x021C, 0x021D, 0x021E, 0x021F,   /* 0x0218-0x021F */ 
+0x0220, 0x0221, 0x0222, 0x0223, 0x0224, 0x0225, 0x0226, 0x0227,   /* 0x0220-0x0227 */ 
+0x0228, 0x0229, 0x022A, 0x022B, 0x022C, 0x022D, 0x022E, 0x022F,   /* 0x0228-0x022F */ 
+0x0230, 0x0231, 0x0232, 0x0233, 0x0234, 0x0235, 0x0236, 0x0237,   /* 0x0230-0x0237 */ 
+0x0238, 0x0239, 0x023A, 0x023B, 0x023C, 0x023D, 0x023E, 0x023F }; /* 0x0238-0x023F */
+
+static const u_int16_t lowcase_table_3[512] = {
+0x0380, 0x0381, 0x0382, 0x0383, 0x0384, 0x0385, 0x03AC, 0x0387,   /* 0x0380-0x0387 */ 
+0x03AD, 0x03AE, 0x03AF, 0x038B, 0x03CC, 0x038D, 0x03CD, 0x03CE,   /* 0x0388-0x038F */ 
+0x0390, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7,   /* 0x0390-0x0397 */ 
+0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF,   /* 0x0398-0x039F */ 
+0x03C0, 0x03C1, 0x03A2, 0x03C3, 0x03C4, 0x03C5, 0x03C6, 0x03C7,   /* 0x03A0-0x03A7 */ 
+0x03C8, 0x03C9, 0x03CA, 0x03CB, 0x03AC, 0x03AD, 0x03AE, 0x03AF,   /* 0x03A8-0x03AF */ 
+0x03B0, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7,   /* 0x03B0-0x03B7 */ 
+0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF,   /* 0x03B8-0x03BF */ 
+0x03C0, 0x03C1, 0x03C2, 0x03C3, 0x03C4, 0x03C5, 0x03C6, 0x03C7,   /* 0x03C0-0x03C7 */ 
+0x03C8, 0x03C9, 0x03CA, 0x03CB, 0x03CC, 0x03CD, 0x03CE, 0x03CF,   /* 0x03C8-0x03CF */ 
+0x03D0, 0x03D1, 0x03D2, 0x03D3, 0x03D4, 0x03D5, 0x03D6, 0x03D7,   /* 0x03D0-0x03D7 */ 
+0x03D8, 0x03D9, 0x03DA, 0x03DB, 0x03DC, 0x03DD, 0x03DE, 0x03DF,   /* 0x03D8-0x03DF */ 
+0x03E0, 0x03E1, 0x03E3, 0x03E3, 0x03E5, 0x03E5, 0x03E7, 0x03E7,   /* 0x03E0-0x03E7 */ 
+0x03E9, 0x03E9, 0x03EB, 0x03EB, 0x03ED, 0x03ED, 0x03EF, 0x03EF,   /* 0x03E8-0x03EF */ 
+0x03F0, 0x03F1, 0x03F2, 0x03F3, 0x03F4, 0x03F5, 0x03F6, 0x03F7,   /* 0x03F0-0x03F7 */ 
+0x03F8, 0x03F9, 0x03FA, 0x03FB, 0x03FC, 0x03FD, 0x03FE, 0x03FF,   /* 0x03F8-0x03FF */ 
+0x0400, 0x0451, 0x0452, 0x0453, 0x0454, 0x0455, 0x0456, 0x0457,   /* 0x0400-0x0407 */ 
+0x0458, 0x0459, 0x045A, 0x045B, 0x045C, 0x040D, 0x045E, 0x045F,   /* 0x0408-0x040F */ 
+0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437,   /* 0x0410-0x0417 */ 
+0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F,   /* 0x0418-0x041F */ 
+0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447,   /* 0x0420-0x0427 */ 
+0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F,   /* 0x0428-0x042F */ 
+0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437,   /* 0x0430-0x0437 */ 
+0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F,   /* 0x0438-0x043F */ 
+0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447,   /* 0x0440-0x0447 */ 
+0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F,   /* 0x0448-0x044F */ 
+0x0450, 0x0451, 0x0452, 0x0453, 0x0454, 0x0455, 0x0456, 0x0457,   /* 0x0450-0x0457 */ 
+0x0458, 0x0459, 0x045A, 0x045B, 0x045C, 0x045D, 0x045E, 0x045F,   /* 0x0458-0x045F */ 
+0x0461, 0x0461, 0x0463, 0x0463, 0x0465, 0x0465, 0x0467, 0x0467,   /* 0x0460-0x0467 */ 
+0x0469, 0x0469, 0x046B, 0x046B, 0x046D, 0x046D, 0x046F, 0x046F,   /* 0x0468-0x046F */ 
+0x0471, 0x0471, 0x0473, 0x0473, 0x0475, 0x0475, 0x0477, 0x0477,   /* 0x0470-0x0477 */ 
+0x0479, 0x0479, 0x047B, 0x047B, 0x047D, 0x047D, 0x047F, 0x047F,   /* 0x0478-0x047F */ 
+0x0481, 0x0481, 0x0482, 0x0483, 0x0484, 0x0485, 0x0486, 0x0487,   /* 0x0480-0x0487 */ 
+0x0488, 0x0489, 0x048A, 0x048B, 0x048C, 0x048D, 0x048E, 0x048F,   /* 0x0488-0x048F */ 
+0x0491, 0x0491, 0x0493, 0x0493, 0x0495, 0x0495, 0x0497, 0x0497,   /* 0x0490-0x0497 */ 
+0x0499, 0x0499, 0x049B, 0x049B, 0x049D, 0x049D, 0x049F, 0x049F,   /* 0x0498-0x049F */ 
+0x04A1, 0x04A1, 0x04A3, 0x04A3, 0x04A5, 0x04A5, 0x04A7, 0x04A7,   /* 0x04A0-0x04A7 */ 
+0x04A9, 0x04A9, 0x04AB, 0x04AB, 0x04AD, 0x04AD, 0x04AF, 0x04AF,   /* 0x04A8-0x04AF */ 
+0x04B1, 0x04B1, 0x04B3, 0x04B3, 0x04B5, 0x04B5, 0x04B7, 0x04B7,   /* 0x04B0-0x04B7 */ 
+0x04B9, 0x04B9, 0x04BB, 0x04BB, 0x04BD, 0x04BD, 0x04BF, 0x04BF,   /* 0x04B8-0x04BF */ 
+0x04C0, 0x04C2, 0x04C2, 0x04C4, 0x04C4, 0x04C5, 0x04C6, 0x04C8,   /* 0x04C0-0x04C7 */ 
+0x04C8, 0x04C9, 0x04CA, 0x04CC, 0x04CC, 0x04CD, 0x04CE, 0x04CF,   /* 0x04C8-0x04CF */ 
+0x04D1, 0x04D1, 0x04D3, 0x04D3, 0x04D5, 0x04D5, 0x04D7, 0x04D7,   /* 0x04D0-0x04D7 */ 
+0x04D9, 0x04D9, 0x04DB, 0x04DB, 0x04DD, 0x04DD, 0x04DF, 0x04DF,   /* 0x04D8-0x04DF */ 
+0x04E1, 0x04E1, 0x04E3, 0x04E3, 0x04E5, 0x04E5, 0x04E7, 0x04E7,   /* 0x04E0-0x04E7 */ 
+0x04E9, 0x04E9, 0x04EB, 0x04EB, 0x04EC, 0x04ED, 0x04EF, 0x04EF,   /* 0x04E8-0x04EF */ 
+0x04F1, 0x04F1, 0x04F3, 0x04F3, 0x04F5, 0x04F5, 0x04F6, 0x04F7,   /* 0x04F0-0x04F7 */ 
+0x04F9, 0x04F9, 0x04FA, 0x04FB, 0x04FC, 0x04FD, 0x04FE, 0x04FF,   /* 0x04F8-0x04FF */ 
+0x0500, 0x0501, 0x0502, 0x0503, 0x0504, 0x0505, 0x0506, 0x0507,   /* 0x0500-0x0507 */ 
+0x0508, 0x0509, 0x050A, 0x050B, 0x050C, 0x050D, 0x050E, 0x050F,   /* 0x0508-0x050F */ 
+0x0510, 0x0511, 0x0512, 0x0513, 0x0514, 0x0515, 0x0516, 0x0517,   /* 0x0510-0x0517 */ 
+0x0518, 0x0519, 0x051A, 0x051B, 0x051C, 0x051D, 0x051E, 0x051F,   /* 0x0518-0x051F */ 
+0x0520, 0x0521, 0x0522, 0x0523, 0x0524, 0x0525, 0x0526, 0x0527,   /* 0x0520-0x0527 */ 
+0x0528, 0x0529, 0x052A, 0x052B, 0x052C, 0x052D, 0x052E, 0x052F,   /* 0x0528-0x052F */ 
+0x0530, 0x0561, 0x0562, 0x0563, 0x0564, 0x0565, 0x0566, 0x0567,   /* 0x0530-0x0537 */ 
+0x0568, 0x0569, 0x056A, 0x056B, 0x056C, 0x056D, 0x056E, 0x056F,   /* 0x0538-0x053F */ 
+0x0570, 0x0571, 0x0572, 0x0573, 0x0574, 0x0575, 0x0576, 0x0577,   /* 0x0540-0x0547 */ 
+0x0578, 0x0579, 0x057A, 0x057B, 0x057C, 0x057D, 0x057E, 0x057F,   /* 0x0548-0x054F */ 
+0x0580, 0x0581, 0x0582, 0x0583, 0x0584, 0x0585, 0x0586, 0x0557,   /* 0x0550-0x0557 */ 
+0x0558, 0x0559, 0x055A, 0x055B, 0x055C, 0x055D, 0x055E, 0x055F,   /* 0x0558-0x055F */ 
+0x0560, 0x0561, 0x0562, 0x0563, 0x0564, 0x0565, 0x0566, 0x0567,   /* 0x0560-0x0567 */ 
+0x0568, 0x0569, 0x056A, 0x056B, 0x056C, 0x056D, 0x056E, 0x056F,   /* 0x0568-0x056F */ 
+0x0570, 0x0571, 0x0572, 0x0573, 0x0574, 0x0575, 0x0576, 0x0577,   /* 0x0570-0x0577 */ 
+0x0578, 0x0579, 0x057A, 0x057B, 0x057C, 0x057D, 0x057E, 0x057F }; /* 0x0578-0x057F */
+
+static const u_int16_t lowcase_table_4[512] = {
+0x1E01, 0x1E01, 0x1E03, 0x1E03, 0x1E05, 0x1E05, 0x1E07, 0x1E07,   /* 0x1E00-0x1E07 */ 
+0x1E09, 0x1E09, 0x1E0B, 0x1E0B, 0x1E0D, 0x1E0D, 0x1E0F, 0x1E0F,   /* 0x1E08-0x1E0F */ 
+0x1E11, 0x1E11, 0x1E13, 0x1E13, 0x1E15, 0x1E15, 0x1E17, 0x1E17,   /* 0x1E10-0x1E17 */ 
+0x1E19, 0x1E19, 0x1E1B, 0x1E1B, 0x1E1D, 0x1E1D, 0x1E1F, 0x1E1F,   /* 0x1E18-0x1E1F */ 
+0x1E21, 0x1E21, 0x1E23, 0x1E23, 0x1E25, 0x1E25, 0x1E27, 0x1E27,   /* 0x1E20-0x1E27 */ 
+0x1E29, 0x1E29, 0x1E2B, 0x1E2B, 0x1E2D, 0x1E2D, 0x1E2F, 0x1E2F,   /* 0x1E28-0x1E2F */ 
+0x1E31, 0x1E31, 0x1E33, 0x1E33, 0x1E35, 0x1E35, 0x1E37, 0x1E37,   /* 0x1E30-0x1E37 */ 
+0x1E39, 0x1E39, 0x1E3B, 0x1E3B, 0x1E3D, 0x1E3D, 0x1E3F, 0x1E3F,   /* 0x1E38-0x1E3F */ 
+0x1E41, 0x1E41, 0x1E43, 0x1E43, 0x1E45, 0x1E45, 0x1E47, 0x1E47,   /* 0x1E40-0x1E47 */ 
+0x1E49, 0x1E49, 0x1E4B, 0x1E4B, 0x1E4D, 0x1E4D, 0x1E4F, 0x1E4F,   /* 0x1E48-0x1E4F */ 
+0x1E51, 0x1E51, 0x1E53, 0x1E53, 0x1E55, 0x1E55, 0x1E57, 0x1E57,   /* 0x1E50-0x1E57 */ 
+0x1E59, 0x1E59, 0x1E5B, 0x1E5B, 0x1E5D, 0x1E5D, 0x1E5F, 0x1E5F,   /* 0x1E58-0x1E5F */ 
+0x1E61, 0x1E61, 0x1E63, 0x1E63, 0x1E65, 0x1E65, 0x1E67, 0x1E67,   /* 0x1E60-0x1E67 */ 
+0x1E69, 0x1E69, 0x1E6B, 0x1E6B, 0x1E6D, 0x1E6D, 0x1E6F, 0x1E6F,   /* 0x1E68-0x1E6F */ 
+0x1E71, 0x1E71, 0x1E73, 0x1E73, 0x1E75, 0x1E75, 0x1E77, 0x1E77,   /* 0x1E70-0x1E77 */ 
+0x1E79, 0x1E79, 0x1E7B, 0x1E7B, 0x1E7D, 0x1E7D, 0x1E7F, 0x1E7F,   /* 0x1E78-0x1E7F */ 
+0x1E81, 0x1E81, 0x1E83, 0x1E83, 0x1E85, 0x1E85, 0x1E87, 0x1E87,   /* 0x1E80-0x1E87 */ 
+0x1E89, 0x1E89, 0x1E8B, 0x1E8B, 0x1E8D, 0x1E8D, 0x1E8F, 0x1E8F,   /* 0x1E88-0x1E8F */ 
+0x1E91, 0x1E91, 0x1E93, 0x1E93, 0x1E95, 0x1E95, 0x1E96, 0x1E97,   /* 0x1E90-0x1E97 */ 
+0x1E98, 0x1E99, 0x1E9A, 0x1E9B, 0x1E9C, 0x1E9D, 0x1E9E, 0x1E9F,   /* 0x1E98-0x1E9F */ 
+0x1EA1, 0x1EA1, 0x1EA3, 0x1EA3, 0x1EA5, 0x1EA5, 0x1EA7, 0x1EA7,   /* 0x1EA0-0x1EA7 */ 
+0x1EA9, 0x1EA9, 0x1EAB, 0x1EAB, 0x1EAD, 0x1EAD, 0x1EAF, 0x1EAF,   /* 0x1EA8-0x1EAF */ 
+0x1EB1, 0x1EB1, 0x1EB3, 0x1EB3, 0x1EB5, 0x1EB5, 0x1EB7, 0x1EB7,   /* 0x1EB0-0x1EB7 */ 
+0x1EB9, 0x1EB9, 0x1EBB, 0x1EBB, 0x1EBD, 0x1EBD, 0x1EBF, 0x1EBF,   /* 0x1EB8-0x1EBF */ 
+0x1EC1, 0x1EC1, 0x1EC3, 0x1EC3, 0x1EC5, 0x1EC5, 0x1EC7, 0x1EC7,   /* 0x1EC0-0x1EC7 */ 
+0x1EC9, 0x1EC9, 0x1ECB, 0x1ECB, 0x1ECD, 0x1ECD, 0x1ECF, 0x1ECF,   /* 0x1EC8-0x1ECF */ 
+0x1ED1, 0x1ED1, 0x1ED3, 0x1ED3, 0x1ED5, 0x1ED5, 0x1ED7, 0x1ED7,   /* 0x1ED0-0x1ED7 */ 
+0x1ED9, 0x1ED9, 0x1EDB, 0x1EDB, 0x1EDD, 0x1EDD, 0x1EDF, 0x1EDF,   /* 0x1ED8-0x1EDF */ 
+0x1EE1, 0x1EE1, 0x1EE3, 0x1EE3, 0x1EE5, 0x1EE5, 0x1EE7, 0x1EE7,   /* 0x1EE0-0x1EE7 */ 
+0x1EE9, 0x1EE9, 0x1EEB, 0x1EEB, 0x1EED, 0x1EED, 0x1EEF, 0x1EEF,   /* 0x1EE8-0x1EEF */ 
+0x1EF1, 0x1EF1, 0x1EF3, 0x1EF3, 0x1EF5, 0x1EF5, 0x1EF7, 0x1EF7,   /* 0x1EF0-0x1EF7 */ 
+0x1EF9, 0x1EF9, 0x1EFA, 0x1EFB, 0x1EFC, 0x1EFD, 0x1EFE, 0x1EFF,   /* 0x1EF8-0x1EFF */ 
+0x1F00, 0x1F01, 0x1F02, 0x1F03, 0x1F04, 0x1F05, 0x1F06, 0x1F07,   /* 0x1F00-0x1F07 */ 
+0x1F00, 0x1F01, 0x1F02, 0x1F03, 0x1F04, 0x1F05, 0x1F06, 0x1F07,   /* 0x1F08-0x1F0F */ 
+0x1F10, 0x1F11, 0x1F12, 0x1F13, 0x1F14, 0x1F15, 0x1F16, 0x1F17,   /* 0x1F10-0x1F17 */ 
+0x1F10, 0x1F11, 0x1F12, 0x1F13, 0x1F14, 0x1F15, 0x1F1E, 0x1F1F,   /* 0x1F18-0x1F1F */ 
+0x1F20, 0x1F21, 0x1F22, 0x1F23, 0x1F24, 0x1F25, 0x1F26, 0x1F27,   /* 0x1F20-0x1F27 */ 
+0x1F20, 0x1F21, 0x1F22, 0x1F23, 0x1F24, 0x1F25, 0x1F26, 0x1F27,   /* 0x1F28-0x1F2F */ 
+0x1F30, 0x1F31, 0x1F32, 0x1F33, 0x1F34, 0x1F35, 0x1F36, 0x1F37,   /* 0x1F30-0x1F37 */ 
+0x1F30, 0x1F31, 0x1F32, 0x1F33, 0x1F34, 0x1F35, 0x1F36, 0x1F37,   /* 0x1F38-0x1F3F */ 
+0x1F40, 0x1F41, 0x1F42, 0x1F43, 0x1F44, 0x1F45, 0x1F46, 0x1F47,   /* 0x1F40-0x1F47 */ 
+0x1F40, 0x1F41, 0x1F42, 0x1F43, 0x1F44, 0x1F45, 0x1F4E, 0x1F4F,   /* 0x1F48-0x1F4F */ 
+0x1F50, 0x1F51, 0x1F52, 0x1F53, 0x1F54, 0x1F55, 0x1F56, 0x1F57,   /* 0x1F50-0x1F57 */ 
+0x1F58, 0x1F51, 0x1F5A, 0x1F53, 0x1F5C, 0x1F55, 0x1F5E, 0x1F57,   /* 0x1F58-0x1F5F */ 
+0x1F60, 0x1F61, 0x1F62, 0x1F63, 0x1F64, 0x1F65, 0x1F66, 0x1F67,   /* 0x1F60-0x1F67 */ 
+0x1F60, 0x1F61, 0x1F62, 0x1F63, 0x1F64, 0x1F65, 0x1F66, 0x1F67,   /* 0x1F68-0x1F6F */ 
+0x1F70, 0x1F71, 0x1F72, 0x1F73, 0x1F74, 0x1F75, 0x1F76, 0x1F77,   /* 0x1F70-0x1F77 */ 
+0x1F78, 0x1F79, 0x1F7A, 0x1F7B, 0x1F7C, 0x1F7D, 0x1F7E, 0x1F7F,   /* 0x1F78-0x1F7F */ 
+0x1F80, 0x1F81, 0x1F82, 0x1F83, 0x1F84, 0x1F85, 0x1F86, 0x1F87,   /* 0x1F80-0x1F87 */ 
+0x1F88, 0x1F89, 0x1F8A, 0x1F8B, 0x1F8C, 0x1F8D, 0x1F8E, 0x1F8F,   /* 0x1F88-0x1F8F */ 
+0x1F90, 0x1F91, 0x1F92, 0x1F93, 0x1F94, 0x1F95, 0x1F96, 0x1F97,   /* 0x1F90-0x1F97 */ 
+0x1F98, 0x1F99, 0x1F9A, 0x1F9B, 0x1F9C, 0x1F9D, 0x1F9E, 0x1F9F,   /* 0x1F98-0x1F9F */ 
+0x1FA0, 0x1FA1, 0x1FA2, 0x1FA3, 0x1FA4, 0x1FA5, 0x1FA6, 0x1FA7,   /* 0x1FA0-0x1FA7 */ 
+0x1FA8, 0x1FA9, 0x1FAA, 0x1FAB, 0x1FAC, 0x1FAD, 0x1FAE, 0x1FAF,   /* 0x1FA8-0x1FAF */ 
+0x1FB0, 0x1FB1, 0x1FB2, 0x1FB3, 0x1FB4, 0x1FB5, 0x1FB6, 0x1FB7,   /* 0x1FB0-0x1FB7 */ 
+0x1FB0, 0x1FB1, 0x1F70, 0x1F71, 0x1FBC, 0x1FBD, 0x1FBE, 0x1FBF,   /* 0x1FB8-0x1FBF */ 
+0x1FC0, 0x1FC1, 0x1FC2, 0x1FC3, 0x1FC4, 0x1FC5, 0x1FC6, 0x1FC7,   /* 0x1FC0-0x1FC7 */ 
+0x1F72, 0x1F73, 0x1F74, 0x1F75, 0x1FCC, 0x1FCD, 0x1FCE, 0x1FCF,   /* 0x1FC8-0x1FCF */ 
+0x1FD0, 0x1FD1, 0x1FD2, 0x1FD3, 0x1FD4, 0x1FD5, 0x1FD6, 0x1FD7,   /* 0x1FD0-0x1FD7 */ 
+0x1FD0, 0x1FD1, 0x1F76, 0x1F77, 0x1FDC, 0x1FDD, 0x1FDE, 0x1FDF,   /* 0x1FD8-0x1FDF */ 
+0x1FE0, 0x1FE1, 0x1FE2, 0x1FE3, 0x1FE4, 0x1FE5, 0x1FE6, 0x1FE7,   /* 0x1FE0-0x1FE7 */ 
+0x1FE0, 0x1FE1, 0x1F7A, 0x1F7B, 0x1FE5, 0x1FED, 0x1FEE, 0x1FEF,   /* 0x1FE8-0x1FEF */ 
+0x1FF0, 0x1FF1, 0x1FF2, 0x1FF3, 0x1FF4, 0x1FF5, 0x1FF6, 0x1FF7,   /* 0x1FF0-0x1FF7 */ 
+0x1F78, 0x1F79, 0x1F7C, 0x1F7D, 0x1FFC, 0x1FFD, 0x1FFE, 0x1FFF }; /* 0x1FF8-0x1FFF */
+
+static const u_int16_t lowcase_table_5[64] = {
+0x2140, 0x2141, 0x2142, 0x2143, 0x2144, 0x2145, 0x2146, 0x2147,   /* 0x2140-0x2147 */ 
+0x2148, 0x2149, 0x214A, 0x214B, 0x214C, 0x214D, 0x214E, 0x214F,   /* 0x2148-0x214F */ 
+0x2150, 0x2151, 0x2152, 0x2153, 0x2154, 0x2155, 0x2156, 0x2157,   /* 0x2150-0x2157 */ 
+0x2158, 0x2159, 0x215A, 0x215B, 0x215C, 0x215D, 0x215E, 0x215F,   /* 0x2158-0x215F */ 
+0x2170, 0x2171, 0x2172, 0x2173, 0x2174, 0x2175, 0x2176, 0x2177,   /* 0x2160-0x2167 */ 
+0x2178, 0x2179, 0x217A, 0x217B, 0x217C, 0x217D, 0x217E, 0x217F,   /* 0x2168-0x216F */ 
+0x2170, 0x2171, 0x2172, 0x2173, 0x2174, 0x2175, 0x2176, 0x2177,   /* 0x2170-0x2177 */ 
+0x2178, 0x2179, 0x217A, 0x217B, 0x217C, 0x217D, 0x217E, 0x217F }; /* 0x2178-0x217F */
+
+static const u_int16_t lowcase_table_6[128] = {
+0x2480, 0x2481, 0x2482, 0x2483, 0x2484, 0x2485, 0x2486, 0x2487,   /* 0x2480-0x2487 */ 
+0x2488, 0x2489, 0x248A, 0x248B, 0x248C, 0x248D, 0x248E, 0x248F,   /* 0x2488-0x248F */ 
+0x2490, 0x2491, 0x2492, 0x2493, 0x2494, 0x2495, 0x2496, 0x2497,   /* 0x2490-0x2497 */ 
+0x2498, 0x2499, 0x249A, 0x249B, 0x249C, 0x249D, 0x249E, 0x249F,   /* 0x2498-0x249F */ 
+0x24A0, 0x24A1, 0x24A2, 0x24A3, 0x24A4, 0x24A5, 0x24A6, 0x24A7,   /* 0x24A0-0x24A7 */ 
+0x24A8, 0x24A9, 0x24AA, 0x24AB, 0x24AC, 0x24AD, 0x24AE, 0x24AF,   /* 0x24A8-0x24AF */ 
+0x24B0, 0x24B1, 0x24B2, 0x24B3, 0x24B4, 0x24B5, 0x24D0, 0x24D1,   /* 0x24B0-0x24B7 */ 
+0x24D2, 0x24D3, 0x24D4, 0x24D5, 0x24D6, 0x24D7, 0x24D8, 0x24D9,   /* 0x24B8-0x24BF */ 
+0x24DA, 0x24DB, 0x24DC, 0x24DD, 0x24DE, 0x24DF, 0x24E0, 0x24E1,   /* 0x24C0-0x24C7 */ 
+0x24E2, 0x24E3, 0x24E4, 0x24E5, 0x24E6, 0x24E7, 0x24E8, 0x24E9,   /* 0x24C8-0x24CF */ 
+0x24D0, 0x24D1, 0x24D2, 0x24D3, 0x24D4, 0x24D5, 0x24D6, 0x24D7,   /* 0x24D0-0x24D7 */ 
+0x24D8, 0x24D9, 0x24DA, 0x24DB, 0x24DC, 0x24DD, 0x24DE, 0x24DF,   /* 0x24D8-0x24DF */ 
+0x24E0, 0x24E1, 0x24E2, 0x24E3, 0x24E4, 0x24E5, 0x24E6, 0x24E7,   /* 0x24E0-0x24E7 */ 
+0x24E8, 0x24E9, 0x24EA, 0x24EB, 0x24EC, 0x24ED, 0x24EE, 0x24EF,   /* 0x24E8-0x24EF */ 
+0x24F0, 0x24F1, 0x24F2, 0x24F3, 0x24F4, 0x24F5, 0x24F6, 0x24F7,   /* 0x24F0-0x24F7 */ 
+0x24F8, 0x24F9, 0x24FA, 0x24FB, 0x24FC, 0x24FD, 0x24FE, 0x24FF }; /* 0x24F8-0x24FF */
+
+static const u_int16_t lowcase_table_7[64] = {
+0xFF00, 0xFF01, 0xFF02, 0xFF03, 0xFF04, 0xFF05, 0xFF06, 0xFF07,   /* 0xFF00-0xFF07 */ 
+0xFF08, 0xFF09, 0xFF0A, 0xFF0B, 0xFF0C, 0xFF0D, 0xFF0E, 0xFF0F,   /* 0xFF08-0xFF0F */ 
+0xFF10, 0xFF11, 0xFF12, 0xFF13, 0xFF14, 0xFF15, 0xFF16, 0xFF17,   /* 0xFF10-0xFF17 */ 
+0xFF18, 0xFF19, 0xFF1A, 0xFF1B, 0xFF1C, 0xFF1D, 0xFF1E, 0xFF1F,   /* 0xFF18-0xFF1F */ 
+0xFF20, 0xFF41, 0xFF42, 0xFF43, 0xFF44, 0xFF45, 0xFF46, 0xFF47,   /* 0xFF20-0xFF27 */ 
+0xFF48, 0xFF49, 0xFF4A, 0xFF4B, 0xFF4C, 0xFF4D, 0xFF4E, 0xFF4F,   /* 0xFF28-0xFF2F */ 
+0xFF50, 0xFF51, 0xFF52, 0xFF53, 0xFF54, 0xFF55, 0xFF56, 0xFF57,   /* 0xFF30-0xFF37 */ 
+0xFF58, 0xFF59, 0xFF5A, 0xFF3B, 0xFF3C, 0xFF3D, 0xFF3E, 0xFF3F }; /* 0xFF38-0xFF3F */
+
diff --git a/libatalk/unicode/utf8.c b/libatalk/unicode/utf8.c
new file mode 100644 (file)
index 0000000..26342cb
--- /dev/null
@@ -0,0 +1,254 @@
+/* 
+   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 <errno.h>
+
+#include <netatalk/endian.h>
+#include <atalk/unicode.h>
+#include <atalk/logger.h>
+#include <atalk/unicode.h>
+#include "byteorder.h"
+
+/* Given a trailing UTF-8 byte, get the contribution from it to
+ * the Unicode scalar value for a particular bit shift amount
+ */
+#define GETUCVAL(utf8_trailbyte,shift)  ((unsigned int) (( utf8_trailbyte & 0x3F) << shift))
+
+/* Given a unicode scalar, get a trail UTF-8 byte for a particular bit shift amount */
+#define GETUTF8TRAILBYTE(uc,shift)      ((char)( 0x80 | ((uc >> shift) & 0x3F) ) )
+
+
+
+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,
+       NULL,
+       NULL, NULL
+};
+
+struct charset_functions charset_utf8_mac =
+{
+       "UTF8-MAC",
+       0x08000103,
+       utf8_pull,
+       utf8_push,
+       CHARSET_VOLUME | CHARSET_CLIENT | CHARSET_MULTIBYTE | CHARSET_DECOMPOSED,
+       NULL,
+       NULL, NULL
+};
+
+/* ------------------- Convert from UTF-8 to UCS-2 -------------------*/
+static size_t utf8_pull(void *cd _U_, char **inbuf, size_t *inbytesleft,
+                        char **outbuf, size_t *outbytesleft)
+{
+       ucs2_t uc = 0;
+       ucs2_t hi, low;     /* surrogate pair */
+       unsigned int codepoint, surrogate;
+       int len;
+
+       while (*inbytesleft >= 1 && *outbytesleft >= 2) {
+               unsigned char *c = (unsigned char *)*inbuf;
+               len = 1;
+
+               /* Arrange conditionals in the order of most frequent occurrence 
+                * for users of Latin-based chars */
+               if ((c[0] & 0x80) == 0) {
+                       uc = c[0];
+               } else if ((c[0] & 0xe0) == 0xc0) {
+                       if (*inbytesleft < 2) {
+                               LOG(log_debug, logtype_default, "short utf8 char");
+                               goto badseq;
+                       }
+                       uc = (ucs2_t) (((c[0] & 0x1f) << 6) | GETUCVAL(c[1],0)) ;
+                       len = 2;
+               } else if ((c[0] & 0xf0) == 0xe0) {
+                       if (*inbytesleft < 3) {
+                               LOG(log_debug, logtype_default, "short utf8 char");
+                               goto badseq;
+                       }
+                       uc = (ucs2_t) (((c[0] & 0x0f) << 12) | GETUCVAL(c[1],6) | GETUCVAL(c[2],0)) ;
+                       len = 3;
+               } else if ((c[0] & 0xf8) == 0xf0) {
+                       /* 4 bytes, which happens for surrogate pairs only */
+                       if (*inbytesleft < 4) {
+                               LOG(log_debug, logtype_default, "short utf8 char");
+                               goto badseq;
+                       }
+                       if (*outbytesleft < 4) {
+                               LOG(log_debug, logtype_default, "short ucs-2 write");
+                               errno = E2BIG;
+                               return -1;
+                       }
+                       codepoint = ((c[0] & 0x07) << 18) | GETUCVAL(c[1],12) |
+                               GETUCVAL(c[2],6) |  GETUCVAL(c[3],0);
+                       hi = (ucs2_t)( ((codepoint - 0x10000) >> 10) + 0xD800);
+                       low = (ucs2_t)(0xDC00 + (codepoint & 0x03FF));
+                       surrogate = (hi << 16) | low;
+                       SIVAL(*outbuf,0,surrogate);
+                       len = 4;
+                       (*inbuf)  += 4;
+                       (*inbytesleft)  -= 4;
+                       (*outbytesleft) -= 4;
+                       (*outbuf) += 4;
+                       continue;
+               }
+               else {
+                       errno = EINVAL;
+                       return -1;
+               }
+
+               SSVAL(*outbuf,0,uc);
+               (*inbuf)  += len;
+               (*inbytesleft)  -= len;
+               (*outbytesleft) -= 2;
+               (*outbuf) += 2;
+       }
+
+       if (*inbytesleft > 0) {
+               errno = E2BIG;
+               return -1;
+       }
+       
+       return 0;
+
+badseq:
+       errno = EINVAL;
+       return -1;
+}
+
+/* --------------------- Convert from UCS-2 to UTF-8 -----------*/
+static size_t utf8_push(void *cd _U_, char **inbuf, size_t *inbytesleft,
+                        char **outbuf, size_t *outbytesleft)
+{
+       ucs2_t uc=0;
+       ucs2_t hi, low;
+       unsigned int surrogatepair, codepoint;
+       int olen, ilen;
+
+       while (*inbytesleft >= 2 && *outbytesleft >= 1) {
+               unsigned char *c = (unsigned char *)*outbuf;
+               uc = SVAL((*inbuf),0);
+               olen=1;
+               ilen=2;
+
+               /* Arrange conditionals in the order of most frequent occurrence for
+                  users of Latin-based chars */
+               if (uc < 0x80) {
+                       c[0] = uc;
+               } else if (uc < 0x800) {
+                       if (*outbytesleft < 2) {
+                               LOG(log_debug, logtype_default, "short utf8 write");
+                               goto toobig;
+                       }
+                       c[1] = GETUTF8TRAILBYTE(uc, 0);
+                       c[0] = (char)(0xc0 | ((uc >> 6) & 0x1f));
+                       olen = 2;
+               }
+               else if ( uc >= 0x202a && uc <= 0x202e ) {
+                       /* ignore bidi hint characters */
+                       olen = 0;
+               }
+               /*
+                * A 2-byte uc value represents a stand-alone Unicode character if
+                *     0 <= uc < 0xd800 or 0xdfff < uc <= 0xffff.
+                * If  0xd800 <= uc <= 0xdfff, uc itself does not represent a Unicode character.
+                * Rather, it is just part of a surrogate pair.  A surrogate pair consists of 
+                * a high surrogate in the range [0xd800 ... 0xdbff] and a low surrogate in the
+                * range [0xdc00 ... 0xdfff].  Together the pair maps to a single Unicode character
+                * whose scalar value is 64K or larger.  It is this scalar value that is transformed
+                * to UTF-8, not the individual surrogates.
+                *
+                * See www.unicode.org/faq/utf_bom.html for more info.
+                */
+
+               else if ( 0xd800 <= uc && uc <= 0xdfff) {
+                       /* surrogate - needs 4 bytes from input and 4 bytes for output to UTF-8 */
+                       if (*outbytesleft < 4) {
+                               LOG(log_debug, logtype_default, "short utf8 write");
+                               goto toobig;
+                       }
+                       if (*inbytesleft < 4) {
+                               errno = EINVAL;
+                               return -1;
+                       }
+                       surrogatepair = IVAL((*inbuf),0);
+                       low = (ucs2_t)surrogatepair;
+                       hi = (ucs2_t)(surrogatepair >> 16);
+                       if ( 0xd800 <= hi && hi <= 0xdbff && 0xdc00 <= low && low <= 0xdfff) {
+                               codepoint = ((hi - 0xd800) << 10) + (low - 0xdc00) + 0x10000;
+                               c[3] = GETUTF8TRAILBYTE(codepoint, 0);
+                               c[2] = GETUTF8TRAILBYTE(codepoint, 6);
+                               c[1] = GETUTF8TRAILBYTE(codepoint, 12);
+                               c[0] = (char)(0xf0 | ((codepoint >> 18) & 0x07));
+                               ilen = olen = 4;
+                       } else { /* invalid values for surrogate */
+                               errno = EINVAL;
+                               return -1;
+                       }
+               } else {
+                       if (*outbytesleft < 3) {
+                               LOG(log_debug, logtype_default, "short utf8 write");
+                               goto toobig;
+                       }
+                       c[2] = GETUTF8TRAILBYTE(uc, 0);
+                       c[1] = GETUTF8TRAILBYTE(uc, 6);
+                       c[0] = (char)(0xe0 | ((uc >> 12) & 0x0f));
+                       olen = 3;
+               }
+
+               (*inbytesleft)  -= ilen;
+               (*outbytesleft) -= olen;
+               (*inbuf)  += ilen;
+               (*outbuf) += olen;
+       }
+
+       if (*inbytesleft == 1) {
+               errno = EINVAL;
+               return -1;
+       }
+
+       if (*inbytesleft > 1) {
+               errno = E2BIG;
+               return -1;
+       }
+       
+       return 0;
+
+toobig:
+       errno = E2BIG;
+       return -1;
+}
diff --git a/libatalk/unicode/util_unistr.c b/libatalk/unicode/util_unistr.c
new file mode 100644 (file)
index 0000000..4f4921b
--- /dev/null
@@ -0,0 +1,548 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <atalk/logger.h>
+#include <errno.h>
+
+#include <netatalk/endian.h>
+
+#include <atalk/unicode.h>
+#include "ucs2_casetable.h"
+#include "precompose.h"
+#include "byteorder.h"
+
+
+ucs2_t toupper_w(ucs2_t val)
+{
+       if ( val >= 0x0040 && val <= 0x007F)
+               return upcase_table_1[val-0x0040];
+       if ( val >= 0x00C0 && val <= 0x02BF)
+               return upcase_table_2[val-0x00C0];
+       if ( val >= 0x0380 && val <= 0x04FF)
+               return upcase_table_3[val-0x0380];
+       if ( val >= 0x0540 && val <= 0x05BF)
+               return upcase_table_4[val-0x0540];
+       if ( val >= 0x1E00 && val <= 0x1FFF)
+               return upcase_table_5[val-0x1E00];
+       if ( val >= 0x2140 && val <= 0x217F)
+               return upcase_table_6[val-0x2140];
+       if ( val >= 0x24C0 && val <= 0x24FF)
+               return upcase_table_7[val-0x24C0];
+       if ( val >= 0xFF40 && val <= 0xFF7F)
+               return upcase_table_8[val-0xFF40];
+
+       return (val);
+}
+
+
+ucs2_t tolower_w(ucs2_t val)
+{
+       if ( val >= 0x0040 && val <= 0x007F)
+               return lowcase_table_1[val-0x0040];
+       if ( val >= 0x00C0 && val <= 0x023F)
+               return lowcase_table_2[val-0x00C0];
+       if ( val >= 0x0380 && val <= 0x057F)
+               return lowcase_table_3[val-0x0380];
+       if ( val >= 0x1E00 && val <= 0x1FFF)
+               return lowcase_table_4[val-0x1E00];
+       if ( val >= 0x2140 && val <= 0x217F)
+               return lowcase_table_5[val-0x2140];
+       if ( val >= 0x2480 && val <= 0x24FF)
+               return lowcase_table_6[val-0x2480];
+       if ( val >= 0xFF00 && val <= 0xFF3F)
+               return lowcase_table_7[val-0xFF00];
+
+       return (val);
+}
+
+/*******************************************************************
+ Convert a string to lower case.
+ return True if any char is converted
+********************************************************************/
+int strlower_w(ucs2_t *s)
+{
+        int ret = 0;
+        while (*s) {
+                ucs2_t v = tolower_w(*s);
+                if (v != *s) {
+                        *s = v;
+                        ret = 1;
+                }
+                s++;
+        }
+        return ret;
+}
+
+/*******************************************************************
+ Convert a string to upper case.
+ return True if any char is converted
+********************************************************************/
+int strupper_w(ucs2_t *s)
+{
+        int ret = 0;
+        while (*s) {
+                ucs2_t v = toupper_w(*s);
+                if (v != *s) {
+                        *s = v;
+                        ret = 1;
+                }
+                s++;
+        }
+        return ret;
+}
+
+
+/*******************************************************************
+determine if a character is lowercase
+********************************************************************/
+int islower_w(ucs2_t c)
+{
+       return ( c == tolower_w(c));
+}
+
+/*******************************************************************
+determine if a character is uppercase
+********************************************************************/
+int isupper_w(ucs2_t c)
+{
+       return ( c == toupper_w(c));
+}
+
+
+/*******************************************************************
+ Count the number of characters in a ucs2_t string.
+********************************************************************/
+size_t strlen_w(const ucs2_t *src)
+{
+       size_t len;
+
+       for(len = 0; *src++; len++) ;
+
+       return len;
+}
+
+/*******************************************************************
+ Count up to max number of characters in a ucs2_t string.
+********************************************************************/
+size_t strnlen_w(const ucs2_t *src, size_t max)
+{
+       size_t len;
+
+       for(len = 0; *src++ && (len < max); len++) ;
+
+       return len;
+}
+
+/*******************************************************************
+wide strchr()
+********************************************************************/
+ucs2_t *strchr_w(const ucs2_t *s, ucs2_t c)
+{
+       while (*s != 0) {
+               if (c == *s) return (ucs2_t *)s;
+               s++;
+       }
+       if (c == *s) return (ucs2_t *)s;
+
+       return NULL;
+}
+
+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++;
+       }
+       if (c == *s) return (ucs2_t *)s;
+
+       return NULL;
+}
+
+
+int strcmp_w(const ucs2_t *a, const ucs2_t *b)
+{
+        while (*b && *a == *b) { a++; b++; }
+        return (*a - *b);
+        /* warning: if *a != *b and both are not 0 we retrun a random
+                greater or lesser than 0 number not realted to which
+                string is longer */
+}
+
+int strncmp_w(const ucs2_t *a, const ucs2_t *b, size_t len)
+{
+        size_t n = 0;
+        while ((n < len) && *b && *a == *b) { a++; b++; n++;}
+        return (len - n)?(*a - *b):0;
+}
+
+/*******************************************************************
+wide strstr()
+********************************************************************/
+ucs2_t *strstr_w(const ucs2_t *s, const ucs2_t *ins)
+{
+       ucs2_t *r;
+       size_t slen, inslen;
+
+       if (!s || !*s || !ins || !*ins) return NULL;
+       slen = strlen_w(s);
+       inslen = strlen_w(ins);
+       r = (ucs2_t *)s;
+       while ((r = strchr_w(r, *ins))) {
+               if (strncmp_w(r, ins, inslen) == 0) return r;
+               r++;
+       }
+       return NULL;
+}
+
+ucs2_t *strcasestr_w(const ucs2_t *s, const ucs2_t *ins)
+{
+       ucs2_t *r;
+       size_t slen, inslen;
+
+       if (!s || !*s || !ins || !*ins) return NULL;
+       slen = strlen_w(s);
+       inslen = strlen_w(ins);
+       r = (ucs2_t *)s;
+       while ((r = strcasechr_w(r, *ins))) {
+               if (strncasecmp_w(r, ins, inslen) == 0) return r;
+               r++;
+       }
+       return NULL;
+}
+
+
+
+
+/*******************************************************************
+case insensitive string comparison
+********************************************************************/
+int strcasecmp_w(const ucs2_t *a, const ucs2_t *b)
+{
+        while (*b && toupper_w(*a) == toupper_w(*b)) { a++; b++; }
+        return (tolower_w(*a) - tolower_w(*b));
+}
+
+/*******************************************************************
+case insensitive string comparison, lenght limited
+********************************************************************/
+int strncasecmp_w(const ucs2_t *a, const ucs2_t *b, size_t len)
+{
+        size_t n = 0;
+        while ((n < len) && *b && (toupper_w(*a) == toupper_w(*b))) { a++; b++; n++; }
+        return (len - n)?(tolower_w(*a) - tolower_w(*b)):0;
+}
+
+/*******************************************************************
+duplicate string
+********************************************************************/
+/* if len == 0 then duplicate the whole string */
+ucs2_t *strndup_w(const ucs2_t *src, size_t len)
+{
+        ucs2_t *dest;
+
+        if (!len) len = strlen_w(src);
+        dest = (ucs2_t *)malloc((len + 1) * sizeof(ucs2_t));
+        if (!dest) {
+                LOG (log_error, logtype_default, "strdup_w: out of memory!");
+                return NULL;
+        }
+
+        memcpy(dest, src, len * sizeof(ucs2_t));
+        dest[len] = 0;
+
+        return dest;
+}
+
+ucs2_t *strdup_w(const ucs2_t *src)
+{
+        return strndup_w(src, 0);
+}
+
+/*******************************************************************
+copy a string with max len
+********************************************************************/
+
+ucs2_t *strncpy_w(ucs2_t *dest, const ucs2_t *src, const size_t max)
+{
+        size_t len;
+
+        if (!dest || !src) return NULL;
+
+        for (len = 0; (src[len] != 0) && (len < max); len++)
+                dest[len] = src[len];
+        while (len < max)
+                dest[len++] = 0;
+
+        return dest;
+}
+
+
+/*******************************************************************
+append a string of len bytes and add a terminator
+********************************************************************/
+
+ucs2_t *strncat_w(ucs2_t *dest, const ucs2_t *src, const size_t max)
+{
+        size_t start;
+        size_t len;
+
+        if (!dest || !src) return NULL;
+
+        start = strlen_w(dest);
+        len = strnlen_w(src, max);
+
+        memcpy(&dest[start], src, len*sizeof(ucs2_t));
+        dest[start+len] = 0;
+
+        return dest;
+}
+
+
+ucs2_t *strcat_w(ucs2_t *dest, const ucs2_t *src)
+{
+        size_t start;
+        size_t len;
+
+        if (!dest || !src) return NULL;
+
+        start = strlen_w(dest);
+        len = strlen_w(src);
+
+        memcpy(&dest[start], src, len*sizeof(ucs2_t));
+        dest[start+len] = 0;
+
+        return dest;
+}
+
+
+/* ------------------------ */
+ucs2_t do_precomposition(unsigned int base, unsigned int comb) 
+{
+       int min = 0;
+       int max = sizeof(precompositions) / sizeof(precompositions[0]) - 1;
+       int mid;
+       u_int32_t sought = (base << 16) | comb, that;
+
+       /* binary search */
+       while (max >= min) {
+               mid = (min + max) / 2;
+               that = (precompositions[mid].base << 16) | (precompositions[mid].comb);
+               if (that < sought) {
+                       min = mid + 1;
+               } else if (that > sought) {
+                       max = mid - 1;
+               } else {
+                       return precompositions[mid].replacement;
+               }
+       }
+       /* no match */
+       return 0;
+}
+
+/* -------------------------- */
+u_int32_t do_decomposition(ucs2_t base) 
+{
+       int min = 0;
+       int max = sizeof(decompositions) / sizeof(decompositions[0]) - 1;
+       int mid;
+       u_int32_t sought = base;
+       u_int32_t result, that;
+
+       /* binary search */
+       while (max >= min) {
+               mid = (min + max) / 2;
+               that = decompositions[mid].replacement;
+               if (that < sought) {
+                       min = mid + 1;
+               } else if (that > sought) {
+                       max = mid - 1;
+               } else {
+                       result = (decompositions[mid].base << 16) | (decompositions[mid].comb);
+                       return result;
+               }
+       }
+       /* no match */
+       return 0;
+}
+
+/* we can't use static, this stuff needs to be reentrant */
+/* static char comp[MAXPATHLEN +1]; */
+
+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 > o_len)
+               return (size_t)-1;
+       i = 0;
+       in  = name;
+       out = (ucs2_t *)comp;
+    
+       base = *in;
+       while (*outlen > 2) {
+               i += 2;
+               in++;
+               if (i == inplen) {
+                       *out = base;
+                       out++;
+                       *out = 0;
+                       *outlen -= 2;
+                       return o_len - *outlen;
+               }
+               comb = *in;
+               if (comb >= 0x300 && (result = do_precomposition(base, comb))) {
+                       *out = result;
+                       out++;
+                       *outlen -= 2;
+                       i += 2;
+                       in++;
+                       if (i == inplen) {
+                               *out = 0;
+                               return o_len - *outlen;
+                       }
+                       base = *in;
+               }
+               else {
+                       *out = base;
+                       out++;
+                       *outlen -= 2;
+                       base = comb;
+               }
+       }
+       
+       errno = E2BIG;
+       return (size_t)-1;
+}
+
+/* --------------- */
+
+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 (size_t)-1;
+       i = 0;
+       in  = name;
+       out = (ucs2_t *)comp;
+    
+       while (i < inplen) {
+               if (*outlen < 2) {
+                       errno = E2BIG;
+                       return (size_t)-1;
+               }
+               base = *in;
+               if ( (base > 0x1fff && base < 0x3000) || (base > 0xfe2f && base < 0xfe50)) {
+                       /* exclude these ranges from decomposition according to AFP 3.1 spec */
+                       /* page 97 */
+                       *out = base;
+                       out++;
+                       *outlen -= 2;
+               }
+               else if ((result = do_decomposition(base))) {
+                       if ( *outlen < 4 ) {
+                               errno = E2BIG;
+                               return (size_t)-1;
+                       }
+                       *out = result  >> 16;
+                       out++;
+                       *outlen -= 2;
+                       *out = result & 0xffff;
+                       out++;
+                       *outlen -= 2;
+               }
+               else {
+                       *out = base;
+                       out++;
+                       *outlen -= 2;
+               }
+               i += 2;
+               in++;
+       }
+
+       *out = 0;
+       return o_len-*outlen;
+}
+
+size_t utf8_charlen ( char* utf8 )
+{
+        unsigned char *p;
+
+        p = (unsigned char*) utf8;
+       
+       if ( *p < 0x80 )
+               return (1);
+       else if ( *p > 0xC1 && *p < 0xe0 && *(p+1) > 0x7f && *(p+1) < 0xC0)
+               return (2);
+       else if ( *p == 0xe0 && *(p+1) > 0x9f && *(p+1) < 0xc0 && *(p+2) > 0x7f && *(p+2) < 0xc0)
+               return (3);
+       else if ( *p > 0xe0  && *p < 0xf0 && *(p+1) > 0x7f && *(p+1) < 0xc0 && *(p+2) > 0x7f && *(p+2) < 0xc0)
+               return (3);
+       else if ( *p == 0xf0 && *(p+1) > 0x8f && *(p+1) < 0xc0 && *(p+2) > 0x7f && *(p+2) < 0xc0 && *(p+3) > 0x7f && *(p+3) < 0xc0 )
+               return (4);
+       else if ( *p > 0xf0 && *p < 0xf4 && *(p+1) > 0x7f && *(p+1) < 0xc0 && *(p+2) > 0x7f && *(p+2) < 0xc0 && *(p+3) > 0x7f && *(p+3) < 0xc0 )
+               return (4);
+       else if ( *p == 0xf4 && *(p+1) > 0x7f && *(p+1) < 0x90 && *(p+2) > 0x7f && *(p+2) < 0xc0 && *(p+3) > 0x7f && *(p+3) < 0xc0 )
+               return (4);
+       else
+               return ((size_t) -1);
+}
+
+
+size_t utf8_strlen_validate ( char * utf8 )
+{
+        size_t len;
+        unsigned char *p;
+
+        p = (unsigned char*) utf8;
+        len = 0;
+
+        /* see http://www.unicode.org/unicode/reports/tr27/ for an explanation */
+
+        while ( *p != '\0')
+        {
+                if ( *p < 0x80 )
+                        p++;
+
+                else if ( *p > 0xC1 && *p < 0xe0 && *(p+1) > 0x7f && *(p+1) < 0xC0)
+                        p += 2;
+
+                else if ( *p == 0xe0 && *(p+1) > 0x9f && *(p+1) < 0xc0 && *(p+2) > 0x7f && *(p+2) < 0xc0)
+                        p += 3;
+
+                else if ( *p > 0xe0  && *p < 0xf0 && *(p+1) > 0x7f && *(p+1) < 0xc0 && *(p+2) > 0x7f && *(p+2) < 0xc0)
+                        p += 3;
+
+                else if ( *p == 0xf0 && *(p+1) > 0x8f && *(p+1) < 0xc0 && *(p+2) > 0x7f && *(p+2) < 0xc0 && *(p+3) > 0x7f && *(p+3) < 0xc0 )
+                        p += 4;
+
+                else if ( *p > 0xf0 && *p < 0xf4 && *(p+1) > 0x7f && *(p+1) < 0xc0 && *(p+2) > 0x7f && *(p+2) < 0xc0 && *(p+3) > 0x7f && *(p+3) < 0xc0 )
+                        p += 4;
+
+                else if ( *p == 0xf4 && *(p+1) > 0x7f && *(p+1) < 0x90 && *(p+2) > 0x7f && *(p+2) < 0xc0 && *(p+3) > 0x7f && *(p+3) < 0xc0 )
+                        p += 4;
+
+                else
+                        return ((size_t) -1);
+
+                len++;
+        }
+
+        return (len);
+}
+
index db6b3f7e85c2e0c2203bc65388bfb267fde8e8d3..3a83debc1fdc7b5b7e1c67159e367c462039500b 100644 (file)
@@ -1,9 +1,9 @@
 # Makefile.am for libatalk/util/
 
-INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/sys
-
 noinst_LTLIBRARIES = libutil.la
 
+CFLAGS = -I$(top_srcdir)/sys @CFLAGS@
+
 libutil_la_SOURCES = \
        atalk_addr.c    \
        bprint.c        \
@@ -11,7 +11,12 @@ libutil_la_SOURCES = \
        logger.c        \
        module.c        \
        server_child.c  \
-       server_lock.c   \
        server_ipc.c    \
+       server_lock.c   \
        strcasestr.c    \
-       strdicasecmp.c
+       strdicasecmp.c  \
+       strlcpy.c       \
+       fault.c         \
+       volinfo.c
+
+#      util_unicode.c
index cb0734fd45e82f5c4b7f464d6d1de0ee65dfdc89..7841f6a4045566442366271bdb483173eb094a7c 100644 (file)
@@ -2,6 +2,7 @@
 #include "config.h"
 #endif
 
+#ifdef DEBUG1
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -48,3 +49,4 @@ void bprint( data, len )
 
     printf("(end)\n");
 }
+#endif
diff --git a/libatalk/util/fault.c b/libatalk/util/fault.c
new file mode 100644 (file)
index 0000000..7ef4fb8
--- /dev/null
@@ -0,0 +1,202 @@
+/* 
+   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
+
+#ifdef DEBUG1
+
+#include <sys/types.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+#ifdef HAVE_BACKTRACE_SYMBOLS
+#include <execinfo.h>
+#endif
+#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)
+{
+#if 0
+       char *cmd;
+       int result;
+#endif
+#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)]",
+                                        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
+}
+
+#endif
index 52f2f7e9a45ddda324dccd508262c27f6409b83f..33947de7d8c9ced86d9e0762efedb02a8939e67d 100644 (file)
@@ -92,7 +92,7 @@ static int getifaces(const int sockfd, char ***list)
     }
 
        new = (char **) malloc((ifc.ifc_len/sizeof(struct ifreq) + 1) * sizeof(char *));
-    for ( ifr = ifc.ifc_req; ifc.ifc_len >= sizeof( struct ifreq );
+    for ( ifr = ifc.ifc_req; ifc.ifc_len >= (int) sizeof( struct ifreq );
            ifc.ifc_len -= ifrsize, ifr = nextifr ) {
 #ifdef BSD4_4
        ifrsize = sizeof(ifr->ifr_name) +
@@ -119,7 +119,7 @@ static int getifaces(const int sockfd, char ***list)
  */
 char **getifacelist()
 {
-  char **list;
+  char **list = NULL; /* FIXME */
   int  i, fd;
 
   if ((fd = socket(PF_INET, SOCK_STREAM, 0)) < 0)
index 3a7b88ab4ab9d5a3803acb0d9043223748abf4a8..8f1a764f0253fcb0f1179235ce9f516aebc43284 100644 (file)
@@ -83,6 +83,8 @@ void set_processname(char *processname);
 /* Log a Message */
 void make_log(enum loglevels loglevel, enum logtypes logtype, 
              char *message, ...);
+int get_syslog_equivalent(enum loglevels loglevel);
+
 #ifndef DISABLE_LOGGER
 make_log_func set_log_location(char *srcfilename, int srclinenumber);
 
@@ -132,7 +134,7 @@ void generate_message_details(char *message_details_buffer,
                               struct tag_log_file_data *log_struct,
                               enum loglevels loglevel, enum logtypes logtype);
 
-int get_syslog_equivalent(enum loglevels loglevel);
+static char *get_command_name(char *commandpath);
 
 /* =========================================================================
     Instanciated data
@@ -233,10 +235,18 @@ bool log_setup(char *filename, enum loglevels loglevel, enum logtypes logtype,
 {
 #ifndef DISABLE_LOGGER
 
+#ifdef CHECK_STAT_ON_NEW_FILES
+  struct stat statbuf;
+  int firstattempt;
+  int retval;
+  gid_t gid;
+  uid_t uid;
+  int access;
+#endif
   char lastchar[2];
 
   log_file_data_pair *logs;
-
+  
   log_init();
 
   logs = log_file_arr[logtype];
@@ -503,6 +513,81 @@ make_log_func set_log_location(char *srcfilename, int srclinenumber)
 }
 #endif /* DISABLE_LOGGER */
 
+/* ---------------------- 
+ * chainsawed from ethereal
+*/
+#ifdef isprint
+#undef isprint
+#endif
+#define isprint(c) ((c) >= 0x20 && (c) < 0x7f)
+
+static char *format_text(char *fmtbuf, const char *string)
+{
+  int column;
+  const char *stringend = string + strlen(string);
+  char c;
+  int i;
+
+  column = 0;
+  while (string < stringend) {
+    c = *string++;
+
+    if (isprint(c)) {
+      fmtbuf[column] = c;
+      column++;
+    } else {
+      fmtbuf[column] =  '\\';
+      column++;
+      switch (c) {
+      case '\\':
+       fmtbuf[column] = '\\';
+       column++;
+       break;
+      case '\a':
+       fmtbuf[column] = 'a';
+       column++;
+       break;
+      case '\b':
+       fmtbuf[column] = 'b';
+       column++;
+       break;
+      case '\f':
+       fmtbuf[column] = 'f';
+       column++;
+       break;
+      case '\n':
+       fmtbuf[column] = 'n';
+       column++;
+       break;
+      case '\r':
+       fmtbuf[column] = 'r';
+       column++;
+       break;
+      case '\t':
+       fmtbuf[column] = 't';
+       column++;
+       break;
+      case '\v':
+       fmtbuf[column] = 'v';
+       column++;
+       break;
+      default:
+       i = (c>>6)&03;
+       fmtbuf[column] = i + '0';
+       column++;
+       i = (c>>3)&07;
+       fmtbuf[column] = i + '0';
+       column++;
+       i = (c>>0)&07;
+       fmtbuf[column] = i + '0';
+       column++;
+       break;
+      }
+    }
+  }
+  fmtbuf[column] = '\0';
+  return fmtbuf;
+}
 /* -------------------------------------------------------------------------
     MakeLog has 1 main flaws:
       The message in its entirity, must fit into the tempbuffer.  
@@ -512,14 +597,27 @@ void make_log_entry(enum loglevels loglevel, enum logtypes logtype,
                    char *message, ...)
 {
   va_list args;
-  char log_buffer[MAXLOGSIZE];
+  char temp_buffer[MAXLOGSIZE];
+  char log_buffer[4*MAXLOGSIZE];
+  /* fn is not reentrant but is used in signal handler 
+   * with LOGGER it's a little late source name and line number
+   * are already changed.
+  */
+  static int inlog = 0;
+
 #ifndef DISABLE_LOGGER
   char log_details_buffer[MAXLOGSIZE];
 #ifdef OPEN_LOGS_AS_UID
   uid_t process_uid;
 #endif
   log_file_data_pair *logs;
+#endif
 
+  if (inlog)
+     return;
+  inlog = 1;
+  
+#ifndef DISABLE_LOGGER
   log_init();
 
   logs = log_file_arr[logtype];
@@ -537,10 +635,11 @@ void make_log_entry(enum loglevels loglevel, enum logtypes logtype,
   /* Initialise the Messages */
   va_start(args, message);
 
-  vsnprintf(log_buffer, sizeof(log_buffer), message, args);
+  vsnprintf(temp_buffer, sizeof(temp_buffer), message, args);
 
   /* Finished with args for now */
   va_end(args);
+  format_text(log_buffer, temp_buffer);
 
 #ifdef DISABLE_LOGGER
   syslog(get_syslog_equivalent(loglevel), "%s", log_buffer);
@@ -597,6 +696,7 @@ void make_log_entry(enum loglevels loglevel, enum logtypes logtype,
         LOG(log_severe, logtype_logger, "can't open Logfile %s", 
            (*logs)[1].log_filename
            );
+       inlog = 0;
         return;
       }
     }
@@ -632,6 +732,7 @@ void make_log_entry(enum loglevels loglevel, enum logtypes logtype,
   global_log_data.temp_src_filename = NULL;
   global_log_data.temp_src_linenumber = 0;
 #endif /* DISABLE_LOGGER */
+  inlog = 0;
 }
 
 #ifndef DISABLE_LOGGER
@@ -660,7 +761,6 @@ void load_proccessname_from_proc()
     Internal function definitions
    ========================================================================= */
 
-#if 0
 static char *get_command_name(char *commandpath)
 {
   char *ptr;
@@ -672,13 +772,12 @@ static char *get_command_name(char *commandpath)
     ptr = commandpath;
   else
     ptr++;
-                                                                                
+
 #ifdef DEBUG_OUTPUT_TO_SCREEN
   printf("Concluded %s\n", ptr);
 #endif
   return ptr;
 }
-#endif
 
 void  workout_what_to_print(struct what_to_print_array *what_to_print, 
                            struct tag_log_file_data *log_struct)
@@ -714,10 +813,20 @@ void generate_message_details(char *message_details_buffer,
                               struct tag_log_file_data *log_struct,
                               enum loglevels loglevel, enum logtypes logtype)
 {
+#if 0
+  char datebuffer[32];
+  char processinfo[64];
+  char log_buffer[MAXLOGSIZE];
+  const char *logtype_string;
+
+  char loglevel_string[12]; /* max int size is 2 billion, or 10 digits */
+#endif
+
   char *ptr = message_details_buffer;
   int   templen;
   int   len = message_details_buffer_length;
 
+
   struct what_to_print_array what_to_print;
 
   workout_what_to_print(&what_to_print, log_struct);
@@ -783,7 +892,7 @@ void generate_message_details(char *message_details_buffer,
   if (what_to_print.print_srcfile || what_to_print.print_srcline)
   {
     char sprintf_buffer[8];
-    char *buff_ptr;
+    char *buff_ptr=NULL;
 
     sprintf_buffer[0] = '[';
     if (what_to_print.print_srcfile)
index 4fbacfb8d5c8bef2e56d5909042a41ab1c83909f..97998261ca1e58e3cb0a5ec86ab8a61fb32c2dd2 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: server_child.c,v 1.8 2003-05-16 15:29:27 didg Exp $
+ * $Id: server_child.c,v 1.9 2005-04-28 20:50:05 bfernhomberg Exp $
  *
  * Copyright (c) 1997 Adrian Sun (asun@zoology.washington.edu)
  * All rights reserved. See COPYRIGHT.
@@ -31,6 +31,8 @@
 #ifdef HAVE_SYS_WAIT_H
 #include <sys/wait.h>
 #endif /* HAVE_SYS_WAIT_H */
+#include <sys/time.h>
+
 #ifndef WEXITSTATUS
 #define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
 #endif /* ! WEXITSTATUS */
 #define HASH(i) ((((i) >> 8) ^ (i)) & (CHILD_HASHSIZE - 1))
 
 struct server_child_data {
-  pid_t pid; 
-  u_int32_t  time;
-  u_int32_t idlen;
-  
-  char *clientid;
+  pid_t     pid;               /* afpd worker process pid (from the worker afpd process )*/
+  uid_t     uid;               /* user id of connected client (from the worker afpd process) */
+  int       valid;             /* 1 if we have a clientid */
+  u_int32_t time;              /* client boot time (from the mac client) */
+  int       killed;            /* 1 if we already tried to kill the client */
+
+  u_int32_t idlen;             /* clientid len (from the Mac client) */
+  char *clientid;              /* clientid (from the Mac client) */
   struct server_child_data **prevp, *next;
 };
 
@@ -134,18 +139,18 @@ int server_child_add(server_child *children, const int forkid,
 {
   server_child_fork *fork;
   struct server_child_data *child;
-  sigset_t sig;
+  sigset_t sig, oldsig;
 
   /* we need to prevent deletions from occuring before we get a 
    * chance to add the child in. */
   sigemptyset(&sig);
   sigaddset(&sig, SIGCHLD);
-  sigprocmask(SIG_BLOCK, &sig, NULL);
+  sigprocmask(SIG_BLOCK, &sig, &oldsig);
 
   /* it's possible that the child could have already died before the
    * sigprocmask. we need to check for this. */
   if (kill(pid, 0) < 0) {
-    sigprocmask(SIG_UNBLOCK, &sig, NULL);
+    sigprocmask(SIG_SETMASK, &oldsig, NULL);
     return 1;
   }
 
@@ -153,20 +158,22 @@ int server_child_add(server_child *children, const int forkid,
 
   /* if we already have an entry. just return. */
   if (resolve_child(fork->table, pid)) {
-    sigprocmask(SIG_UNBLOCK, &sig, NULL);
+    sigprocmask(SIG_SETMASK, &oldsig, NULL);
     return 0;
   }
 
   if ((child = (struct server_child_data *) 
        calloc(1, sizeof(struct server_child_data))) == NULL) {
-    sigprocmask(SIG_UNBLOCK, &sig, NULL);
+    sigprocmask(SIG_SETMASK, &oldsig, NULL);
     return -1;
   }
 
   child->pid = pid;
+  child->valid = 0;
+  child->killed = 0;
   hash_child(fork->table, child);
   children->count++;
-  sigprocmask(SIG_UNBLOCK, &sig, NULL);
+  sigprocmask(SIG_SETMASK, &oldsig, NULL);
 
   return 0;
 }
@@ -241,7 +248,22 @@ void server_child_kill(server_child *children, const int forkid,
  * a plain-old linked list 
  * FIXME use resolve_child ?
  */
-void server_child_kill_one(server_child *children, const int forkid, const pid_t pid)
+static int kill_child(struct server_child_data *child)
+{
+  if (!child->killed) {
+     kill(child->pid, SIGTERM);
+     /* we don't wait because there's no guarantee that we can really kill it */
+     child->killed = 1;
+     return 1;
+  }
+  else {
+     LOG(log_info, logtype_default, "Already tried to kill (%d) before! Still there?",  child->pid);
+  }
+  return 0;
+}
+
+/* -------------------- */
+void server_child_kill_one(server_child *children, const int forkid, const pid_t pid, const uid_t uid)
 {
   server_child_fork *fork;
   struct server_child_data *child, *tmp;
@@ -253,7 +275,16 @@ void server_child_kill_one(server_child *children, const int forkid, const pid_t
     while (child) {
       tmp = child->next;
       if (child->pid == pid) {
-          kill(child->pid, SIGTERM);
+          if (!child->valid) {
+             /* hmm, client 'guess' the pid, rogue? */
+             LOG(log_info, logtype_default, "Disconnecting old session (%d) no token, bailout!",  child->pid);
+          }
+          else if (child->uid != uid) {
+             LOG(log_info, logtype_default, "Disconnecting old session (%d) not the same user, bailout!",  child->pid);
+          }
+          else {
+              kill_child(child);
+          }
       }
       child = tmp;
     }
@@ -263,7 +294,8 @@ void server_child_kill_one(server_child *children, const int forkid, const pid_t
 
 /* see if there is a process for the same mac     */
 /* if the times don't match mac has been rebooted */
-void server_child_kill_one_by_id(server_child *children, const int forkid, const pid_t pid, 
+void server_child_kill_one_by_id(server_child *children, const int forkid, const pid_t pid,
+          const uid_t uid, 
           const u_int32_t idlen, char *id, u_int32_t boottime)
 {
   server_child_fork *fork;
@@ -278,11 +310,26 @@ void server_child_kill_one_by_id(server_child *children, const int forkid, const
       if ( child->pid != pid) {
           if ( child->idlen == idlen && !memcmp(child->clientid, id, idlen)) {
             if ( child->time != boottime ) {
-                 kill(child->pid, SIGTERM);
-                 LOG(log_info, logtype_default, "Disconnecting old session %d, client rebooted.",  child->pid);
+                 if (uid == child->uid) {
+                     if (kill_child(child)) {
+                         LOG(log_info, logtype_default, "Disconnecting old session %d, client rebooted.",  child->pid);
+                     }
+                 }
+                 else {
+                     LOG(log_info, logtype_default, "Disconnecting old session not the same uid, bailout!");
+                 }
+            }
+            else if (child->killed) {
+                 /* there's case where a Mac close a connection and restart a new one before
+                  * the first is 'waited' by the master afpd process
+                 */
+                 LOG(log_info, logtype_default, 
+                     "WARNING: connection (%d) killed but still there.", child->pid);
             }
             else {
-                 LOG(log_info, logtype_default, "WARNING: 2 connections (%d, %d), boottime identical, don't know if one needs to be disconnected.");
+                 LOG(log_info, logtype_default, 
+                     "WARNING: 2 connections (%d, %d), boottime identical, don't know if one needs to be disconnected.",
+                      child->pid, pid);
             } 
                
          }
@@ -294,6 +341,8 @@ void server_child_kill_one_by_id(server_child *children, const int forkid, const
          if (child->clientid) {
              free(child->clientid);
          }
+          child->uid = uid; 
+          child->valid = 1;
          child->idlen = idlen;
           child->clientid = id;
          LOG(log_info, logtype_default, "Setting clientid (len %d) for %d, boottime %X", idlen, child->pid, boottime);
@@ -317,7 +366,6 @@ void server_child_setup(server_child *children, const int forkid,
 /* keep track of children. */
 void server_child_handler(server_child *children)
 {
-  server_child_fork *fork;
   int status, i;
   pid_t pid;
   
@@ -328,13 +376,15 @@ void server_child_handler(server_child *children)
   while ((pid = waitpid(WAIT_ANY, &status, WNOHANG)) > 0) {
     for (i = 0; i < children->nforks; i++) {
       if (server_child_remove(children, i, pid)) {
+        server_child_fork *fork;
+        
        fork = (server_child_fork *) children->fork + i;
        if (fork->cleanup)
          fork->cleanup(pid);
        break;
       }
     }
-    
+
     if (WIFEXITED(status)) {
       if (WEXITSTATUS(status)) {
        LOG(log_info, logtype_default, "server_child[%d] %d exited %d", i, pid, 
@@ -355,3 +405,32 @@ void server_child_handler(server_child *children)
     }
   }
 }
+
+/* --------------------------- 
+ * reset children signals
+*/
+void server_reset_signal(void)
+{
+    struct sigaction    sv;
+    sigset_t            sigs;
+    const struct itimerval none = {{0, 0}, {0, 0}};
+
+    setitimer(ITIMER_REAL, &none, NULL);
+    memset(&sv, 0, sizeof(sv));
+    sv.sa_handler =  SIG_DFL;
+    sigemptyset( &sv.sa_mask );
+    
+    sigaction(SIGALRM, &sv, 0 );
+    sigaction(SIGHUP,  &sv, 0 );
+    sigaction(SIGTERM, &sv, 0 );
+    sigaction(SIGUSR1, &sv, 0 );
+    sigaction(SIGCHLD, &sv, 0 );
+    
+    sigemptyset(&sigs);
+    sigaddset(&sigs, SIGALRM);
+    sigaddset(&sigs, SIGHUP);
+    sigaddset(&sigs, SIGUSR1);
+    sigaddset(&sigs, SIGCHLD);
+    sigprocmask(SIG_UNBLOCK, &sigs, NULL);
+        
+}
index 6881bb8f4c2885ccaae344e2ea8c5afc5d033086..dadeda6ae4c7b803f7559a31da26eea32a97aa19 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: server_ipc.c,v 1.1 2003-05-16 15:29:28 didg Exp $
+ * $Id: server_ipc.c,v 1.2 2005-04-28 20:50:05 bfernhomberg Exp $
  *
  * All rights reserved. See COPYRIGHT.
  *
@@ -26,6 +26,7 @@
 typedef struct ipc_header {
        u_int16_t command;
         pid_t    child_pid;
+        uid_t     uid;
         u_int32_t len;
        char      *msg;
 } ipc_header;
@@ -41,7 +42,7 @@ void *server_ipc_create(void)
 }
 
 /* ----------------- */
-int server_ipc_child(void *obj)
+int server_ipc_child(void *obj _U_)
 {
     /* close input */
     close(pipe_fd[0]);
@@ -49,7 +50,7 @@ int server_ipc_child(void *obj)
 }
 
 /* ----------------- */
-int server_ipc_parent(void *obj)
+int server_ipc_parent(void *obj _U_)
 {
     return pipe_fd[0];
 }
@@ -65,8 +66,8 @@ int ipc_kill_token (struct ipc_header *ipc, server_child *children)
     /* assume signals SA_RESTART set */
     memcpy (&pid, ipc->msg, sizeof(pid_t));
 
-    LOG(log_info, logtype_default, "child %d disconnected", pid); 
-    server_child_kill_one(children, CHILD_DSIFORK, pid);
+    LOG(log_info, logtype_default, "child %d user %d disconnected", pid, ipc->uid);
+    server_child_kill_one(children, CHILD_DSIFORK, pid, ipc->uid);
     return 0;
 }
 
@@ -97,16 +98,22 @@ int ipc_get_session (struct ipc_header *ipc, server_child *children)
     }
     memcpy (clientid, p, idlen);
   
-    server_child_kill_one_by_id (children, CHILD_DSIFORK, ipc->child_pid, idlen, clientid, boottime);
+    server_child_kill_one_by_id (children, CHILD_DSIFORK, ipc->child_pid, ipc->uid, idlen, clientid, boottime);
     /* FIXME byte to ascii if we want to log clientid */
     LOG (log_info, logtype_afpd, "ipc_get_session: len: %u, idlen %d, time %x", ipc->len, idlen, boottime); 
     return 0;
 }
 
-#define IPC_HEADERLEN 10
+#define IPC_HEADERLEN 14
 #define IPC_MAXMSGSIZE 90
 
-/* ----------------- */
+/* ----------------- 
+ * Ipc format
+ * command
+ * pid
+ * uid
+ * 
+*/
 int server_ipc_read(server_child *children)
 {
     int       ret = 0;
@@ -119,10 +126,16 @@ int server_ipc_read(server_child *children)
     } 
 
     p = buf;
+
     memcpy(&ipc.command, p, sizeof(ipc.command));
     p += sizeof(ipc.command);
+
     memcpy(&ipc.child_pid, p, sizeof(ipc.child_pid));
     p += sizeof(ipc.child_pid);
+
+    memcpy(&ipc.uid, p, sizeof(ipc.uid));
+    p += sizeof(ipc.uid);
+
     memcpy(&ipc.len, p, sizeof(ipc.len));
 
     /* This should never happen */
@@ -134,7 +147,7 @@ int server_ipc_read(server_child *children)
 
     memset (buf, 0, IPC_MAXMSGSIZE);
     if ( ipc.len != 0) {
-           if ((ret = read(pipe_fd[0], buf, ipc.len)) != ipc.len) {
+           if ((ret = read(pipe_fd[0], buf, ipc.len)) != (int) ipc.len) {
                LOG (log_info, logtype_afpd, "Reading IPC message failed (%u of %u  bytes read)", ret, ipc.len);
                return -1;
        }        
@@ -163,6 +176,7 @@ int server_ipc_write( u_int16_t command, int len, void *msg)
 {
    char block[IPC_MAXMSGSIZE], *p;
    pid_t pid;
+   uid_t uid;
    p = block;
 
    memset ( p, 0 , IPC_MAXMSGSIZE);
@@ -175,6 +189,15 @@ int server_ipc_write( u_int16_t command, int len, void *msg)
    pid = getpid();
    memcpy(p, &pid, sizeof(pid_t));
    p += sizeof(pid_t);
+   
+   /* FIXME 
+    * using uid is wrong. It will not disconnect if the new connection
+    * is with a different user. 
+    * But we really don't want a remote kill command.
+   */
+   uid = geteuid();
+   memcpy(p, &uid, sizeof(uid_t));
+   p += sizeof(uid_t);
 
    memcpy(p, &len, 4);
    p += 4;
index 8d023e7033aff244c5c9473e82eb8cf81a8edd2c..90864efa138da5677e6099c4f71937c52a547d93 100644 (file)
 #include <sys/stat.h>
 #include <errno.h>
 
+#include <sys/time.h>
+
 #include <atalk/compat.h>
 #include <atalk/util.h>
 
+#ifdef ATACC
+#define fork aTaC_fork
+#endif
+static struct itimerval itimer;
+
 /* this creates an open lock file which hangs around until the program
  * dies. it returns the pid. due to problems w/ solaris, this has
  * been changed to do the kill() thing. */
@@ -59,11 +66,16 @@ pid_t server_lock(char *program, char *pidfile, int debug)
   if ( !debug ) {
     int                i;
 
+    getitimer(ITIMER_PROF, &itimer);
     switch (pid = fork()) {
     case 0 :
+      setitimer(ITIMER_PROF, &itimer, NULL);
       fclose(stdin);
       fclose(stdout);
       fclose(stderr);
+      i = open( "/dev/null", O_RDWR );
+      i = open( "/dev/null", O_RDWR );
+      i = open( "/dev/null", O_RDWR );
 
 #ifdef TIOCNOTTY
       if (( i = open( "/dev/tty", O_RDWR )) >= 0 ) {
@@ -87,3 +99,4 @@ pid_t server_lock(char *program, char *pidfile, int debug)
   fclose(pf);
   return 0;
 }
+
index 31e65bee113474ec1f4a3db8c73d11e0f7723109..b26c89fff71b21fd5aaf3b2aaa8aac27559d5954 100644 (file)
@@ -81,7 +81,7 @@ char * FUNC ( const char *phaystack, const char *pneedle)
                                a = *++haystack;
                                if (a == '\0')
                                        goto ret0;
-                 shloop:}
+                 shloop:;}
                        while (VAL(a) != VAL(b));
 
                  jin:a = *++haystack;
diff --git a/libatalk/util/strlcpy.c b/libatalk/util/strlcpy.c
new file mode 100644 (file)
index 0000000..314b039
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+   Copy from samba lib/replace.c
+
+   Unix SMB/CIFS implementation.
+   replacement routines for broken systems
+   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.
+
+   strlcpy strlcat functions.
+*/
+                          
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <atalk/util.h>
+#include <string.h>
+
+#ifndef HAVE_STRLCPY
+/* like strncpy but does not 0 fill the buffer and always null
+   terminates. bufsize is the size of the destination buffer */
+ size_t strlcpy(char *d, const char *s, size_t bufsize)
+{
+        size_t len = strlen(s);
+        size_t ret = len;
+
+        if (bufsize <= 0) 
+               return 0;
+
+        if (len >= bufsize) 
+               len = bufsize-1;
+
+        memcpy(d, s, len);
+        d[len] = 0;
+        return ret;
+}
+#endif
+#ifndef HAVE_STRLCAT
+/* like strncat but does not 0 fill the buffer and always null
+   terminates. bufsize is the length of the buffer, which should
+   be one more than the maximum resulting string length */
+ size_t strlcat(char *d, const char *s, size_t bufsize)
+{
+        size_t len1 = strlen(d);
+        size_t len2 = strlen(s);
+        size_t ret = len1 + len2;
+
+       if (len1 >= bufsize) {
+               return 0;
+       } 
+        if (len1+len2 >= bufsize) {
+                len2 = bufsize - (len1+1);
+        }
+        if (len2 > 0) {
+                memcpy(d+len1, s, len2);
+                d[len1+len2] = 0;
+        }
+        return ret;
+}
+#endif
diff --git a/libatalk/util/volinfo.c b/libatalk/util/volinfo.c
new file mode 100644 (file)
index 0000000..2b04960
--- /dev/null
@@ -0,0 +1,380 @@
+/*
+   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.
+
+   .volinfo file handling, command line utilities
+   copyright Bjoern Fernhomberg, 2004
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#ifdef HAVE_STRINGS_H
+#include <strings.h>
+#endif
+#ifdef STDC_HEADERS
+#include <string.h>
+#endif
+#include <sys/param.h>
+
+#include <atalk/adouble.h>
+#include <atalk/util.h>
+#include <atalk/logger.h>
+#include <atalk/volinfo.h>
+#ifdef CNID_DB
+#include <atalk/cnid.h>
+#endif /* CNID_DB*/
+
+#define MAC_CHARSET 0
+#define VOL_CHARSET 1
+#define ADOUBLE_VER 2
+#define CNIDBACKEND 3
+#define CNIDDBDHOST 4
+#define CNIDDBDPORT 5
+#define CNID_DBPATH 6
+#define VOLUME_OPTS 7
+#define VOLCASEFOLD 8
+
+typedef struct _info_option {
+    const char *name;
+    int type;
+} _info_option;
+
+static const _info_option info_options[] = {
+    {"MAC_CHARSET", MAC_CHARSET},
+    {"VOL_CHARSET", VOL_CHARSET},
+    {"ADOUBLE_VER", ADOUBLE_VER},
+    {"CNIDBACKEND", CNIDBACKEND},
+    {"CNIDDBDHOST", CNIDDBDHOST},
+    {"CNIDDBDPORT", CNIDDBDPORT},
+    {"CNID_DBPATH", CNID_DBPATH},
+    {"VOLUME_OPTS", VOLUME_OPTS},
+    {"VOLCASEFOLD", VOLCASEFOLD},
+    {NULL, 0}
+};
+
+typedef struct _vol_opt_name {
+    const u_int32_t option;
+    const char      *name;
+} _vol_opt_name;
+
+static const _vol_opt_name vol_opt_names[] = {
+    {AFPVOL_A2VOL,      "PRODOS"},      /* prodos volume */
+    {AFPVOL_CRLF,       "CRLF"},        /* cr/lf translation */
+    {AFPVOL_NOADOUBLE,  "NOADOUBLE"},   /* don't create .AppleDouble by default */
+    {AFPVOL_RO,         "READONLY"},    /* read-only volume */
+    {AFPVOL_MSWINDOWS,  "MSWINDOWS"},   /* deal with ms-windows yuckiness. this is going away. */
+    {AFPVOL_NOHEX,      "NOHEX"},       /* don't do :hex translation */
+    {AFPVOL_USEDOTS,    "USEDOTS"},     /* use real dots */
+    {AFPVOL_LIMITSIZE,  "LIMITSIZE"},   /* limit size for older macs */
+    {AFPVOL_MAPASCII,  "MAPASCII"},    /* map the ascii range as well */
+    {AFPVOL_DROPBOX,   "DROPBOX"},     /* dropkludge dropbox support */
+    {AFPVOL_NOFILEID,  "NOFILEID"},    /* don't advertise createid resolveid and deleteid calls */
+    {AFPVOL_NOSTAT,    "NOSTAT"},      /* advertise the volume even if we can't stat() it
+                                        * maybe because it will be mounted later in preexec */
+    {AFPVOL_UNIX_PRIV,  "UNIXPRIV"},    /* support unix privileges */
+    {AFPVOL_NODEV,      "NODEV"},       /* always use 0 for device number in cnid calls */
+    {0, NULL}
+};
+
+static const _vol_opt_name vol_opt_casefold[] = {
+    {AFPVOL_MTOUUPPER,  "MTOULOWER"},
+    {AFPVOL_MTOULOWER,  "MTOULOWER"},
+    {AFPVOL_UTOMUPPER,  "UTOMUPPER"},
+    {AFPVOL_UTOMLOWER,  "UTOMLOWER"},
+    {0, NULL}
+};
+
+static char* find_in_path( char *path, char *subdir, size_t maxlen)
+{
+    char       *pos;
+    struct stat st;
+
+    strlcat(path, subdir, maxlen);
+    pos = strrchr(path, '/');
+
+    while ( stat(path, &st) != 0) {
+#ifdef DEBUG
+        fprintf(stderr, "searching in path %s\n", path);
+#endif
+        path[pos-path]=0;
+        if ((pos = strrchr(path, '/'))) {
+            path[pos-path]=0;
+            strlcat(path, subdir, maxlen);
+        }
+        else {
+            return NULL;
+        }
+    }
+
+    path[pos-path] = '/';
+    path[pos-path+1] = 0;
+#ifdef DEBUG
+    fprintf(stderr, "%s path %s\n", subdir, path);
+#endif
+    return path;
+}
+
+static char * make_path_absolute(char *path, size_t bufsize)
+{
+    struct     stat st;
+    char       savecwd[MAXPATHLEN];
+    char       abspath[MAXPATHLEN];
+    char       *p;
+
+    if (stat(path, &st) != 0) {
+        return NULL;
+    }
+
+    strlcpy (abspath, path, sizeof(abspath));
+
+    if (!S_ISDIR(st.st_mode)) {
+        if (NULL == (p=strrchr(abspath, '/')) )
+            return NULL;
+        *p = '\0';
+    }
+
+    getcwd(savecwd, sizeof(savecwd));
+    if ((chdir(abspath)) < 0)  
+        return NULL;
+
+    getcwd(abspath, sizeof(abspath));
+    chdir (savecwd);
+
+    if (strlen(abspath) > bufsize)
+        return NULL;
+
+    strlcpy(path, abspath, bufsize);
+
+    return path;
+}
+
+static char * find_volumeroot(char *path, size_t maxlen)
+{
+    char *volume = make_path_absolute(path, maxlen);
+        
+    if (volume == NULL)
+       return NULL;
+
+    if (NULL == (find_in_path(volume, "/.AppleDesktop", maxlen)) )
+       return NULL;
+
+    return volume;
+}
+
+int vol_load_charsets( struct volinfo *vol)
+{
+    if ( (charset_t) -1 == ( vol->v_maccharset = add_charset(vol->v_maccodepage)) ) {
+        fprintf( stderr, "Setting codepage %s as Mac codepage failed", vol->v_maccodepage);
+        return (-1);
+    }
+
+    if ( (charset_t) -1 == ( vol->v_volcharset = add_charset(vol->v_volcodepage)) ) {
+        fprintf( stderr, "Setting codepage %s as volume codepage failed", vol->v_volcodepage);
+        return (-1);
+    }
+
+    return 0;
+}
+
+static int parse_options (char *buf, int *flags, const _vol_opt_name* options)
+{
+    char *p, *q;
+    const _vol_opt_name *op;
+
+    q = p = buf; 
+
+    while ( *p != '\0') {
+        if (*p == ' ') {
+            *p = '\0';
+            op = options;
+            for (;op->name; op++) {
+                if ( !strcmp(op->name, q )) {
+                    *flags |= op->option;
+                    break;
+                }
+            }
+            q = p+1;
+        }
+        p++;
+    }
+
+    return 0;
+} 
+            
+
+
+static int parseline ( char *buf, struct volinfo *vol)
+{
+    char *value;
+    size_t len;
+    int  option=-1;
+    const _info_option  *p  = &info_options[0];
+
+    if (NULL == ( value = strchr(buf, ':')) )
+       return 1;
+
+    *value = '\0';
+    value++;
+
+    if ( 0 == (len = strlen(value)) )
+        return 0;
+
+    if (value[len-1] == '\n')
+        value[len-1] = '\0';
+
+    for (;p->name; p++) {
+        if ( !strcmp(p->name, buf )) {
+            option=p->type;
+            break;
+        }
+    }
+
+    switch (option) {
+      case MAC_CHARSET:
+        if ((vol->v_maccodepage = strdup(value)) == NULL) {
+           fprintf (stderr, "strdup: %m");
+            return -1;
+        }
+        break;
+      case VOL_CHARSET:
+        if ((vol->v_volcodepage = strdup(value)) == NULL) {
+           fprintf (stderr, "strdup: %m");
+            return -1;
+        }
+        break;
+      case CNIDBACKEND:
+        if ((vol->v_cnidscheme = strdup(value)) == NULL) {
+           fprintf (stderr, "strdup: %m");
+            return -1;
+        }
+        break;
+      case CNIDDBDHOST:
+        if ((vol->v_dbd_host = strdup(value)) == NULL) {
+           fprintf (stderr, "strdup: %m");
+            return -1;
+        }
+        break;
+      case CNIDDBDPORT:
+        vol->v_dbd_port = atoi(value);
+        break;
+      case CNID_DBPATH:
+        if ((vol->v_dbpath = strdup(value)) == NULL) {
+           fprintf (stderr, "strdup: %m");
+            return -1;
+        }
+        break;
+      case ADOUBLE_VER:
+        if (strcasecmp(value, "v1") == 0) {
+            vol->v_adouble = AD_VERSION1;
+            vol->ad_path = ad_path;
+        }
+#if AD_VERSION == AD_VERSION2
+        else if (strcasecmp(value, "v2") == 0) {
+            vol->ad_path = ad_path;
+            vol->v_adouble = AD_VERSION2;
+        }
+        else if (strcasecmp(value, "osx") == 0) {
+            vol->v_adouble = AD_VERSION2_OSX;
+            vol->ad_path = ad_path_osx;
+        }
+#endif
+        else  {
+           fprintf (stderr, "unknown adouble version: %s, %s", buf, value);
+           return -1;
+        }
+        break;
+      case VOLUME_OPTS:
+        parse_options(value, &vol->v_flags, &vol_opt_names[0]);
+        break;
+      case VOLCASEFOLD:
+        parse_options(value, &vol->v_casefold, &vol_opt_casefold[0]);
+        break;
+      default:
+       fprintf (stderr, "unknown volume information: %s, %s", buf, value);
+       return (-1);
+        break;
+    }
+#ifdef DEBUG
+    printf ("volume information: %s, %s", buf, value);
+#endif
+        
+    return 0;
+}
+    
+
+int loadvolinfo (char *path, struct volinfo *vol)
+{
+
+    char   volinfofile[MAXPATHLEN];
+    char   buf[MAXPATHLEN];
+    struct flock lock;
+    int    fd;
+    FILE   *fp;
+
+    if ( !path || !vol)
+        return -1;
+
+    memset(vol, 0, sizeof(struct volinfo));
+    strlcpy(volinfofile, path, sizeof(volinfofile));
+
+    /* volinfo file is in .AppleDesktop */ 
+    if ( NULL == find_volumeroot(volinfofile, sizeof(volinfofile)))
+        return -1;
+
+    if ((vol->v_path = strdup(volinfofile)) == NULL ) {
+       fprintf (stderr, "strdup: %m");
+        return (-1);
+    }
+    strlcat(volinfofile, ".AppleDesktop/", sizeof(volinfofile));
+    strlcat(volinfofile, VOLINFOFILE, sizeof(volinfofile));
+
+    /* open the file read only */
+    if ( NULL == (fp = fopen( volinfofile, "r")) )  {
+       fprintf (stderr, "error opening volinfo (%s): %m", volinfofile);
+        return (-1);
+    }
+    fd = fileno(fp); 
+
+    /* try to get a read lock */ 
+    lock.l_start  = 0;
+    lock.l_whence = SEEK_SET;
+    lock.l_len    = 0;
+    lock.l_type   = F_RDLCK;
+
+    /* wait for read lock */
+    if (fcntl(fd, F_SETLKW, &lock) < 0) {
+        fclose(fp);
+        return (-1);
+    }
+
+    /* read the file */
+    while (NULL != fgets(buf, sizeof(buf), fp)) {
+        parseline(buf, vol);
+    }
+
+    /* unlock file */
+    lock.l_type = F_UNLCK;
+    fcntl(fd, F_SETLK, &lock);
+
+    fclose(fp);
+    return 0;
+}
index 4c7a38bf13b8add66c533e72ea137550a31394e1..a64c3153303daaf7b76bfa35a61954e6d87589c7 100644 (file)
@@ -1,13 +1,20 @@
 EXTRA_DIST = \
        afs-check.m4            \
+       cnid-backend.m4         \
        config-checks.m4        \
        db3-check.m4            \
        grep-check.m4           \
+       gssapi-check.m4         \
+       iconv.m4                \
+       largefile-check.m4      \
        pam-check.m4            \
        perl-check.m4           \
        ps-check.m4             \
        quota-check.m4          \
+       snprintf-check.m4       \
        srvloc.m4               \
        ssl-check.m4            \
-       largefile-check.m4      \
-       snprintf-check.m4
+       summary.m4              \
+       tcp-wrappers.m4         \
+       util.m4
+
diff --git a/macros/admingrp-check.m4 b/macros/admingrp-check.m4
deleted file mode 100644 (file)
index 2c724a5..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-dnl $Id: admingrp-check.m4,v 1.1 2003-12-15 06:56:33 srittau Exp $
-dnl Autoconf macro to check whether admin group support should be enabled
-
-AC_DEFUN([NETATALK_ADMINGRP_CHECK], [
-       admingrp=yes
-       AC_MSG_CHECKING([for administrative group support])
-       AC_ARG_ENABLE(admin-group,
-               [  --disable-admin-group   disable admin group], [
-                       if test "x$enableval" = "xno"; then
-                               admingrp=no
-                       fi
-               ]
-       )
-
-       AC_DEFINE_UNQUOTED(ADMIN_GRP,
-               `test "x$admingrp" = "xyes"`,
-       [Define if the admin group should be enabled]
-       )
-
-       if test "x$admingrp" = "xyes"; then
-               AC_MSG_RESULT([yes])
-       else
-               AC_MSG_RESULT([no])
-       fi
-])
-
index 7453a1757993e6debdf80ff496bbab3cbc0ce3cc..f71e48192bd49e0a54a9d7fc97acd793334c5b73 100644 (file)
@@ -1,15 +1,16 @@
-dnl $Id: afs-check.m4,v 1.2 2003-01-29 00:16:30 srittau Exp $
+dnl $Id: afs-check.m4,v 1.3 2005-04-28 20:50:05 bfernhomberg Exp $
 dnl Autoconf macro to check whether AFS support should be enabled
 
 AC_DEFUN([NETATALK_AFS_CHECK], [
        AFS_LIBS=
        AFS_CFLAGS=
 
+       netatalk_cv_afs=no
        AC_ARG_ENABLE(afs,
                [  --enable-afs            enable AFS support],
                [
                        if test "x$enableval" = "xyes"; then
-                               AC_CHECK_LIB(afsauthent, pioctl, ,
+                               AC_CHECK_LIB(afsauthent, pioctl, netatalk_cv_afs=yes,
                                        AC_MSG_ERROR([AFS installation not found])
                                )
                                AFS_LIBS=-lafsauthent
@@ -18,6 +19,13 @@ AC_DEFUN([NETATALK_AFS_CHECK], [
                ]
        )
 
+       AC_MSG_CHECKING([whether to enable AFS support])        
+       if test x"$netatalk_cv_afs" = x"yes"; then
+               AC_MSG_RESULT([yes])
+       else
+               AC_MSG_RESULT([no])
+       fi
+
        AC_SUBST(AFS_LIBS)
        AC_SUBST(AFS_CFLAGS)
 ])
diff --git a/macros/cnid-backend.m4 b/macros/cnid-backend.m4
new file mode 100644 (file)
index 0000000..a304b24
--- /dev/null
@@ -0,0 +1,250 @@
+AC_DEFUN([AC_NETATALK_CNID], [
+
+    dnl Don't use BDB unless it's needed
+    bdb_required=no
+    compiled_backends=""
+
+    dnl Determine whether or not to use BDB Concurrent Data Store
+    AC_MSG_CHECKING([whether or not to use BDB Concurrent Data Store])
+    AC_ARG_WITH(cnid-cdb-backend,
+       [  --with-cnid-cdb-backend      build CNID with Concurrent BDB Data Store],[
+           if test x"$withval" = x"no"; then
+               use_cdb_backend=no
+        else
+            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 BDB backend should be compiled.])        
+        DEFAULT_CNID_SCHEME=cdb
+        bdb_required=yes
+        compiled_backends="$compiled_backends cdb"
+    else
+        AC_MSG_RESULT([no])
+    fi
+    AM_CONDITIONAL(USE_CDB_BACKEND, test x"$use_cdb_backend" = x"yes")
+
+    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       build 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=yes
+        AC_MSG_RESULT([yes])
+    ])
+
+    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           build 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
+        compiled_backends="$compiled_backends dbd"
+        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
+    AM_CONDITIONAL(BUILD_DBD_DAEMON, test x"$use_dbd_backend" = x"yes")
+
+    dnl Determine whether or not to use BDB transactional data store
+    AC_MSG_CHECKING([whether or not to use BDB transactional DB store])
+    AC_ARG_WITH(cnid-db3-backend,
+    [  --with-cnid-db3-backend build CNID with transactional BDB Data Store],
+       [
+           if test x"$withval" = x"no"; then
+            use_db3_backend=no
+        else
+            use_db3_backend=yes
+        fi
+    ],[
+        use_db3_backend=no
+    ])
+
+    if test x"$use_db3_backend" = x"yes"; then
+        AC_MSG_RESULT([yes])
+        AC_DEFINE(CNID_BACKEND_DB3, 1, [Define if CNID transactional BDB backend should be compiled.])
+        if test x"$DEFAULT_CNID_SCHEME" = x; then
+            DEFAULT_CNID_SCHEME=db3
+        fi
+        compiled_backends="$compiled_backends db3"
+        bdb_required=yes
+    else
+        AC_MSG_RESULT([no])
+    fi
+    AM_CONDITIONAL(USE_DB3_BACKEND, test x"$use_db3_backend" = x"yes")
+
+    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     build LAST CNID scheme],
+       [
+        if test x"$withval" = x"no"; then
+            use_last_backend=no
+        else
+            use_last_backend=yes
+        fi
+    ],[
+        use_last_backend=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
+        compiled_backends="$compiled_backends last"
+    else
+        AC_MSG_RESULT([no])
+    fi
+
+    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     build 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
+        compiled_backends="$compiled_backends hash"
+    else
+        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      build DID CNID scheme],
+    [
+        if test x"$withval" = x"no"; then
+            use_tdb_backend=no
+        else
+            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_CNID_SCHEME=tdb
+        fi
+        compiled_backends="$compiled_backends tdb"
+    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     build 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_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
+        compiled_backends="$compiled_backends mtab"
+    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
+
+    AC_MSG_CHECKING([whether default CNID scheme has been activated])
+    found_scheme=no
+    for scheme in $compiled_backends ; do
+        if test x"$scheme" = x"$DEFAULT_CNID_SCHEME"; then     
+            found_scheme=yes
+        fi
+    done
+    if test x"$found_scheme" = x"no"; then
+        AC_MSG_RESULT([no])
+        AC_MSG_ERROR([Specified default CNID scheme $DEFAULT_CNID_SCHEME was not selected for compilation])
+    else
+        AC_MSG_RESULT([yes])
+    fi
+
+    AC_DEFINE_UNQUOTED(DEFAULT_CNID_SCHEME, "$DEFAULT_CNID_SCHEME", [Default CNID scheme to be used])
+    AC_SUBST(DEFAULT_CNID_SCHEME)
+    AC_SUBST(compiled_backends)
+
+    if test "x$bdb_required" = "xyes"; then
+       ifelse([$1], , :, [$1])
+    else
+       ifelse([$2], , :, [$2])     
+    fi
+])
index 4e0c72eb0c40afbae83332b326565eeff1925275..eb4cf882efe7fe8ceaec72e974149fbaa3e835c3 100644 (file)
@@ -1,4 +1,4 @@
-dnl $Id: config-checks.m4,v 1.5 2003-06-06 19:45:51 srittau Exp $
+dnl $Id: config-checks.m4,v 1.6 2005-04-28 20:50:05 bfernhomberg Exp $
 dnl Autoconf macro to set the configuration directories.
 
 AC_DEFUN([NETATALK_CONFIG_DIRS], [
@@ -6,7 +6,7 @@ AC_DEFUN([NETATALK_CONFIG_DIRS], [
 
        AC_ARG_WITH(pkgconfdir,
                [  --with-pkgconfdir=DIR   package specific configuration in DIR
-                          [SYSCONF/netatalk]],
+                          [[SYSCONF/netatalk]]],
                        [
                        if test "x$withval" != "x"; then
                                PKGCONFDIR="$withval"
@@ -14,21 +14,11 @@ AC_DEFUN([NETATALK_CONFIG_DIRS], [
                ]
        )
 
-       NLSDIR="${datadir}/netatalk/nls"
-
-       AC_ARG_WITH(nls-dir,
-               [  --with-nls-dir=PATH     path to NLS files [DATA/netatalk/nls]],
-               [
-                       if test "x$withval" != "x"; then
-                               NLSDIR="$withval"
-                       fi
-               ]
-       )
 
        SERVERTEXT="${PKGCONFDIR}/msg"
 
        AC_ARG_WITH(message-dir,
-               [  --with-message-dir=PATH path to server message files [PKGCONF/msg]],
+               [  --with-message-dir=PATH path to server message files [[PKGCONF/msg]]],
                [
                        if test x"$withval" = x"no";  then 
                                AC_MSG_WARN([*** message-dir is mandatory and cannot be disabled, using default ***])
@@ -39,6 +29,5 @@ AC_DEFUN([NETATALK_CONFIG_DIRS], [
        )
 
        AC_SUBST(PKGCONFDIR)
-       AC_SUBST(NLSDIR)
        AC_SUBST(SERVERTEXT)
 ])
diff --git a/macros/cups.m4 b/macros/cups.m4
new file mode 100644 (file)
index 0000000..b46e4f2
--- /dev/null
@@ -0,0 +1,67 @@
+dnl $Id: cups.m4,v 1.2 2005-04-28 20:50:05 bfernhomberg Exp $
+dnl Autoconf macros to check for CUPS
+
+AC_DEFUN([NETATALK_AC_CUPS], [
+
+       dnl Don't use spool unless it's needed
+       spool_required=no
+       netatalk_cv_use_cups=no
+
+       AC_ARG_ENABLE(cups,
+       [  --enable-cups           Turn on CUPS support (default=auto)])
+
+       if test x$enable_cups != xno; then
+               AC_PATH_PROG(CUPS_CONFIG, cups-config)
+
+               if test "x$CUPS_CONFIG" != x; then
+                       AC_DEFINE(HAVE_CUPS, 1, [Define to enable CUPS Support])
+                       CUPS_CFLAGS="`$CUPS_CONFIG --cflags`"
+                       CUPS_LDFLAGS="`$CUPS_CONFIG --ldflags`"
+                       CUPS_LIBS="`$CUPS_CONFIG --libs`"
+                       CUPS_VERSION="`$CUPS_CONFIG --version`"
+                       AC_DEFINE_UNQUOTED(CUPS_API_VERSION, "`$CUPS_CONFIG --api-version`", [CUPS API Version])
+                       AC_SUBST(CUPS_CFLAGS)
+                       AC_SUBST(CUPS_LDFLAGS)
+                       AC_SUBST(CUPS_LIBS)
+       
+                       AC_MSG_CHECKING([CUPS version])
+                       AC_MSG_RESULT([$CUPS_VERSION])
+                       netatalk_cv_use_cups=yes
+       
+                       if test x"$netatalk_cv_HAVE_USABLE_ICONV" = x"no" ; then
+                               AC_WARN([*** Warning: iconv not found on your system, using simple ascii mapping***])
+                       fi
+                       spool_required="yes"
+               elif test x"$enable_cups" = "xyes"; then
+                       AC_MSG_ERROR([*** CUPS not found. You might need to specify the path to cups-config ***])
+               fi
+       fi
+
+       AC_MSG_CHECKING([whether CUPS support can be enabled])
+       AC_MSG_RESULT([$netatalk_cv_use_cups])
+
+
+       AC_ARG_WITH(spooldir,
+               [  --with-spooldir=PATH     path for spooldir used for CUPS support (LOCALSTATEDIR/spool/netatalk)],[
+
+               if test "$withval" = "no"; then
+                      if test x"$spool_required" == x"yes"; then
+                              AC_MSG_ERROR([*** CUPS support requires a spooldir ***])
+                      else
+                              AC_DEFINE(DISABLE_SPOOL, 1, [Define to enable spooldir support])
+                              AC_MSG_RESULT([spool disabled])
+                               fi
+               elif test "$withval" != "yes"; then
+                       SPOOLDIR="$withval"
+                       AC_MSG_RESULT([spooldir set to $withval])
+               else
+                       SPOOLDIR="${localstatedir}/spool/netatalk"
+                       AC_MSG_RESULT([spool set to default])
+               fi
+       ],[
+               SPOOLDIR="${localstatedir}/spool/netatalk"
+       ])
+
+       AM_CONDITIONAL(USE_SPOOLDIR, test x"$spool_required" = x"yes")
+       AC_SUBST(SPOOLDIR)
+])
index b036882bf2076e675f13f05c313dcee2c9fc5c87..b4c5a3b4a03671c7131a38889eba34721a62d3f1 100644 (file)
-dnl $Id: db3-check.m4,v 1.12 2003-06-06 19:45:51 srittau Exp $
-dnl Autoconf macro to check for the Berkeley DB library
+dnl $Id: db3-check.m4,v 1.13 2005-04-28 20:50:05 bfernhomberg Exp $
+dnl Autoconf macros to check for the Berkeley DB library
 
-AC_DEFUN([AC_PATH_BDB], [
+
+AC_DEFUN([NETATALK_BDB_LINK_TRY],
+[if test $atalk_cv_lib_db = no ; then
+       AC_MSG_CHECKING([for Berkeley DB link (]ifelse($2,,default,$2)[)])
+       atalk_DB_LIB=ifelse($2,,-ldb,$2)
+       atalk_LIBS=$LIBS
+       LIBS="$atalk_DB_LIB $LIBS"
+
+       AC_TRY_LINK([
+#include <db.h>
+],[
+       char *version;
+       int major, minor, patch;
+
+       version = db_version( &major, &minor, &patch );
+       return (0);
+],[$1=yes],[$1=no])
+
+       AC_MSG_RESULT([$$1])
+       LIBS="$atalk_LIBS"
+       if test $$1 = yes ; then
+               atalk_cv_lib_db=ifelse($2,,-ldb,$2)
+       fi
+fi
+])
+
+
+AC_DEFUN([NETATALK_BDB_CHECK_VERSION],
+[
+       atalk_LIBS=$LIBS
+       LIBS="${atalk_cv_lib_db} $LIBS"
+
+       AC_MSG_CHECKING([Berkeley DB library version >= ${DB_MAJOR_REQ}.${DB_MINOR_REQ}.${DB_PATCH_REQ}])
+       AC_TRY_RUN([
+#if STDC_HEADERS
+#include <stdlib.h>
+#endif
+#include <stdio.h>
+#include <db.h>
+
+int main(void) {
+        int major, minor, patch;
+        char *version_str;
+
+        version_str = db_version(&major, &minor, &patch);
+
+        /* check library version */
+        if (major < DB_MAJOR_REQ || minor < DB_MINOR_REQ || patch < DB_PATCH_REQ) {
+                printf("library version too old (%d.%d.%d), ",major, minor, patch);
+                return (2);
+        }
+
+        /* check header and library match */
+        if ( major != DB_VERSION_MAJOR || minor != DB_VERSION_MINOR || patch != DB_VERSION_PATCH) {
+                printf("header/library version mismatch (%d.%d.%d/%d.%d.%d), ",
+                         DB_VERSION_MAJOR, DB_VERSION_MINOR, DB_VERSION_PATCH, major, minor, patch);
+                return (3);
+        }
+
+        printf("%d.%d.%d, ",major, minor, patch);
+        return (0);
+}
+], atalk_cv_bdb_version="yes", atalk_cv_bdb_version="no", atalk_cv_bdb_version="cross")
+
+
+        if test ${atalk_cv_bdb_version} = "yes"; then
+               AC_MSG_RESULT(yes)
+        else
+               AC_MSG_RESULT(no)
+        fi
+       LIBS="$atalk_LIBS"
+])
+
+
+AC_DEFUN([NETATALK_BDB_HEADER],
+[
+       savedcflags="$CFLAGS"
+       CFLAGS="-I$1 $CFLAGS"
+       dnl check for header version
+        AC_MSG_CHECKING(ifelse($1,,default,$1)[/db.h version >= ${DB_MAJOR_REQ}.${DB_MINOR_REQ}.${DB_PATCH_REQ}])
+        AC_TRY_RUN([
+#if STDC_HEADERS
+#include <stdlib.h>
+#endif
+#include <stdio.h>
+#include <db.h>
+
+int main(void) {
+
+        /* check header version */
+        if (DB_VERSION_MAJOR < DB_MAJOR_REQ || DB_VERSION_MINOR < DB_MINOR_REQ ||
+            DB_VERSION_PATCH < DB_PATCH_REQ ) {
+                printf("header file version too old (%d.%d.%d), ", DB_VERSION_MAJOR, DB_VERSION_MINOR, DB_VERSION_PATCH);
+                return (1);
+        }
+
+        printf("%d.%d.%d, ", DB_VERSION_MAJOR, DB_VERSION_MINOR, DB_VERSION_PATCH);
+        return (0);
+}
+], atalk_cv_bdbheader="yes", atalk_cv_bdbheader="no", atalk_cv_bdbheader="cross")
+
+        if test ${atalk_cv_bdbheader} = "no"; then
+               bdbfound=no
+               AC_MSG_RESULT([no])
+        else
+                AC_MSG_RESULT([yes])
+        fi
+       CFLAGS="$savedcflags"
+])
+
+
+AC_DEFUN([NETATALK_BERKELEY_LINK],
+[
+atalk_cv_lib_db=no
+NETATALK_BDB_LINK_TRY(atalk_cv_db_db_4_dot_2,[-ldb-4.2])
+NETATALK_BDB_LINK_TRY(atalk_cv_db_db42,[-ldb42])
+NETATALK_BDB_LINK_TRY(atalk_cv_db_db_42,[-ldb-42])
+NETATALK_BDB_LINK_TRY(atalk_cv_db_db_4_2,[-ldb-4-2])
+NETATALK_BDB_LINK_TRY(atalk_cv_db_db_4_dot_2,[-ldb-4.3])
+NETATALK_BDB_LINK_TRY(atalk_cv_db_db42,[-ldb43])
+NETATALK_BDB_LINK_TRY(atalk_cv_db_db_42,[-ldb-43])
+NETATALK_BDB_LINK_TRY(atalk_cv_db_db_4_2,[-ldb-4-3])
+NETATALK_BDB_LINK_TRY(atalk_cv_db_db_4_dot_1,[-ldb-4.1])
+NETATALK_BDB_LINK_TRY(atalk_cv_db_db41,[-ldb41])
+NETATALK_BDB_LINK_TRY(atalk_cv_db_db_41,[-ldb-41])
+NETATALK_BDB_LINK_TRY(atalk_cv_db_db_4_1,[-ldb-4-1])
+NETATALK_BDB_LINK_TRY(atalk_cv_db_db_4,[-ldb-4])
+NETATALK_BDB_LINK_TRY(atalk_cv_db_db4,[-ldb4])
+NETATALK_BDB_LINK_TRY(atalk_cv_db_db,[-ldb])
+])
+
+
+AC_DEFUN([AC_PATH_BDB], 
+[
        trybdbdir=""
+       dobdbsearch=yes
+       bdb_search_dirs="/usr/local/include /usr/include"
+       search_subdirs="/db4.2 /db42 /db4.3 /db43 /db4.1 /db41 /db4 /"
+
+dnl required BDB version
+       DB_MAJOR_REQ=4
+       DB_MINOR_REQ=1
+       DB_PATCH_REQ=0
+
+dnl make sure atalk_libname is defined beforehand
+[[ -n "$atalk_libname" ]] || AC_MSG_ERROR([internal error, atalk_libname undefined])
+
+dnl define the required BDB version
+       AC_DEFINE_UNQUOTED(DB_MAJOR_REQ, ${DB_MAJOR_REQ}, [Required BDB version, major])
+       AC_DEFINE_UNQUOTED(DB_MINOR_REQ, ${DB_MINOR_REQ}, [Required BDB version, minor])
+       AC_DEFINE_UNQUOTED(DB_PATCH_REQ, ${DB_PATCH_REQ}, [Required BDB version, patch])
+
+
        AC_ARG_WITH(bdb,
-               [  --with-bdb=PATH         specify path to Berkeley DB installation],
-               if test "x$withval" != "xno"; then
-                       trybdbdir="$withval"
+               [  --with-bdb=PATH         specify path to Berkeley DB installation[[auto]]],
+               if test "x$withval" = "xno"; then
+                       dobdbsearch=no
+               elif test "x$withval" = "xyes"; then
+                       dobdbsearch=yes
+               else
+                       bdb_search_dirs="$withval/include $withval"
                fi
        )
 
+
        bdbfound=no
-       for bdbdir in "" "$trybdbdir" "$trybdbdir/include" "$trybdbdir/include/db3" "/usr/local/BerkeleyDB.3.3/include" "/usr/local/include/db3" "/usr/local/include" "/usr/include/db3" "/usr/include" ; do
-               if test -f "$bdbdir/db.h" ; then
-                       bdblibdir="`echo $bdbdir | sed 's/include\/db3$/lib/'`"
-                       bdblibdir="`echo $bdblibdir | sed 's/include$/lib/'`"
-                       bdbbindir="`echo $bdbdir | sed 's/include\/db3$/bin/'`"
-                       bdbbindir="`echo $bdbbindir | sed 's/include$/bin/'`"
-
-                       savedcflags="$CFLAGS"
-                       savedldflags="$LDFLAGS"
-                       CFLAGS="$CFLAGS -I$bdbdir"
-                       LDFLAGS="-L$bdblibdir $LDFLAGS"
-                       AC_CHECK_LIB(db, main, [
-                               bdbfound=yes
-                               if test "$bdbdir" != "/usr/include"; then
-                                   BDB_CFLAGS="-I$bdbdir"
-                               fi
-                               if test "$bdblibdir" != "/usr/lib"; then
-                                   BDB_LIBS="-L$bdblibdir"
-                               fi
-                               BDB_LIBS="$BDB_LIBS -ldb"
-                               BDB_BIN=$bdbbindir
-                               BDB_PATH="`echo $bdbdir | sed 's,include/db3$,,'`"
-                               BDB_PATH="`echo $BDB_PATH | sed 's,include$,,'`"
-                       ])
-                       CFLAGS="$savedcflags"
-                       LDFLAGS="$savedldflags"
+        savedcflags="$CFLAGS"
+       savedldflags="$LDFLAGS"
+       savedcppflags="$CPPFLAGS"
+       savedlibs="$LIBS"
+
+       if test "x$dobdbsearch" = "xyes"; then
+           for bdbdir in $bdb_search_dirs; do
+               if test $bdbfound = "yes"; then
                        break;
                fi
-       done
+               for subdir in ${search_subdirs}; do
+                   AC_MSG_CHECKING([for Berkeley DB headers in ${bdbdir}${subdir}])
+                   if test -f "${bdbdir}${subdir}/db.h" ; then
+                       AC_MSG_RESULT([yes])
+                       NETATALK_BDB_HEADER([${bdbdir}${subdir}])
+                       if test ${atalk_cv_bdbheader} != "no"; then
+                       
+dnl                      bdblibdir="`echo $bdbdir | sed 's/\/include\/db4\.*.*//'`"
+                         bdblibdir="`echo $bdbdir | sed 's/\/include\/db4.*//'`"
+                         bdblibdir="`echo $bdblibdir | sed 's/\/include$//'`"
+                         bdblibdir="${bdblibdir}/${atalk_libname}"
+dnl                      bdbbindir="`echo $bdbdir | sed 's/include\/db4\.*.*/bin/'`"
+                         bdbbindir="`echo $bdbdir | sed 's/\/include\/db4.*/bin/'`"
+                         bdbbindir="`echo $bdbbindir | sed 's/include$/bin/'`"
+
+                         CPPFLAGS="-I${bdbdir}${subdir} $CFLAGS"
+                         CFLAGS=""
+                         LDFLAGS="-L$bdblibdir $LDFLAGS"
+                         NETATALK_BERKELEY_LINK
+                         if test x"${atalk_cv_lib_db}" != x"no"; then
+                               NETATALK_BDB_CHECK_VERSION
+                               if test x"${atalk_cv_bdb_version}" != x"no"; then
+                                   BDB_LIBS="-L${bdblibdir} ${atalk_cv_lib_db}"
+                                   BDB_CFLAGS="-I${bdbdir}${subdir}"
+                                    BDB_BIN=$bdbbindir
+                                    BDB_PATH="`echo $bdbdir | sed 's,include\/db4$,,'`"
+                                    BDB_PATH="`echo $BDB_PATH | sed 's,include$,,'`"
+                                   bdbfound=yes
+                                   break;
+                               fi
+                         fi    
+                         CFLAGS="$savedcflags"
+                         LDFLAGS="$savedldflags"
+                         CPPFLAGS="$savedcppflags"
+                         LIBS="$savedlibs"
+                       fi
+                   else
+                       AC_MSG_RESULT([no])
+                   fi
+               done
+           done
+       fi
+
+        CFLAGS="$savedcflags"
+        LDFLAGS="$savedldflags"
+        CPPFLAGS="$savedcppflags"
+        LIBS="$savedlibs"
 
        if test "x$bdbfound" = "xyes"; then
                ifelse([$1], , :, [$1])
@@ -47,8 +231,12 @@ AC_DEFUN([AC_PATH_BDB], [
                ifelse([$2], , :, [$2])     
        fi
 
+        CFLAGS_REMOVE_USR_INCLUDE(BDB_CFLAGS)
+        LIB_REMOVE_USR_LIB(BDB_LIBS)
        AC_SUBST(BDB_CFLAGS)
        AC_SUBST(BDB_LIBS)
        AC_SUBST(BDB_BIN)
        AC_SUBST(BDB_PATH)
 ])
+
+
diff --git a/macros/did-scheme.m4 b/macros/did-scheme.m4
deleted file mode 100644 (file)
index baa31d2..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-dnl $Id: did-scheme.m4,v 1.1 2003-06-08 14:52:37 srittau Exp $
-
-AC_DEFUN([NETATALK_ARG_DID], [
-
-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) [cnid]],
-       [ 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" = "xcnid"; then
-       bdb_required="yes"
-       AC_DEFINE(CNID_DB, 1, [Define if the CNID DB DID scheme should be used])
-       AC_MSG_RESULT([CNID DB])
-else
-       AC_MSG_ERROR([unknown DID scheme])
-fi
-AM_CONDITIONAL(COMPILE_CNID, test "x$did_scheme" = "xcnid")
-
-dnl Check for Berkeley DB library
-if test "x$bdb_required" = "xyes"; then
-       AC_PATH_BDB(, [AC_MSG_ERROR([Berkeley DB library not found!])])
-fi
-
-])
index 9748c487aeebf30a5064eea6466a0098f5aa508d..15fecfe54d77ae74efe141147428432aac4c5f17 100644 (file)
@@ -1,7 +1,5 @@
-dnl $Id: gssapi-check.m4,v 1.2 2003-12-15 06:03:33 srittau Exp $
-dnl Autoconf macro to check for kerberos/gssapi support
-dnl based on samba3 configure.in
-dnl modified for netatalk use by bfernhomberg
+dnl $Id: gssapi-check.m4,v 1.3 2005-04-28 20:50:05 bfernhomberg Exp $
+dnl Autoconf macro to check for kerberos
 
 AC_DEFUN([NETATALK_GSSAPI_CHECK], 
 [
@@ -10,139 +8,147 @@ AC_DEFUN([NETATALK_GSSAPI_CHECK],
        GSSAPI_CFLAGS=""
 
         AC_ARG_WITH(gssapi,
-                [  --with-gssapi[=DIR]       compile Kerberos V UAM],
+                [  --with-gssapi[[=PATH]]    path to GSSAPI for Kerberos V UAM [[auto]]],
                 [compilegssapi=$withval],
-                [compilegssapi=no]
+                [compilegssapi=auto]
         )
 
        if test x"$compilegssapi" != x"no"; then
 
-                if test "x$compilegssapi" != "xyes"; then
+                if test "x$compilegssapi" != "xyes" -a "x$compilegssapi" != "xauto"; then
                        GSSAPI_CFLAGS="-I$withval/include"
                        GSSAPI_CPPFLAGS="-I$withval/include"
-                       GSSAPI_LDFLAGS="-L$withval/lib"
+                       GSSAPI_LDFLAGS="-L$withval/${atalk_libname}"
                        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.
+         # 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
+         #################################################
+         # 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
+       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 libs
 
-               AC_CHECK_LIB(gssapi, gss_display_status) 
-               AC_CHECK_LIB(gssapi_krb5, gss_display_status) 
+       # check for gssapi headers
 
-               # check for functions
+       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) 
 
-               AC_CHECK_FUNC(gss_acquire_cred,[],[AC_MSG_ERROR([GSSAPI: required function gss_acquire_cred missing])])
+       # check for functions
 
-               # 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_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_CHECKING(whether GSSAPI support is used)
+       if test x"$ac_cv_func_gss_acquire_cred" = x"yes"; then
+               AC_DEFINE(HAVE_GSSAPI,1,[Whether to enable GSSAPI support])
+               AC_MSG_RESULT([yes])
+               GSSAPI_LIBS="$LDFLAGS $LIBS"
+       else
+               AC_MSG_RESULT([no])
+               if test x"$compilegssapi" = x"yes"; then
                        AC_MSG_ERROR([GSSAPI installation not found])
-                       GSSAPI_LIBS=""
-               fi
+               fi
+               GSSAPI_LIBS=""
+       fi
 
-               LIBS="$ac_save_LIBS"
-               CFLAGS="$ac_save_CFLAGS"
-               LDFLAGS="$ac_save_LDFLAGS"
-               CPPFLAGS="$ac_save_CPPFLAGS"
+        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)
+        if test x"$ac_cv_func_gss_acquire_cred" = x"yes"; then
+                ifelse([$1], , :, [$1])
+        else
+                ifelse([$2], , :, [$2])
+        fi
+
+
+       AC_SUBST(GSSAPI_LIBS)
+       AC_SUBST(GSSAPI_CFLAGS)
 
 ])
index 738c60de026258ebab7935a2cf31a199f0ae22c4..c7c91034b6f190193be7bb409a564b5a0d9f8b2a 100644 (file)
@@ -1,47 +1,72 @@
-AC_DEFUN([AM_ICONV],
+AC_DEFUN([AC_CHECK_ICONV],
 [
 
 dnl    #################################################
 dnl    # check for libiconv support
-       AC_MSG_CHECKING(whether to use libiconv)
         savedcflags="$CFLAGS"
         savedldflags="$LDFLAGS"
+       ICONV_CFLAGS=""
+       ICONV_LIBS=""
+
        AC_ARG_WITH(libiconv,
-       [  --with-libiconv=BASEDIR Use libiconv in BASEDIR/lib and BASEDIR/include (default=auto) ],
+       [  --with-libiconv=BASEDIR Use libiconv in BASEDIR/lib and BASEDIR/include [[default=auto]]],
        [ case "$withval" in
          no)
-           AC_MSG_RESULT(no)
+           ;;
+         yes)
            ;;
          *)
-           AC_MSG_RESULT(yes)
-           CFLAGS="$CFLAGS -I$withval/include"
-           LDFLAGS="$LDFLAGS -L$withval/lib"
-           AC_CHECK_LIB(iconv, iconv_open, [
-                                if test "$withval" != "/usr" && test "$withval" != ""; then
-                                    ICONV_CFLAGS="-I$withval/include"
-                                    ICONV_LIBS ="-L$withval/lib"
-                                fi
-                                ICONV_LIBS="$ICONV_LIBS -liconv"
-                        ])
-           AC_DEFINE_UNQUOTED(WITH_LIBICONV, "${withval}",[Path to iconv])
+           ICONV_CFLAGS="-I$withval/include"
+           ICONV_LIBS="-L$withval/$atalk_libname"
            ;;
          esac ],
-         AC_MSG_RESULT(no)
-       )
+         withval="no"
+       )       
+
+       CFLAGS="$ICONV_CFLAGS $CFLAGS"
+        LDFLAGS="$LDFLAGS $ICONV_LIBS -liconv"
+
+       AC_CACHE_CHECK([for libiconv],netatalk_cv_iconv,[
+          AC_TRY_LINK([
+#include <stdlib.h>
+#include <iconv.h>
+],[
+       iconv_t cd = iconv_open("","");
+        iconv(cd,NULL,NULL,NULL,NULL);
+        iconv_close(cd);
+], netatalk_cv_iconv=yes, netatalk_cv_iconv=no, netatalk_cv_iconv=cross)])
+
+       if test x"$netatalk_cv_iconv" = x"yes"; then
+           ICONV_LIBS="$ICONV_LIBS -liconv"
+        else
+dnl        # unset C-/LDFLAGS so we can detect glibc iconv, if available
+           CFLAGS="$savedcflags"
+           LDFLAGS="$savedldflags"
+           ICONV_LIBS=""
+           ICONV_CFLAGS=""
+           if test x"$withval" != x"no"; then
+               AC_MSG_ERROR([libiconv not found])
+           fi
+       fi
+
+
+       CFLAGS_REMOVE_USR_INCLUDE(ICONV_CFLAGS)
+       LIB_REMOVE_USR_LIB(ICONV_LIBS)
        AC_SUBST(ICONV_CFLAGS)
        AC_SUBST(ICONV_LIBS)
 
 dnl    ############
 dnl    # check for iconv usability
+
        AC_CACHE_CHECK([for working iconv],netatalk_cv_HAVE_USABLE_ICONV,[
-               AC_TRY_RUN([
-       #include <iconv.h>
-       main() {
-              iconv_t cd = iconv_open("MAC", "UTF8");
-              if (cd == 0 || cd == (iconv_t)-1) return -1;
-              return 0;
-       }
-       ], netatalk_cv_HAVE_USABLE_ICONV=yes,netatalk_cv_HAVE_USABLE_ICONV=no,netatalk_cv_HAVE_USABLE_ICONV=cross)])
+               AC_TRY_RUN([\
+#include <iconv.h>
+main() {
+       iconv_t cd = iconv_open("ASCII", "UTF-8");
+       if (cd == 0 || cd == (iconv_t)-1) return -1;
+       return 0;
+}
+], netatalk_cv_HAVE_USABLE_ICONV=yes,netatalk_cv_HAVE_USABLE_ICONV=no,netatalk_cv_HAVE_USABLE_ICONV=cross)])
 
        if test x"$netatalk_cv_HAVE_USABLE_ICONV" = x"yes"; then
            AC_DEFINE(HAVE_USABLE_ICONV,1,[Whether to use native iconv])
@@ -49,26 +74,46 @@ dnl # check for iconv usability
 
 dnl    ###########
 dnl    # check if iconv needs const
-       if test x"$cv_HAVE_USABLE_ICONV" = x"yes"; then
+       if test x"$netatalk_cv_HAVE_USABLE_ICONV" = x"yes"; then
                AC_CACHE_VAL(am_cv_proto_iconv, [
-               AC_TRY_COMPILE([
-               #include <stdlib.h>
-               #include <iconv.h>
-               extern
-               #ifdef __cplusplus
-               "C"
-               #endif
-               #if defined(__STDC__) || defined(__cplusplus)
-               size_t iconv (iconv_t cd, char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft);
-               #else
-               size_t iconv();
-               #endif
-               ], [], am_cv_proto_iconv_arg1="", am_cv_proto_iconv_arg1="const")
+               AC_TRY_COMPILE([\
+#include <stdlib.h>
+#include <iconv.h>
+extern
+#ifdef __cplusplus
+"C"
+#endif
+#if defined(__STDC__) || defined(__cplusplus)
+size_t iconv (iconv_t cd, char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft);
+#else
+size_t iconv();
+#endif
+], [], am_cv_proto_iconv_arg1="", am_cv_proto_iconv_arg1="const")
                am_cv_proto_iconv="extern size_t iconv (iconv_t cd, $am_cv_proto_iconv_arg1 char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft);"])
                AC_DEFINE_UNQUOTED(ICONV_CONST, $am_cv_proto_iconv_arg1,
                        [Define as const if the declaration of iconv() needs const.])
        fi
+
+dnl     ###########
+dnl     # check if (lib)iconv supports UCS-2-INTERNAL
+       if test x"$netatalk_cv_HAVE_USABLE_ICONV" = x"yes"; then
+           AC_CACHE_CHECK([whether iconv supports UCS-2-INTERNAL],netatalk_cv_HAVE_UCS2INTERNAL,[
+               AC_TRY_RUN([\
+#include <iconv.h>
+int main() {
+       iconv_t cd = iconv_open("ASCII", "UCS-2-INTERNAL");
+       if (cd == 0 || cd == (iconv_t)-1) return -1;
+       return 0;
+}
+], netatalk_cv_HAVE_UCS2INTERNAL=yes,netatalk_cv_HAVE_UCS2INTERNAL=no,netatalk_cv_HAVEUCS2INTERNAL=cross)])
+
+       if test x"$netatalk_cv_HAVE_UCS2INTERNAL" = x"yes"; then
+               AC_DEFINE(HAVE_UCS2INTERNAL,1,[Whether UCS-2-INTERNAL is supported])
+       fi
+       fi
+
         CFLAGS="$savedcflags"
         LDFLAGS="$savedldflags"
+       CPPFLAGS="$saved_CPPFLAGS"
        
 ])
index d16df4eb1c27d37837e00733411b060791cfea7a..75ba94747ed7781e29e35b2458508269b454d4ec 100644 (file)
@@ -34,6 +34,9 @@ define(WX_SYS_LARGEFILE_MACRO_VALUE,
     fi
 ])
 
+
+
+
 dnl AC_SYS_LARGEFILE
 dnl ----------------
 dnl By default, many hosts won't let programs access large files;
@@ -52,11 +55,23 @@ if test "$enable_largefile" != no; then
         WX_SYS_LARGEFILE_MACRO_VALUE(_LARGE_FILES, 1, ac_cv_sys_large_files)
     fi
 
-    AC_MSG_CHECKING(if large file support is available)
-    if test "x$wx_largefile" = "xyes"; then
+    
+    AC_CACHE_CHECK([for 64 bit off_t],netatalk_cv_SIZEOF_OFF_T,[
+    AC_TRY_RUN([#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+main() { exit((sizeof(off_t) == 8) ? 0 : 1); }],
+netatalk_cv_SIZEOF_OFF_T=yes,netatalk_cv_SIZEOF_OFF_T=no,netatalk_cv_SIZEOF_OFF_T=cross)])
+
+    AC_MSG_CHECKING([if large file support is available])
+    if test "x$netatalk_cv_SIZEOF_OFF_T" = "xyes"; then
         AC_DEFINE(HAVE_LARGEFILE_SUPPORT, [], [LARGEFILE support])
+       AC_MSG_RESULT([yes])
+        ifelse([$1], , :, [$1])
+    else
+        AC_MSG_RESULT([no])
+        ifelse([$2], , :, [$2])
     fi
-    AC_MSG_RESULT($wx_largefile)
 fi
 ])
 
index 4c7c1b962833e4398e469ce90673a3bc5614f277..ac4ffc604f306acb58f8ec5787915e336c64fc02 100644 (file)
@@ -1,9 +1,8 @@
-dnl $Id: pam-check.m4,v 1.2 2001-11-25 21:48:01 srittau Exp $
+dnl $Id: pam-check.m4,v 1.3 2005-04-28 20:50:05 bfernhomberg Exp $
 dnl PAM finding macro
 
 AC_DEFUN([AC_PATH_PAM], [
-       AC_MSG_CHECKING([for PAM])
-       AC_ARG_WITH(pam, [  --with-pam=PATH         specify path to PAM installation],
+       AC_ARG_WITH(pam, [  --with-pam[[=PATH]]       specify path to PAM installation [[auto]]],
                [
                        require_pam="yes"
                        if test "x$withval" = "xno"; then
@@ -18,43 +17,78 @@ AC_DEFUN([AC_PATH_PAM], [
                [PAMDIR="NONE";require_pam="no"]
        )
 
-       if test "x$PAMDIR" = "xNONE" -a "x$require_pam" != "xnever"; then
-               dnl Test for PAM
-               pam_paths="/ /usr /usr/local"
-               for path in $pam_paths; do
-                       if test -d "$path/etc/pam.d"; then
+       AC_MSG_CHECKING([for PAM installation directory])
+       if test "$host_os" != "solaris"; then
+               if test "x$PAMDIR" = "xNONE" -a "x$require_pam" != "xnever"; then
+                 dnl Test for PAM
+                 pam_paths="/ /usr/ /usr/local/"
+                 for path in $pam_paths; do
+                       if test -d "${path}etc/pam.d"; then
                                PAMDIR="$path"
                                break
                        fi
-               done
+                 done
+               fi
+
+               if test "x$PAMDIR" != "xNONE"; then
+                       AC_MSG_RESULT([yes (path: ${PAMDIR}etc/pam.d)])
+               else
+                       AC_MSG_RESULT([no])
+               fi
+       else
+               AC_MSG_RESULT([/etc/pam.conf (solaris)])
        fi
+               
+       pam_found="no"
+       if test "x$require_pam" != "xnever"; then
 
-       PAM_CFLAGS=""
-       PAM_LIBS=""
+               savedCFLAGS="$CFLAGS"
+               savedLDFLAGS="$LDFLAGS"
+               savedLIBS="$LIBS"
 
-       pam_found="no"
-       if test "x$PAMDIR" != "xNONE"; then
-               AC_MSG_RESULT([yes (path: $PAMDIR)])
-               AC_CHECK_HEADER([security/pam_appl.h],[
+               if test "x$PAMDIR" != "xNONE" -a "x$PAMDIR" != "x/"; then
+                       PAM_CFLAGS="-I${PAMDIR}include"
+                       PAM_LDFLAGS="-L${PAMDIR}lib"
+                       LDFLAGS="$LDFLAGS $PAM_LDFLAGS"
+                       CFLAGS="$CFLAGS $PAM_CFLAGS"
+               fi
+
+               AC_CHECK_HEADERS(security/pam_appl.h pam/pam_appl.h)
+
+               if test x"$ac_cv_header_security_pam_appl_h" = x"no" -a x"$ac_cv_header_pam_pam_appl_h" = x"no"; then
+                       pam_found=no
+               else
                        AC_CHECK_LIB(pam, pam_set_item, [
-                               PAM_CFLAGS="-I$PAMDIR/include"
-                               PAM_LIBS="-L$PAMDIR/lib -lpam"
+                               PAM_LIBS="$PAM_LDFLAGS -lpam"
                                pam_found="yes"
                        ])
-               ])
-       else
-               AC_MSG_RESULT([no])
+               fi
+               CFLAGS="$savedCFLAGS"
+               LDFLAGS="$savedLDFLAGS"
+               LIBS="$savedLIBS"
+       fi
+
+       netatalk_cv_install_pam=yes
+       if test x"$pam_found" = "xyes" -a "x$PAMDIR" = "xNONE"; then
+               AC_MSG_WARN([PAM support can be compiled, but the install location for the netatalk.pamd file could not be determined. Either install this file by hand or specify the install path.])
+               netatalk_cv_install_pam=no
        fi
 
+       AC_MSG_CHECKING([whether to enable PAM support])
        if test "x$pam_found" = "xno"; then
                if test "x$require_pam" = "xyes"; then
                        AC_MSG_ERROR([PAM support missing])
+               else
+                       AC_MSG_RESULT([no])
                fi
                ifelse([$2], , :, [$2])
        else
+               AC_MSG_RESULT([yes])
                ifelse([$1], , :, [$1])
        fi
 
+        LIB_REMOVE_USR_LIB(PAM_LIBS)
+        CFLAGS_REMOVE_USR_INCLUDE(PAM_CFLAGS)
        AC_SUBST(PAMDIR)
        AC_SUBST(PAM_CFLAGS)
        AC_SUBST(PAM_LIBS)
index b13ced7751d5425008f3e6c4f173209c3a7c773a..9bd95ee786ca2842e7bb6cf991736b4f8de481b7 100644 (file)
@@ -1,35 +1,17 @@
-dnl $Id: quota-check.m4,v 1.4 2003-12-28 13:42:06 srittau Exp $
+dnl $Id: quota-check.m4,v 1.5 2005-04-28 20:50:05 bfernhomberg Exp $
 dnl Autoconf macro to check for quota support
-dnl FIXME: This is in no way complete.
+dnl FIXME: This is in now way complete.
 
 AC_DEFUN([AC_CHECK_QUOTA], [
-       AC_CHECK_HEADERS(sys/quota.h ufs/quota.h)
-
-       QUOTA_LIBS=
-       AC_CHECK_LIB(rpcsvc, main, [QUOTA_LIBS=-lrpcsvc])
-       AC_SUBST(QUOTA_LIBS)
-
-       dnl ----- Linux 2.6 changed the quota interface
-       ac_have_struct_if_dqblk=no
-       AC_MSG_CHECKING([for struct if_dqblk])
-       AC_COMPILE_IFELSE([
-#include <asm/types.h>
-#include <sys/types.h>
-#include <linux/quota.h>
-
-int main() {
-       struct if_dqblk foo;
-
-       return 0;
-}
-       ], [
-               ac_have_struct_if_dqblk=yes
-               AC_MSG_RESULT([yes])
-       ], [
-               AC_MSG_RESULT([no])
+       QUOTA_LIBS=""
+       netatalk_cv_quotasupport="yes"
+       AC_CHECK_LIB(rpcsvc, main, [QUOTA_LIBS="-lrpcsvc"])
+       AC_CHECK_HEADERS([rpc/rpc.h rpc/pmap_prot.h rpcsvc/rquota.h],[],[
+               QUOTA_LIBS=""
+               netatalk_cv_quotasupport="no"
+               AC_DEFINE(NO_QUOTA_SUPPORT, 1, [Define if quota support should not compiled])
        ])
 
-       if test "x$ac_have_struct_if_dqblk" = "xyes"; then
-               AC_DEFINE(HAVE_STRUCT_IF_DQBLK, 1, [set if struct if_dqblk exists])
-       fi
+       AC_SUBST(QUOTA_LIBS)
 ])
+
index 2087f7f8eb0344d90aeb17598cbecaa76a6d4030..bee8ad784a46d0a505c27b5b84743be2bcbfb96d 100644 (file)
@@ -27,6 +27,7 @@ AC_DEFUN([NETATALK_SNPRINTF_CHECK], [
                #endif
                #ifdef HAVE_ERRNO_H
                #include <errno.h>
+               #endif
                ],[return(sys_nerr);],
                        ac_cv_decl_errno=yes, ac_cv_decl_errno=no)
                ])
@@ -90,7 +91,7 @@ AC_DEFUN([NETATALK_SNPRINTF_CHECK], [
 
 
 
-       AC_CACHE_CHECK(checking for long long,
+       AC_CACHE_CHECK(for long long,
        ac_cv_long_long,
        [
        AC_TRY_COMPILE([
@@ -103,7 +104,7 @@ AC_DEFUN([NETATALK_SNPRINTF_CHECK], [
          AC_DEFINE(HAVE_LONG_LONG, 1, [Define if long long is a valid data type])
        fi
 
-       AC_CACHE_CHECK(checking for long double,
+       AC_CACHE_CHECK(for long double,
        ac_cv_long_double,
        [
        AC_TRY_COMPILE([
@@ -116,7 +117,7 @@ AC_DEFUN([NETATALK_SNPRINTF_CHECK], [
          AC_DEFINE(HAVE_LONG_DOUBLE, 1, [Define if long double is a valid data type])
        fi
 
-       AC_CACHE_CHECK(checking for quad_t,
+       AC_CACHE_CHECK(for quad_t,
        ac_cv_quad_t,
        [
        AC_TRY_COMPILE([
index d3aa8ac797c1b2e37bcb709db3fbfbbdbf879c82..04d338daf79af1ce7487b1865bafb18eeee0b2bd 100644 (file)
@@ -1,50 +1,77 @@
 dnl Check for optional server location protocol support (used by MacOS X)
 
-dnl $Id: srvloc.m4,v 1.8 2003-02-23 16:09:28 jmarcus Exp $
+dnl $Id: srvloc.m4,v 1.9 2005-04-28 20:50:05 bfernhomberg Exp $
 
 AC_DEFUN([NETATALK_SRVLOC], [
 
        SLP_LIBS=""
        SLP_CFLAGS=""
+       found_slp=no
+       srvlocdir=""
 
        AC_ARG_ENABLE(srvloc,
-               [  --enable-srvloc[=DIR]     turn on Server Location Protocol support],
+               [  --enable-srvloc[[=DIR]]   enable Server Location Protocol (SLP) support [[auto]]],
                [srvloc=$enableval],
-               [srvloc=no]
+               [srvloc=try]
        )
 
+    dnl make sure atalk_libname is defined beforehand
+    [[ -n "$atalk_libname" ]] || AC_MSG_ERROR([internal error, atalk_libname undefined])
+
        if test "x$srvloc" != "xno"; then
 
                savedcppflags="$CPPFLAGS"
                savedldflags="$LDFLAGS"
-               if test "x$srvloc" = "xyes"; then
-                       srvloc="/usr"
+               if test "x$srvloc" = "xyes" -o "x$srvloc" = "xtry"; then
+                       srvlocdir="/usr"
+               else
+                       srvlocdir="$srvloc"
                fi
-               CPPFLAGS="$CPPFLAGS -I$srvloc/include"
-               LDFLAGS="$LDFLAGS -L$srvloc/lib"
+               CPPFLAGS="$CPPFLAGS -I$srvlocdir/include"
+               LDFLAGS="$LDFLAGS -L$srvlocdir/$atalk_libname"
 
                AC_MSG_CHECKING([for slp.h])
                AC_TRY_CPP([#include <slp.h>],
-                       [AC_MSG_RESULT([yes])],
+                       [
+                               AC_MSG_RESULT([yes])
+                               found_slp=yes
+                       ],
                        [
                                AC_MSG_RESULT([no])
-                               AC_MSG_ERROR([SLP installation not found])
                        ]
                )
-               AC_CHECK_LIB(slp, SLPOpen, [
-                       if test "$srvloc" != "/usr"; then
-                           SLP_LIBS="-L$srvloc/lib"
-                           SLP_CFLAGS="-I$srvloc/include"
-                       fi
-                       SLP_LIBS="$SLP_LIBS -lslp"
-               ], AC_MSG_ERROR([SLP installation not found]))
-
-               AC_DEFINE(USE_SRVLOC, 1, [Define to enable SLP support])
+               
+               if test "x$found_slp" = "xyes"; then
+                       AC_CHECK_LIB(slp, SLPOpen, [
+                          SLP_LIBS="-L$srvlocdir/$atalk_libname -lslp"
+                          SLP_CFLAGS="-I$srvlocdir/include"
+                       ],[ 
+                          AC_MSG_RESULT([no])
+                          found_slp=no
+                       ])
+               fi
 
                CPPFLAGS="$savedcppflags"
                LDFLAGS="$savedldflags"
        fi
+       
+       netatalk_cv_srvloc=no
+       AC_MSG_CHECKING([whether to enable srvloc (SLP) support])
+       if test "x$found_slp" = "xyes"; then
+               AC_MSG_RESULT([yes])
+               AC_DEFINE(USE_SRVLOC, 1, [Define to enable SLP support])
+               netatalk_cv_srvloc=yes
+       else
+               AC_MSG_RESULT([no])
+               if test "x$srvloc" != "xno" -a "x$srvloc" != "xtry"; then
+                       AC_MSG_ERROR([SLP installation not found])
+               fi
+       fi
+               
+
 
+       LIB_REMOVE_USR_LIB(SLP_LIBS)
+       CFLAGS_REMOVE_USR_INCLUDE(SLP_CFLAGS)
        AC_SUBST(SLP_LIBS)
        AC_SUBST(SLP_CFLAGS)
 ])
index 66c8f7a8caecd5c1b7473fb9c890e8859a126d33..6ff4242542673ca7816430ee544d2b9e4b9dc921 100644 (file)
@@ -1,42 +1,22 @@
-dnl $Id: ssl-check.m4,v 1.12 2004-01-14 16:10:29 bfernhomberg Exp $
+dnl $Id: ssl-check.m4,v 1.13 2005-04-28 20:50:05 bfernhomberg Exp $
 dnl Autoconf macro to check for SSL or OpenSSL
 
-AC_DEFUN([AC_PATH_GCRYPT], [
+AC_DEFUN([AC_CRYPT], [
 
-       GCRYPT_CFLAGS=""
-       GCRYPT_LIBS=""
+       saveLIBS=$LIBS
+       LIBS=""
+       CRYPT_LIBS=""
 
-       search="yes"
-       errifnotfound="no"
+       AC_CHECK_HEADERS(crypt.h)
+       AC_CHECK_LIB(crypt, main)
 
-       AC_ARG_ENABLE(gcrypt, [  --disable-gcrypt        disable compilation with libgcrypt], [
-               if test "x$enableval" != "xno"; then
-                       errifnotfound="yes"
-               else
-                       search="no"
-               fi
-       ])
-
-       GCRYPT_CONFIG=""
-       if test "x$search" == "xyes"; then
-               AC_PATH_PROG([GCRYPT_CONFIG], [libgcrypt-config], [no])
+       CRYPT_LIBS=$LIBS
+       LIBS=$saveLIBS
 
-               if test "x$GCRYPT_CONFIG" == "xno"; then
-                       if test "x$errifnotfound" == "xyes"; then
-                               AC_MSG_ERROR([libgcrypt-config not found])
-                       fi
-               else
-                       GCRYPT_CFLAGS="`$GCRYPT_CONFIG --cflags`"
-                       GCRYPT_LIBS="`$GCRYPT_CONFIG --libs`"
-                       AC_DEFINE(HAVE_GCRYPT, 1, [Define if libgcrypt is available])
-               fi
-       fi
-
-       AC_SUBST(GCRYPT_CFLAGS)
-       AC_SUBST(GCRYPT_LIBS)
-       AM_CONDITIONAL(HAVE_GCRYPT, test "x$GCRYPT_CONFIG" != "xno")
+       AC_SUBST(CRYPT_LIBS)
 ])
 
+
 AC_DEFUN([AC_PATH_SSL], [
        AC_ARG_WITH(ssl-dir, [  --with-ssl-dir=PATH     specify path to OpenSSL installation (must contain
                           lib and include dirs)],
@@ -56,22 +36,37 @@ AC_DEFUN([AC_PATH_SSL], [
 
        SSL_CFLAGS=""
        SSL_LIBS=""
+       saved_LIBS=$LIBS
+       saved_CFLAGS=$CFLAGS
        compile_ssl=no
 
+       dnl make sure atalk_libname is defined beforehand
+       [[ -n "$atalk_libname" ]] || AC_MSG_ERROR([internal error, atalk_libname undefined])
+
        if test "$tryssl" = "yes"; then
                AC_MSG_CHECKING([for SSL])
-               for ssldir in "" $tryssldir /usr /usr/local/openssl /usr/lib/openssl /usr/local/ssl /usr/lib/ssl /usr/local /usr/pkg /opt /opt/openssl /usr/local/ssl ; do
+               for ssldir in "" $tryssldir /usr /usr/local/openssl /usr/$atalk_libname/openssl /usr/local/ssl /usr/$atalk_libname/ssl /usr/local /usr/pkg /opt /opt/openssl /usr/local/ssl ; do
                        if test -f "$ssldir/include/openssl/cast.h" ; then
                                SSL_CFLAGS="$SSL_CFLAGS -I$ssldir/include -I$ssldir/include/openssl"
-                               SSL_LIBS="$SSL_LIBS -L$ssldir/lib -L$ssldir -lcrypto"
+                               SSL_LIBS="$SSL_LIBS -L$ssldir/$atalk_libname -L$ssldir -lcrypto"
                                if test "x$need_dash_r" = "xyes"; then
-                                       SSL_LIBS="$SSL_LIBS -R$ssldir/lib -R$ssldir"
+                                       SSL_LIBS="$SSL_LIBS -R$ssldir/$atalk_libname -R$ssldir"
                                fi
                                AC_MSG_RESULT([$ssldir (enabling RANDNUM and DHX support)])
+                               CFLAGS="$CFLAGS $SSL_CFLAGS"
+                               LIBS="$LIBS $SSL_LIBS"
+
+dnl FIXME: The following looks crude and probably doesn't work properly.
+                               dnl Check for the crypto library:
+                               AC_CHECK_LIB(crypto, main)
+                               dnl Check for "DES" library (for SSLeay, not openssl):
+                               AC_CHECK_LIB(des, main)
 
                                AC_DEFINE(OPENSSL_DHX,  1, [Define if the OpenSSL DHX modules should be built])
                                AC_DEFINE(UAM_DHX,      1, [Define if the DHX UAM modules should be compiled])
                                compile_ssl=yes
+                               CFLAGS=$saved_CFLAGS
+                               LIBS=$saved_LIBS
                                break
                        fi
                done
@@ -79,6 +74,9 @@ AC_DEFUN([AC_PATH_SSL], [
                        AC_MSG_RESULT([no])
                fi
        fi
+       CFLAGS_REMOVE_USR_INCLUDE(SSL_CFLAGS)
+       LIB_REMOVE_USR_LIB(SSL_LIBS)
        AC_SUBST(SSL_CFLAGS)
        AC_SUBST(SSL_LIBS)
+       LIBS=$saved_LIBS
 ])
diff --git a/macros/summary.m4 b/macros/summary.m4
new file mode 100644 (file)
index 0000000..5f25f91
--- /dev/null
@@ -0,0 +1,111 @@
+dnl $Id: summary.m4,v 1.2 2005-04-28 20:50:05 bfernhomberg Exp $
+dnl Autoconf macros, display configure summary
+
+AC_DEFUN([AC_NETATALK_CONFIG_SUMMARY], [
+
+       AC_MSG_RESULT([Configure summary:])
+       AC_MSG_RESULT([    Install style:])
+       if test "x$sysv_style" != "x"; then
+               AC_MSG_RESULT([         $sysv_style])
+       else
+               AC_MSG_RESULT([         none])
+       fi
+       AC_MSG_RESULT([    AFP:])
+       AC_MSG_RESULT([         AFP 3.x calls activated: $afp3])
+       if test "x$afp3" = "xyes"; then
+               AC_MSG_RESULT([         Large file support (>2GB) for AFP3: $wx_largefile])
+       fi
+       AC_MSG_RESULT([         DDP enabled: $netatalk_cv_ddp_enabled])
+       AC_MSG_RESULT([    CNID:])
+       AC_MSG_RESULT([         backends: $compiled_backends])
+       AC_MSG_RESULT([    UAMS:])
+       uams_using_options=""
+       if test x"$netatalk_cv_use_pam" != x"no"; then
+               uams_using_options="PAM"
+       fi
+       if test "x$netatalk_cv_use_shadowpw" = "xyes"; then
+               uams_using_options="$uams_using_options SHADOW"
+       fi
+       if test "x$compile_ssl" = "xyes"; then
+               AC_MSG_RESULT([         DHX     ($uams_using_options)])
+               AC_MSG_RESULT([         RANDNUM ($uams_using_options)])
+       fi
+       if test x"$netatalk_cv_build_krb5_uam" = x"yes"; then
+               AC_MSG_RESULT([         Kerberos V])
+       fi
+       if test x"$compile_kerberos" = x"yes"; then
+               AC_MSG_RESULT([         Kerberos IV])
+       fi
+       if test x"$compile_pgp" = x"yes"; then
+               AC_MSG_RESULT([         PGP])
+       fi
+       AC_MSG_RESULT([         passwd  ($uams_using_options)])
+       AC_MSG_RESULT([         guest])
+       AC_MSG_RESULT([    Options:])
+       AC_MSG_RESULT([         CUPS support:           $netatalk_cv_use_cups])
+       AC_MSG_RESULT([         SLP support:            $netatalk_cv_srvloc])
+       AC_MSG_RESULT([         tcp wrapper support:    $netatalk_cv_tcpwrap])
+dnl    if test x"$netatalk_cv_linux_sendfile" != x; then
+dnl            AC_MSG_RESULT([         Linux sendfile support: $netatalk_cv_linux_sendfile])
+dnl    fi
+       AC_MSG_RESULT([         quota support:          $netatalk_cv_quotasupport])
+       AC_MSG_RESULT([         admin group support:    $netatalk_cv_admin_group])
+       AC_MSG_RESULT([         valid shell check:      $netatalk_cv_use_shellcheck])
+       AC_MSG_RESULT([         cracklib support:       $netatalk_cv_with_cracklib])
+       AC_MSG_RESULT([         dropbox kludge:         $netatalk_cv_dropkludge])
+       AC_MSG_RESULT([         force volume uid/gid:   $netatalk_cv_force_uidgid])
+       AC_MSG_RESULT([         Apple 2 boot support:   $compile_a2boot])
+       if test x"$use_pam_so" = x"yes" -a x"$netatalk_cv_install_pam" = x"no"; then
+               AC_MSG_RESULT([])
+               AC_MSG_WARN([ PAM support was configured for your system, but the netatalk PAM configuration file])
+               AC_MSG_WARN([ cannot be installed. Please install the config/netatalk.pamd file manually.])
+               AC_MSG_WARN([ If you're running Solaris or BSD you'll have to edit /etc/pam.conf to get PAM working.])
+               AC_MSG_WARN([ You can also re-run configure and specify --without-pam to disable PAM support.])
+       fi
+
+])
+
+
+AC_DEFUN([AC_NETATALK_LIBS_SUMMARY], [
+       dnl #################################################
+       dnl # Display summary of libraries detected
+
+       AC_MSG_RESULT([Using libraries:])
+       AC_MSG_RESULT([    LIBS = $LIBS])
+       AC_MSG_RESULT([    CFLAGS = $CFLAGS])
+       if test x"$compile_ssl" = x"yes"; then
+               AC_MSG_RESULT([    SSL:])
+               AC_MSG_RESULT([        LIBS   = $SSL_LIBS])
+               AC_MSG_RESULT([        CFLAGS = $SSL_CFLAGS])
+       fi
+       if test x"$netatalk_cv_use_pam" = x"yes"; then
+               AC_MSG_RESULT([    PAM:])
+               AC_MSG_RESULT([        LIBS   = $PAM_LIBS])
+               AC_MSG_RESULT([        CFLAGS = $PAM_CFLAGS])
+       fi
+       if test x"$netatalk_cv_use_pam" = x"yes"; then
+               AC_MSG_RESULT([    WRAP:])
+               AC_MSG_RESULT([        LIBS   = $WRAP_LIBS])
+               AC_MSG_RESULT([        CFLAGS = $WRAP_CFLAGS])
+       fi
+       if test x"$bdb_required" = x"yes"; then
+               AC_MSG_RESULT([    BDB:])
+               AC_MSG_RESULT([        LIBS   = $BDB_LIBS])
+               AC_MSG_RESULT([        CFLAGS = $BDB_CFLAGS])
+       fi
+       if test x"$netatalk_cv_build_krb5_uam" = x"yes"; then
+               AC_MSG_RESULT([    GSSAPI:])
+               AC_MSG_RESULT([        LIBS   = $GSSAPI_LIBS])
+               AC_MSG_RESULT([        CFLAGS = $GSSAPI_CFLAGS])
+       fi
+       if test x"$netatalk_cv_srvloc" = x"yes"; then
+               AC_MSG_RESULT([    SRVLOC:])
+               AC_MSG_RESULT([        LIBS   = $SLP_LIBS])
+               AC_MSG_RESULT([        CFLAGS = $SLP_CFLAGS])
+       fi
+       if test x"$netatalk_cv_use_cups" = x"yes"; then
+               AC_MSG_RESULT([    CUPS:])
+               AC_MSG_RESULT([        LIBS   = $CUPS_LIBS])
+               AC_MSG_RESULT([        CFLAGS = $CUPS_CFLAGS])
+       fi
+])
index 50a0ac2e1e483424b2721d05e72fcb21635a97e8..f3d463e8a613efe19b2032e1a804d06281caaede 100644 (file)
@@ -1,4 +1,4 @@
-dnl $Id: tcp-wrappers.m4,v 1.2 2004-01-14 16:10:29 bfernhomberg Exp $
+dnl $Id: tcp-wrappers.m4,v 1.3 2005-04-28 20:50:05 bfernhomberg Exp $
 
 AC_DEFUN([NETATALK_TCP_WRAPPERS], [
        check=maybe
@@ -6,25 +6,36 @@ AC_DEFUN([NETATALK_TCP_WRAPPERS], [
                [  --disable-tcp-wrappers  disable TCP wrappers support],
                [
                        if test "x$enableval" = "xno"; then
-                               check=no
+                               wrapcheck=no
                        else
-                               check=yes
+                               wrapcheck=yes
                        fi
                ]
        )
 
        enable=no
-       if test "x$check" != "xno"; then
-               AC_CHECK_LIB(wrap, tcpd_warn, enable=yes)
+       netatalk_cv_tcpwrap=no
+       if test "x$wrapcheck" != "xno"; then
+               saved_LIBS=$LIBS
+               LIBS="$LIBS -lwrap"
+               AC_TRY_LINK([
+#include <tcpd.h>
+int allow_severity = 0;
+int deny_severity = 0;
+],[
+       tcpd_warn ("link test");
+], netatalk_cv_tcpwrap=yes, netatalk_cv_tcpwrap=no, netatalk_cv_tcpwrap=cross)
+
+               LIBS=$saved_LIBS
        fi
 
        AC_MSG_CHECKING([whether to enable the TCP wrappers])
-       if test "x$enable" = "xyes"; then
+       if test "x$netatalk_cv_tcpwrap" = "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
+               if test "x$wrapcheck" = "xyes"; then
                        AC_MSG_ERROR([libwrap not found])
                else
                        AC_MSG_RESULT([no])
diff --git a/macros/tex-check.m4 b/macros/tex-check.m4
deleted file mode 100644 (file)
index ba788f7..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-# M4 macros to check for the existence of dvips and troff2ps
-# $Id: tex-check.m4,v 1.2 2003-06-07 12:04:52 srittau Exp $
-
-AC_DEFUN([AC_PROG_DVIPS], [
-       AC_ARG_WITH(dvips, [  --with-dvips=PATH       path to the dvips command], [
-               DVIPS="$withval"
-       ], [
-               AC_PATH_PROG(DVIPS, dvips)
-       ])
-       AC_SUBST(DVIPS)
-])
-
-AC_DEFUN([AC_PROG_TROFF2PS], [
-       AC_ARG_WITH(troff2ps, [  --with-troff2ps=PATH    path to the troff2ps command], [
-               TROFF2PS="$withval"
-       ], [
-               AC_PATH_PROG(TROFF2PS, troff2ps)
-       ])
-       AC_SUBST(TROFF2PS)
-])
diff --git a/macros/util.m4 b/macros/util.m4
new file mode 100644 (file)
index 0000000..aea9d55
--- /dev/null
@@ -0,0 +1,24 @@
+dnl Removes -I/usr/include/? from given variable
+AC_DEFUN([CFLAGS_REMOVE_USR_INCLUDE],[
+  ac_new_flags=""
+  for i in [$]$1; do
+    case [$]i in
+    -I/usr/include|-I/usr/include/) ;;
+    *) ac_new_flags="[$]ac_new_flags [$]i" ;;
+    esac
+  done
+  $1=[$]ac_new_flags
+])
+
+dnl Removes -L/usr/lib/? from given variable
+AC_DEFUN([LIB_REMOVE_USR_LIB],[
+  ac_new_flags=""
+  for i in [$]$1; do
+    case [$]i in
+    -L/usr/lib|-L/usr/lib/|-L/usr|-L/usr/) ;;
+    *) ac_new_flags="[$]ac_new_flags [$]i" ;;
+    esac
+  done
+  $1=[$]ac_new_flags
+])
+
index 282522db0342d8750454b3dc162493b5fc709cc8..0ac9461e8a4ab22a449d068e52155a4879735fd3 100644 (file)
@@ -1,2 +1,3 @@
 Makefile
 Makefile.in
+*.1
index b904471ecf90b240beaed889d077d0273fb3c002..4dbf05e30cffd941fac065403f321e2a4d1a4f87 100644 (file)
@@ -1,30 +1,45 @@
 # Makefile.am for man/man1/
 
-man_MANS = \
-       achfile.1               \
-       acleandir.1             \
-       aecho.1                 \
-       afile.1                 \
-       afppasswd.1             \
-       apple_cp.1              \
-       apple_mv.1              \
-       apple_rm.1              \
-       getzones.1              \
-       hqx2bin.1               \
-       macbinary.1             \
-       megatron.1              \
-       nbp.1                   \
-       nbplkup.1               \
-       nbprgstr.1              \
-       nbpunrgstr.1            \
-       netatalk-config.1       \
-       pap.1                   \
-       papstatus.1             \
-       psorder.1               \
-       single2bin.1            \
-       timeout.1               \
-       unbin.1                 \
-       unhex.1                 \
-       unsingle.1
-
-EXTRA_DIST = $(man_MANS)
+pkgconfdir = @PKGCONFDIR@
+
+SUFFIXES= .tmpl .
+
+.tmpl:
+       sed -e s@:SBINDIR:@${sbindir}@ \
+           -e s@:BINDIR:@${bindir}@ \
+           -e s@:ETCDIR:@${pkgconfdir}@ \
+           -e s@:LIBDIR:@${libdir}@ \
+           -e s@:DEFAULT_CNID_SCHEME:@${DEFAULT_CNID_SCHEME}@ \
+           <$< >$@
+
+GENERATED_MANS = apple_cp.1 apple_mv.1 apple_rm.1 uniconv.1 asip-status.pl.1
+TEMPLATE_FILES = apple_cp.1.tmpl apple_mv.1.tmpl apple_rm.1.tmpl uniconv.1.tmpl asip-status.pl.1.tmpl
+NONGENERATED_MANS      =       achfile.1  \
+                               acleandir.1 \
+                               aecho.1 \
+                               afile.1 \
+                               afppasswd.1 \
+                               getzones.1 \
+                               hqx2bin.1 \
+                               macbinary.1 \
+                               megatron.1 \
+                               nbp.1 \
+                               nbplkup.1 \
+                               nbprgstr.1 \
+                               nbpunrgstr.1 \
+                               netatalk-config.1 \
+                               pap.1 \
+                               papstatus.1 \
+                               psorder.1 \
+                               single2bin.1 \
+                               timeout.1 \
+                               unbin.1 \
+                               unhex.1 \
+                               unsingle.1
+
+man_MANS = $(GENERATED_MANS) $(NONGENERATED_MANS)
+
+CLEANFILES = $(GENERATED_MANS)
+
+EXTRA_DIST = $(TEMPLATE_FILES) $(NONGENERATED_MANS)
+
index 2f0ea9c221297e4cce5d640718ed934a8ea3aac0..596b67d6e4b1919b2f338eb92971c83937373b13 100644 (file)
@@ -1,40 +1,20 @@
-.TH ACHFILE 1 "26 Feb 1998" 
+.TH achfile 1 "26 Feb 1998" 2.0.0 Netatalk 
 .SH NAME
-achfile \- change type and/or creator of Apple Macintosh  files (netatalk format)
+achfile \- change type and/or creator of Apple Macintosh files (netatalk format)
 .SH SYNOPSIS
-.B achfile 
-[
-.B -t
-.I type
-]
-[
-.B -c
-.I creator
-]
-.I file ...
-
+\fBachfile\fR [ \-t \fBtype\fR ] [ \-c \fBcreator\fR ] \fBfile\fR \&...
 .SH DESCRIPTION
-.B achfile
-changes the Macintosh  type and/or creator of the 
-.I file
-arguments which have a
+achfile changes the Macintosh type and/or creator
+of the \fIfile\fR arguments which have a
 corresponding .AppleDouble file.
-
 .SH OPTIONS
-.HP
-.B -t 
-.I type
-.br
-change the type.
-
-.HP
-.B -c
-.I creator
-.br
-change the creator.
-
+\fB\-t\fR \fItype\fR change the type.
+.PP
+\fB\-c\fR \fIcreator\fR change the
+creator.
 .SH DIAGNOSTICS
 returns exit status 0 if all files changed successfully
-.SH SEE ALSO
-.BR afile (1),
-.BR afpd (1)
+.SH "SEE ALSO"
+\fBafile\fR(1),
+\fBafpd\fR(8)
+
index 0a2949ae0b3f3225cd3a4da9687f85e3b0f6abfb..97ac752a1896fe5cbc13ce97c32d3727d4a8d1a2 100644 (file)
@@ -1,65 +1,49 @@
-.TH ACLEANDIR 1 "26 Feb 1998" 
+.TH acleandir 1 "26 Feb 1998" 2.0.0 Netatalk 
 .SH NAME
-acleandir \- clean up a directory containing netatalk Apple Macintosh files 
+acleandir \- clean up a directory containing netatalk Apple Macintosh files
 .SH SYNOPSIS
-.B acleandir 
-[
-.B -rnvi
-]
-.I dirname
-
+\fBacleandir\fR [\-rnvi] \fBdirname\fR 
+.sp 1
 .SH DESCRIPTION
-.B acleandir
-cleans up the directory
-.I dirname.
-By default 
-it simply removes
-"orphan" AppleDouble files, i.e. those
-which do not have a corresponding data file.
+acleandir cleans up the directory \fIdirname.\fR By default it simply removes
+"orphan" AppleDouble files, i.e. those which do not have a
+corresponding data file.
 .SH OPTIONS
-.TP
-.B -d
-Also remove the .AppleDouble directory if it contains no AppleDouble
-files after "orphan" removal. This will result in the finder location of 
-.I dirname
+.TP 
+\fB\-d\fR
+Also remove the .AppleDouble directory if it contains no
+AppleDouble files after "orphan" removal. This will result
+in the finder location of \fIdirname\fR
 within its parent being lost.
-.TP
-.B -r
-.PD 0
-.TP
-.B -R
+.TP 
+\fB\-r\fR, \fB\-R\fR
 Recursive. Clean up directories recursively.
-
-.TP
-.B -n
-Display the filenames of "orphans" but don't remove any. Display size
-if "orphan" appears to contain a resource fork.
-
-.TP
-.B -i
-Interactive. Prompt for confirmation before a removal.
-A y in answer confirms that the removal should proceed.
-
-.TP
-.B -v
-Verbose. Display the names of all "orphans" and .AppleDouble directories removed. Reports the size if the "orphan" appears to contain a resource fork.
-
-.TP
-.B -a
-Aggressive. Remove all AppleDouble files, not just "orphans".  Also remove
-the .AppleDesktop directory if present.
-Impies
-.B -d 
-option. 
-Use with caution as the Macintosh type/creator and finder location
-of all files will be lost and  the content of some documents, such
-as Symantec Projects, will be destroyed.
-
+.TP 
+\fB\-n\fR
+Display the filenames of "orphans" but don't
+remove any. Display size if "orphan" appears to contain a
+resource fork.
+.TP 
+\fB\-i\fR
+Interactive. Prompt for confirmation before a removal. A y in
+answer confirms that the removal should proceed.
+.TP 
+\fB\-v\fR
+Verbose. Display the names of all "orphans" and
+\&.AppleDouble directories removed. Reports the size if the
+"orphan" appears to contain a resource fork.
+.TP 
+\fB\-a\fR
+Aggressive. Remove all AppleDouble files, not just
+"orphans". Also remove the .AppleDesktop directory if
+present. Impies \fB\-d\fR option. Use with caution as the
+Macintosh type/creator and finder location of all files will be lost
+and the content of some documents, such as Symantec Projects, will
+be destroyed.
 .SH DIAGNOSTICS
-returns exit status 0 unless bad options are provided  or a directory is not given
-on the command line.
+returns exit status 0 unless bad options are provided or a directory
+is not given on the command line.
+.SH "SEE ALSO"
+\fBafile\fR(1),
+\fBafpd\fR(8)
 
-.SH SEE ALSO
-.BR afile (1),
-.BR afpd (1)
index eb799adfe7bf8a6dce52458ee71a0c4ec17de240..f5d915173fdf0025b27d3317a81f15737436d293 100644 (file)
@@ -1,68 +1,50 @@
-.TH AECHO 1 "17 Dec 1991" "netatalk 1.2"
+.TH aecho 1 "17 Dec 1991" 2.0.0 Netatalk 
 .SH NAME
 aecho \- send AppleTalk Echo Protocol packets to network hosts
 .SH SYNOPSIS
-.B aecho
-[
-.B \-c\fI count
-]
-{
-.I address
-|
-.I nbpname
-}
+aecho [ \fB\-c\fR\fI count\fR
+] ( address | nbpname )
 .SH DESCRIPTION
-.B aecho
-repeatedly sends an Apple Echo Protocol (AEP) packet to the host
-specified by the given AppleTalk
-.I address
-or
-.I nbpname
-and reports whether a reply was received.  Requests are sent at the
-rate of one per second.
-.LP
-.I address
-is parsed by
-.BR atalk_aton (3).
-.I nbpname
-is parsed by
-.BR nbp_name (3).
-The nbp type defaults to
-.RB ` Workstation '.
-.LP
-When
-.B aecho
-is terminated, it reports the number of packets sent, the number of
-responses received, and the percentage of packets lost.  If any
-responses were received, the minimum, average, and maximum round trip
-times are reported.
+aecho repeatedly sends an Apple Echo Protocol
+(AEP) packet to the host specified by the given AppleTalk
+address or nbpname and reports
+whether a reply was received. Requests are sent at the rate of one per
+second.
+.PP
+address is parsed by
+\fBatalk_aton\fR(3).
+nbpname is parsed by \fBnbp_name\fR(3).
+The nbp type defaults to `\fIWorkstation\fR'.
+.PP
+When aecho is terminated, it reports the number
+of packets sent, the number of responses received, and the percentage of
+packets lost. If any responses were received, the minimum, average, and
+maximum round trip times are reported.
 .SH EXAMPLE
-Check to see if a particular host is up and responding to AEP packets:
-.sp
-.RS
+Check to see if a particular host is up and responding to AEP
+packets:
+.PP
 .nf
-       example% aecho bloodsport
-       11 bytes from 8195.13: aep_seq=0. time=10. ms
-       11 bytes from 8195.13: aep_seq=1. time=10. ms
-       11 bytes from 8195.13: aep_seq=2. time=10. ms
-       11 bytes from 8195.13: aep_seq=3. time=10. ms
-       11 bytes from 8195.13: aep_seq=4. time=10. ms
-       11 bytes from 8195.13: aep_seq=5. time=9. ms
-       ^C
-       ----8195.13 AEP Statistics----
-       6 packets sent, 6 packets received, 0% packet loss
-       round-trip (ms)  min/avg/max = 9/9/10
-.fi
-.RE
+example% \fBaecho bloodsport
+11 bytes from 8195.13: aep_seq=0. time=10. ms
+11 bytes from 8195.13: aep_seq=1. time=10. ms
+11 bytes from 8195.13: aep_seq=2. time=10. ms
+11 bytes from 8195.13: aep_seq=3. time=10. ms
+11 bytes from 8195.13: aep_seq=4. time=10. ms
+11 bytes from 8195.13: aep_seq=5. time=9. ms
+^C
+\-\-\-\-8195.13 AEP Statistics\-\-\-\-
+6 packets sent, 6 packets received, 0% packet loss
+round\-trip (ms)  min/avg/max = 9/9/10
+\fR.fi
 .SH OPTIONS
-.TP
-.B \-c\fI count
-Stop after
-.I count
-packets.
-.SH SEE ALSO
-.BR ping (1),
-.BR atalk_aton (3),
-.BR nbp_name (3),
-.\" .BR aep (4),
-.BR atalkd (8).
+.TP 
+\fB\-c\fR\fI count\fR
+Stop after \fIcount\fR packets.
+.SH "SEE ALSO"
+\fBping\fR(1),
+\fBatalk_aton\fR(3),
+\fBnbp_name\fR(3),
+\fBaep\fR(4),
+\fBatalkd\fR(8).
+
index 5aa37b7be68ccd7f56a161b8be71917eff1520e0..3e120cb01ddd01206fceac909eee8deee8ca1ef0 100644 (file)
@@ -1,55 +1,48 @@
-.TH AFILE 1 "26 Feb 1998" 
+.TH afile 1 "26 Feb 1998" 2.0.0 Netatalk 
 .SH NAME
 afile \- display type and creator of Apple Macintosh files (netatalk format)
 .SH SYNOPSIS
-.B afile 
-[
-.B -a
-]
-.I file ...
-
+\fBafile\fR [\-a] \fBfile\fR \&...
+.sp 1
 .SH DESCRIPTION
-.B afile
-displays the name and Macintosh type and creator of the 
-.I file
-arguments. Tests whether the file is an AppleDouble header,
-in which case it checks the corresponding data fork exists, or assumes
-it is a data fork in which case it looks for the corresponding AppleDouble
-to find the type/creator information.
-
-.LP
-.B afile
-does not look at any of the extension mapping files such
-as AppleVolumes.system.
-
+afile displays the name and Macintosh type and
+creator of the \fIfile\fR arguments. Tests
+whether the file is an AppleDouble header, in which case it checks the
+corresponding data fork exists, or assumes it is a data fork in which case
+it looks for the corresponding AppleDouble to find the type/creator
+information.
+.PP
+afile does not look at any of the extension
+mapping files such as AppleVolumes.system.
 .SH OPTIONS
-.TP
-.B -a
-Include directories and data files of unknown type (i.e. without 
-corresponding AppleDouble) in output.
-
+.TP 
+\fB\-a\fR
+Include directories and data files of unknown type (i.e.
+without corresponding AppleDouble) in output.
 .SH DIAGNOSTICS
-returns exit status 0 if all files have a corresponding valid  .AppleDouble header or data fork, or 99 for bad command line options. Otherwise it returns the following error code relating to the last invalid file.
-.br
+returns exit status 0 if all files have a corresponding valid
+\&.AppleDouble header or data fork, or 99 for bad command line options.
+Otherwise it returns the following error code relating to the last invalid
+file.
+.PP
+1 file doesn't exist
+.PP
+2 file is unreadable
+.PP
+3 file is directory
+.PP
+4 file is AppleDouble without data fork
+.PP
+5 file is AppleDouble with unreadable data fork
+.PP
+6 file is data fork without AppleDouble
+.PP
+7 file is data fork with unreadable AppleDouble
+.PP
+8 file is data fork with short AppleDouble
+.PP
+9 bad magic in AppleDouble
+.SH "SEE ALSO"
+\fBachfile\fR(1),
+\fBafpd\fR(8)
 
-1  file doesn't exist
-.br
-2  file is unreadable
-.br
-3  file is directory
-.br
-4  file is AppleDouble without data fork
-.br
-5  file is AppleDouble with unreadable data fork
-.br
-6  file is data fork without AppleDouble
-.br
-7  file is data fork with unreadable AppleDouble
-.br
-8  file is data fork with short AppleDouble
-.br
-9  bad magic in AppleDouble
-.SH SEE ALSO
-.BR achfile (1),
-.BR afpd (1)
index 81aa3eaa79917ad5e5b6fff846ff0fe9a1c84957..601a4d87c950e244f6ffb8e1970e3ae87e2dac06 100644 (file)
@@ -1,69 +1,63 @@
-.TH AFPPASSWD 1 "03 Aug 2000" "netatalk 1.5"
+.TH afppasswd 1 "22 Aug 2004" 2.0.0 Netatalk 
 .SH NAME
 afppasswd \- netatalk password maintenance utility
 .SH SYNOPSIS
-.B afppasswd
-[
-.B \-acfn
-]
-[
-.B \-p\fI passwd file
-]
-[
-.B \-u\fI minimum uid
-]
+\fBafppasswd\fR [\-acfn] [ \-p
+\fBpasswd\fR \fBfile\fR ] [ \-u
+\fBminimum\fR \fBuid\fR ]
 .SH DESCRIPTION
-.B afppasswd
-allows the maintenance of afppasswd files created by netatalk for
-use by some User Authentication Modules (UAMs)
-.LP
-.B afppasswd
-can either be called by root with parameters, or can be called by
-local system users with no parameters to change their passwords.
+afppasswd allows the maintenance of afppasswd
+files created by netatalk for use by the uams_randnum.so UAM (providing
+the "Randnum exchange" and "2\-Way Randnum exchange" User Authentication
+Modules).
+.PP
+afppasswd can either be called by root with
+parameters, or can be called by local system users with no parameters to
+change their AFP passwords.
+.RS 
+\fBNote\fR
+.PP
+With this utility you can only change the passwords used by two
+specific UAMs. As they provide only weak password encryption, the use of
+the "Randnum exchange" and "2\-Way Randnum exchange" UAMs is deprecated
+unless one has to support very old AFP clients, that can not deal with
+the more secure "DHCAST128" UAM instead. Please compare with the [Cross reference to non\-existant ID \(lqauthentication\(rq] inside Netatalk's
+documentation.
+.RE
 .SH EXAMPLE
 Local user changing their own password:
-.sp
-.RS
+.PP
 .nf
-       example% afppasswd
-       Enter NEW AFP password: (hidden)
-       Enter NEW AFP password again: (hidden)
-       afppasswd: updated password.
+example% \fBafppasswd\fR
+Enter NEW AFP password: \fB(hidden)\fR
+Enter NEW AFP password again: \fB(hidden)\fR
+afppasswd: updated password.
 .fi
-.RE
 .SH OPTIONS
-.TP
-.B \-a
-Add a new user to the
-.B afppasswd
+.TP 
+\fB\-a\fR
+Add a new user to the afppasswd
 file.
-.TP
-.B \-c
-Create and/or initialize
-.B afppasswd
-file or specific user.
-.TP
-.B \-f
+.TP 
+\fB\-c\fR
+Create and/or initialize afppasswd file or
+specific user.
+.TP 
+\fB\-f\fR
 Force the current action.
-.TP
-.B \-p\fI path
-Path to
-.B afppasswd
-file.
-.TP
-.B \-n
-If cracklib support is built into
-.B netatalk
-this option will cause cracklib checking to be disabled, if the
-superuser does not want to have the password run against the
-cracklib dictionary.
-.TP
-.B \-u\fI minimum uid
-This is the minimum
-.I user id
-(uid) that
-.B afppasswd
-will use when creating users.
-.SH SEE ALSO
-.BR afpd (8),
-.BR atalkd (8).
+.TP 
+\fB\-p\fR\fI path\fR
+Path to afppasswd file.
+.TP 
+\fB\-n\fR
+If cracklib support is built into \fInetatalk\fR this option will cause cracklib
+checking to be disabled, if the superuser does not want to have the
+password run against the cracklib dictionary.
+.TP 
+\fB\-u\fR\fI minimum uid\fR
+This is the minimum \fIuser id\fR
+(uid) that afppasswd will use when creating
+users.
+.SH "SEE ALSO"
+\fBafpd\fR(8), \fBatalkd\fR(8).
+
diff --git a/man/man1/apple_cp.1 b/man/man1/apple_cp.1
deleted file mode 100644 (file)
index c088772..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-.TH APPLE_CP 1 "15 Oct 2001" "Netatalk 1.5"
-.SH NAME
-apple_cp \- Do an apple copy, copying the resource fork as well
-.SH SYNOPSIS
-.BR apple_cp
-\fISOURCE DEST\fR
-.br
-.BR apple_cp
-\fISOURCE\fR... \fIDIRECTORY\fR
-
-.SH DESCRIPTION
-.BR apple_cp
-is a perl script to copy SOURCE to DEST or multiple SOURCE(s) to
-DIRECTORY. It also copies the resource forks to the .AppleDouble
-directory for DEST or DIRECTORY. If the .AppleDouble directory doesn't
-exist for DEST or DIRECTORY it will create it.
-
-.SH EXAMPLES
-
-.BR apple_cp
-test.text /target/directory/
-
-.BR apple_cp
-test.text /target/directory/test2.text
-
-.BR apple_cp
-test.text testing.text /target/directory/
-
-.SH REPORTING BUGS
-Report bugs to the Netatalk-devel list <netatalk-devel@lists.sourceforge.net>.
-
-.SH SEE ALSO
-.BR apple_mv (1),
-.BR apple_rm (1).
diff --git a/man/man1/apple_cp.1.tmpl b/man/man1/apple_cp.1.tmpl
new file mode 100644 (file)
index 0000000..153b74d
--- /dev/null
@@ -0,0 +1,28 @@
+.TH apple_cp 1 "22 Aug 2004" 2.0.0 Netatalk 
+.SH NAME
+apple_cp \- Do an apple copy, copying file metadata and the resource fork as well
+.SH SYNOPSIS
+\fI:BINDIR:/apple_cp\fR \fISOURCE
+DEST\fR \fI:BINDIR:/apple_cp\fR \fISOURCE\fR... \fIDIRECTORY\fR
+.SH DESCRIPTION
+\fIapple_cp\fR is a perl script to copy
+SOURCE to DEST or multiple SOURCE(s) to DIRECTORY. It also copies the file 
+specific metadata (including resource forks) to the .AppleDouble directory
+for DEST or DIRECTORY. If the .AppleDouble directory doesn't exist for 
+DEST or DIRECTORY it will create it.
+.SH EXAMPLES
+\fI:BINDIR:/apple_cp\fR test.text
+/target/directory/
+.PP
+\fI:BINDIR:/apple_cp\fR test.text
+/target/directory/test2.text
+.PP
+\fI:BINDIR:/apple_cp\fR test.text
+testing.text /target/directory/
+.SH "REPORTING BUGS"
+Report bugs to the Netatalk\-devel list
+<netatalk\-devel@lists.sourceforge.net>.
+.SH "SEE ALSO"
+\fBapple_mv\fR(1),
+\fBapple_rm\fR(1).
+
diff --git a/man/man1/apple_mv.1 b/man/man1/apple_mv.1
deleted file mode 100644 (file)
index 4450605..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-.TH APPLE_MV 1 "16 Oct 2001" "Netatalk 1.5"
-.SH NAME
-apple_mv \- Do an apple move, moving the resource fork as well
-.SH SYNOPSIS
-.BR apple_mv
-\fISOURCE DEST\fR
-.br
-.BR apple_mv
-\fISOURCE\fR... \fIDIRECTORY\fR
-
-.SH DESCRIPTION
-.BR apple_mv
-is a perl script to move SOURCE to DEST or multiple SOURCE(s) to
-DIRECTORY. It also moves the resource forks to the .AppleDouble
-directory for DEST or DIRECTORY. If the .AppleDouble directory doesn't
-exist for DEST or DIRECTORY it will create it.
-
-.SH EXAMPLES
-
-.BR apple_mv
-test.text /target/directory/
-
-.BR apple_mv
-test.text /target/directory/test2.text
-
-.BR apple_mv
-test.text testing.text /target/directory/
-
-.SH REPORTING BUGS
-Report bugs to the Netatalk-devel list <netatalk-devel@lists.sourceforge.net>.
-
-.SH SEE ALSO
-.BR apple_cp (1),
-.BR apple_rm (1).
diff --git a/man/man1/apple_mv.1.tmpl b/man/man1/apple_mv.1.tmpl
new file mode 100644 (file)
index 0000000..0225736
--- /dev/null
@@ -0,0 +1,28 @@
+.TH apple_mv 1 "22 Aug 2004" 2.0.0 Netatalk 
+.SH NAME
+apple_mv \- Do an apple move, moving metadata and the resource fork as well
+.SH SYNOPSIS
+\fI:BINDIR:/apple_mv\fR \fISOURCE
+DEST\fR \fI:BINDIR:/apple_mv\fR \fISOURCE\fR... \fIDIRECTORY\fR
+.SH DESCRIPTION
+\fIapple_mv\fR is a perl script to move
+SOURCE to DEST or multiple SOURCE(s) to DIRECTORY. It also moves the file 
+specific metadata (including resource forks) to the .AppleDouble directory
+for DEST or DIRECTORY. If the .AppleDouble directory doesn't exist for 
+DEST or DIRECTORY it will create it.
+.SH EXAMPLES
+\fI:BINDIR:/apple_mv\fR test.text
+/target/directory/
+.PP
+\fI:BINDIR:/apple_mv\fR test.text
+/target/directory/test2.text
+.PP
+\fI:BINDIR:/apple_mv\fR test.text
+testing.text /target/directory/
+.SH "REPORTING BUGS"
+Report bugs to the Netatalk\-devel list
+<netatalk\-devel@lists.sourceforge.net>.
+.SH "SEE ALSO"
+\fBapple_cp\fR(1),
+\fBapple_rm\fR(1).
+
diff --git a/man/man1/apple_rm.1 b/man/man1/apple_rm.1
deleted file mode 100644 (file)
index fa8a1a1..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-.TH APPLE_RM 1 "16 Oct 2001" "Netatalk 1.5"
-.SH NAME
-apple_rm \- Do an apple remove, remove the resource fork as well
-
-.SH SYNOPSIS
-.BR apple_rm
-\fIFILE\fR...
-
-.SH DESCRIPTION
-.BR apple_rm
-is a perl script that removes FILE(s) as well as the .AppleDouble
-resource fork file(s) that corresponds to FILE(s). 
-.BR apple_rm
-does not delete directories.
-
-.SH EXAMPLES
-
-.BR apple_rm
-test.text 
-
-.BR apple_rm
-test.text testing.text
-
-.SH REPORTING BUGS
-Report bugs to the Netatalk-devel list <netatalk-devel@lists.sourceforge.net>.
-
-.SH SEE ALSO
-.BR apple_cp (1),
-.BR apple_mv (1).
-
diff --git a/man/man1/apple_rm.1.tmpl b/man/man1/apple_rm.1.tmpl
new file mode 100644 (file)
index 0000000..99a48ce
--- /dev/null
@@ -0,0 +1,21 @@
+.TH apple_rm 1 "22 Aug 2004" 2.0.0 Netatalk 
+.SH NAME
+apple_rm \- Do an apple remove, remove metadata and resource fork as well
+.SH SYNOPSIS
+\fI:BINDIR:/apple_rm\fR \fIFILE\fR...
+.SH DESCRIPTION
+\fIapple_rm\fR is a perl script that
+removes FILE(s) as well as the .AppleDouble metadata file(s) that
+corresponds to FILE(s). These AppleDouble header files eventually also
+contain the resource fork if the files had one. \fIapple_rm\fR does not delete directories.
+.SH EXAMPLES
+\fI:BINDIR:/apple_rm\fR test.text
+.PP
+\fI:BINDIR:/apple_rm\fR test.text
+testing.text
+.SH "REPORTING BUGS"
+Report bugs to the Netatalk\-devel list
+<netatalk\-devel@lists.sourceforge.net>.
+.SH "SEE ALSO"
+\fBapple_cp\fR(1), \fBapple_mv\fR(1).
+
diff --git a/man/man1/asip-status.pl.1.tmpl b/man/man1/asip-status.pl.1.tmpl
new file mode 100644 (file)
index 0000000..1dd043b
--- /dev/null
@@ -0,0 +1,59 @@
+.TH asip\-status.pl 1 "22 Aug 2004" 2.0.0 Netatalk 
+.SH NAME
+asip\-status.pl \- Queries AFP servers for their capabilities
+.SH SYNOPSIS
+\fI:BINDIR:/asip\-status.pl\fR ADDRESS\fI:PORT\fR...
+.SH DESCRIPTION
+\fIasip\-status.pl\fR is a perl script that
+sends a FPGetSrvrInfo request to an AFP server at ADDRESS:PORT and
+displays the results, namely "Machine type", the server's name, supported
+AFP versions, UAMs and AFP flags, the "server signature" and the network
+addresses, the server provides AFP services on.
+.PP
+When you don't supply :PORT, then the default AFP port, 548, will be
+used.
+.SH EXAMPLES
+.nf
+\fI:BINDIR:/asip\-status.pl\fR 192.168.21.2
+AFP reply from 192.168.21.2:548
+Flags: 1  Cmd: 3  ID: 57005
+Reply: DSIGetStatus
+Request ID: 57005
+Machine type: Macintosh
+AFP versions: AFPVersion 1.1,AFPVersion 2.0,AFPVersion 2.1,AFP2.2
+UAMs: Cleartxt passwrd,Randnum exchange,2\-Way Randnum exchange
+Flags: SupportsCopyFile,SupportsChgPwd,SupportsServerMessages,
+SupportsServerSignature,SupportsTCP/IP,SupportsSuperClient
+Server name: PowerMac 9600/200
+Signature:
+04 c1 6e 59 04 c1 6e 59 04 c1 6e 59 04 c1 6e 59  ..nY..nY..nY..nY
+                                                  
+Network address: 192.168.21.2:548 (tcp/ip address and port)
+Network address: 10.20 (ddp address)
+.fi
+.PP
+.nf
+\fI:BINDIR:/asip\-status.pl\fR 192.168.21.1:10548
+AFP reply from 192.168.21.1:10548
+Flags: 1  Cmd: 3  ID: 57005
+Reply: DSIGetStatus
+Request ID: 57005
+Machine type: Netatalk
+AFP versions: AFPVersion 1.1,AFPVersion 2.0,AFPVersion 2.1,AFP2.2,AFPX03,
+AFP3.1
+UAMs: Cleartxt passwrd,Randnum exchange,2\-Way Randnum exchange,DHCAST128
+Flags: SupportsCopyFile,SupportsServerMessages,SupportsServerSignature,
+SupportsTCP/IP,SupportsSrvrNotifications,SupportsOpenDirectory,
+SupportsUTF8Servername,SupportsSuperClient
+Server name: Fire V480
+Signature:
+83 29 cc 60 83 29 cc 60 83 29 cc 60 83 29 cc 60  .).`.).`.).`.).`
+                                                  
+Network address: 192.168.21.1:10548 (TCP/IP address and port)
+Network address: 65282.142 (ddp address)
+UTF8 Servername: Fire V480
+.fi
+.SH "REPORTING BUGS"
+Report bugs to the Netatalk\-devel list
+<netatalk\-devel@lists.sourceforge.net>.
+
index 188df2d1580def61e183db8f23f72e437f71d5c6..47eaf86749a7794c0c143cecad98b792064deea5 100644 (file)
@@ -1,39 +1,28 @@
-.TH GETZONES 1 "17 Dec 1991" "netatalk 1.2"
+.TH getzones 1 "17 Dec 1991" 2.0.0 Netatalk 
 .SH NAME
 getzones \- list AppleTalk zone names
 .SH SYNOPSIS
-.B getzones
-[
-.B -m
-|
-.B -l
-] [
-.I address
-]
+\fBgetzones\fR [\-m | \-l] [\fBaddress\fR]
 .SH DESCRIPTION
-.B Getzones
-is used to obtain a list of AppleTalk zone names using the Zone
-Information Protocol (ZIP).  It sends a GetZoneList request to an
-AppleTalk router.  By default, it sends the request to the locally
-running
-.BR atalkd (8).
+\fIGetzones\fR is used to obtain a list of
+AppleTalk zone names using the Zone Information Protocol (ZIP). It sends a
+GetZoneList request to an AppleTalk router. By default, it sends the
+request to the locally running \fBatalkd\fR(8).
 .SH OPTIONS
-.TP
-.B -m
-List the name of the local zone only; this is accomplished by sending a
-ZIP GetMyZone request.
-.TP
-.B -l
-List the local zones; this is accomplished by sending a GetLocalZones
-request.
-.TP
-.I address
-Contact the AppleTalk router at
-.I address.
-.I address
-is parsed by
-.BR atalk_aton (3).
-.SH SEE ALSO
-.BR atalk_aton (3),
-.\" .BR zip (4),
-.BR atalkd (8).
+.TP 
+\fB\-m\fR
+List the name of the local zone only; this is accomplished by
+sending a ZIP GetMyZone request.
+.TP 
+\fB\-l\fR
+List the local zones; this is accomplished by sending a
+GetLocalZones request.
+.TP 
+\fIaddress\fR
+Contact the AppleTalk router at \fIaddress.\fR
+\fIaddress\fR is parsed by
+\fBatalk_aton\fR(3).
+.SH "SEE ALSO"
+\fBatalk_aton\fR(3),
+\fBatalkd\fR(8).
+
index 1b8be127cc22905f874cf427261814c4e2e65b11..98bc866068a3293a3bda9bb88e8e52db5ae89f0d 100644 (file)
-.TH MEGATRON 1 "8 Jan 1992" "netatalk 1.2"
+.TH megatron 1 "8 Jan 1992" 2.0.0 Netatalk 
 .SH NAME
 megatron, unhex, unbin, unsingle, hqx2bin, single2bin, macbinary \- Macintosh file format transformer
 .SH SYNOPSIS
-.B megatron
-[
-.I sourcefile...
-]
-.LP
-.B unbin
-[
-.I sourcefile...
-]
-.LP
-.B unhex
-[
-.I sourcefile...
-]
-.LP
-.B unsingle
-[
-.I sourcefile...
-]
-.LP
-.B hqx2bin
-[
-.I sourcefile...
-]
-.LP
-.B single2bin
-[
-.I sourcefile...
-]
-.LP
-.B macbinary
-[
-.I sourcefile...
-]
+\fBmegatron\fR [\fBsourcefile\fR]\&...
+.sp 1
+\fBunbin\fR [\fBsourcefile\fR]\&...
+.sp 1
+\fBunhex\fR [\fBsourcefile\fR]\&...
+.sp 1
+\fBunsingle\fR [\fBsourcefile\fR]\&...
+.sp 1
+\fBhqx2bin\fR [\fBsourcefile\fR]\&...
+.sp 1
+\fBsingle2bin\fR [\fBsourcefile\fR]\&...
+.sp 1
+\fBmacbinary\fR [\fBsourcefile\fR]\&...
 .SH DESCRIPTION
-.B megatron
-is used to transform files from BinHex, MacBinary, AppleSingle, or 
-.B netatalk
-style AppleDouble formats into MacBinary or
-.B netatalk 
-style AppleDouble formats.  The
-.B netatalk
-style AppleDouble format is the file format used by
-.B afpd,
-the
-.B netatalk
-Apple Filing Protocol (AppleShare) server.  BinHex, MacBinary, and
-AppleSingle are commonly used formats for transferring Macintosh files
-between machines via email or file transfer protocols.
-.B megatron
-uses its name to determine what type of tranformation is being asked of
-it.
-.LP
-If
-.B megatron
-is called as
-.B unhex, unbin,
-or
-.B unsingle,
-it tries to convert file(s) from BinHex, MacBinary, or AppleSingle into
-AppleDouble format.  BinHex is the format most often used to send
-Macintosh files by e-mail.  Usually these files have an extension of
-".hqx".  MacBinary is the format most often used by terminal emulators
-"on the fly" when transferring Macintosh files in binary mode.
-MacBinary files often have an extension of ".bin".  Some Macintosh
-LAN-based email packages use uuencoded AppleSingle format to "attach"
-or "enclose" files in email.  AppleSingle files don't have a standard
-filename extension.
-.LP
-If
-.B megatron
-is called as
-.B hqx2bin, single2bin,
-or
-.B macbinary,
-it will try to convert the file(s) from BinHex, AppleSingle, or
-AppleDouble into MacBinary.  This last translation may be useful in
-moving Macintosh files from your
-.B afpd
-server to some other machine when you can't copy them from the server
-using a Macintosh for some reason.
-.LP
-If
-.B megatron
-is called with any other name, it uses the default translation, namely
-.B unhex.
-.LP
-If no source file is given, or if
-.I sourcefile
-is
-.RB ` - ',
-and if the conversion is from a BinHex or MacBinary file,
-.B megatron
+megatron is used to transform files from BinHex,
+MacBinary, AppleSingle, or \fBnetatalk\fR style
+AppleDouble formats into MacBinary or \fInetatalk\fR
+style AppleDouble formats. The \fInetatalk\fR
+style AppleDouble format is the file format used by \fIafpd,\fR
+the \fInetatalk\fR Apple Filing Protocol
+(AppleShare) server. BinHex, MacBinary, and AppleSingle are commonly used
+formats for transferring Macintosh files between machines via email or
+file transfer protocols. megatron uses its name to
+determine what type of tranformation is being asked of it.
+.PP
+If megatron is called as unhex
+, unbin or unsingle, it tries to
+convert file(s) from BinHex, MacBinary, or AppleSingle into AppleDouble
+format. BinHex is the format most often used to send Macintosh files by
+e\-mail. Usually these files have an extension of ".hqx". MacBinary
+is the format most often used by terminal emulators "on the fly"
+when transferring Macintosh files in binary mode. MacBinary files often
+have an extension of ".bin". Some Macintosh LAN\-based email
+packages use uuencoded AppleSingle format to "attach" or
+"enclose" files in email. AppleSingle files don't have a
+standard filename extension.
+.PP
+If megatron is called as hqx2bin,
+single2bin, or macbinary, it will
+try to convert the file(s) from BinHex, AppleSingle, or AppleDouble into
+MacBinary. This last translation may be useful in moving Macintosh files
+from your afpd server to some other machine when you
+can't copy them from the server using a Macintosh for some reason.
+.PP
+If megatron is called with any other name, it
+uses the default translation, namely unhex.
+.PP
+If no source file is given, or if \fIsourcefile\fR
+is `\fB\-\fR', and if the
+conversion is from a BinHex or MacBinary file, megatron
 will read from standard input.
-.LP
+.PP
 The filename used to store any output file is the filename that is
-encoded in the source file.  MacBinary files are created with a ".bin"
-extension.  In the case of conflicts, the old file is overwritten!
-.SH SEE ALSO
-.BR afpd (8)
+encoded in the source file. MacBinary files are created with a
+".bin" extension. In the case of conflicts, the old file is
+overwritten!
+.SH "SEE ALSO"
+\fBafpd\fR(8)
+
index fe2607ecae26925735f27e1906c772acade16ac0..ed2a324bd1b284d77d2bccc4115b18383eac124b 100644 (file)
@@ -1,69 +1,44 @@
-.TH NBP 1 "17 Dec 1991" "netatalk 1.2"
+.TH nbp 1 "24 June 2004" 2.0.0 Netatalk 
 .SH NAME
 nbplkup, nbprgstr, nbpunrgstr \- access NBP database
 .SH SYNOPSIS
-.B nbplkup
-[
-.B -r
-.I nresp
-]
-[
-.I nbpname
-]
-.sp
-.B nbprgstr
-[
-.B -p
-.I port
-]
-.I nbpname
-.sp
-.B nbpunrgstr
-.I nbpname
+\fBnbplkup \fR[\-r \fBmaxresponses\fR] [\-A \fBaddress\fR] [\-m \fBmaccodepage\fR] \fBnbpname\fR 
+.PP
+\fBnbprgstr \fR[\-A \fBaddress\fR] [\-p \fBport\fR] [\-m \fBmaccodepage\fR] \fBnbpname\fR 
+.PP
+\fBnbpunrgstr \fR[\-A \fBaddress\fR] [\-m \fBmaccodepage\fR] \fBnbpname\fR 
 .SH DESCRIPTION
-.B nbprgstr
-registers
-.I nbpname
-with
-.BR atalkd (8),
-at the given
-.IR port .
-.B nbpunrgstr
-informs
-.B atalkd
-that
-.I nbpname
-is no longer to be advertised.
-.LP
-.B nbplkup
-displays up to
-.I nresp
-(default 1000) entities registered on the AppleTalk internet.
-.I nbpname
-is parsed by
-.BR nbp_name (3).
-An
-.RB ` = '
-for the
-.I object
-or
-.I type
-matches anything, and an
-.RB ` * '
-for
-.I zone
-means the local zone. The default values are taken from the
-.B NBPLKUP
-environment variable, parsed as an
-.IR nbpname .
+nbprgstr registers \fInbpname\fR
+with \fBatalkd\fR(8),
+at the given \fIport\fR. nbpunrgstr
+informs \fIatalkd\fR that
+\fInbpname\fR is no longer to be advertised.
+.PP
+nbplkup displays up to
+\fImaxresponses\fR (default 1000) entities registered
+on the AppleTalk internet. \fInbpname\fR
+is parsed by \fBnbp_name\fR(3).
+An `\fI=\fR' for the \fIobject\fR
+or \fItype\fR matches anything, and an `\fI*\fR' for \fIzone\fR means
+the local zone. The default values are taken from the \fINBPLKUP\fR
+environment variable, parsed as an \fInbpname\fR.
+.SH "ENVIRONMENT VARIABLES"
+.TP 
+NBPLKUP
+default nbpname for nbplkup
+.TP 
+ATALK_MAC_CHARSET
+the codepage used by the clients on the Appletalk network
+.TP 
+ATALK_UNIX_CHARSET
+the codepage used to display extended characters on this
+shell.
 .SH EXAMPLE
-Find all devices of type
-.B LaserWriter
+Find all devices of type \fILaserWriter\fR
 in the local zone.
-.sp
-.RS
+.PP
 .nf
-example% nbplkup :LaserWriter
+example% \fBnbplkup :LaserWriter\fR
                Petoskey:LaserWriter        7942.129:218
              Gloucester:LaserWriter        8200.188:186
                  Rahway:LaserWriter        7942.2:138
@@ -74,9 +49,7 @@ example% nbplkup :LaserWriter
          Iron Mountain :LaserWriter        7942.128:250
 example%
 .fi
-.RE
-.SH SEE ALSO
-.BR nbp_name (3),
-.\" .BR nbp (4),
-.\" .BR zip (4),
-.BR atalkd (8).
+.SH "SEE ALSO"
+\fBnbp_name\fR(3),
+\fBatalkd\fR(8).
+
index ab02ef80163e01786db085d230dbb7db7d6dc7fd..bcc7d0cd5128269fb6aba8d99e4d0e6838ac09d1 100644 (file)
@@ -1,62 +1,64 @@
-.TH netatalk\-config 1 "09 June 2001" "netatalk 1.5pre6" "The Netatalk Project"
+.TH netatalk\-config 1 "09 June 2001" 2.0.0 Netatalk 
 .SH NAME
-netatalk-config - script to get information about the installed version of netatalk
+netatalk\-config \- script to get information about the installed version of netatalk
 .SH SYNOPSIS
-.B netatalk-config
-[\-\-prefix\fI[=DIR]\fP] [\-\-exec_prefix\fI[=DIR]\fP] [\-\-help] [\-\-version]
-[\-\-libs] [\-\-libs\-dirs] [\-\-libs\-names] [\-\-cflags] [\-\-macros]
+\fBnetatalk\-config\fR [ \-\-prefix [\fB=DIR\fR]] [ \-\-exec_prefix [\fB=DIR\fR]] [\-\-help] [\-\-version] [\-\-libs] [\-\-libs\-dirs] [\-\-libs\-names] [\-\-cflags] [\-\-macros]
 .SH DESCRIPTION
-.PP
-\fInetatalk-config\fP is a tool that is used to configure to determine
-the compiler and linker flags that should be used to compile
-and link programs that use the \fInetatalk\fP run-time libraries.
-.
+netatalk\-config is a tool that is used to
+determine the compiler and linker flags that should be used
+to compile and link programs that use the \fInetatalk\fR
+run\-time libraries.
 .SH OPTIONS
-.l
-\fInetatalk-config\fP accepts the following options:
-.TP 8
-.B  \-\-help
+netatalk\-config accepts the following options:
+.TP 
+\fB\-\-help\fR
 Print a short help for this command and exit.
-.TP 8
-.B  \-\-version
-Print the currently installed version of \fInetatalk\fP on the standard output.
-.TP 8
-.B  \-\-libs
-Print the linker flags that are necessary to link against the \fInetatalk\fP
-run-time libraries.
-.TP 8
-.B  \-\-libs-dirs
+.TP 
+\fB\-\-version\fR
+Print the currently installed version of \fInetatalk\fR
+on the standard output.
+.TP 
+\fB\-\-libs\fR
+Print the linker flags that are necessary to link against the
+\fInetatalk\fR run\-time libraries.
+.TP 
+\fB\-\-libs\-dirs\fR
 Print only the \-l/\-R part of \-\-libs.
-.TP 8
-.B  \-\-libs-names
+.TP 
+\fB\-\-libs\-names\fR
 Print only the \-l part of \-\-libs.
-.TP 8
-.B  \-\-cflags
-Print the compiler flags that are necessary to compile a program linked
-against the \fInetatalk\fP run-time libraries.
-.TP 8
-.B  \-\-macros
-Print the \fInetatalk\fP m4 directory.
-.TP 8
-.B  \-\-prefix=PREFIX
-If specified, use PREFIX instead of the installation prefix that \fInetatalk\fP
-was built with when computing the output for the \-\-cflags and
-\-\-libs options. This option is also used for the exec prefix
-if \-\-exec\-prefix was not specified. This option must be specified
-before any \-\-libs or \-\-cflags options.
-.TP 8
-.B  \-\-exec\_prefix=PREFIX
-If specified, use PREFIX instead of the installation exec prefix that
-\fInetatalk\fP was built with when computing the output for the \-\-cflags
-and \-\-libs options.  This option must be specified before any
-\-\-libs or \-\-cflags options.
+.TP 
+\fB\-\-cflags\fR
+Print the compiler flags that are necessary to compile a
+program linked against the \fInetatalk\fR
+run\-time libraries.
+.TP 
+\fB\-\-macros\fR
+Print the \fInetatalk\fR m4
+directory.
+.TP 
+\fB\-\-prefix=PREFIX\fR
+If specified, use PREFIX instead of the installation prefix
+that \fInetatalk\fR was built with when
+computing the output for the \-\-cflags and \-\-libs options. This
+option is also used for the exec prefix if \-\-exec\-prefix was not
+specified. This option must be specified before any \-\-libs or
+\-\-cflags options.
+.TP 
+\fB\-\-exec\\_prefix=PREFIX\fR
+If specified, use PREFIX instead of the installation exec
+prefix that \fInetatalk\fR was built with
+when computing the output for the \-\-cflags and \-\-libs options. This
+option must be specified before any \-\-libs or \-\-cflags options.
 .SH COPYRIGHT
-Copyright \(co  1998 Owen Taylor
-
-Permission to use, copy, modify, and distribute this software and its
-documentation for any purpose and without fee is hereby granted,
+Copyright \(co 1998 Owen Taylor
+.PP
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby granted,
 provided that the above copyright notice appear in all copies and that
-both that copyright notice and this permission notice appear in
-supporting documentation.
+both that copyright notice and this permission notice appear in supporting
+documentation.
+.PP
+Man page adapted for netatalk\-config by Sebastian
+Rittau in 2001.
 
-Man page adapted for \fInetatalk-config\fP by Sebastian Rittau in 2001.
index 80f937b8ec937bc59e9a0fa8367862fd8236a059..c82f9caa9b9a045f23eb8ffbbdf4d660c8af6307 100644 (file)
-.TH PAP 1 "6 May 2002" "netatalk 1.5"
+.TH pap 1 "6 May 2002" 2.0.0 Netatalk 
 .SH NAME
-pap, papstatus \- client interface to remote printers using Printer Access Protocol
+pap \- client interface to remote printers using Printer Access Protocol
 .SH SYNOPSIS
-.B pap
-[
-.B -A
-.I address
-] [
-.B -c
-] [
-.B -d
-] [
-.B -e
-] [
-.B -E
-] [
-.B -p
-.I nbpname
-] [
-.B -s
-.I statusfile
-] [
-.B -w
-] [
-.B -W
-] [
-.I FILES
-]
-.sp
-.B papstatus
-[
-.B -p
-.I nbpname
-]
+\fBpap\fR [ \-A \fBaddress\fR ] [\-c] [\-d] [\-e] [\-E] [ \-p \fBnbpname\fR ] [ \-s \fBstatusfile\fR ] [\-w] [\-W] [\fBFILES\fR]
 .SH DESCRIPTION
-.B pap
-is used to connect and send files to an AppleTalk connected printer using
-the Apple Printer Access Protocol (PAP).
-When
-.B pap
-starts execution, it
-tries to open a session with the printer using PAP, and
-then downloads the
-.I files
+pap is used to connect and send files to an
+AppleTalk connected printer using the Apple Printer Access Protocol (PAP).
+When pap starts execution, it tries to open a session
+with the printer using PAP, and then downloads the \fIfiles\fR
 to the printer.
-.LP
-If no
-.I files
-are given on the command line,
-.B pap
-begins reading from standard input.
-.LP
-If no printer is specified on the command line,
-.B pap
-looks for a file called
-.B .paprc
-in the current working directory and reads it to obtain the
-.I nbpname
-of a
-printer.
-Blank lines and lines that begin with a
-.RB ` # '
-are ignored.
-.I type
-and
-.I zone
-default to
-.B LaserWriter
-and the zone of the local host, respectively.
-.LP
-Note that
-.B pap
-is designed to be useful as a communication filter for sending
-.BR lpd (8)
-spooled print jobs to AppleTalk connected printers.  See
-.BR psf (8)
+.PP
+If no \fIfiles\fR are given on the command
+line, pap begins reading from standard input.
+.PP
+If no printer is specified on the command line, pap
+looks for a file called .paprc in the current working
+directory and reads it to obtain the \fInbpname\fR
+of a printer. Blank lines and lines that begin with a `\fI#\fR'
+are ignored. \fItype\fR and \fIzone\fR
+default to \fILaserWriter\fR and the zone of the
+local host, respectively.
+.PP
+Note that pap is designed to be useful as a
+communication filter for sending \fBlpd\fR(8)
+spooled print jobs to AppleTalk connected printers. See
+\fBpsf\fR(8)
 for hints on how to use it this way.
 .SH OPTIONS
-.HP
-.B -A
-.I address
-.br
-Connect to the printer with Appletalk address
-.I address
-and do not consult the
-.B .paprc
-file to find a printer name.  See
-.BR atalk_aton (3)
-for the syntax of
-.IR address .
-.TP
-.B -c
-Take cuts.  The PAP protocol specified a simple queuing
-procedure, such that the clients tell the printer how long
-they have been waiting to print.  This option causes
-.B pap
-to lie about how long it has been waiting.
-.TP
-.B -d
+.TP 
+\fB\-A \fR\fIaddress\fR
+Connect to the printer with Appletalk address \fIaddress\fR and do not consult the
+\&.paprc file to find a printer name. See
+\fBatalk_aton\fR(3)
+for the syntax of \fIaddress\fR.
+.TP 
+\fB\-c\fR
+Take cuts. The PAP protocol specified a simple queuing
+procedure, such that the clients tell the printer how long they have
+been waiting to print. This option causes pap to
+lie about how long it has been waiting.
+.TP 
+\fB\-d\fR
 Enable debug output.
-.TP
-.B -e
+.TP 
+\fB\-e\fR
 Send any message from the printer to stderr instead of stdout.
-.BR psf (8)
-invokes
-.B pap
-with this option.
-.TP
-.B -E
-Don't wait for EOF from the printer.  This option is useful
-for printers which don't implement PAP correctly.  In a correct
+\fBpsf\fR(8)
+invokes pap with this option.
+.TP 
+\fB\-E\fR
+Don't wait for EOF from the printer. This option is useful
+for printers which don't implement PAP correctly. In a correct
 implementation, the client side should wait for the printer to
-return EOF before closing the connection.  Some clients don't
+return EOF before closing the connection. Some clients don't
 wait, and hence some printers have related bugs in their
 implementation.
-.HP
-.B -p
-.I nbpname
-.br
-Connect to the printer named
-.I nbpname
-and do not consult the
-.B .paprc
-file to find a printer name.  See
-.BR nbp_name (3)
-for the syntax of
-.IR nbpname .
-.HP
-.B -s
-.I statusfile
-.br
-Update the file called
-.I statusfile
+.TP 
+\fB\-p\fR \fInbpname\fR
+Connect to the printer named \fInbpname\fR
+and do not consult the .paprc file to find a
+printer name. See \fBnbp_name\fR(3)
+for the syntax of \fInbpname\fR.
+.TP 
+\fB\-s\fR \fIstatusfile\fR
+Update the file called \fIstatusfile\fR
 to contain the most recent status message from the printer.
-.B pap
-gets the status from the printer when it is waiting for the printer to
-process input.  The
-.I statusfile
-will contain a single line terminated with a newline.  This is useful
-when
-.B pap
-is invoked by
-.BR psf (8)
-within
-.BR lpd 's
-spool directory.
-.TP
-.B -w
-Wait for the printer status to contain the word "waiting" before
-sending the job.  This is to defeat printer-side spool available
-on HP IV and V printers.
-.TP
-.B -W
-Wait for the printer status to contain the word "idle" before
-sending the job.  This is to defeat printer-side spool available
-on HP IV and V printers.
+pap gets the status from the printer when it is
+waiting for the printer to process input. The \fIstatusfile\fR
+will contain a single line terminated with a newline. This is useful
+when pap is invoked by
+\fBpsf\fR(8)
+within \fIlpd\fR's spool directory.
+.TP 
+\fB\-w\fR
+Wait for the printer status to contain the word
+"waiting" before sending the job. This is to defeat
+printer\-side spool available on HP IV and V printers.
+.TP 
+\fB\-W\fR
+Wait for the printer status to contain the word "idle"
+before sending the job. This is to defeat printer\-side spool
+available on HP IV and V printers.
 .SH FILES
-.TP 20
-.B .paprc
-file read to obtain printer name if not specified on command line
-.SH SEE ALSO
-.BR nbp_name (3),
-.BR atalk_aton (3),
-.BR lpd (8),
-.BR psf (8).
+.TP 
+\&.paprc
+file read to obtain printer name if not specified on command
+line
+.SH "SEE ALSO"
+\fBnbp_name\fR(3),
+\fBatalk_aton\fR(3),
+\fBlpd\fR(8),
+\fBpsf\fR(8).
+
index 41aa36b39f93442ca9a2ea448664a43961f56bde..8c3c71a00b987d4ac2c69490173be934ad49da60 100644 (file)
@@ -1,48 +1,38 @@
-.TH PSORDER 1 "17 Dec 1991" "netatalk 1.2"
+.TH psorder 1 "17 Dec 1991" 2.0.0 Netatalk 
 .SH NAME
 psorder \- PostScript pageorder filter
 .SH SYNOPSIS
-.B psorder
-[
-.B -duf
-]
-.I sourcefile
+\fBpsorder\fR [\-duf] \fBsourcefile\fR 
 .SH DESCRIPTION
-.B psorder
-is a filter that re-orders the pages of a PostScript document.
-The result is written to the standard output.  By default,
-documents are processed into ascending order (the lowest numbered page
-is printed first).  Some PostScript documents specify that the order of
-their pages should never be changed; the default action of
-.B psorder
-is to follow this specification.
-.LP
-If no source file is given, or if 
-.I sourcefile
-is
-.RB ` - ',
-.B psorder
+psorder is a filter that re\-orders the pages of a
+PostScript document. The result is written to the standard output. By
+default, documents are processed into ascending order (the lowest numbered
+page is printed first). Some PostScript documents specify that the order
+of their pages should never be changed; the default action of
+psorder is to follow this specification.
+.PP
+If no source file is given, or if \fIsourcefile\fR
+is `\fI\-\fR', psorder
 reads from the standard input file.
-.br
 .SH OPTIONS
-.TP
-.B \-d
-Re-order the pages of the document in downward or descending
-order.  This is typically used to change the order of a document to
-be printed by a printer that stacks pages face-up,
-such as an Apple LaserWriter or LaserWriter Plus.
-.TP
-.B \-u
-Specifies forward order, and is the default.  It is used to
-try and ensure the correct ordering when a document will be printed
-by a printer that stacks the pages face-down.
-.TP
-.B \-f
-Force
-.B psorder
-to re-order the pages, even if the document claims that its page
-order is not to be trifled with.  This option should only be used 
-experimentally, as it may cause documents to print incorrectly.
-.SH SEE ALSO
-.BR psf (8),
-.BR lpr (1).
+.TP 
+\fB\-d\fR
+Re\-order the pages of the document in downward or descending
+order. This is typically used to change the order of a document to
+be printed by a printer that stacks pages face\-up, such as an Apple
+LaserWriter or LaserWriter Plus.
+.TP 
+\fB\-u\fR
+Specifies forward order, and is the default. It is used to try
+and ensure the correct ordering when a document will be printed by a
+printer that stacks the pages face\-down.
+.TP 
+\fB\-f\fR
+Force psorder to re\-order the pages, even
+if the document claims that its page order is not to be trifled
+with. This option should only be used experimentally, as it may
+cause documents to print incorrectly.
+.SH "SEE ALSO"
+\fBpsf\fR(8),
+\fBlpr\fR(1).
+
index ddc70e8ff59a135ac61ec1a71e19714d4e00c082..0aab483cccdc0a047b10a76547dc4bee98ea05e5 100644 (file)
@@ -1,34 +1,28 @@
-.TH "timeout" "1" "19 Jul 2001" "netatalk 1.5pre7" "The Netatalk Project"
-
-.SH "NAME"
-.LP 
+.TH timeout 1 "19 Jul 2001" 2.0.0 Netatalk 
+.SH NAME
 timeout \- Send a signal to a program after a certain time
-
-.SH "SYNTAX"
-.LP 
-timeout [\-s \fIsignal\fP] \fIseconds\fP \fIprogram\fP [\fIargs\fP]
-
-.SH "DESCRIPTION"
-.LP 
-\fBtimeout\fR executes a \fIprogram\fP (with arguments \fIargs\fP) and sends a
-\fIsignal\fP to it after a certain amount of \fIseconds\fP.
-
-.SH "OPTIONS"
-.LP 
+.SH SYNTAX
+timeout [\-s \fIsignal\fR] \fIseconds\fR \fIprogram\fR [\fIargs\fR]
+.SH DESCRIPTION
+\fItimeout\fR executes a \fIprogram\fR (with arguments \fIargs\fR)
+and sends a \fIsignal\fR to it after a certain
+amount of \fIseconds\fR.
+.SH OPTIONS
+.TP 
+\fB\-s\fR \fIsignal\fR
+Signal to send to the spawned process. This can be a numerical
+or symbolic ID. This defaults to \fBTERM\fR.
+.SH EXAMPLES
 .TP 
-\fB\-s\fR \fIsignal\fP
-Signal to send to the spawned process. This can be a numerical or symbolic ID.
-This defaults to \fBTERM\fR.
-
-.SH "EXAMPLES"
-.LP
-.TP
 timeout 10 pap foo.ps
-Execute "pap foo.ps" and send a \fBSIGTERM\fR if \fBpap\fR doesn't return
-after 10 seconds.
-.TP
-timeout -s HUP 60 sh
+Execute "pap foo.ps" and send a SIGTERM
+if \fIpap\fR doesn't return after 10
+seconds.
+.TP 
+timeout \-s HUP 60 sh
 Spawn a shell and send a hangup signal after one minute.
-.TP
-timeout -s 9 10 evilprog
-Execute a program and \fBKILL\fR it if it doesn't quit after 10 seconds.
+.TP 
+timeout \-s 9 10 evilprog
+Execute a program and \fIKILL\fR it
+if it doesn't quit after 10 seconds.
+
diff --git a/man/man1/uniconv.1.tmpl b/man/man1/uniconv.1.tmpl
new file mode 100644 (file)
index 0000000..915dc3d
--- /dev/null
@@ -0,0 +1,123 @@
+.TH uniconv 1 "24 Jun 2004" 2.0.0 Netatalk 
+.SH NAME
+uniconv \- convert Netatalk volume encoding
+.SH SYNOPSIS
+\fBuniconv\fR [\-ndv] \-c \fBcnidbackend\fR \-f \fBfromcode\fR \-t \fBtocode\fR [\-m \fBmaccode\fR] \fBvolumepath\fR 
+.SH DESCRIPTION
+uniconv converts the volume encoding of
+\fIvolumepath\fR from the \fIfromcode\fR
+to the \fItocode\fR encoding.
+.SH OPTIONS
+.TP 
+\-c
+CNID backend used on this volume, usually cdb or dbd. Should
+match the backend selected with afpd for this volume. If not
+specified, the default CNID backend `:DEFAULT_CNID_SCHEME:' is
+used
+.TP 
+\-d
+don't CAP encode leading dots (:2e), equivalent to
+\fBusedots\fR in \fBAppleVolumes.default\fR(5)
+.TP 
+\-f
+encoding to convert from, use ASCII for CAP encoded volumes
+.TP 
+\-h
+display help
+.TP 
+\-m
+Macintosh client codepage, required for CAP encoded volumes.
+Defaults to `MAC_ROMAN'
+.TP 
+\-n
+`dry run', don't do any real changes
+.TP 
+\-t
+volume encoding to convert to, e.g. UTF8
+.TP 
+\-v
+verbose output, use twice for maximum logging.
+.TP 
+\-V
+print version and exit
+.PP
+.SH WARNING
+Setting the wrong options might render your data unusable!!! Make
+sure you know what you are doing. Always backup your data first.
+.PP
+It is \fB*strongly*\fR recommended to do
+a `dry run' first and to check the output for conversion errors.
+.PP
+\fBafpd\fR(8)
+should \fInot\fR be running while you change the volume
+encoding. Remember to change \fBvolcodepage\fR in
+\fBAppleVolumes.default\fR(5)
+to the new codepage, before restarting afpd.
+.PP
+\fBUSE AT YOUR OWN RISK!!!\fR
+.SH "SELECTABLE CHARSETS"
+Netatalk provides internal support for UTF\-8 (pre\- and decomposed)
+and CAP. If you want to use other charsets, they must be provided by
+\fBiconv\fR(1)
+.PP
+uniconv also knows iso\-8859.adapted, an old style
+1.x NLS widely used. This is only intended for upgrading old volumes,
+\fBafpd\fR(8)
+cannot handle iso\-8859.adapted anymore.
+.SH "CNID BACKGROUND"
+The CNID backends maintains name to ID mappings. If you change a
+filename outside afpd(8) (shell, samba), the CNID db, i.e. the DIDNAME
+index, gets inconsistent. Netatalk tries to recover from such
+inconsistencies as gracefully as possible. The mechanisms to resolve such
+inconsistencies may fail sometimes, though, as this is not an easy task to
+accomplish. I.e. if several names in the path to the file or directory
+have changed, things may go wrong.
+.PP
+If you change a lot of filenames at once, chances are higher that
+the afpds fallback mechanisms fail, i.e. files will be assigned new IDs,
+even though the file hasn't changed. uniconv
+therefore updates the CNID entry for each file/directory directly after it
+changes the name to avoid inconsistencies. The two supported backends for
+volumes, dbd and cdb, use the same CNID db format. Therefore, you
+\fIcould\fR use uniconv with cdb and
+afpd with dbd later.
+.PP
+\fBWarning\fR: There must not be two
+processes opening the CNID database using different backends at once! If a
+volume is still opened with dbd (cnid_metad/cnid_dbd) and you start
+uniconv with cdb, the result will be a corrupted CNID
+database, as the two backends use different locking schemes. You might run
+into additional problems, e.g. if dbd is compiled with transactions, cdb
+will not update the transaction logs.
+.PP
+In general, it is recommended to use the same backend for
+uniconv you are using with
+\fBafpd\fR(8).
+.SH EXAMPLES
+convert 1.x CAP encoded volume to UTF\-8, clients used MacRoman
+codepage, cnidscheme is dbd:
+.PP
+.nf
+example%\fB uniconv \-c dbd \-f ASCII \-t UTF8 \-m MAC_ROMAN /path/to/share\fR
+.fi
+.PP
+convert iso8859\-1 volume to UTF\-8, cnidscheme is cdb:
+.PP
+.nf
+example%\fB uniconv \-c cdb \-f ISO\-8859\-1 \-t UTF8 \-m MAC_ROMAN /path/to/share\fR
+.fi
+.PP
+convert 1.x volume using iso8859\-1 adapted NLS to CAP encoding:
+.PP
+.nf
+example%\fB uniconv \-f ISO\-8859\-ADAPTED \-t ASCII \-m MAC_ROMAN/path/to/share\fR
+.fi
+.PP
+convert UTF\-8 volume to CAP, for MacCyrillic clients:
+.PP
+.nf
+example%\fB uniconv \-f UTF8 \-t ASCII \-m MAC_CYRILLIC /path/to/share\fR
+.fi
+.SH "SEE ALSO"
+\fBAppleVolumes.default\fR(5),\fBafpd\fR(8),\fBiconv\fR(1),\fBcnid_metad\fR(8),\fBcnid_dbd\fR(8)
+
index f7949eb437d5932d4d31e3c5a6c40505486478a0..e49b8e53dd3993b2fb95192b367e3058dff093b9 100644 (file)
@@ -1,24 +1,23 @@
-.TH ATALK_ATON 3 "12 Jan 1994" "netatalk 1.3"
+.TH atalk_aton 3 "12 Jan 1994" 2.0.0 Netatalk 
 .SH NAME
 atalk_aton \- AppleTalk address parsing
 .SH SYNOPSIS
 .nf
 #include <sys/types.h>
 #include <netatalk/at.h>
-.LP
-atalk_aton( cp, ata )
-char *cp;
-struct at_addr *ata;
 .fi
+.sp 1
+.PP
+\fIatalk_aton\fR(char * \fIcp\fR, struct at_addr * \fIata\fR);
 .SH DESCRIPTION
-The
-.B atalk_aton()
-routine converts an ascii representation of an AppleTalk address to a
-format appropriate for system calls.  Acceptable ascii representations
-include both hex and base 10, in triples or doubles.  For instance, the
-address `0x1f6b.77' has a network part of `8043' and a node part of
-`119'.  This same address could be written `8043.119', `31.107.119', or
-`0x1f.6b.77'.  If the address is in hex and the first digit is one of
-`A-F', a leading `0x' is redundant.
-.SH SEE ALSO
-.BR atalk (4).
+The atalk_aton() routine converts an ASCII
+representation of an AppleTalk address to a format appropriate for system
+calls. Acceptable ASCII representations include both hex and base 10, in
+triples or doubles. For instance, the address `0x1f6b.77' has a
+network part of `8043' and a node part of `119'. This same address
+could be written `8043.119', `31.107.119', or `0x1f.6b.77'. If
+the address is in hex and the first digit is one of `A\-F', a leading
+`0x' is redundant.
+.SH "SEE ALSO"
+\fBatalk\fR(4).
+
index 4cc4625af13a7a9f4089b875a13c34b07935739b..4a31196e1a43ebda54626737ca9bb5d33821d782 100644 (file)
@@ -1,78 +1,40 @@
-.TH NBP_NAME 3 "12 Jan 1994" "netatalk 1.3"
+.TH nbp_name 3 "12 Jan 1994" 2.0.0 Netatalk 
 .SH NAME
 nbp_name \- NBP name parsing
 .SH SYNOPSIS
-.nf
-int nbp_name(char * name, char **obj, char **type, char **zone)
-.fi
+int \fInbp_name\fR(char *\fIname\fR, char **\fIobj\fR, char **\fItype\fR, char **\fIzone\fR);
 .SH DESCRIPTION
-.B nbp_name()
-parses user supplied names into their component object, type, and
-zone.
-.BR obj ,
-.BR type ,
-and
-.B zone
-should be passed by reference, and should point to the caller's default
-values.
-.B nbp_name()
-will change the pointers to the parsed-out values.
-.B name
-is of the form
-.IB object : \c
-.IB type @ \c
-.IR zone ,
-where each of
-.IR object ,
-.BI : type ,
-and
-.BI @ zone
-replace
-.BR obj ,
-.BR type ,
-and
-.BR zone,
-respectively.
-.I type
-must be proceeded by
-.RB ` : ',
-and
-.I zone
-must be preceded by
-.RB ` @ '.
+nbp_name() parses user supplied names into
+their component object, type, and zone. \fIobj\fR,
+\fItype\fR, and zone
+should be passed by reference, and should point to the caller's
+default values. nbp_name() will change the pointers
+to the parsed\-out values. \fIname\fR is of the
+form \fIobject\fR\fI:\fR\fI\fR\fItype\fR\fI@\fR\fI\fRzone, where each of \fIobject\fR,
+\fI:\fR\fItype\fR\fI,\fR and \fI@\fRzone replace \fIobj\fR,
+\fItype\fR, and \fIzone,\fR
+respectively. \fItype\fR must be proceeded by `\fI:\fR', and zone
+must be preceded by `\fI@\fR'.
 .SH EXAMPLE
-The argument of
-.BR afpd (8)'s
-.B -n
-option is parsed with
-.BR nbp_name() .
-The default value of
-.B obj
-is the first component of the machine's hostname (as returned by
-.BR gethostbyname (3)).
-The default value of
-.B type
-is ``AFPServer'', and of
-.B zone
-is ``*'', the default zone.  To cause
-.B afpd
-to register itself in some zone other than the default, one would
-invoke it as
-.sp
-.RS
+The argument of \fBafpd\fR(8)'s
+\fB\-n\fR option is parsed with nbp_name().
+The default value of \fIobj\fR is the first
+component of the machine's hostname (as returned by
+\fBgethostbyname\fR(3)).
+The default value of \fItype\fR is
+``AFPServer'', and of zone is
+``*'', the default zone. To cause \fIafpd\fR
+to register itself in some zone other than the default, one would invoke
+it as
+.PP
 .nf
-afpd -n @some-other-zone
+afpd \-n @some\-other\-zone
 .fi
-.RE
-.sp
-.B obj
-and
-.B type
+.PP
+\fIobj\fR and \fItype\fR
 would retain their default values.
 .SH BUGS
-.BR obj ,
-.BR type ,
-and
-.B zone
-return pointers into static area which may be over-written on each
-call.
+\fIobj\fR, \fItype\fR,
+and zone return pointers into static
+area which may be over\-written on each call.
+
index ecb5c270c14ecd305040782b39029e88ef999de4..93a713c53f55d415f2dfea3b73aeb442fccd4fad 100644 (file)
@@ -1,10 +1,12 @@
-.TH ATALK 4F "17 Dec 1991" "netatalk 1.2"
+.TH atalk 4 "17 Dec 1991" 2.0.0 Netatalk 
 .SH NAME
 atalk \- AppleTalk protocol family
 .SH SYNOPSIS
-.B #include <sys/types.h>
-.br
-.B #include <netatalk/at.h>
+.nf
+#include <sys/types.h>
+#include <netatalk/at.h>
+.fi
+.sp 1
 .SH DESCRIPTION
 The AppleTalk protocol family is a collection of protocols layered
 above the Datagram Delivery Protocol (DDP), and using AppleTalk address
@@ -14,50 +16,34 @@ implemented in the kernel; ATP and ASP are implemented in user level
 libraries; and ADSP is planned.
 .SH ADDRESSING
 AppleTalk addresses are three byte quantities, stored in network
-byte order. The include file
-.RB < netatalk/at.h >
+byte order. The include file <\fInetatalk/at.h\fR>
 defines the AppleTalk address format.
-.LP
+.PP
 Sockets in the AppleTalk protocol family use the following address
 structure:
-.sp 1
-.RS
+.PP
 .nf
 struct sockaddr_at {
-       short           sat_family;
-       u_char          sat_port;
-       struct at_addr  sat_addr;
-       char            sat_zero[ 8 ];
+    short sat_family;
+    u_char sat_port;
+    struct at_addr sat_addr;
+    char sat_zero[ 8 ];
 };
 .fi
-.RE
-.sp 1
-The port of a socket may be set with
-.BR bind (2).
-The node for
-.B bind
-must always be
-.BR ATADDR_ANYNODE :
-``this node.'' The net may be
-.B ATADDR_ANYNET
-or
-.BR ATADDR_LATENET .
-.B ATADDR_ANYNET
-coresponds to the machine's ``primary'' address (the first
-configured).
-.B ATADDR_LATENET
-causes the address in outgoing packets to be determined when a packet
-is sent, i.e. determined late.
-.B ATADDR_LATENET
-is equivalent to opening one socket for each network interface.  The
-port of a socket and either the primary address or
-.B ATADDR_LATENET
-are returned with
-.BR getsockname (2).
-.SH SEE ALSO
-.\" .BR ddp (4P),
-.\" .BR atp (3N),
-.\" .BR asp (3N),
-.BR bind (2),
-.BR getsockname (2),
-.BR atalkd (8).
+.PP
+The port of a socket may be set with \fBbind\fR(2).
+The node for \fIbind\fR must always be \fIATADDR_ANYNODE\fR: ``this node.'' The net may be
+\fIATADDR_ANYNET\fR or \fIATADDR_LATENET\fR.
+\fIATADDR_ANYNET\fR coresponds to the
+machine's ``primary'' address (the first configured).
+\fIATADDR_LATENET\fR causes the address in
+outgoing packets to be determined when a packet is sent, i.e. determined
+late. \fIATADDR_LATENET\fR is equivalent to
+opening one socket for each network interface. The port of a socket and
+either the primary address or \fIATADDR_LATENET\fR
+are returned with \fBgetsockname\fR(2).
+.SH "SEE ALSO"
+\fBbind\fR(2),
+\fBgetsockname\fR(2),
+\fBatalkd\fR(8).
+
index b31d78c0012eb63f0cfa1ce30921493eae06f374..74e9c4ce23bffab95cd812e17c587a1c799e4bb9 100644 (file)
-.\" $Id: AppleVolumes.default.5.tmpl,v 1.2 2001-02-28 16:53:24 rufustfirefly Exp $
-.TH AppleVolumes.default 5 "20 September 2000" "netatalk 1.5"
-.UC 4
+.TH AppleVolumes.default 5 "06 September 2004" 2.0.0 Netatalk 
 .SH NAME
-AppleVolumes.default \- Configuration file used by \fBafpd\fR(8)
-to determine the shares made available through Appletalk
-
+AppleVolumes.default \- Configuration file used by afpd(8) to determine the shares made available through Appletalk
 .SH DESCRIPTION
-\fB:ETCDIR:/AppleVolumes.default\fR is the configuration file used
-by afpd to determine what portions of the file system will be shared via
-Appletalk, as well as their behaviors.
-
-Any line not prefixed with \fB#\fR is interpreted. The configuration lines
-are composed like:
-
-.RS
-.sp
-.I path
-.B [
-.I chooser name
-.B ] [
-.I options
-.B ]
-
-.sp
-.RE
-The path name must be a fully qualified path name, or a path name using
-either the \fB~\fR shell shorthand or any of the substitution variables,
+\fB:ETCDIR:/AppleVolumes.default\fR is the
+configuration file used by afpd to determine what
+portions of the file system will be shared via Apple Filing Protocol, as
+well as their behaviour. Any line not prefixed with # is interpreted. The
+configuration lines are composed like:
+.PP
+\fBpath\fR \fI[ volume name ] [ options
+]\fR
+.PP
+The path name must be a fully qualified path name, or a path name
+using either the ~ shell shorthand or any of the substitution variables,
 which are listed below.
-
-The chooser name is the name that appears in the Chooser on Macintoshes
-to represent the appropriate share. If there are spaces in the name, it
-should be in quotes (i.e. \fB"File Share"\fR). The chooser name may not
-exceed 27 characters in length, and cannot contain the \fB:\fR character.
-
+.PP
+The volume name is the name that appears in the Chooser ot the
+"connect to server" dialog on Macintoshes to represent the appropriate
+share. If there are spaces in the name, it should be in quotes (i.e. "File
+Share"). The volume name may not exceed 27 characters in length, and
+cannot contain the \fB':'\fR character.
+.RS 
+\fBNote\fR
+.PP
+Each volume has to be configured on a \fBsingle\fR line.
+.RE
+.PP
 The possible options and their meanings are:
-
-.TP
-.B allow:[users/groups]
-The allow option allows the users and groups that access a share to
-be specified. Users and groups are specified, delimited by commas. Groups
-are designated by a \fB@\fR prefix.
-
-\fIExample:\fR \fBallow:user1,user2,@group\fR
-
-.TP
-.B casefold:[option]
-The casefold option handles how casenames should be mangled. The available
-options are:
-
-\fBtolower\fR - Lowercases names in both directions.
-
-\fBtoupper\fR - Uppercases names in both directions.
-
-\fBxlatelower\fR - Client sees lowercase, server sees uppercase.
-
-\fBxlateupper\fR - Client sees uppercase, server sees lowercase.
-
-.TP
-.B codepage:[nls file]
-The codepage option loads a specific codepage from the nls directory.
-
-.TP
-.B dbpath:[path]
-Sets the database information to be stored in \fBpath\fR.
-
-.TP
-.B deny:[users/groups]
-The deny option specifies users and groups who are not allowed access
-to the share. It follows the same format as the \fBallow\fR option.
-
-.TP
-.B options:[option]
-This allows multiple options to be specified in a comma delimited format.
-The available options are:
-
-\fBcrlf\fR - Enables crlf translation for TEXT files.
-
-\fBdropbox\fR - Allows a volume to be declared as being a "dropbox." Note
-that netatalk must be compiled with dropkludge support for this to
-function.
-
-\fBlimitsize\fR - Hack for older Macintoshes using newer Appleshare
-clients to limit the disk size reporting to 2 GB.
-
-\fBmswindows\fR - Forces filename restrictions imposed by MS WinXX, and
-invokes the MS default codepage (iso8859-1) if one is not already
-specified.
-
-\fBnoadouble\fR - Forces afpd to not create .AppleDouble unless a resource
-fork needs to be created.
-
-\fBnohex\fR - Disables :hex translations for anything except dot files.
-This option makes the \fB/\fR character illegal.
-
-\fBprodos\fR - Provides compatibility with Apple II clients.
-
-\fBro\fR - Specifies the share as being read only for all users.
-
-\fBusedots\fR - Don't do :hex translation for dot files. This makes all
-files such as .Parent, .Apple* illegal. Dot files created on the server
-side will be invisible to the client.
-
-.TP
-.B password:[password]
-This option allows you to set a volume password, which can be a maximum
-of 8 characters long.
-
-.TP
-.B rolist:[users/groups]
-Allows certain users and groups to have read-only access to a share.
-This follows the \fBallow\fR option format.
-
-.TP
-.B rwlist:[users/groups]
-Allows certain users and groups to have read/write access to a share.
-This follows the \fBallow\fR option format.
-
-.P
-The variables which can be used for subsitutions are:
-
-.TP
-.B $c
+.TP 
+adouble:\fI[v1|v2|osx]\fR
+specify the format of the metadata files, which are used for
+saving Mac resource fork as well. Earlier versions used AppleDouble
+V1, the new default format is V2. Starting with Netatalk 2.0, the
+scheme MacOS X uses currently (10.3.x), is also supported
+.RS 
+\fBNote\fR
+
+Using \fBadouble:osx\fR is \fBnot\fR recommended for production use. Its
+only aim is to temporarely share eg. FAT32 formatted FireWire
+harddrives written on a Macintosh with afpd. Apple's metadata
+scheme lacks several essential features, so using it on the
+server's side will break both CNIDs and MacOS 9
+compatibility
+.RE
+.TP 
+allow:\fI[users/groups]\fR
+The allow option allows the users and groups that access a
+share to be specified. Users and groups are specified, delimited by
+commas. Groups are designated by a @ prefix. Example:
+allow:user1,user2,@group
+.TP 
+deny:\fI[users/groups]\fR
+The deny option specifies users and groups who are not allowed
+access to the share. It follows the same format as the allow
+option.
+.TP 
+cnidscheme:\fI[backend]\fR
+set the CNID backend to be used for the volume, default is
+[:DEFAULT_CNID_SCHEME:] available schemes:
+[:COMPILED_BACKENDS:]
+.TP 
+dbpath:\fI[path]\fR
+Sets the database information to be stored in path. You have
+to specifiy a writable location, even if the volume is read
+only.
+.TP 
+maccharset:\fI[charset]\fR
+specifies the mac client codepage for this Volume, e.g.
+"MAC_ROMAN", "MAC_CYRILLIC". If not specified the setting from
+\fBafpd.conf\fR is inherited. This setting is only
+required if you need volumes, where the mac codepage differs from
+the one globally set in \fBafpd.conf\fR.
+.TP 
+options:\fI[option]\fR
+This allows multiple options to be specified in a comma
+delimited format. The available options are:
+.RS 
+.TP 
+limitsize
+Limit disk size reporting to 2GB. This can be used for
+older Macintoshes using newer Appleshare clients.
+.TP 
+ro
+Specifies the share as being read only for all users.
+The .AppleDB directory has to be writeable, you can use the
+\fB\-dbpath\fR option to relocate it.
+.TP 
+usedots
+Don't do :hex translation for dot files. note: when this
+option gets set, certain file names become illegal. These are
+\&.Parent and anything that starts with .Apple. Also, dot files
+created on the unix side are marked invisible.
+.TP 
+root_preexec_close
+a non\-zero return code from root_preexec closes the
+volume immediately, preventing clients to mount/see the volume
+in question.
+.TP 
+preexec_close
+a non\-zero return code from preexec close the volume
+being immediately, preventing clients to mount/see the volume
+in question.
+.RE
+.TP 
+password:\fI[password]\fR
+This option allows you to set a volume password, which can be
+a maximum of 8 characters long (using ASCII strongly recommended at
+the time of this writing).
+.TP 
+preexec:\fI[command]\fR
+command to be run when the volume is mounted, ignored for user
+defined volumes
+.TP 
+postexec:\fI[command]\fR
+command to be run when the volume is closed, ignored for user
+defined volumes
+.TP 
+root_preexec:\fI[command]\fR
+command to be run as root when the volume is mounted, ignored
+for user defined volumes
+.TP 
+root_postexec:\fI[command]\fR
+command to be run as root when the volume is closed, ignored
+for user defined volumes
+.TP 
+rolist:[\fBusers/groups\fR]
+Allows certain users and groups to have read\-only access to a
+share. This follows the allow option format.
+.TP 
+rwlist:\fI[users/groups]\fR
+Allows certain users and groups to have read/write access to a
+share. This follows the allow option format.
+.TP 
+veto:\fI[vetoed name]\fR
+hide files and directories,where the path matches one of the
+\&'/' delimited vetoed names. Matches are partial, e.g. path is
+\fB/abc/def/file\fR and veto:/abc/ will hide the
+file.
+.TP 
+volcharset:\fI[charset]\fR
+specifies the volume codepage, e.g. "UTF8", "UTF8\-MAC",
+"ISO\-8859\-15". Defaults to "UTF8".
+.SH "VARIABLE SUBSTITUTIONS"
+You can use variables in both volume path and volume name.
+.TP 
+1.
+if you specify an unknown variable, it will not get
+converted.
+.TP 
+2.
+if you specify a known variable, but that variable doesn't have
+a value, it will get ignored.
+.PP
+The variables which can be used for substitutions are:
+.TP 
+$b
+basename
+.TP 
+$c
 client's ip or appletalk address
-
-.TP
-.B $f
-full name (contents of the gecos field in the passwd file)
-
-.TP
-.B $g
+.TP 
+$d
+volume pathname on server
+.TP 
+$f
+full name (contents of the gecos field in the passwd
+file)
+.TP 
+$g
 group name
-
-.TP
-.B $h
+.TP 
+$h
 hostname
-
-.TP
-.B $s
+.TP 
+$i
+client's ip, without port
+.TP 
+$s
 server name (this can be the hostname)
-
-.TP
-.B $u
-user name (if guest, it is the user that guest is running as)
-
-.TP
-.B $v
+.TP 
+$u
+user name (if guest, it is the user that guest is running
+as)
+.TP 
+$v
 volume name (either ADEID_NAME or basename of path)
-
-.TP
-.B $z
+.TP 
+$z
 appletalk zone (may not exist)
+.TP 
+$$
+prints dollar sign ($)
+.PP
+When using variable substitution in the volume name, always keep in
+mind, not to exceed the 27 characters limit
+.PP
+\fBUsing variable substitution when defining volumes\fR
+.PP
+.nf
+/home/groups/$g "Groupdir for $g"
+~ "$f is the best one"
+.fi
+
+We define "groupdirs" for each primary
+group and use a personalized server name for homedir shares.
+.SH "CNID BACKENDS"
+The AFP protocol mostly refers to files and directories by ID and
+not by name. Netatalk needs a way to store these ID's in a persistent way,
+to achieve this several different CNID backends are available. The CNID
+Databases are by default located in the \fB.AppleDB\fR
+folder in the volume root.
+.TP 
+cdb
+"Concurrent database", backend is based on Sleepycat's Berkely
+DB. With this backend several afpd deamons access
+the CNID database directly. Berkeley DB locking is used to
+synchronize access, if more than one afpd process
+is active for a volume. The drawback is, that the crash of a single
+afpd process might corrupt the database.
+.TP 
+dbd
+Access to the CNID database is restricted to the
+cnid_metad daemon process.
+afpd processes communicate with the daemon for
+database reads and updates. If built with Berkeley DB transactions
+the probability for database corruption is practically zero, but
+performance can be slower than with \fBcdb\fR
+.TP 
+last
+This backend is an exception, in terms of ID persistency. ID's
+are only valid for the current session. This is basically what
+afpd did in the 1.5 (and 1.6) versions. This
+backend is still available, as it is useful for e.g. sharing
+cdroms.
+
+\fBWarning\fR: It is
+\fINOT\fR recommended to use this backend for volumes
+anymore, as afpd now relies heavily on a
+persistent ID database. Aliases will likely not work and filename
+mangling is not supported.
+.PP
+Even though ./configure \-\-help might show that
+there are other CNID backends available, be warned those are likely broken
+or mainly used for testing. Don't use them unless you know what you're
+doing, they may be removed without further notice from future
+versions.
+.SH "CHARSET OPTIONS"
+With OS X Apple introduced the AFP3 protocol. One of the most
+important changes was that AFP3 uses unicode names encoded as UTF\-8
+decomposed. Previous AFP/OS versions used codepages, like MacRoman,
+MacCentralEurope, etc.
+.PP
+afpd needs a way to preserve extended macintosh
+characters, or characters illegal in unix filenames, when saving files on
+a unix filesystem. Earlier versions used the the so called CAP encoding.
+An extended character (>0x7F) would be converted to a :xx sequence,
+e.g. the Apple Logo (MacRoman: 0XF0) was saved as \fB:f0\fR.
+Some special characters will be converted as to :xx notation as well.
+\&'\fB/\fR' will be encoded to \fB:2f\fR, if
+\fB\-usedots\fR is not specified, a leading dot
+\&'\fB.\fR' will be encoded as \fB:2e\fR.
+.PP
+This version now uses UTF\-8 as the default encoding for names.
+Special characters, like '\fB/\fR' and a leading
+\&'\fB.\fR' will still be CAP style encoded .
+.PP
+The \fB\-volcharset\fR option will allow you to select
+another volume encoding. E.g. for western users another useful setting
+could be \-volcharset ISO\-8859\-15. apfd will accept any
+\fBiconv\fR(1) provided charset. If a character cannot be converted
+from the mac codepage to the selected volcharset, afpd will save it as a
+CAP encoded character. For AFP3 clients, afpd will
+convert the UTF\-8 character to \fB\-maccharset\fR first. If this
+conversion fails, you'll receive a \-50 error on the mac.
+.PP
+\fINote\fR: Whenever you can, please stick with the
+default UTF\-8 volume format.
+.SH "COMPATIBILITY WITH EARLIER VERSIONS"
+To use a volume created with an earlier afpd
+version, you'll have to specify the following options:
+.PP
+\fBuse a 1.x style volume\fR
+.PP
+.nf
+/path/to/volume "Volname" adouble:v1 volcharset:ASCII
+.fi
+.PP
+In case you used an NLS you could try using a compatible iconv
+charset for \fB\-volcharset\fR.
+.PP
+\fBuse a 1.x style volume, created with maccode.iso8859\-1\fR
+.PP
+.nf
+/path/to/volume "Volname" adouble:v1 volcharset:ISO\-8859\-1
+.fi
+.PP
+You should consider converting old style volumes to the new
+UTF\-8/AD2 format. The safest way to do this, is to create a new volume
+with the default options and copy the files between this volumes with a
+mac.
+.PP
+\fINote\fR: Using above example options will allow
+you to downgrade to 1.x netatalk again.
+.PP
+\fINote\fR: Some 1.x NLS files used non standard
+mappings, e.g. \fBmaccode.iso8859\-1.adapted\fR. This is not
+supported anymore. You'll have to copy the contents of those volumes files
+to a Mac and then back to the netatalk server, preferably to an UTF\-8
+volume.
+.SH "ADVANCED OPTIONS"
+The following options should only be used after serious
+consideration. Be sure you fully understood the, sometimes complex,
+consequences, before using them.
+.TP 
+casefold:\fB[option]\fR
+The casefold option handles, if the case of filenames should
+be changed. The available options are:
+
+\fBtolower\fR \- Lowercases names in both
+directions.
+
+\fBtoupper\fR \- Uppercases names in both
+directions.
+
+\fBxlatelower\fR \- Client sees lowercase, server
+sees uppercase.
+
+\fBxlateupper\fR \- Client sees uppercase, server
+sees lowercase.
+.TP 
+options:[\fBoption\fR]
+This allows multiple options to be specified in a comma
+delimited format. The available options are:
+.RS 
+.TP 
+crlf
+Enables crlf translation for TEXT files, automatically
+converting macintosh line breaks into Unix ones. Use of this
+option might be dangerous since some older programs store
+binary data files as type "TEXT" when saving and switch the
+filetype in a second step. Afpd will
+potentially destroy such files when "erroneously" changing
+bytes in order to do line break translation.
+.TP 
+dropbox
+Allows a volume to be declared as being a "dropbox."
+Note that netatalk must be compiled with dropkludge support
+for this to function. \fIWarning\fR: This
+option is deprecated and might not work as expected.
+.TP 
+mswindows
+Forces filename restrictions imposed by MS WinXX.
+\fIWarning\fR: This is \fINOT\fR
+recommened for volumes mainly used by Macs. Please make sure
+you fully understand this option before using it.
+.TP 
+noadouble
+Forces afpd to not create
+\&.AppleDouble directories unless macintosh metadata needs to be
+written. This option is only useful if you want to share files
+mostly used NOT by macs, causing afpd to
+not automatically create .AppleDouble subdirs containing AD
+header files in every directory it enters (which will it do by
+default).
+
+In case, you save or change files from mac clients, AD
+metadata files have to be written even in case you set this
+option. So you can't avoid the creation of .AppleDouble
+directories and its contents when you give macs write access
+to a share and they make use of it.
+
+Try to avoid \fBnoadouble\fR whenever
+possible.
+.TP 
+nodev
+always use 0 for device number, helps when the device
+number is not constant across a reboot, cluster, ...
+.TP 
+nofileid
+don't advertise createfileid, resolveid, deleteid
+calls.
+.TP 
+nohex
+Disables :hex translations for anything except dot
+files. This option makes the \fB'/\fR' character
+illegal.
+.TP 
+prodos
+Provides compatibility with Apple II clients.
+.TP 
+nostat
+don't stat volume path when enumerating volumes list,
+useful for automounting or volumes created by a preexec
+script.
+.TP 
+upriv
+use AFP3 unix privileges. Become familiar with the new
+"unix privileges" AFP permissions concepts in MacOS X before
+using this option.
+.RE
+.SH "SEE ALSO"
+\fBafpd.conf\fR(5), \fBafpd\fR(8)
 
-.TP
-.B $$
-prints dollar sign (\fb$\fR)
-
-.SH SEE ALSO
-afpd(8)
index eac82b2a2298e948687d3d3eadfa42828a1062b1..7331e44babc4c89e74540915a316d5e6af695568 100644 (file)
@@ -14,7 +14,8 @@ SUFFIXES = .tmpl .
 man_MANS = AppleVolumes.default.5 afpd.conf.5 \
        atalkd.conf.5 netatalk.conf.5 papd.conf.5 
 
-TEMPLATE_FILES = $(foreach f,$(man_MANS),$(f).tmpl)
+TEMPLATE_FILES = AppleVolumes.default.5.tmpl afpd.conf.5.tmpl \
+       atalkd.conf.5.tmpl netatalk.conf.5.tmpl papd.conf.5.tmpl 
 
 CLEANFILES = $(man_MANS)
 
index ce20135ae656b9d00342e2c820e6088a2ba26e77..f768f5eb3350383ad650ec1976a43c2eecc0090e 100644 (file)
-.\" $Id: afpd.conf.5.tmpl,v 1.3 2002-05-03 22:51:34 jmarcus Exp $
-.TH afpd.conf 5 "28 September 2000" "netatalk 1.5"
-.UC 4
+.TH afpd.conf 5 "24 September 2004" 2.0.0 Netatalk 
 .SH NAME
-afpd.conf \- Configuration file used by \fBafpd\fR(8)
-to determine the setup of its file sharing services
-
+afpd.conf \- Configuration file used by afpd(8) to determine the setup of its file sharing services
 .SH DESCRIPTION
-\fB:ETCDIR:/afpd.conf\fR is the configuration file used
-by afpd to determine the behavior and configuration of the different
-virtual file servers that it provides.
-
-Any line not prefixed with \fB#\fR is interpreted. The configuration lines
-are composed like:
-
-.RS
-.sp
-.I server name
-.B [
-.I options
-.B ]
-
-.sp
-.RE
-If a \fB-\fR is used instead of a server name, the default server is
-specified. Server names must be quoted if they contain spaces.
-
+\fB:ETCDIR:/afpd.conf\fR is the configuration file
+used by afpd to determine the behavior and
+configuration of the different virtual file servers that it
+provides.
+.PP
+Any line not prefixed with # is interpreted. The configuration lines
+are composed like: server name [ options ] If a \fB\-\fR is used
+instead of a server name, the default server is specified. Server names
+must be quoted if they contain spaces. They must not contain ":" or "@".
 The path name must be a fully qualified path name, or a path name using
-either the \fB~\fR shell shorthand or any of the substitution variables,
-which are listed below.
+either the ~ shell shorthand or any of the substitution variables, which
+are listed below.
+.PP
+.RS 
+\fBNote\fR
+.PP
+Each server has to be configured on a \fBsingle\fR line.
+.RE
 
 The possible options and their meanings are:
-
-.TP
-.I AppleVolumes Files
-
-.TP
-.B -defaultvol [path]
-Specifies path to AppleVolumes.default file (default is 
+.SH "APPLEVOLUMES FILES"
+.TP 
+\-defaultvol \fI[path]\fR
+Specifies path to AppleVolumes.default file (default is
 \fB:ETCDIR:/AppleVolumes.default\fR).
-
-.TP
-.B -nlspath [path]
-Specifies the path to the code pages (default is \fB:ETCDIR:/nls\fR).
-
-.TP
-.B -systemvol [path]
-Specifies path to AppleVolumes.system file (default is 
+.TP 
+\-systemvol \fI[path]\fR
+Specifies path to AppleVolumes.system file (default is
 \fB:ETCDIR:/AppleVolumes.system\fR).
-
-.TP
-.B -[no]uservol
-Enables or disables reading of the users' individual volumes file
-entirely.
-
-.TP
-.B -[no]uservolfirst
-Enables or disables reading of the users' individual volumes file
-before processing the global \fBAppleVolumes.default\fR file.
-
-.TP
-.I Authentication Methods
-
-.TP
-.B -uamlist [uams list]
+.TP 
+\-[no]uservol
+Enables or disables reading of the users' individual volumes
+file entirely.
+.TP 
+\-[no]uservolfirst
+Enables or disables reading of the users' individual volumes
+file before processing the global
+\fBAppleVolumes.default\fR file.
+.SH "AUTHENTICATION METHODS"
+.TP 
+\-uamlist \fI[uams list]\fR
 Comma separated list of UAMs. (The default is
-\fBuams_guest.so,uams_passwd.so,uams_dhx_passwd.so\fR).
-The most commonly used UAMs are:
-
-\fBuams_dhx_passwd.so or uams_dhx_pam.so\fR - allows logins
-using Diffie-Hellman eXchange (DHX)
-
-\fBuams_guest.so\fR - allows guest logins
-
-\fBuams_passwd.so or uams_pam.so\fR - allows logins with clear
-text passwords
-
-\fBuams_randum.so\fR - allows Random Number and Two-Way Random
-Number Exchange for authentication (requires \fB:ETCDIR:/afppaswd\fR
-file)
+uams_guest.so,uams_clrtxt.so,uams_dhx.so).
 
-.TP
-.B -uampath [path]
-Sets the default path for UAMs for this server (default is 
+The most commonly used UAMs are:
+.RS 
+.TP 
+uams_guest.so
+allows guest logins
+.TP 
+uams_clrtxt.so
+(uams_pam.so or uams_passwd.so) Allow logins with
+passwords transmitted in the clear.
+.TP 
+uams_randum.so
+allows Random Number and Two\-Way Random Number Exchange
+for authentication (requires a separate file containing the
+passwords, either :ETCDIR:/afppasswd file or the one specified
+via \fB\-passwdfile\fR. See \fBafppasswd\fR(1) for details
+.TP 
+uams_dhx.so
+(uams_dhx_pam.so or uams_dhx_passwd.so) Allow
+Diffie\-Hellman eXchange (DHX) for authentication.
+.TP 
+uam_gss.so
+Allow Kerberos V for authentication (optional)
+.RE
+.TP 
+\-uampath \fI[path]\fR
+Sets the default path for UAMs for this server (default is
 :ETCDIR:/uams).
+.TP 
+\-k5keytab \fI[path]\fR, \-k5service \fI[service]\fR, \-k5realm \fI[realm]\fR
+These are required if the server supports the Kerberos 5
+authentication UAM.
+.SH "CODEPAGE OPTIONS"
+With OS X Apple introduced the AFP3 protocol. One of the big changes
+was, that AFP3 uses Unicode names encoded as UTF\-8 decomposed. Previous
+AFP/OS versions used codepages like MacRoman, MacCentralEurope,
+etc.
+.PP
+To be able to serve AFP3 and older clients at the same time,
+afpd needs to be able to convert between UTF\-8 and Mac
+codepages. Even OS X clients partly still rely on codepages. As there's no
+way, afpd can detect the codepage a pre AFP3 client
+uses, you have to specify it using the \fB\-maccodepage\fR
+option. The default is MacRoman, which should be fine for most western
+users.
+.PP
+As afpd needs to interact with unix operating
+system as well, it need's to be able to convert from UTF\-8/MacCodepage to
+the unix codepage. By default afpd uses the systems
+LOCALE, or ASCII if your system doesn't support locales. You can set the
+unix codepage using the \fB\-unixcodepage\fR option. If you're
+using extended characters in the configuration files for
+afpd, make sure your terminal matches the
+\fB\-unixcodepage\fR.
+.TP 
+\-unixcodepage [CODEPAGE]
+Specifies the servers unix codepage, e.g. "ISO\-8859\-15" or
+"UTF8". This is used to convert strings to/from the systems locale,
+e.g. for authenthication, server messages and volume names. Defaults
+to LOCALE if your system supports it, otherwise ASCII will be
+used.
+.TP 
+\-maccodepage [CODEPAGE]
+Specifies the mac clients codepage, e.g. "MAC_ROMAN". This is
+used to convert strings and filenames to the clients codepage for
+OS9 and Classic, i.e. for authentication and AFP messages (SIGUSR2
+messaging). This will also be the default for the volumes
+maccharset. Defaults to MAC_ROMAN.
+.SH "PASSWORD OPTIONS"
+.TP 
+\-loginmaxfail [number]
+Sets the maximum number of failed logins, if supported by the
+UAM (currently none)
+.TP 
+\-passwdfile [path]
+Sets the path to the Randnum UAM passwd file for this server
+(default is :ETCDIR:/afppasswd).
+.TP 
+\-passwdminlen [number]
+Sets the minimum password length, if supported by the
+UAM
+.TP 
+\-[no]savepassword
+Enables or disables the ability of clients to save passwords
+locally
+.TP 
+\-[no]setpassword
+Enables or disables the ability of clients to change their
+passwords via chooser or the "connect to server" dialog
+.SH "TRANSPORT PROTOCOLS"
+.TP 
+\-[no]ddp
+Enables or disables AFP\-over\-Appletalk. If
+\fB\-proxy\fR is specified, you must instead use
+\fB\-uamlist ""\fR to prevent DDP connections from
+working.
+.TP 
+\-[no]tcp
+Enables or disables AFP\-over\-TCP
+.TP 
+\-transall
+Make both available (default)
+.SH "TRANSPORT OPTIONS"
+.TP 
+\-advertise_ssh
+Allows Mac OS X clients (10.3.3 or above) to automagically
+establish a tunneled AFP connection through SSH. If this option is
+set, the server's answers to client's FPGetSrvrInfo requests contain
+an additional entry. It depends on both client's settings and a
+correctly configured and running \fBsshd\fR(8) on the server to let things work.
+.RS 
+\fBNote\fR
+
+Setting this option is not recommended since globally
+encrypting AFP connections via SSH will increase the server's load
+significantly. On the other hand, Apple's client side
+implementation of this feature in MacOS X versions prior to 10.3.4
+contained a security flaw.
+.RE
+.TP 
+\-ddpaddr \fI[ddp address]\fR
+Specifies the DDP address of the server. The default is to
+auto\-assign an address (0.0). This is only useful if you are running
+AppleTalk on more than one interface.
+.TP 
+\-fqdn \fI[name:port]\fR
+Specifies a fully\-qualified domain name, with an optional
+port. This is discarded if the server cannot resolve it. This option
+is not honored by AppleShare clients <= 3.8.3. This option is
+disabled by default. Use with caution as this will involve a second
+name resolution step on the client side. Also note that afpd will
+advertise this name:port combination but not automatically listen to
+it.
+.TP 
+\-ipaddr \fI[ip address]\fR
+Specifies the IP address that the server should advertise
+\fBand\fR listens to (the default is the
+first IP address of the system). This option also allows to use one
+machine to advertise the AFP\-over\-TCP/IP settings of another machine
+via NBP when used together with the \fB\-proxy\fR
+option.
+.TP 
+\-port \fI[port number]\fR
+Allows a different TCP port to be used for AFP\-over\-TCP. The
+default is 548.
+.TP 
+\-proxy
+Runs an AppleTalk proxy server for the specified AFP\-over\-TCP
+server. If the address and port aren't given, then the first IP
+address of the system and port 548 will be used. If you don't want
+the proxy server to act as a DDP server as well, set \fB\-uamlist
+""\fR.
+.TP 
+\-server_quantum \fI[number]\fR
+This specifoes the DSI server quantum. The minimum value is
+303840 (0x4A2E0). The maximum value is 0xFFFFFFFFF. If you specify a
+value that is out of range, the default value will be set (which is
+the minimum). Do not change this value unless you're absolutely
+sure, what you're doing
+.TP 
+\-noslp
+Do not register this server using the Service Location
+Protocol (if SLP support was compiled in). This is useful if you are
+running multiple servers and want one to be hidden, perhaps because
+it is advertised elsewhere, ie. by a SLP Directory Agent.
+.SH "MISCELLANEOUS OPTIONS"
+.TP 
+\-admingroup \fI[group]\fR
+Allows users of a certain group to be seen as the superuser
+when they log in. This option is disabled by default.
+.TP 
+\-authprintdir \fI[path]\fR
+Specifies the path to be used (per server) to store the files
+required to do CAP\-style print authentication which papd will
+examine to determine if a print job should be allowed. These files
+are created at login and if they are to be properly removed, this
+directory probably needs to be umode 1777.
+.RS 
+\fBNote\fR
+
+\fB\-authprintdir\fR will only work for clients
+connecting via DDP. Almost all modern Clients will use TCP.
+.RE
+.TP 
+\-client_polling
+With this switch enabled, afpd won't advertise that it is
+capable of server notifications, so that connected clients poll the
+server every 10 seconds to detect changes in opened server windows.
+\fINote\fR: Depending on the number of simultaneously
+connected clients and the network's speed, this can lead to a
+significant higher load on your network!
+.RS 
+\fBNote\fR
+
+Do not use this option any longer as Netatalk 2.0 correctly
+supports server notifications, allowing connected clients to
+update folder listings in case another client changed the
+contents.
+.RE
+.TP 
+\-cnidserver \fI[ipaddress:port]\fR
+Specifies the IP address and port of a cnid_metad server,
+required for CNID dbd backend. Defaults to localhost:4700.
+.TP 
+\-guestname \fI[name]\fR
+Specifies the user that guests should use (default is
+"nobody"). The name should be quoted.
+.TP 
+\-icon
+Use the platform\-specific icon
+.TP 
+\-loginmesg \fI[message]\fR
+Sets a message to be displayed when clients logon to the
+server. The message should be in \fBunixcodepage\fR and
+should be quoted. Extended characters are allowed.
+.TP 
+\-nodebug
+Disables debugging.
+.TP 
+\-sleep \fI[number]\fR
+AFP 3.x waits number hours before
+disconnecting clients in sleep mode. Default is 10 hours.
+.TP 
+\-signature { user:<text> | host }
+Specify a server signature. This option is useful while
+running multiple independent instances of afpd on one machine (eg.
+in clustered environments, to provide fault isolation etc.). "host"
+signature type allows afpd generating signature automatically (based
+on machine primary IP address). "user" signature type allows
+administrator to set up a signature string manually. The maximum
+length is 16 characters
+
+\fBThree server definitions using 2 different server
+signatures\fR
+
+.nf
+first \-signature user:USERS 
+second \-signature user:USERS 
+third \-signature user:ADMINS
+.fi
+
+First two servers will appear as one logical AFP service to
+the clients \- if user logs in to first one and then connects to
+second one, session will be automatically redirected to the first
+one. But if client connects to first and then to third, will be
+asked for password twice and will see resources of both servers.
+Traditional method of signature generation causes two independent
+afpd instances to have the same signature and thus cause clients to
+be redirected automatically to server (s)he logged in first.
+.SH "LOGGING OPTIONS"
+.RS 
+\fBNote\fR
+.PP
+Extended logging capabilities are only available if Netatalk was
+built using \-\-with\-logfile. As of Netatalk 2.0, the
+default is \-\-without\-logfile since the logger code is
+partially broken and needs a complete rewrite (the
+\fB\-setuplog\fR option might not work as expected). If
+Netatalk was built without logger support then the daemons log to
+syslog.
+.RE
+.TP 
+\-[un]setuplog "<logtype> <loglevel> [<filename>]"
+Specify that the given loglevel should be applied to log
+messages of the given logtype and that these messages should be
+logged to the given file. If the filename is ommited the loglevel
+applies to messages passed to syslog. Each logtype may have a
+loglevel applied to syslog and a loglevel applied to a single file.
+Latter \fB\-setuplog\fR settings will override earlier
+ones of the same logtype (file or syslog).
+
+logtypes: Default, Core, Logger, CNID, AFP
+
+Daemon loglevels: LOG_SEVERE, LOG_ERROR, LOG_WARN, LOG_NOTE,
+LOG_INFO, LOG_DEBUG, LOG_DEBUG6, LOG_DEBUG7, LOG_DEBUG8, LOG_DEBUG9,
+LOG_MAXDEBUG
+
+\fBSome ways to change afpd's logging behaviour via
+\-[un]setuplog\fR
+
+Example: 
+
+.nf
+\-setuplog "logger log_maxdebug /var/log/netatalk\-logger.log" 
+\-setuplog "afpdaemon log_maxdebug /var/log/netatalk\-afp.log" 
+\-unsetuplog "default level file" 
+\-setuplog "default log_maxdebug"
+.fi
+.SH "DEBUG OPTIONS"
+These options are useful for debugging only.
+.TP 
+\-tickleval \fI[number]\fR
+Sets the tickle timeout interval (in seconds). Defaults to
+30.
+.TP 
+\-timeout \fI[number]\fR
+Specify the number of tickles to send before timing out a
+connection. The default is 4, therefore a connection will timeout
+after 2 minutes.
+.SH EXAMPLES
+\fBafpd.conf default configuration\fR
+.PP
+.nf
+\- \-transall \-uamlist uams_clrtxt.so,uams_dhx.so,uams_guest.so
+.fi
+.PP
+\fBafpd.conf MacCyrillic setup / UTF8 unix locale\fR
+.PP
+.nf
+\- \-transall \-maccodepage mac_cyrillic \-unixcodepage utf8
+.fi
+.PP
+\fBafpd.conf setup for Kerberos V auth\fR
+.PP
+.nf
+\- \-transall \-uamlist uams_clrtxt.so,uams_dhx.so,uams_guest.so,uams_gss.so \\ 
+\-k5service afpserver \-k5keytab /path/to/afpserver.keytab \\ 
+\-k5realm YOUR.REALM \-fqdn your.fqdn.namel:548
+.fi
+.PP
+\fBafpd.conf letting afpd appear as three servers on the net\fR
+.PP
+.nf
+"Guest Server" \-uamlist uams_guest.so \-loginmesg "Welcome guest!"
+"User Server" \-uamlist uams_dhx.so \-port 12000
+"special" \-notcp \-defaultvol <path> \-systemvol <path>
+.fi
+.SH "SEE ALSO"
+\fBafpd\fR(8), \fBafppasswd\fR(1), \fBAppleVolumes.default\fR(5)
 
-.TP
-.I Password Options
-
-.TP
-.B -loginmaxmail [number]
-Sets the maximum number of failed logins, if supported by the UAM
-
-.TP
-.B -passwdfile [path]
-Sets the path to the Randnum passwd file for this server (default is
-\fB:ETCDIR:/afppasswd\fR).
-
-.TP
-.B -passwdminlen [number]
-Sets the minimum password length, if supported by the UAM
-
-.TP
-.B -[no]savepassword
-Enables or disables the ability of clients to save passwords locally
-
-.TP
-.B -[no]setpassword
-Enables or disables the ability of clients to change their passwords
-
-
-.TP
-.I Transport Protocols
-
-.TP
-.B -[no]ddp
-Enables or disables AFP-over-Appletalk. If \fB-proxy\fR is specified, you must
-instead use \fB-uamlist ""\fR to prevent DDP connections from working.
-
-.TP
-.B -[no]tcp
-Enables or disables AFP-over-TCP
-
-.TP
-.I Transport Options
-
-.TP
-.B -admingroup [group]
-Allows users of a certain group to be seen as the superuser when they
-log in. This option is disabled, by default.
-
-.TP
-.B -ddpaddr [ddp address]
-Specifies the DDP address of the server. The default is to auto-assign an
-address (0.0). This is only useful if you are running on a multihomed host.
-
-.TP
-.B -fqdn [name:port]
-Specifies a fully-qualified domain name, with an optional port. This is
-discarded if the server cannot resolve it. This option is not honored by
-AppleShare clients <= 3.8.3. This option is disabled by default.
-
-.TP
-.B -ipaddr [ip address]
-Specifies the IP that the server should respond to (the default is the
-first IP address of the system). This option also allows one machine to
-advertise TCP/IP for another machine.
-
-.TP
-.B -port [port number]
-Allows a different TCP port to be specified for AFP-over-TCP. The default
-is 548.
-
-.TP
-.B -proxy
-Runs an AppleTalk proxy server for the specified AFP-over-TCP server. If
-the address and port aren't given, then the first IP address of the system
-and port 548 will be used. If you don't want the proxy server to act as a
-DDP server as well, set \fB-uamlist ""\fR.
-
-.TP
-.B -server_quantum [number]
-This specifoes the DSI server quantum. The minimum value is 1 MB. The
-maximum value is 0xFFFFFFFFF. If you specify a value that is out of
-range, the default value will be set (which is the minimum).
-
-.TP
-.B -noslp
-Do not register this server using the Service Location Protocol (if SLP
-support was compiled in).  This is useful if you are running multiple
-servers and want one to be hidden, perhaps because it is advertised elsewhere.
-
-.TP
-.I Miscellaneous Options
-
-.TP
-.B -guestname [name]
-Specifies the user that guests should use (default is \fB"nobody"\fR). The
-name should be quoted.
-
-.TP
-.B -icon
-Use the platform-specific icon
-
-.TP
-.B -loginmsg [message]
-Sets a message to be displayed when clients logon to the server. The
-message should be quoted.
-
-.TP
-.B -nodebug
-Disables debugging
-
-.TP
-.B -tickleval [number]
-Sets the tickle timeout interval (in seconds).
-
-.SH SEE ALSO
-afpd(8), AppleVolumes.default(5)
index 1e78497482e987e5a03e2e83aac5964810fb546b..31f3a5e5c360d46b1166cbb60fd9e64350988dee 100644 (file)
@@ -1,68 +1,65 @@
-.\" $Id: atalkd.conf.5.tmpl,v 1.1 2000-09-22 20:01:39 rufustfirefly Exp $
-.TH atalkd.conf 5 "22 September 2000" "netatalk 1.5"
-.UC 4
+.TH atalkd.conf 5 "22 September 2000" 2.0.0 Netatalk 
 .SH NAME
-atalkd.conf \- Configuration file used by \fBatalkd\fR(8)
-to determine the interfaces used by the master Netatalk daemon
-
+atalkd.conf \- Configuration file used by atalkd(8) to determine the interfaces used by the master Netatalk daemon
 .SH DESCRIPTION
-\fB:ETCDIR:/atalkd.conf\fR is the configuration file used
-by atalkd to configure the Appletalk interfaces and their behavior
-
-Any line not prefixed with \fB#\fR is interpreted. The configuration lines
-are composed like:
-
-.RS
-.sp
-.I interface
-.B [
-.I options
-.B ]
-
-.sp
-.RE
-The simplest case is to have either no atalkd.conf, or to have one that
-has no active lines. In this case, atalkd should auto-discover the local
-interfaces on the machine. Please note that you cannot split lines.
-
-The interface is the network interface that this to work over, such as
-\fBeth0\fR for Linux, or \fBle0\fR for Sun.
-
+\fI:ETCDIR:/atalkd.conf\fR is the
+configuration file used by atalkd to configure the Appletalk interfaces
+and their behavior
+.PP
+Any line not prefixed with \fI#\fR is
+interpreted. The configuration lines are composed like:
+.PP
+\fIInterface\fR \fI[\fR \fIoptions\fR \fI]\fR
+.PP
+The simplest case is to have either no atalkd.conf, or to have one
+that has no active lines. In this case, atalkd should auto\-discover the
+local interfaces on the machine. Please note that you cannot split
+lines.
+.PP
+The interface is the network interface that this to work over, such
+as \fIeth0\fR for Linux, or \fIle0\fR for Sun.
+.PP
 The possible options and their meanings are:
-
-.TP
-.B -addr net.node
-Allows specification of the net and node numbers for this interface,
-specified in Appletalk numbering format (example: \fI-addr 66.6\fR).
-
-.TP
-.B -dontroute
-Disables Appletalk routing. It is the opposite of \fB-router\fR.
-
-.TP
-.B -net first[-last]
-Allows the available net to be set, optionally as a range.
-
-.TP
-.B -phase ( 1 | 2 )
-Specifies the Appletalk phase that this interface is to use (either Phase
-1 or Phase 2).
-
-.TP
-.B -router
-Like \fB-seed\fR, but allows single interface routing. It is the opposite
-of \fB-dontroute\fR.
-
-.TP
-.B -seed
-The seed option only works if you have multiple interfaces. It also causes
-all missing arguments to be automagically configured from the network.
-
-.TP
-.B -zone zonename
+.TP 
+\fB\-addr \fInet.node\fB\fR
+Allows specification of the net and node numbers for this
+interface, specified in Appletalk numbering format (example:
+\fB\-addr 66.6\fR).
+.TP 
+\fB\-dontroute\fR
+Disables Appletalk routing. It is the opposite of
+\fB\-router\fR.
+.TP 
+\fB\-net first[\-last]\fR
+Allows the available net to be set, optionally as a
+range.
+.TP 
+\fB\-noallmulti\fR (linux only)
+On linux the interfaces, atalkd uses, are set to
+ALLMULTI by default caused by countless NICs having problems
+without being forced into this mode (some even don't work with
+allmulti set). In case, you've a NIC known to support multicasts
+properly, you might want to set this option causing less packets to
+be processed
+.TP 
+\fB\-phase ( 1 | 2 )\fR
+Specifies the Appletalk phase that this interface is to use
+(either Phase 1 or Phase 2).
+.TP 
+\fB\-router\fR
+Like \fB\-seed\fR, but allows single interface
+routing. It is the opposite of \fB\-dontroute\fR.
+.TP 
+\fB\-seed\fR
+The seed option only works if you have multiple interfaces. It
+also causes all missing arguments to be automagically configured
+from the network.
+.TP 
+\fB\-zone \fIzonename\fB\fR
 Specifies a specific zone that this interface should appear on (example:
-\fI-zone "Parking Lot"\fR). Please note that zones with spaces and other
-special characters should be enclosed in parentheses.
+\fB\-zone "Parking Lot"\fR). Please note that zones with
+spaces and other special characters should be enclosed in
+parentheses.
+.SH "SEE ALSO"
+\fBatalkd\fR(8)
 
-.SH SEE ALSO
-atalkd(8)
index 5b148dbd5ced49a44154050243e17447a7e800e7..7ebe7ac6d171139eaf1773b828ac53ded9ac0eb0 100644 (file)
@@ -1,72 +1,67 @@
-.\" $Id: netatalk.conf.5.tmpl,v 1.2 2000-09-28 16:49:21 rufustfirefly Exp $
-.TH netatalk.conf 5 "28 September 2000" "netatalk 1.5"
-.UC 4
+.TH netatalk.conf 5 "24 June 2004" 2.0.0 Netatalk 
 .SH NAME
-netatalk.conf \- Configuration file used by \fBnetatalk\fR(8)
-to determine its general configuration
-
+netatalk.conf \- Configuration file used by netatalk(8) to determine its general configuration 
 .SH DESCRIPTION
-\fB:ETCDIR:/netatalk.conf\fR is the configuration file used
-by afpd to determine what portions of the file system will be shared via
-Appletalk, as well as their behaviors.
-
-Any line not prefixed with \fB#\fR is interpreted. The configuration lines
-are composed like:
-
-.RS
-.sp
-.I option
-.B =
-.I value
-
-.sp
-.RE
+\fI:ETCDIR:/netatalk.conf\fR is the
+configuration file used by afpd to determine what portions of the file
+system will be shared via Appletalk, as well as their behaviors.
+.PP
+Any line not prefixed with \fI#\fR is
+interpreted. The configuration lines are composed like:
+.PP
+\fIoption\fR \fI=\fR
+\fIvalue\fR
+.PP
 The possible options and their meanings are:
-
-.TP
-.B AFPD_GUEST
+.TP 
+\fIAFPD_GUEST\fR
 Sets the id of the guest user to a local user on the system.
+.TP 
+\fIAFPD_MAX_CLIENTS\fR
+Sets the maximum number of clients that can simultaneously
+connect to the server.
+.TP 
+\fIAFPD_RUN\fR
+Enables the afpd daemon if set to "yes". This should
+be enabled if you are planning on using netatalk as a file server.
+.TP 
+\fIAFPD_UAM_LIST\fR
+Sets the default UAMs for afpd (and papd, if printer
+authentication is compiled in) to use.
 
-.TP
-.B AFPD_MAX_CLIENTS
-Sets the maximum number of clients that can simultaneously connect to
-the server.
-
-.TP
-.B AFPD_RUN
-Enables the afpd daemon if set to "yes". This should be enabled if you
-are planning on using netatalk as a file server.
-
-.TP
-.B AFPD_UAM_LIST
-Sets the default UAMs for afpd (and papd, if printer authentication is
-compiled in) to use.
-
-\fIExample:\fR
-\fBAFPD_UAMLIST\fR=\fB"-U uams_guest.so,uams_randnum.so"\fR
-
-.TP
-.B ATALK_BGROUND
-"yes" will set netatalk to initialize in the background, and "no" will
-cause normal initialization.
-
-.TP
-.B ATALK_NAME
+\fIExample:\fR \fIAFPD_UAMLIST\fR=\fI"\-U uams_guest.so,uams_randnum.so"\fR
+.TP 
+\fICNID_METAD_RUN\fR
+Enables the cnid_metad daemon if set to "yes". This
+should be enabled if you are going to use the dbd CNID backend.
+.TP 
+\fIATALK_BGROUND\fR
+"yes" will set netatalk to initialize in the
+background, and "no" will cause normal initialization.
+.TP 
+\fIATALK_NAME\fR
 Sets the machines' Appletalk name.
-
-.TP
-.B ATALK_ZONE
+.TP 
+\fIATALK_ZONE\fR
 Sets the machines' Appletalk zone.
+.TP 
+\fIATALKD_RUN\fR
+Enables the atalkd daemon if set to "yes". This should
+be enabled if you are planning on providing Appletalk services.
+.TP 
+\fIPAPD_RUN\fR
+Enables the papd daemon if set to "yes". This should
+be enabled if you are planning on using netatalk as a print server.
+.TP 
+\fIATALK_MAC_CHARSET\fR
+Set the Mac client codepage, used by atalkd and papd to
+convert extended characters from the Unix to the Mac codepage.
+.TP 
+\fIATALK_UNIX_CHARSET\fR
+Set the Unix codepage, used by atalkd and papd to convert
+extended characters from the Unix to the Mac codepage. Has to match
+the codepage of the configuration files.
+.SH "SEE ALSO"
+\fBatalkd\fR(8),
+\fBatalkd.conf\fR(5)
 
-.TP
-.B ATALKD_RUN
-Enables the atalkd daemon if set to "yes". This should be enabled if
-you are planning on providing Appletalk services.
-
-.TP
-.B PAPD_RUN
-Enables the papd daemon if set to "yes". This should be enabled if you
-are planning on using netatalk as a print server.
-
-.SH SEE ALSO
-atalkd(8), atalkd.conf(5)
index 066866c96bcc97577967426775f0078041bd5e6a..065898e68d43e919164f22f70429200d46471b59 100644 (file)
-.\" $Id: papd.conf.5.tmpl,v 1.2 2002-03-19 23:23:53 morgana Exp $
-.TH papd.conf 5 "26 September 2000" "netatalk 1.5"
-.UC 4
+.TH papd.conf 5 "06 Sep 2004" 2.0.0 Netatalk 
 .SH NAME
-papd.conf \- Configuration file used by \fBpapd\fR(8)
-to determine the configuration of printers used by the Netatalk printing
-daemon
-
+papd.conf \- Configuration file used by papd(8) to determine the configuration of printers used by the Netatalk printing daemon
 .SH DESCRIPTION
-\fB:ETCDIR:/papd.conf\fR is the configuration file used
-by papd to configure the printing services offered by netatalk. Please note
-that papd must be enabled in \fB:ETCDIR:/netatalk.conf\fR for this to take
-any effect. \fBpapd\fR shares the same defaults as lpd on many systems, but not
-Solaris.
-
-Any line not prefixed with \fB#\fR is interpreted. The configuration lines
-are composed like:
-
-.RS
-.sp
-.I printername:[options]
-
-.sp
-.RE
-The simplest case is to have either no papd.conf, or to have one that
-has no active lines. In this case, atalkd should auto-discover the local
-printers on the machine. Please note that you can split lines by using
-\fB\\\fR.
-
-printername may be just a name (\fBPrinter 1\fR), or it may be a full name
-in nbp_name format (\fBPrinter 1:LaserWriter@My Zone\fR).  If more than 15
-printers are defined, you should explicitly define the zone for each printer.
-Otherwise, the Mac Chooser not show all the printers.
-
-The possible options are colon delimited (\fB:\fR), and lines must be
-terminated with colons. The possible options and flags are:
+\fI:ETCDIR:/papd.conf\fR is the
+configuration file used by papd to configure the printing services offered
+by netatalk. Please note that papd must be enabled in \fI:ETCDIR:/netatalk.conf\fR for this to take any effect.
+\fIpapd\fR shares the same defaults as lpd on
+many systems, but not Solaris.
+.PP
+Any line not prefixed with \fI#\fR is
+interpreted. The configuration lines are composed like:
+.PP
+\fIprintername:[options]\fR
+.PP
+On systems running a System V printing system the simplest case is
+to have either no papd.conf, or to have one that has no active lines. In
+this case, atalkd should auto\-discover the local printers on the machine.
+Please note that you can split lines by using \fI\\\\fR.\fR
+.PP
+printername may be just a name (\fIPrinter
+1\fR), or it may be a full name in nbp_name format (\fIPrinter 1:LaserWriter@My Zone\fR).
+.PP
+Systems using a BSD printing system should make use of a pipe to the
+printing command in question within the \fIpr\fR
+option (eg. \fIpr=|/usr/bin/lpr \-J%J \-u%U\fR).
+Note: When printing using a pipe, papd recognizes several wildcards: %F
+will be replaced by the name present in the "%%For:" comment in the
+PostScript stream, same with %J for the "%%Title:" comment. %U will be
+substituted with the login name (the latter applies only when
+authenticated printing is in effect).
+.PP
+When CUPS support is compiled in, then \fIcupsautoadd \fRas the first entry in papd.conf will
+automagically share all CUPS printers by papd utilizing the PPDs assigned
+in CUPS (customizable \-\- see below). This can be overwritten for individal
+printers by subsequently adding individual entries using the CUPS queue
+name as \fIpr \fRentry. Note: CUPS support is
+mutually exclusive with System V support described above.
+.PP
+The possible options are colon delimited (\fI:\fR), and lines must be terminated with colons. The
+possible options and flags are:
+.TP 
+\fIam=(uams list)\fR
+The \fIam\fR option allows specific
+UAMs to be specified for a particular printer. It has no effect if
+the \fIau\fR flag is not present or if papd
+authentication was not built into netatalk. Note: possible values
+are \fIuams_guest.so\fR and \fIuams_clrtxt.so\fR only. The first method requires
+a valid username, but no password. The second requires both a valid
+username and the correct password.
+.TP 
+\fIau\fR
+If present, this flag enables authentication for the printer.
+Please note that papd authentication must be built into netatalk for
+this to take effect.
+.TP 
+\fIco=(CUPS options)\fR
+The \fIco\fR option allows options to
+be passed through to CUPS (eg. \fIco="protocol=TBCP" \fRor \fIco="raw"\fR).
+.TP 
+\fIcupsautoadd[:type][@zone]\fR
+If used as the first entry in papd.conf this will share all
+CUPS printers via papd. type/zone settings as well as other
+parameters assigned to this special printer share will apply to all
+CUPS printers. Unless the \fIpd\fR option
+is set, the CUPS PPDs will be used. To overwrite these global
+settings for individual printers simply add them subsequently to
+papd.conf and assign different settings.
+.TP 
+\fIfo\fR
+If present, this flag enables a hack to translate line endings
+originating from pre Mac OS X LaserWriter drivers to let \fIfoomatic\-rip\fR recognize foomatic PPD options set
+in the printer dialog. Attention: Use with caution since this might
+corrupt binary print jobs!
+.TP 
+\fIop=(operator)\fR
+This specifies the operator name, for lpd spooling.
+.TP 
+\fIpa=(appletalk address)\fR
+Allows specification of Appletalk addresses. Usually not
+needed.
+.TP 
+\fIpd=(path to ppd file)\fR
+Specifies a particular PPD (printer description file) to
+associate with the selected printer.
+.TP 
+\fIpr=(lpd/CUPS printer name or pipe command)\fR
+Sets the \fIlpd\fR or \fICUPS\fR printer that this is spooled to.
+.SH EXAMPLES
+Unless CUPS support has been compiled in (which is default from
+Netatalk 2.0 on) one simply defines the lpd queue in question by setting
+the \fBpr\fR parameter to the queue name, in the following
+example "ps". If no \fBpr\fR parameter is set, the default
+printer will be used.
+.PP
+\fBpapd.conf System V printing system examples\fR
+.PP
+The first spooler is known by the AppleTalk name Mac Printer
+Spooler, and uses a PPD file located in
+\fB/usr/share/lib/ppd\fR. In addition, the user mcs will
+be the owner of all jobs that are spooled. The second spooler is known
+as HP Printer and all options are the default. 
 
-.TP
-.B am=(uams list)
-The \fBam\fR option allows specific UAMs to be specified for a particular
-printer. It has no effect if the \fBau\fR flag is not present or if papd
-authentication was not built into netatalk.
+.nf
+Mac Printer Spooler:\\
+   :pr=ps:\\
+   :pd=/usr/share/lib/ppd/HPLJ_4M.PPD:\\
+   :op=mcs:
 
-.TP
-.B au
-If present, this flag enables authentication for the printer. Please note
-that papd authentication must be built into netatalk for this to take
-effect.
+HP Printer:\\
+   :
+.fi
+.PP
+An alternative to the technique outlined above is to direct papd's
+output via a pipe into another program. Using this mechanism almost all
+printing systems can be driven. Netatalk supplies three "wildcards" that
+get substituted with values of the already printed job:
+\fB%F\fR, \fB%U\fR and \fB%J\fR. Using
+these wildcards, one can pass those parameters directly to programs or
+implement small wrapper scripts to call the printing system in
+question.
+.PP
+\fBpapd.conf examples using pipes\fR
+.PP
+The first spooler is known as HP 8100. It pipes the print job to
+/usr/bin/lpr for printing using the value of the
+\fI%%Title: \fRcomment as job name. PSSP authenticated
+printing is enabled, as is CAP\-style authenticated printing. Both
+methods support guest and cleartext authentication as specified by the
+\&'\fBam\fR' option. The PPD used is
+\fB/etc/atalk/ppds/hp8100.ppd\fR. The second spooler is
+called "Dump PostScript" and uses a pipe to cat to
+send the raw PostScript code into the user's home directory into a file
+called like the printjob. 
 
-.TP
-.B op=(operator)
-This specifies the operator name, for lpd spooling.
+.nf
+HP 8100:\\
+   :pr=|/usr/bin/lpr \-Plp \-J"%J":\\
+   :sp:\\
+   :ca=/tmp/print:\\
+   :am=uams_guest.so,uams_pam.so:\\
+   :pd=/etc/atalk/ppds/hp8100.ppd:
 
-.TP
-.B pa=(appletalk address)
-Allows specification of Appletalk addresses. Usually not needed.
+Dump PostScript:LaserWriter@Server:\\
+   :pr=|cat >/home/%U/%J\-prn.out:\\
+   :pd=/usr/share/lib/ppd/mooralana.ppd:\\
+   :sp:au:op=lp:\\
+   :am=uams_clrtxt.so:
+.fi
+.PP
+Starting with Netatalk 2.0 direct CUPS integration is available. In
+this case, defining only a queue name as \fBpr\fR parameter
+won't invoke the SysV lpd daemon but uses CUPS instead. Unless a specific
+PPD has been assigned using the \fBpd\fR switch, the PPD
+configured in CUPS will be used by papd, too.
+.PP
+There exists one special share named "cupsautoadd". If this is
+present as the first entry then all available CUPS queues will be served
+automagically using the parameters assigned to this global share. But
+subsequent printer definitions can be used to override these global
+settings for individual spoolers.
+.PP
+\fBpapd.conf CUPS examples\fR
+.PP
+The first entry sets up automatic sharing of all CUPS printers.
+All those shares appear in the zone "1st floor" and since no additional
+settings have been made, they use the CUPS printer name as NBP name and
+use the PPD configured in CUPS. The second entry defines different
+settings for one single CUPS printer. It's NBP name is differing from
+the printer's name and the registration happens in another zone.
 
-.TP
-.B pd=(path to ppd file)
-Specifies a particular PPD (printer description file) to associate with
-the selected printer.
+.nf
+cupsautoadd@1st floor:op=root:
 
-.TP
-.B pr=(lpd printer name)
-Sets the \fBlpd\fR printer that this is spooled to.
+Boss' LaserWriter@2nd floor:\\
+   :pr=laserwriter\-chief:
+.fi
+.SH "SEE ALSO"
+\fBpapd\fR(8), \fBatalkd.conf\fR(5), \fBlpd\fR(8), \fBlpoptions\fR(8)
 
-.SH SEE ALSO
-papd(8), atalkd.conf(5), lpd(8)
index 5aa4ca15163871e1c3ce9da6904be9e6f70f4459..093ec0d6d589c8a6cd665cb62eca4df52584beeb 100644 (file)
@@ -10,11 +10,12 @@ SUFFIXES = .tmpl .
            -e s@:ETCDIR:@${pkgconfdir}@ \
            -e s@:LIBDIR:@${libdir}@ \
            -e s@:LIBEXECDIR:@${libexecdir}@ \
+           -e s@:NETATALK_VERSION:@${NETATALK_VERSION}@ \
            <$< >$@
 
 NONGENERATED_MANS = timelord.8
-GENERATED_MANS    = afpd.8 atalkd.8 papd.8 papstatus.8 psf.8
-TEMPLATE_FILES    = $(foreach f,$(GENERATED_MANS),$(f).tmpl)
+GENERATED_MANS    = afpd.8 atalkd.8 cnid_dbd.8 cnid_metad.8 papd.8 papstatus.8 psf.8
+TEMPLATE_FILES    = afpd.8.tmpl atalkd.8.tmpl cnid_dbd.8.tmpl cnid_metad.8.tmpl papd.8.tmpl papstatus.8.tmpl psf.8.tmpl
 
 man_MANS = $(GENERATED_MANS) $(NONGENERATED_MANS)
 
index a17e1fa8c0ae959074cf9b8e5e5eb29c42834d8a..2ab57cf14b82eec730371514dbab0a8169bc1572 100644 (file)
-.TH AFPD 8 "23 Feb 1999" "netatalk 1.4b2/asun 2.1.3"
-
+.TH afpd 8 "06 Jan 2004" 2.0.0 Netatalk 
 .SH NAME
 afpd \- AppleTalk Filing Protocol daemon
 .SH SYNOPSIS
-.B afpd
-[
-.B -duptDTvI
-]
-[
-.B -f
-.I defaultvolumes
-]
-[
-.B -s
-.I systemvolumes
-]
-[
-.B -n
-.I nbpname
-]
-[
-.B -c
-.I maxconnections
-]
-[
-.B -g
-.I guest
-]
-[
-.B -P
-.I pidfile
-]
-[
-.B -S
-.I port
-]
-[
-.B -L
-.I message
-]
-[
-.B -F
-.I config
-]
-[
-.B -U
-.I uams
-]
-[
-.B -m
-.I umask
-]
+\fBafpd\fR [\-duptDTvI] [\-f \fBdefaultvolumes\fR] [\-s \fBsystemvolumes\fR] [\-n \fBnbpname\fR] [\-c \fBmaxconnections\fR] [\-g \fBguest\fR] [\-P \fBpidfile\fR] [\-S \fBport\fR] [\-L \fBmessage\fR] [\-F \fBconfig\fR] [\-U \fBuamsv\fR] [\-m \fBumask\fR]
 .SH DESCRIPTION
-.B afpd
-provides an AppleTalk Filing Protocol (AFP)
-interface to the Unix file system.  It is normally started at boot time
-from
-.BR /etc/rc .
+afpd provides an AppleTalk Filing Protocol (AFP)
+interface to the Unix file system. It is normally started at boot time
+from /etc/rc. 
+.PP
 The list of volumes offered to the user is generated from
-.B :ETCDIR:/AppleVolumes.system
-and one of
-.BR :ETCDIR:/AppleVolumes.default ,
-.BR ~/AppleVolumes ,
-or
-.BR ~/.AppleVolumes .
-.LP
-The
-.B AppleVolumes
-files is used to specify volumes to mount and file name extension mappings.
-It is formatted as follows, one specification per line:
-.RS
-.sp
-.I pathname
-[
-.I volumename
-]
-.br
-.RI . extension
-[
-.I type
-[
-.I creator
-]
-]
-.sp
-.RE
-If
-.I volumename
-is unspecified, the last component of
-.I pathname
-is used.  No two volumes may have the same name.  If
-.I type
-is unspecified
-.RB ' ???? '
-is used.  If
-.I creator
-is unspecified
-.RB ' UNIX '
-is used.  The extension
-.RB ' . '
-sets the default creator and type for otherwise untyped Unix files.
-Blank lines and lines beginning with `#' are ignored.
+\fB:ETCDIR:/AppleVolumes.system\fR and one of
+\fB:ETCDIR:/AppleVolumes.default\fR, \fB~/AppleVolumes\fR,
+or \fB~/.AppleVolumes\fR. The \fBAppleVolumes\fR
+files is used to specify volumes to mount and file name extension
+mappings. It is formatted as follows, one specification per line: pathname
+[ volumename ] .extension [ type [ creator ] ] If volumename is
+unspecified, the last component of pathname is used. No two volumes may
+have the same name. If type is unspecified '????' is used. If
+creator is unspecified 'UNIX' is used. The extension '.'
+sets the default creator and type for otherwise untyped Unix files. Blank
+lines and lines beginning with `#' are ignored.
+.PP
 .SH OPTIONS
-.TP
-.B \-d
-Specifies that the daemon not fork, and that a trace of all AFP
-commands be written to stdout.
-.TP
-.BI \-f " defaultvolumes"
-Specifies that
-.I defaultvolumes
-should be read for a list of default volumes to offer, instead of
-.BR :ETCDIR:/AppleVolumes.default .
-.TP
-.BI \-s " systemvolumes"
-Specifies that
-.I systemvolumes
-should be read for a list of volume that all users will be offered,
-instead of
-.BR :ETCDIR:/AppleVolumes.system .
-.TP
-.B \-u
-Read the user's
-.B AppleVolumes
-file first.  This option causes volume names in the user's
-.B AppleVolumes
-file to override volume names in the system's
-.B AppleVolumes
-file.  The default is to read the system
-.B AppleVolumes
-file first.  Note that this option doesn't effect the precendence of
-filename extension mappings: the user's AppleVolumes file always has
-precedence.
-.TP
-.BI \-n " nbpname"
-Specifies that
-.I nbpname
-should be used for NBP registration, instead of the first component of
-the hostname in the local zone.
-.TP
-.BI \-c " maxconnections"
-Specifies the maximum number of connections to allow for this
-.BR afpd .
-The default is 5.
-.TP
-.BI \-g " guest"
-Specifies the name of the guest account.  The default is ``nobody''.
-.TP
-.BI \-P " pidfile"
-Specifies the file in which
-.B afpd
-stores its process id.
-.TP
-.B \-p
-Prevents clients from saving their passwords. (Equivalent to
-.I \-nosavepasswd
-in
-.BR afpd.conf .)
-.TP
-.B \-t
+.TP 
+\-d
+Specifies that the daemon should not fork. If netatalk has been
+configured with \fI\-\-enable\-debug1\fR, a trace of
+all AFP commands will be written to stdout.
+.TP 
+\-p
+Prevents clients from saving their passwords. (Equivalent to \-\fBnosavepasswd\fR
+in \fBafpd.conf\fR.)
+.TP 
+\-t
 Allows clients to change their passwords. (Equivalent to
-.I \-setpasswd
-in
-.BR afpd.conf .)
-.TP
-.B \-D
+\fB\-setpasswd\fR in \fBafpd.conf\fR.)
+.TP 
+\-D
 Use DDP (AppleTalk) as transport protocol. (Equivalent to
-.I \-ddp
-in
-.BR afpd.cond .)
-.TP
-.B \-T
+\fB\-ddp\fR in \fBafpd.cond\fR.)
+.TP 
+\-T
 Use TCP/IP as transport protocol. (Equivalent to
-.I \-tcp
-in
-.BR afpd.conf .)
-.TP
-.BI \-S " port"
-Specifies the port to register with when doing AFPoverTCP. Defaults to
-.IR 548 .
-(Equivalent to
-.I -port
-in
-.BR afpd.conf .)
-.TP
-.BI \-L " message"
-Specifies the login message that will be sent to clients. (Equivalent to
-.I \-loginmsg
-in
-.BR afpd.conf .)
-.TP
-.BI \-F " config"
-Specifies the configuration file to use. (Defaults to
-.IR :ETCDIR:/afpd.conf .)
-.TP
-.BI \-U " uams"
-Comma-separated list of UAMs to use for the authentication process.
-(Equivalent to
-.I -uamlist
-in
-.BR afpd.conf .)
-.TP
-.B \-I
-Use a platform specific icon. (Equivalent to
-.I \-icon
-in
-.BR afpd.conf .)
-.TP
-.BR \-m " umask"
-Use this umask for the creation of folders in Netatalk.
-.TP
-.B \-v
+\fB\-tcp\fR in \fBafpd.conf\fR.)
+.TP 
+\-v
 Print version information and exit.
-.SH AUTHENTICATION
-.B afpd
-currently understands three User Authentication Methods (UAMs):
-.BR NoUserAuthent ,
-or guest,
-.B Cleartxt
-.BR passwrd ,
-and
-.B Kerberos
-.BR IV .
-If a user uses
-.BR NoUserAuthent ,
-s/he will only be offered default volumes to mount, and will only be able
-to read and write files that are permitted to the guest user.  The
-.B -G
-option disables
-.BR NoUserAuthent .
-With
-.B Cleartxt passwd
-and
-.B Kerberos
-.BR IV ,
-.B afpd
-offers the user all volumes listed in
-.BR ~/AppleVolumes .
-The user may also read and write all files that s/he normally could.
-.B Cleartxt passwd
-is not recommended for AFS use.
-.B Kerberos IV
-is recommended for AFS use.
-A forth, depricated UAM is also included in the distribution,
-.B AFS
-.BR Kerberos .
-.SH CAVEATS
-.BR afpd 's
-Directory IDs are only fixed for the duration of a session.  This means
-that Mac aliases won't work correctly in all cases.
-.LP
-If a user renames a folder that has an application as its progeny, the
-.B APPL
-mapping for the application will not longer be available. This implies
-that double-clicking on one of the application's documents will no
-longer launch the application. The
-.B APPL
-mapping will be rebuilt by the mac, the next time the Finder see the
-application.
-.LP
-If
-.B afpd
-is configured to downcase Macintosh filenames, Unix filenames with
-mixed case will be unavailable.
-.LP
-If carriage return/line feed translation is enabled, it is not
-safe to copy Unix binaries to a Macintosh.
-.LP
-It is not possible to move directories between devices.
-.LP
-When mounting the parent of an existing volume, the desktop database of
-the existing volume will not be available to the parent volume.  The
-.B APPL
-mappings and icons of applications with the
-.B BNDL
-bit set will be generated in the parent volume as the applications are
-seen by the Finder.
-.LP
-If a user edits his
-.B ~/AppleVolumes
-so that his home directory is no longer offered, he will no longer be able
-to edit his
-.B ~/AppleVolumes
-from the Macintosh.
-.LP
-Unix files beginning with `.' are not accessible from the mac.
-.LP
-If the
-.I pathname
-in an
-.B ~/AppleVolumes
-file does not exist, the volume will not be offered in the Chooser.
-.LP
-Microsoft Word
-.B TEXT
-documents do not get carriage return/line feed translation.  This is
-because MS Word uses a type other than
-.B TEXT
-while writing the document, then changes the type to
-.BR TEXT .
-To allow users to edit their
-.BR ~/AppleVolumes ,
-.B afpd
-parses the files with either end of line character.
-.LP
-Unix filenames that are longer than 31 characters are inaccessible from
-the Macintosh.
-
+.TP 
+\-I
+Use a platform specific icon. (Equivalent to \fB\-icon\fR
+in \fBafpd.conf\fR.)
+.TP 
+\-f \fIdefaultvolumes\fR
+Specifies that \fIdefaultvolumes\fR
+should be read for a list of default volumes to offer, instead of
+\fB:ETCDIR:/AppleVolumes.default\fR.
+.TP 
+\-s \fIsystemvolumes\fR
+Specifies that \fIsystemvolumes\fR should
+be read for a list of volume that all users will be offered, instead
+of \fB:ETCDIR:/AppleVolumes.system\fR.
+.TP 
+\-u
+Read the user's \fBAppleVolumes\fR file
+first. This option causes volume names in the user's
+\fBAppleVolumes\fR file to override volume names in
+the system's \fBAppleVolumes\fR file. The default
+is to read the system \fBAppleVolumes\fR file first.
+Note that this option doesn't effect the precendence of filename
+extension mappings: the user's \fBAppleVolumes\fR
+file always has precedence.
+.TP 
+\-n \fInbpname\fR
+Specifies that \fInbpname\fR should be
+used for NBP registration, instead of the first component of the
+hostname in the local zone.
+.TP 
+\-c \fImaxconnections\fR
+Specifies the maximum number of connections to allow for this
+afpd. The default is 20.
+.TP 
+\-g \fIguest\fR
+Specifies the name of the guest account. The default is
+\&'\fInobody\fR'.
+.TP 
+\-P \fIpidfile\fR
+Specifies the file in which afpd stores its
+process id.
+.TP 
+\-S \fIport\fR
+Specifies the port to register with when doing AFPoverTCP.
+Defaults to 548. (Equivalent to \fB\-port \fRin
+\fBafpd.conf\fR.)
+.TP 
+\-L \fImessage\fR
+Specifies the login message that will be sent to clients.
+(Equivalent to \fB\-loginmsg\fR in \fBafpd.conf\fR.)
+.TP 
+\-F \fIconfigfile\fR
+Specifies the configuration file to use. (Defaults to
+\fB:ETCDIR:/netatalk/afpd.conf\fR.)
+.TP 
+\-U \fIuams\fR
+Comma\-separated list of UAMs to use for the authentication
+process. (Equivalent to \fB\-uamlist\fR in
+\fBafpd.conf\fR.)
+.TP 
+\-m \fIumask\fR
+Use this umask for the creation of
+folders in Netatalk.
 .SH SIGNALS
-Signals that are sent to the main
-.B afpd
-process are propagated to the children, so all will be affected.
-.TP 13
-.B SIGHUP
-The
-.B afpd
-process will send the message "The server is going down for maintenance."
-to the client and shut itself down in 5 minutes.  New connections are not
-allowed.  If this is sent to a child
-.BR afpd ,
-the other children are not affected.  However, the main process will still
-exit, disabling all new connections.
-.TP 13
-.B SIGUSR1
-If the
-.B --with-message-dir
-configure option was used, the
-.B afpd
-process will set the
-.B debug
-option and redirect the messages to
-.RI /var/tmp/afpd-debug- pid .
-This should only be sent to a child
-.BR afpd .
-.B Warning:
-If the
-.B --with-message-dir
-option was not used, this will kill the
-.B afpd
-process.
-
-.TP 13
-.B SIGUSR2
-The
-.B afpd
-process will look in the
-.I msg
-directory for a file named
-.RI message. pid .
-For each one found, a the contents will be sent as a message to the
-associated AFP client.  The file is removed after the message is sent.
+Signals that are sent to the main afpd process
+are propagated to the children, so all will be affected.
+.TP 
+SIGHUP
+Sending a SIGHUP to afpd will cause it to
+reload its configuration files.
+.TP 
+SIGUSR1
+The afpd process will send the message
+"The server is going down for maintenance." to the client
+and shut itself down in 5 minutes. New connections are not allowed.
+If this is sent to a child afpd, the other children are not
+affected. However, the main process will still exit, disabling all
+new connections.
+.TP 
+SIGUSR2
+The afpd process will look in the message
+directory configured at build time for a file named message.pid. For
+each one found, a the contents will be sent as a message to the
+associated AFP client. The file is removed after the message is
+sent. This should only be sent to a child afpd.
+Warning: If the \-\-with\-message\-dir option was not used, this will
+kill the afpd process
 
+To shut down a user's afpd process it
+is recommended that SIGKILL (\-9)
+\fINOT\fR be used, except as a last resort, as this
+may leave the CNID database in an inconsistent state. The safe way
+to terminate an afpd is to send it a
+SIGTERM (\-15) signal and wait for it to die on
+its own.
 .SH FILES
-.TP 20
-.B :ETCDIR:/AppleVolumes.default
+.TP 
+\fB:ETCDIR:/AppleVolumes.default\fR
 list of default volumes to mount
-.TP 20
-.B :ETCDIR:/AppleVolumes.system
+.TP 
+\fB:ETCDIR:/AppleVolumes.system\fR
 list of volumes to offer all users
-.TP 20
-.B ~/AppleVolumes
+.TP 
+\fB~/AppleVolumes\fR
 user's list of volumes to mount
-.TP 20
-.BI :ETCDIR:/msg/message. pid
+.TP 
+\fB:ETCDIR:/netatalk/msg/message.pid\fR
 contains messages to be sent to users.
-.TP 20
-.BI /var/tmp/afpd-debug- pid
-contains debug output, if triggered.
 .SH BUGS
-A few calls from the AFP specification are not implemented, because the
-Macintosh does not use them.
+.SH "SEE ALSO"
+\fBhosts_access\fR(5),
+\fBafpd.conf\fR(5),
+\fBAppleVolumes.default\fR(5),
+\fBAppleVolumes.system\fR(5).
+
index c6e4d8b3712a25a99a890f4c3dd0649f1dedfac2..42ac78f10a48757e0a69e858e84305c6767b788d 100644 (file)
-.TH ATALKD 8 "17 Nov 1995" "netatalk 1.3"
+.TH atalkd 8 "06 Sep 2004" 2.0.0 Netatalk 
 .SH NAME
 atalkd \- AppleTalk RTMP, NBP, ZIP, and AEP manager
 .SH SYNOPSIS
-.B :SBINDIR:/atalkd
-[
-.B -f
-.I configfile
-] [
-.B -1
-|
-.B -2
-]
+\fBatalkd\fR [\-f \fBconfigfile\fR] [\-1] [\-2]
 .SH DESCRIPTION
-.B atalkd
-is responsible for all user level AppleTalk network management. This
-includes routing, name registration and lookup, zone lookup, and the
-AppleTalk Echo Protocol (similar to
-.BR ping (8)).
-.B atalkd
-is typically started at boot time, out of
-.B /etc/rc.
-It first reads from its configuration file,
-.BR :ETCDIR:/atalkd.conf .
-If there is no configuration file,
-.B atalkd
-will attempt to configure all available interfaces and will create a
-configuration file.  The file consists of a series of interfaces, one
-per line.  Lines with
-.RB ` # '
-in the first column are ignored, as are blank lines.  The syntax is
-.RS
-.sp
-.I interface
-[
-.B -seed
-] [
-.B -phase
-.I number
-] [
-.B -net
-.I net-range
-] [
-.B -addr
-.I address
-] [
-.B -zone
-.I zonename
-] ...
-.sp
-.RE
-Note that all field except the
-.I interface
-are optional.  The loopback interface is configured automatically.  If
-.B -seed
-is specified, all other fields must be present.  Also,
-.B atalkd
-will exit during bootstrapping, if a router disagrees with its seed
-information.  If
-.B -seed
-is not given, all other information may be overriden during
-auto-configuration.  If no
-.B -phase
-option is given, the default phase as given on the command line is used
-(the default is 2).  If
-.B -addr
-is given and
-.B -net
-is not, a
-.I net-range
-of one is assumed.
-.LP
-The first
-.B -zone
-directive for each interface is the ``default'' zone.  Under Phase 1, there
-is only one zone.  Under Phase 2, all routers on the network are
-configured with the default zone and must agree.
-.B atalkd
-maps ``*'' to the default zone of the first interface.  Note:  The
-default zone for a machine is determined by the configuration of the
-local routers; to appear in a non-default zone, each service, e.g.
-.BR afpd ,
-must individually specify the desired zone.  See also
-.BR nbp_name (3).
+atalkd is responsible for all user level
+AppleTalk network management. This includes routing, name registration and
+lookup, zone lookup, and the AppleTalk Echo Protocol (similar to
+\fBping\fR(8)). atalkd is typically started at boot
+time, out of \fB/etc/rc\fR. It first reads from its
+configuration file, \fB:ETCDIR:/atalkd.conf\fR. If there is
+no configuration file, atalkd will attempt to configure
+all available interfaces and will create a configuration file. The file
+consists of a series of interfaces, one per line. Lines with `#' in the
+first column are ignored, as are blank lines. The syntax is
+.PP
+\fIinterface\fR [ \fB\-seed\fR ]
+[ \fB\-phase\fR \fInumber\fR ] [
+\fB\-net\fR \fInet\-range\fR ] [
+\fB\-addr\fR \fIaddress\fR ] [
+\fB\-zone\fR \fIzonename\fR ] ...
+.PP
+Note that all fields except the interface are optional. The loopback
+interface is configured automatically. If \fB\-seed\fR is
+specified, all other fields must be present. Also,
+atalkd will exit during bootstrap\%ping, if a router
+disagrees with its seed information. If \fB\-seed\fR is not
+given, all other information may be overriden during auto\-configuration.
+If no \fB\-phase\fR option is given, the default phase as given
+on the command line is used (the default is 2). If \fB\-addr\fR
+is given and \fB\-net\fR is not, a net\-range of one is
+assumed.
+.PP
+The first \-zone directive for each interface is the ``default''
+zone. Under Phase 1, there is only one zone. Under Phase 2, all routers on
+the network are configured with the default zone and must agree.
+atalkd maps ``*'' to the default zone of the first
+interface. Note: The default zone for a machine is determined by the
+configuration of the local routers; to appear in a non\-default zone, each
+service, e.g. afpd, must individually specify the
+desired zone. See also \fBnbp_name\fR(3).
 .SH ROUTING
 If you are connecting a netatalk router to an existing AppleTalk
 internet, you should first contact your local network administrators to
 obtain appropriate network addresses.
-.LP
-.B atalkd
-can provide routing between interfaces by configuring multiple
-interfaces.  Each interface must be assigned a unique
-.I net-range
-between 1 and 65279 (0 and 65535 are illegal, and addresses between
-65280 and 65534 are reserved for startup).  It is best to choose the
-smallest useful
-.IR net-range ,
-i.e. if you have three machines on an Ethernet, don't chose a
-.I net-range
-of 1000-2000.  Each
-.I net-range
-may have an arbitrary list of zones associated with it.
-.SH EXAMPLE
-Below is an example configuration file for a sun4/40.  The machine has
-two interfaces, ``le0'' and ``le1''.  The ``le0'' interface is
-configured automatically from other routers on the network.  The
-machine is the only router for the ``le1'' interface.
-.sp
-.RS
+.PP
+atalkd can provide routing between interfaces by
+configuring multiple interfaces. Each interface must be assigned a unique
+net\-range between 1 and 65279 (0 and 65535 are illegal, and addresses
+between 65280 and 65534 are reserved for startup). It is best to choose
+the smallest useful net\-range, i.e. if you have three machines on an
+Ethernet, don't chose a net\-range of 1000\-2000. Each net\-range may have an
+arbitrary list of zones associated with it.
+.SH EXAMPLES
+Below is an example configuration file for a sun4/40. The machine
+has two interfaces, ``le0'' and ``le1''. The ``le0'' interface is
+configured automatically from other routers on the network. The machine is
+the only router for the ``le1'' interface.
+.PP
 .nf
-le0
-le1 -seed -net 9461-9471 -zone netatalk -zone Argus
+   le0
+   le1 \-seed \-net 9461\-9471 \-zone netatalk \-zone Argus
 .fi
-.RE
-.sp
-.B atalkd
+
+atalkd
 automatically acts as a router if there is more than one interface.
 .SH FILES
-.TP 30
-.B :ETCDIR:/atalkd.conf
-configuration file
+\fB:ETCDIR:/atalkd.conf\fR configuration file
 .SH BUGS
-On some systems, atalkd can not be restarted.
+On some systems, atalkd can not be
+restarted.
+.SH "SEE ALSO"
+\fBatalkd.conf\fR(5)
+
diff --git a/man/man8/cnid_dbd.8.tmpl b/man/man8/cnid_dbd.8.tmpl
new file mode 100644 (file)
index 0000000..d8640f8
--- /dev/null
@@ -0,0 +1,153 @@
+.TH cnid_dbd 8 "2 Dec 2003" 2.0.0 Netatalk 
+.SH NAME
+cnid_dbd \- implement access to CNID databases through a dedicated daemon process
+.SH SYNOPSIS
+\fBcnid_dbd\fR \fBdbdir\fR \fBctrlfd\fR \fBclntfd\fR 
+.SH DESCRIPTION
+cnid_dbd provides an interface for storage and
+retrieval of catalog node IDs (CNIDs) and related information to the
+\fIafpd\fR daemon. CNIDs are a component of
+Macintosh based file systems with semantics that map not easily onto Unix
+file systems. This makes separate storage in a database necessary.
+cnid_dbd is part of the \fICNID
+backend\fR framework of \fIafpd\fR and
+implements the \fIdbd\fR backend.
+.PP
+cnid_dbd is never started via the command line or
+system startup scripts but only by the \fIcnid_metad\fR daemon. There is at most one instance of
+cnid_dbd per netatalk volume.
+.PP
+cnid_dbd uses the \fIBerkleley
+DB\fR database library and optionally supports transactionally
+protected updates if the netatalk package is compiled with the appropriate
+options. Using the \fIdbd\fR backend without
+transactions will protect the CNID database against unexpected crashes of
+the \fIafpd\fR daemon. Using the \fIdbd\fR backend with transactions will avoid corruption
+of the CNID database even if the system crashes unexpectedly.
+.PP
+cnid_dbd uses the same on\-disk database format as
+the \fIcdb\fR backend. It is therefore possible
+to switch between the two backends as necessary.
+.PP
+cnid_dbd inherits the effective userid and
+groupid from \fIcnid_metad\fR on startup, which
+is normally caused by \fIafpd\fR serving a
+netatalk volume to a client. It changes to the \fIBerkleley DB\fR database home directory \fIdbdir\fR that is associated with the volume. If the
+userid inherited from \fIcnid_metad\fR is 0
+(root), cnid_dbd will change userid and groupid to the
+owner and group of the database home directory. Otherwise, it will
+continue to use the inherited values. cnid_dbd will
+then attempt to open the database and start serving requests using
+filedescriptor \fIclntfd\fR. Subsequent instances
+of \fIafpd\fR that want to access the same volume
+are redirected to the running cnid_dbd process by
+\fIcnid_metad\fR via the filedescriptor \fIctrlfd\fR.
+.PP
+cnid_dbd can be configured to run forever or to
+exit after a period of inactivity. If cnid_dbd receives
+a TERM or an INT signal it will exit cleanly after flushing dirty database
+buffers to disk and closing \fIBerkleley DB\fR
+database environments. It is safe to terminate cnid_dbd
+this way, it will be restarted when necessary. Other signals are not
+handled and will cause an immediate exit, possibly leaving the CNID
+database in an inconsistent state (no transactions) or losing recent
+updates during recovery (transactions).
+.PP
+If transactions are used the \fIBerkleley
+DB\fR database subsystem will create files named log.xxxxxxxxxx in
+the database home directory \fIdbdir\fR, where
+xxxxxxxxxx is a monotonically increasing integer. These files contain
+information to replay database changes and are not automatically removed,
+unless the \fIlogfile_autoremove\fR option is
+specified in the \fIdb_param\fR configuration
+file (see below). Please see the sections \fIDatabase and
+log file archival\fR, \fILog file
+removal\fR and the documentation of the \fI
+db_archive\fR command line utility in the Berkeley DB Tutorial and
+Reference for information when and how it is safe to remove these files
+manually.
+.PP
+Do not use cnid_dbd for databases on
+NFS mounted file systems. It makes the whole point of securing
+database changes properly moot. Use the dbdir: Option in the appropriate
+\fIAppleVolumes\fR configuration file to put the
+database onto a local disk.
+.SH CONFIGURATION
+cnid_dbd reads configuration information from the
+file \fIdb_param\fR in the database directory
+\fIdbdir\fR on startup. If the file does not
+exist or a parameter is not listed, suitable default values 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:
+.TP 
+\fIlogfile_autoremove\fR
+This flag is ignored unless transactional support is enabled.
+If set to 1, unused Berkeley DB transactional logfiles
+(log.xxxxxxxxxx in the database home directory) are removed on
+startup of cnid_dbd. This is usually safe if the
+content of the database directory is backed up on a regular basis.
+Default: 0.
+.TP 
+\fIcachesize\fR
+Determines the size of the Berkeley DB cache in kilobytes.
+Default: 1024. Each cnid_dbd process grabs that
+much memory on top of its normal memory footprint. It can be used to
+tune database performance. The \fIdb_stat\fR utility with the \fB\-m\fR
+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 \fIBerkeley DB Tutorial and Reference Guide\fR has a
+section \fISelecting a cache size\fR that
+gives more detailed information.
+.TP 
+\fInosync\fR
+This flag is ignored unless 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 \fITransaction
+Throughput\fR in the Berkeley DB Tutorial for more
+information. Default: 0.
+.TP 
+\fIflush_frequency\fR, \fIflush_interval\fR
+\fIflush_frequency\fR (Default: 100)
+and \fIflush_interval\fR (Default: 30)
+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 \fIflush_frequency\fR requests have been received or
+ii) more than \fIflush_interval\fR seconds
+have elapsed since the last save/checkpoint. If you use transactions
+with \fInosync\fR set to zero these
+parameters only influence how long recovery takes after a crash,
+there should never be any lost data. If \fInosync\fR 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.
+.TP 
+\fIfd_table_size\fR
+is the maximum number of connections (filedescriptors) that
+can be open for \fIafpd\fR client processes
+in \fIcnid_dbd.\fR Default: 16. If this
+number is exceeded, one of the existing connections is closed and
+reused. The affected \fIafpd\fR 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 \fIafpd\fR client
+process is expected to run, e.g. home directories.
+.TP 
+\fIidle_timeout\fR
+is the number of seconds of inactivity before an idle
+cnid_dbd exits. Default: 600. Set this to 0 to
+disable the timeout.
+.SH "SEE ALSO"
+\fBcnid_metad\fR(8), \fBafpd\fR(8)
+
diff --git a/man/man8/cnid_metad.8.tmpl b/man/man8/cnid_metad.8.tmpl
new file mode 100644 (file)
index 0000000..77761f8
--- /dev/null
@@ -0,0 +1,66 @@
+.TH cnid_metad 8 "28 Nov 2003" 2.0.0 Netatalk 
+.SH NAME
+cnid_metad \- start cnid_dbd daemons on request
+.SH SYNOPSIS
+\fBcnid_metad\fR [\-d] [ \-h \fBhostname\fR ] [ \-p \fBport\fR ] [ \-u \fBuser\fR ] [ \-g \fBgroup\fR ] [ \-s \fBcnid_dbdpathname\fR ]
+.SH DESCRIPTION
+cnid_metad waits for requests from \fIafpd\fR to start up instances of the \fIcnid_dbd\fR
+daemon. It keeps track of the status of a \fIcnid_dbd\fR
+instance once started and will restart it if necessary.
+cnid_metad is normally started at boot time from
+\fB/etc/rc\fR or equivalent and runs until shutdown.
+\fIafpd\fR needs to be configured with the
+\fB\-cnidserver\fR option in \fIafpd.conf\fR
+in order to access \fIcnid_metad.\fR It is
+possible to run more than one instance of cnid_metad on
+the same machine if different values for the interface and/or port are
+specified with the \fB\-h\fR and \fB\-p\fR options.
+.SH OPTIONS
+.TP 
+\fB\-d\fR
+\fIcnid_metad will remain in the foreground
+and\fR will also leave the standard input, standard output
+and standard error file descriptors open. Useful for debugging.
+.TP 
+\fB\-h\fR\fI hostname\fR
+Use \fIhostname\fR as the network
+interface for requests as opposed to the default \fIlocalhost
+\fR\&.
+.TP 
+\fB\-p\fR\fI port\fR
+Use \fIport\fR as the port number for
+reqests. Default is 4700.
+.TP 
+\fB\-u\fR\fI user\fR
+Switch to the userid of \fIuser\fR
+before serving requests. This userid will be inherited by all
+\fIcnid_dbd\fR daemon processes started.
+.TP 
+\fB\-u\fR\fI group\fR
+Switch to the groupid of \fIgroup\fR
+before serving requests. This groupid will be inherited by all
+\fIcnid_dbd\fR daemon processes started.
+Both \fIuser\fR and \fIgroup\fR
+must be specified as strings.
+.TP 
+\fB\-s\fR\fI cnid_dbd pathname\fR
+Use \fIcnid_dbd pathname\fR as the
+pathname of the executeable of the \fIcnid_dbd\fR
+daemon. The default is \fI:SBINDIR:/cnid_dbd.\fR
+.SH CAVEATS
+The number of \fIcnid_dbd\fR subprocecesses
+is currently limited to 128. This restriction will be lifted in the
+future.
+.PP
+cnid_metad does not block or catch any signals
+apart from SIGPIPE. It will therefore exit on most signals received. This
+will also cause all instances of \fIcnid_dbd's\fR
+started by that cnid_metad to exit gracefully. Since
+state about and IPC access to the subprocesses is only maintained in
+memory by cnid_metad this is desired behaviour. As soon
+as cnid_metad is restarted \fIafpd\fR
+processes will transparently reconnect.
+.SH "SEE ALSO"
+\fBcnid_dbd\fR(8),
+\fBafpd\fR(8)
+
index c8425b8a090eec2bdffa0a923a1adb783781135b..e5ac3155930cd0909f44018448e8dad15795dc10 100644 (file)
-'\" t
-.TH PAPD 8 "06 Mar 2001" "netatalk 1.5"
+.\" t
+.TH papd 8 "06 September 2004" 2.0.0 Netatalk 
 .SH NAME
 papd \- AppleTalk print server daemon
 .SH SYNOPSIS
-.B :SBINDIR:/papd
-[
-.B -d
-] [
-.B -f
-.I configfile
-] [
-.B -p
-.I printcap
-]
+\fBpapd\fR [\-d] [\-f configfile] [\-p printcap]
 .SH DESCRIPTION
-.B papd
-is the AppleTalk printer daemon.  This daemon accepts print jobs from
-AppleTalk clients (typically Macintosh computers) using the Printer
-Access Protocol (PAP).
-.B papd
-spools jobs directly into an
-.BR lpd (8)
-spool directory and wakes up
-.B lpd
-after accepting a job from the network to have it re-examine the
-appropriate spool directory.  The actual printing and spooling is
-handled entirely by
-.B lpd.
-.B papd
-can also pipe the print job to an external program for processing, and
-this is the preferred method to avoid compatibility problems with all
-the flavors of lpd in use.
-.LP
-.B papd
-is typically started at boot time, out of system init scripts.
-It first reads from its configuration file,
-.BR :ETCDIR:/papd.conf .
-The file is in the same format as
-.BR /etc/printcap .
-See
-.BR printcap (5)
-for details.  The name of the entry is registered with
-.BR NBP .
-The following options are supported:
-.LP
+papd is the AppleTalk printer daemon. This daemon
+accepts print jobs from AppleTalk clients (typically Macintosh computers)
+using the Printer Access Protocol (PAP). When used with System V printing
+systems, papd spools jobs directly into an
+\fBlpd\fR(8) spool directory and wakes up lpd
+after accepting a job from the network to have it re\-examine the
+appropriate spool directory. The actual printing and spooling is handled
+entirely by lpd.
+.PP
+papd can also pipe the print job to an external
+program for processing, and this is the preferred method on systems not
+using CUPS to avoid compatibility problems with all the flavours of
+lpd in use.
+.PP
+As of version 2.0, CUPS is also supported. Simply using \fIcupsautoadd\fR as first papd.conf entry will share all
+CUPS printers automagically using the PPD files configured in CUPS. It ist
+still possible to overwrite these defaults by individually define printer
+shares. See \fBpapd.conf\fR(5) for details.
+.PP
+papd is typically started at boot time, out of
+system init scripts. It first reads from its configuration file,
+\fB:ETCDIR:/papd.conf\fR. The file is in the same format as
+\fB/etc/printcap\fR. See \fBprintcap\fR(5) for details. The name of the entry is registered with
+NBP.
+.PP
+The following options are supported: 
 .TS
-c c l l
-cfB l l l .
-Name   Type    Default Descripton
-.sp .5
-pd     str     `.ppd'  Pathname to PPD file
-pr     str     `lp'    LPD printer name (or print command)
-op     str     `operator'      Operator name for LPD spooling
-ca     str     NULL    Pathname used for CAP-style authentication
-sp     bool    false   PSSP-style authentication
-am     str     NULL    UAMS to use for authentication
-pa     str     NULL    Printer's AppleTalk address?
+c c c l.
+T{
+Name
+T}     T{
+Type
+T}     T{
+Default
+T}     T{
+Description
+T}
+.T&
+c l l l.
+T{
+pd
+T}     T{
+str
+T}     T{
+\&'.ppd'
+T}     T{
+Pathname to PPD file
+T}
+T{
+pr
+T}     T{
+str
+T}     T{
+\&'lp'
+T}     T{
+LPD or CUPS printer name (or pipe to a print
+command)
+T}
+T{
+op
+T}     T{
+str
+T}     T{
+\&'operator'
+T}     T{
+Operator name for LPD spooling
+T}
+T{
+au
+T}     T{
+bool
+T}     T{
+false
+T}     T{
+Whether to do authenticated printing or not
+T}
+T{
+ca
+T}     T{
+str
+T}     T{
+NULL
+T}     T{
+Pathname used for CAP\-style authentification
+T}
+T{
+sp
+T}     T{
+bool
+T}     T{
+false
+T}     T{
+PSSP\-style authetication
+T}
+T{
+am
+T}     T{
+str
+T}     T{
+NULL
+T}     T{
+UAMS to use for authentication
+T}
+T{
+pa
+T}     T{
+str
+T}     T{
+NULL
+T}     T{
+Printer's AppleTalk address
+T}
+T{
+co
+T}     T{
+str
+T}     T{
+NULL
+T}     T{
+CUPS options as supplied to the \fBlp\fR(1) command with "\-o"
+T}
+T{
+fo
+T}     T{
+bool
+T}     T{
+false
+T}     T{
+adjust lineending for foomatic\-rip
+T}
 .TE
-.LP
-If no configuration file is given, the hostname of the machine is used
-as the NBP name and all options take their default value.
+If no configuration file is given, the hostname of the
+machine is used as the NBP name and all options take their default
+value.
 .SH OPTIONS
-.TP
-.B -d
-Do not fork or disassociate from the terminal.  Write some
+.TP 
+\-d
+Do not fork or disassociate from the terminal. Write some
 debugging information to stderr.
-.HP
-.B -f
-.I configfile
-.br
-Consult
-.I configfile
-instead of
-.B :ETCDIR:/papd.conf
-for the configuration information.
-.HP
-.B -p
-.I printcap
-.br
-Consult
-.I printcap
-instead of
-.B /etc/printcap
-for LPD configuration information.
-.SH EXAMPLE
-The following papd configuration file sets up three print spoolers.
-The first spooler is known by the NBP name
-.B Mac Printer Spooler,
-and uses a PPD file located in /usr/share/lib/ppd.
-In addition, the user mcs
-will be the owner of all jobs that are spooled.
-The second spooler is known as
-.B HP Printer
-and all options are the default. The third spooler is known as
-.B HP 8100 .
-It pipes the print job to lpr for printing.  PSSP authenticated printing
-is enabled, as is CAP-style authenticated printing.  Both methods support
-guest and cleartext authentication as specified by the 'am' option.  The
-PPD used is /etc/atalk/ppds/hp8100.ppd.
-.sp
-.RS
-.nf
-Mac Printer Spooler:\\ 
-       :pr=ps:\\
-       :pd=/usr/share/lib/ppd/HPLJ_4M.PPD:\\
-       :op=mcs:
-
-HP Printer:\\ 
-       :
-
-HP 8100:\\
-       :pr=|/usr/bin/lpr -Plp:\\
-       :sp:\\
-       :ca=/tmp/print:\\
-       :am=uams_guest.so,uams_pam.so:\\
-       :pd=/etc/atalk/ppds/hp8100.ppd:
-.fi
-.RE
+.TP 
+\-f \fIconfigfile\fR
+Consult \fIconfigfile\fR instead of
+\fB:ETCDIR:/papd.conf\fR for the configuration
+information.
+.TP 
+\-p \fIprintcap\fR
+Consult \fIprintcap\fR instead of
+\fB/etc/printcap\fR for LPD configuration
+information.
 .SH NOTES
-PSSP (Print Server Security Protocol) is an authentication protocol
-carried out through postscript printer queries to the print server.  Using
-PSSP requires LaserWriter 8.6.1 or greater on the client mac.  The user
-will be prompted to enter their username and password before they print.
-It may be necessary to re-setup the printer on each client the first time
-PSSP is enabled, so that the client can figure out that authentication is
-required to print.  You can enable PSSP on a per-printer basis.  PSSP is
-the recommended method of authenticating printers as it is more robust
-that CAP-style authentication, described below.
-.LP
-CAP-style authentication gets its name from the method the CAP (Columbia
-APpletalk) package used to authenticate its mac clients' printing.  This
-method requires that a user login to a file share before they print.
-.B afpd
-records the username in a temporary file named after the clients
-Appletalk address, and it deletes the temporary file when the user
-disconnects.
-.B papd
-gets the username from the file with the same Appletalk address as the
-machine connecting to it.  CAP-style authentication will work with any
-mac client.  If both CAP and PSSP are enabled for a particular printer, CAP
-will be tried first, then it will fall back to PSSP.
-.LP
-
-The list of UAMS to use for authentication (specified with the 'am'
-option) applies to all printers.  It is not possible to define different
+PSSP (Print Server Security Protocol) is an authentication
+protocol carried out through postscript printer queries to the print
+server. Using PSSP requires LaserWriter 8.6.1 or greater on the client
+mac. The user will be prompted to enter their username and password before
+they print. It may be necessary to re\-setup the printer on each client the
+first time PSSP is enabled, so that the client can figure out that
+authentication is required to print. You can enable PSSP on a per\-printer
+basis. PSSP is the recommended method of authenticating printers as it is
+more robust than CAP\-style authentication, described below.
+.PP
+CAP\-style authentication gets its name from the method the CAP (Columbia APpletalk)
+package used to authenticate its mac clients' printing. This method
+requires that a user login to a file share before they print.
+afpd records the username in a temporary file named
+after the client's Appletalk address, and it deletes the temporary file
+when the user disconnects. Therefore CAP style authentification will
+\fInot\fR work for clients connected to
+afpd via TCP/IP. papd gets the
+username from the file with the same Appletalk address as the machine
+connecting to it. CAP\-style authentication will work with any mac client.
+If both CAP and PSSP are enabled for a particular printer, CAP will be
+tried first, then papd will fall back to PSSP.
+.PP
+The list of UAMs to use for authentication (specified with the 'am' option)
+applies to all printers. It is not possible to define different
 authentication methods on each printer. You can specify the list of UAMS
-multiple times, but only the last setting will be used.  Currently only
-uams_guest.so, uams_passwd.so, and uams_pam.so are supported as printer
-authentication methods.  The guest method requires a valid username, but
-not a password. The passwd and pam methods require both a valid username
-and the correct password.
+multiple times, but only the last setting will be used. Currently only
+uams_guest.so and uams_clrtxt.so are supported as printer authentication
+methods. The guest method requires a valid username, but not a password.
+The Cleartext UAM requires both a valid username and the correct
+password.
+.RS 
+\fBNote\fR
+.PP
+As of this writing, Mac OS X makes no use of PSSP authentication
+any longer. CAP\-style authentication normally won't be an option, too
+caused by the use of AFP over TCP these days.
+.RE
+.PP
 .SH FILES
-.TP 16
-.B :ETCDIR:/papd.conf
+.TP 
+\fB:ETCDIR:/papd.conf\fR
 Default configuration file.
-.TP 16
-.B /etc/printcap
+.TP 
+\fB/etc/printcap\fR
 Printer capabilities database.
-.TP 16
-.B .ppd
-PostScript Printer Description file.
-.B papd
-answers configuration and font queries from printing clients by
-consulting the configured PPD file.  Such files are available from
-Adobe, Inc, via anonymous ftp from ftp.adobe.com in /pub/adobe/printerdrivers/mac/all/ppdfiles/
-(ftp://ftp.adobe.com//pub/adobe/printerdrivers/mac/all/ppdfiles/), or from the printer's
-manufacturer.  If no PPD file is configured,
-.B papd
-will return the default answer, possibly causing the client to send
-excessively large jobs.
-.SH SEE ALSO
-.BR lpr (1),
-.BR lprm (1),
-\." .BR pap (4),
-.BR printcap (5).
-.BR lpc (8),
-.BR lpd (8).
+.TP 
+\fB\&.ppd\fR
+PostScript Printer Description file. papd answers
+configuration and font queries from printing clients by consulting
+the configured PPD file. Such files are available for download from
+Adobe, Inc. (http://www.adobe.com/support/downloads/main.htm),
+or from the printer's manufacturer. If no PPD file is configured,
+papd will return the default answer, possibly causing the client to
+send excessively large jobs.
 .SH CAVEATS
-.I papd
-accepts characters with the high bit set (a full 8-bits) from the clients,
-but some PostScript printers (including Apple Computer's LaserWriter family)
-only accept 7-bit characters on their serial interface by default.  You will
-need to configure your printer to accept a full 8 bits.
+papd accepts characters with the high bit set (a
+full 8\-bits) from the clients, but some PostScript printers (including
+Apple Computer's LaserWriter family) only accept 7\-bit characters on their
+serial interface by default. The same applies for some printers when
+they're accessed via TCP/IP methods (remote LPR or socket). You will need
+to configure your printer to accept a full 8 bits or take special
+precautions and convert the printjob's encoding (eg. by using \fIco="protocol=BCP"\fR when using CUPS 1.1.19 or
+above).
+.PP
+When printing clients run MacOS 10.2 or above, take care that PPDs
+do not make use of \fI*cupsFilter:\fR comments
+unless the appropriate filters are installed at the client's side, too
+(remember: Starting with 10.2 Apple chose to integrate CUPS into MacOS X).
+For in\-depth information on how CUPS uses PPDs see chapter 3.4 in http://tinyurl.com/zbxn).
+.SH "SEE ALSO"
+\fBlpr\fR(1),\fBlprm\fR(1),\fBprintcap\fR(5),\fBlpc\fR(8),\fBlpd\fR(8), \fBlp\fR(1).
+
index 8d8ab00653950fd18107f8244477aaa97f98475d..ee33f1143a61a8a587d91e2b01b4279f9ca77408 100644 (file)
@@ -1,84 +1,46 @@
-.TH PAPSTATUS 8 "17 Dec 1991"
+.TH papstatus 8 "17 Dec 1991" 2.0.0 Netatalk 
 .SH NAME
-papstatus \- get the status of an AppleTalk-connected printer
+papstatus \- get the status of an AppleTalk\-connected printer
 .SH SYNOPSIS
-.B :SBINDIR:/papstatus
-[
-.BI -d
-] [
-.B -p
-.I printer
-] [
-.I retrytime
-]
+\fB:SBINDIR:/papstatus\fR [\-d] [ \-p \fBprinter\fR ] [\fBretrytime\fR]
 .SH DESCRIPTION
-.B papstatus
-is used to obtain the current status message from an AppleTalk connected
-printer.  It uses the Printer Access Protocol (PAP) to obtain the
-status information.
-.LP
-If no printer is specified on the command line,
-.B papstatus
-looks for a file called
-.B .paprc
-in the current directory and reads it to obtain the name of a printer.  The
-.B .paprc
-file should contain a single line of the form
-.IB object : \c
-.IB type @ \c
-.I zone
-where each of
-.IR object ,
-.BI : type ,
-and
-.BI @ zone
-are optional.
-.I type
-and
-.I zone
-must be proceeded by
-.RB ` : '
-and
-.RB ` @ '
-respectively.  Blank lines and lines the begin with a
-.RB ` # '
-are ignored.
-.I type
-and
-.I zone
-default to
-.B LaserWriter
-and the zone of the local host, respectively.
+\fIpapstatus\fR is used to obtain the
+current status message from an AppleTalk connected printer. It uses the
+Printer Access Protocol (PAP) to obtain the status information.
+.PP
+If no printer is specified on the command line, \fIpapstatus\fR
+looks for a file called .paprc in the current directory
+and reads it to obtain the name of a printer. The .paprc
+file should contain a single line of the form \fIobject\fR\fI:\fR\fI\fR\fItype\fR\fI@\fR\fI\fR\fIzone\fR
+where each of \fIobject\fR, \fI:\fR\fItype\fR\fI,\fR and \fI@\fR\fIzone\fR are optional.
+\fItype\fR and \fIzone\fR
+must be proceeded by `\fI:\fR' and `\fI@\fR' respectively. Blank lines and lines the begin
+with a `\fI#\fR' are ignored. \fItype\fR and \fIzone\fR default
+to \fILaserWriter\fR and the zone of the local
+host, respectively.
 .SH OPTIONS
-.TP
-.B -d
-Turns on a debugging mode that prints some extra information to standard error.
-.HP
-.B -p
-.I printer
-.br
-Get status from
-.I printer
-(do not consult any
-.B .paprc
-files to find a printer name).  The syntax for
-.I printer
-is the same as discussed above for the
-.B .paprc
-file.
-.TP
-.I retrytime
-Normally,
-.B papstatus
-only gets the status from the printer once.  If
-.I retrytime
+.TP 
+\fB\-d\fR
+Turns on a debugging mode that prints some extra information
+to standard error.
+.TP 
+\fB\-p\fR \fIprinter\fR
+Get status from \fIprinter\fR (do not
+consult any .paprc files to find a printer name).
+The syntax for \fIprinter\fR is the same as
+discussed above for the .paprc file.
+.TP 
+\fIretrytime\fR
+Normally, \fIpapstatus\fR only gets
+the status from the printer once. If \fIretrytime\fR
 is specified, the status is obtained repeatedly, with a sleep of
-.I retrytime
-seconds between inquiring the printer.
+\fIretrytime\fR seconds between inquiring
+the printer.
 .SH FILES
-.TP 20
-.B .paprc
+.TP 
+\&.paprc
 file that contains printer name
-.SH SEE ALSO
-.BR nbp (1),
-.BR pap (8)
+.SH "SEE ALSO"
+\fBnbp\fR(1),
+\fBpap\fR(1)
+
index ca83684c7887f46b3491be237519c39e2f811bf8..57b58b40a372aafe0dbd82315e4c03a3c5aae5e4 100644 (file)
-.TH PSF 8 "17 Dec 1991" "netatalk 1.2"
+.TH psf 8 "17 Dec 1991" 2.0.0 Netatalk 
 .SH NAME
 psf \- PostScript filter
 .SH SYNOPSIS
-.B psf
-[
-.B -n
-.I name
-] [
-.B -h
-.I host
-] [
-.B -w
-.I width
-] [
-.B -l
-.I length
-] [
-.B -i
-.I indent
-] [
-.B -c
-]
+\fBpsf\fR [ \-n \fBname\fR ] [ \-h \fBhost\fR ] [ \-w \fBwidth\fR ] [ \-l \fBlength\fR ] [ \-i \fBindent\fR ] [\-c]
 .SH DESCRIPTION
-.B psf
-is an
-.B lpd
-filter for PostScript printing.
-.B psf
-interprets the name it was called with to determine what filters to
-invoke. First, if the string ``pap'' appears anywhere in the name,
-.B psf
-invokes
-.B pap
-to talk to a printer via AppleTalk. Next, if the string ``rev'' appears,
-.B psf
-invokes
-.B psorder
-to reverse the pages of the job. Finally, if
-.B psf
-was called with a filter's name as the leading string, it invokes that
-filter. If there is no filter to run,
-.B psf
-examines the magic number of the input, and if the input is not
-PostScript, converts it to PostScript.
+psf is an \fIlpd\fR
+filter for PostScript printing. psf interprets the name
+it was called with to determine what filters to invoke. First, if the
+string ``pap'' appears anywhere in the name, psf
+invokes \fIpap\fR to talk to a printer via
+AppleTalk. Next, if the string ``rev'' appears,
+psf invokes \fIpsorder\fR to
+reverse the pages of the job. Finally, if psf was
+called with a filter's name as the leading string, it invokes that
+filter. If there is no filter to run, psf examines the
+magic number of the input, and if the input is not PostScript, converts it
+to PostScript.
 .SH KLUDGE
-In the default configuration,
-.B psf
-supports two kludges.  The first causes
-.B psf
-to check its name for the letter `m'.  If this letter is found and accounting
-is turned on,
-.B psf
-calls
-.B pap
-twice, once to get an initial page count and to print the job, and
-another time to get a final page count.  This is a work-around for bugs
-in a variety of PAP implementions that cause printers to never properly
-close the PAP output file.  A notable example is any printer by
-Hewlett-Packard.
-.LP
-The second kludge causes
-.B psf
-to examine its name for the letter `w'.  If this letter is found and
-accounting is turned on,
-.B psf
-calls
-.B pap
-with the
-.B \-w
-flag.  This flag causes
-.B pap
-to wait until the printer's status contains the string `idle'.  Once
-this string is found, the job is printed as normal.  This kludge is a
-work-around for printers, notably Hewlett-Packard's LaserJet IV, which
+In the default configuration, psf supports two
+kludges. The first causes psf to check its name for the
+letter `m'. If this letter is found and accounting is turned on,
+psf calls \fIpap\fR twice,
+once to get an initial page count and to print the job, and another time
+to get a final page count. This is a work\-around for bugs in a variety of
+PAP implementions that cause printers to never properly close the PAP
+output file. A notable example is any printer by Hewlett\-Packard.
+.PP
+The second kludge causes psf to examine its name
+for the letter `w'. If this letter is found and accounting is turned
+on, psf calls \fIpap\fR with
+the \fB\-w\fR flag. This flag causes \fIpap\fR
+to wait until the printer's status contains the string `idle'.
+Once this string is found, the job is printed as normal. This kludge is a
+work\-around for printers, notably Hewlett\-Packard's LaserJet IV, which
 will report a page count while a previous jobs is still printing.
 .SH EXAMPLE
-The sample
-.B printcap
-entry below invokes
-.B psf
-to print text files, PostScript files,
-.BR troff 's
-C/A/T output, and
-.BR TeX 's
-DVI output, to an AppleTalk connected LaserWriter Plus. Since the
-LaserWriter Plus stacks pages in descending order, we reverse the pages
-and print the burst page last.
-.sp
-.RS
+The sample \fIprintcap\fR entry below
+invokes psf to print text files, PostScript files,
+\fItroff\fR's C/A/T output, and \fITeX\fR's DVI output, to an AppleTalk connected
+LaserWriter Plus. Since the LaserWriter Plus stacks pages in descending
+order, we reverse the pages and print the burst page last.
+.PP
 .nf
+
 laser|lp|LaserWriter Plus on AppleTalk:\\
     :sd=/usr/spool/lpd/laser:\\
     :lp=/usr/spool/lpd/laser/null:\\
-    :lf=/var/adm/lpd-errs:pw#80:hl:\\
+    :lf=/var/adm/lpd\-errs:pw#80:hl:\\
     :of=:LIBEXECDIR:/ofpap:\\
     :if=:LIBEXECDIR:/ifpaprev:\\
     :tf=:LIBEXECDIR:/tfpaprev:\\
     :df=:LIBEXECDIR:/dfpaprev:
 .fi
-.RE
-.sp
+.PP
 Note that if the host in question spools to more than one AppleTalk
-printer,
-.B /dev/null
-should not be used for the
-.B lp
-capability. Instead, a null device should be created with
-.B mknod
-for each printer, as has been done above.
-.LP
+printer, \fB/dev/null\fR should not be used for the
+\fIlp\fR capability. Instead, a null device
+should be created with \fImknod\fR for each
+printer, as has been done above.
+.PP
 Finally, there is a file in the spool directory,
-.BR /var/spool/lpd/laser ,
-called
-.BR .paprc ,
-which
-.B pap
-reads for the AppleTalk name of the printer.
-.SH SEE ALSO
-.BR psorder (1),
-.BR printcap (5),
-.BR lpd (8),
-.BR mknod (8),
-.BR pap (8).
+\fB/var/spool/lpd/laser\fR, called .paprc,
+which \fIpap\fR reads for the AppleTalk name of
+the printer.
+.SH "SEE ALSO"
+\fBpsorder\fR(1),
+\fBprintcap\fR(5),
+\fBlpd\fR(1),
+\fBmknod\fR(1),
+\fBpap\fR(1).
+
index 1e656ba15b02256481ab3e138e1301e6e07397df..aecc79fe214a7f65a5e70626ccc408b9a732daf9 100644 (file)
@@ -1,20 +1,19 @@
-.TH "timelord" "8" "27 Jun 2001" "netatalk 1.5pre7" "The Netatalk Project"
-.SH "NAME"
-.LP 
+.TH timelord 8 "27 Jun 2001" 2.0.0 Netatalk 
+.SH NAME
 timelord \- Macintosh time server daemon
-.SH "SYNTAX"
-.LP 
-timelord [\-d] [\-n \fIfilename\fP]
-.SH "DESCRIPTION"
-.LP 
-\fBtimelord\fR is a simple time server for Macintosh
-computers that use the \fBtardis\fR client.
-.SH "OPTIONS"
-.LP 
+.SH SYNOPSIS
+.SH SYNTAX
+timelord [\-d] [\-n \fIfilename\fR]
+.SH DESCRIPTION
+\fItimelord\fR is a simple time server for
+Macintosh computers that use the \fItardis\fR
+client.
+.SH OPTIONS
 .TP 
 \fB\-d\fR
-Debug mode, i.e. don't disassociate from controlling TTY.
+Debug mode, i.e. don't disassociate from controlling
+TTY.
 .TP 
-\fB\-n\fR \fInbpname\fP
-Register this server as \fInbpname\fP. This defaults to
-the hostname.
+\fB\-n\fR \fInbpname\fR
+Register this server as \fInbpname\fR. This defaults to the hostname.
+
index b13ad76f2e10626a9e2a24043d750b6dbb13695b..bbcf94622882d99e05f09e289de84159fd7bbd13 100644 (file)
@@ -1,3 +1,5 @@
 # Makefile.am for sys/netatalk/
 
-pkginclude_HEADERS = aarp.c aarp.h at.h at_control.c at_proto.c at_var.h ddp.h ddp_input.c ddp_output.c ddp_usrreq.c ddp_var.h endian.h phase2.h
+pkginclude_HEADERS = aarp.h at.h at_var.h ddp.h ddp_var.h endian.h phase2.h
+
+SOURCES = aarp.c at_control.c at_proto.c ddp_input.c ddp_output.c ddp_usrreq.c
index ebe96bc15653c3375807009b879575fa47f31be1..fb7239d4f1a945ccf1d5d14fa3dde7e7efe6dfdc 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: at.h,v 1.4 2003-12-15 04:33:28 srittau Exp $
+ * $Id: at.h,v 1.5 2005-04-28 20:50:07 bfernhomberg Exp $
  *
  * Copyright (c) 1990,1991 Regents of The University of Michigan.
  *
@@ -10,7 +10,6 @@
 #define __AT_HEADER__
 
 #if defined(linux) /* pull in the linux header */
-
 #include <sys/socket.h>
 #include <asm/types.h>
 #include <linux/atalk.h>
@@ -128,3 +127,4 @@ extern struct protosw       atalksw[];
 
 #endif /* linux */
 #endif /* __AT_HEADER__ */
+
index bd7ae86417d697f32e83c443b267f142e8eda4e3..b299751afd59f3b0c3415372733636e2e5ce236f 100644 (file)
@@ -1,4 +1,2 @@
 Makefile
-Makefile.in
-Makefile.kernel
 ddp
diff --git a/sys/solaris/Makefile.am b/sys/solaris/Makefile.am
deleted file mode 100644 (file)
index 97dd2f6..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-EXTRA_DIST = \
-       Makefile.kernel.in      \
-       aarp.c          \
-       ddp.c           \
-       ddp.conf        \
-       dlpi.c          \
-       if.c if.h       \
-       ioc.c ioc.h     \
-       linkage.c       \
-       rt.c rt.h       \
-       sock.c sock.h   \
-       tpi.c
diff --git a/sys/solaris/Makefile.in b/sys/solaris/Makefile.in
new file mode 100644 (file)
index 0000000..b14d056
--- /dev/null
@@ -0,0 +1,124 @@
+# Solaris specific defines, passed to subdirectories.
+# To use Sun CC, uncomment the CC and KFLAGS variables.
+#
+# $Id: Makefile.in,v 1.2 2005-04-28 20:50:07 bfernhomberg Exp $
+
+
+CC     = @CC@
+# LD hardcoded to sun ld, GNU ld has been reported to cause some trouble with 64 bit
+LD     = /usr/ccs/bin/ld
+
+INSTALL = @INSTALL@
+GREP=@GREP@
+
+
+# -D_ISOC9X_SOURCE is handled by OSVERSION. basically, it's not needed
+# with 2.5.1.
+DEFS=  -D__svr4__ -DSOLARIS -I../../sys/generic \
+       -I.. @DEFS@
+
+# Variables
+KCFLAGS=@KCFLAGS@
+KLDFLAGS=@KLDFLAGS@
+COMPILE_KERNEL_GCC=@COMPILE_KERNEL_GCC@
+SPARC64=@COMPILE_64BIT_KMODULE@
+SOLARIS_MODULE_FALSE=@SOLARIS_MODULE_FALSE@
+SOLARIS_MODULE_TRUE=@SOLARIS_MODULE_TRUE@
+USE_SOLARIS_TRUE=@USE_SOLARIS_TRUE@
+USE_SOLARIS_FALSE=@USE_SOLARIS_FALSE@
+
+OPTOPTS=
+
+# Local build stuff.
+
+SRC= linkage.c tpi.c dlpi.c ioc.c if.c aarp.c ddp.c sock.c rt.c
+OBJ= linkage.o tpi.o dlpi.o ioc.o if.o aarp.o ddp.o sock.o rt.o
+HEADERS= if.h ioc.h rt.h sock.h
+EXTRA_DIST= ddp.conf Makefile
+
+INCPATH=       -I../../include -I../netatalk -I../..
+CFLAGS=        ${DEFS} ${OPTOPTS} ${INCPATH} ${KCFLAGS}
+
+# Not building on Solaris
+@USE_SOLARIS_FALSE@all:
+
+# No Solaris kernel module build
+@USE_SOLARIS_TRUE@@SOLARIS_MODULE_FALSE@all:
+@USE_SOLARIS_TRUE@@SOLARIS_MODULE_FALSE@       @echo
+@USE_SOLARIS_TRUE@@SOLARIS_MODULE_FALSE@       @echo "Solaris kernel module cannot be build"
+@SOLARIS_MODULE_FALSE@install:
+@SOLARIS_MODULE_FALSE@
+@SOLARIS_MODULE_FALSE@uninstall:
+
+# Build Solaris kernel module
+@SOLARIS_MODULE_TRUE@all :     kernel
+
+@SOLARIS_MODULE_TRUE@kernel: ddp 
+
+@SOLARIS_MODULE_TRUE@FRC: 
+
+@SOLARIS_MODULE_TRUE@ddp :     ${OBJ}
+@SOLARIS_MODULE_TRUE@  ${LD} ${KLDFLAGS} -r -o ddp ${OBJ}
+
+@SOLARIS_MODULE_TRUE@linkage.o : linkage.c
+@SOLARIS_MODULE_TRUE@  ${CC} ${CFLAGS} -DVERSION=\"`cat ../../VERSION`\" -c linkage.c
+
+@SOLARIS_MODULE_TRUE@kuninstall : FRC
+@SOLARIS_MODULE_TRUE@  @if [ x"${SPARC64}" = x"yes" ] ; then \
+@SOLARIS_MODULE_TRUE@          ${RM} /usr/kernel/drv/sparcv9/ddp; \
+@SOLARIS_MODULE_TRUE@          ${RM} /usr/kernel/strmod/sparcv9/ddp; \
+@SOLARIS_MODULE_TRUE@  else \
+@SOLARIS_MODULE_TRUE@          ${RM} /usr/kernel/drv/ddp; \
+@SOLARIS_MODULE_TRUE@          ${RM} /usr/kernel/strmod/ddp; \
+@SOLARIS_MODULE_TRUE@  fi
+@SOLARIS_MODULE_TRUE@  ${RM} /usr/kernel/drv/ddp.conf
+@SOLARIS_MODULE_TRUE@  -rem_drv ddp
+@SOLARIS_MODULE_TRUE@  sync;sync;sync
+
+@SOLARIS_MODULE_TRUE@kinstall : kernel kuninstall
+@SOLARIS_MODULE_TRUE@  @if [ x"${SPARC64}" = x"yes" ]; then \
+@SOLARIS_MODULE_TRUE@          ${INSTALL} -o root -g sys -c ddp /usr/kernel/drv/sparcv9/ddp; \
+@SOLARIS_MODULE_TRUE@          ln /usr/kernel/drv/sparcv9/ddp /usr/kernel/strmod/sparcv9/ddp; \
+@SOLARIS_MODULE_TRUE@  else \
+@SOLARIS_MODULE_TRUE@          ${INSTALL} -o root -g sys -c ddp /usr/kernel/drv/ddp; \
+@SOLARIS_MODULE_TRUE@          ln /usr/kernel/drv/ddp /usr/kernel/strmod/ddp; \
+@SOLARIS_MODULE_TRUE@  fi
+@SOLARIS_MODULE_TRUE@  ${INSTALL} -o root -g sys -c ddp.conf /usr/kernel/drv/ddp.conf
+@SOLARIS_MODULE_TRUE@  add_drv -m '* 0666 root sys' ddp
+@SOLARIS_MODULE_TRUE@  sync;sync;sync
+@SOLARIS_MODULE_TRUE@  @if ${GREP} 'ddp' /etc/netconfig; then \
+@SOLARIS_MODULE_TRUE@            echo "netconfig already contains a ddp module, skipping"; \
+@SOLARIS_MODULE_TRUE@        else \
+@SOLARIS_MODULE_TRUE@            echo "adding ddp module to netconfig"; \
+@SOLARIS_MODULE_TRUE@            echo "ddp        tpi_clts      -    appletalk ddp   /dev/ddp        -" >> /etc/netconfig; \
+@SOLARIS_MODULE_TRUE@  fi
+@SOLARIS_MODULE_TRUE@  @echo "Installed Solaris kernel module"
+
+
+@SOLARIS_MODULE_TRUE@install:
+@SOLARIS_MODULE_TRUE@  @echo
+@SOLARIS_MODULE_TRUE@  @echo "To install the Solaris kernel module type 'make kinstall' as root user"
+
+@SOLARIS_MODULE_TRUE@uninstall:
+@SOLARIS_MODULE_TRUE@  @echo
+@SOLARIS_MODULE_TRUE@  @echo "To uninstall the Solaris kernel module type 'make kuninstall' as root user"
+
+distdir :
+
+clean : sysclean
+
+klean sysclean :
+       rm -f a.out core* *.o *.bak *[Ee]rrs tags
+       rm -f ddp
+
+distclean: clean
+        -rm -f Makefile
+
+maintainer-clean: distclean
+
+depend :
+
+check:
+
+# DO NOT DELETE THIS LINE
+
diff --git a/sys/solaris/Makefile.kernel.in b/sys/solaris/Makefile.kernel.in
deleted file mode 100644 (file)
index 5624a89..0000000
+++ /dev/null
@@ -1,206 +0,0 @@
-# Solaris specific defines, passed to subdirectories.
-# To use Sun CC, uncomment the CC and KFLAGS variables.
-#
-# $Id: Makefile.kernel.in,v 1.5 2003-12-15 05:27:24 srittau Exp $
-
-
-# uncomment for 64-bit sparc kernel
-#SPARC64=true
-
-# solaris has -lcrypt, but we shouldn't use it. this may only be true 
-# for solaris 2.5.1
-USE_CRYPTLIB=no
-
-INSTALL = @INSTALL@
-
-CC             = @CC@
-LD             = ld
-
-# use gcc
-KCFLAGS                = -D_KERNEL -Wall -Wstrict-prototypes ${KGCCFLAGS} # -mcpu=ultrasparc
-# optimization has been reported to cause problems, leave it off
-OPTOPTS                = 
-CSHAREDFLAGS   = -fPIC
-LDSHARED       = ${CC}
-LDSHAREDFLAGS  = -shared
-# LDSHAREDFLAGS        = -shared -64
-
-# use Sun CC (for a 64-bit kernel, uncomment " -xarch=v9 -xregs=no%appl ") 
-#KCFLAGS=      -D_KERNEL # -xarch=v9 -xregs=no%appl 
-#OPTOPTS=      -fast -xO5 -xstrconst
-#CSHAREDFLAGS=   -KPIC
-#LDSHARED=       cc
-#LDSHAREDFLAGS=  -G
-#LDFLAGS_EXPORT=
-
-LIBSHARED=      -ldl
-
-# -D_ISOC9X_SOURCE is handled by OSVERSION. basically, it's not needed
-# with 2.5.1.
-# add -DHAVE_IFNAMEINDEX if you're using solaris 8.
-DEFS=  -DHAVE_IFNAMEINDEX -D__svr4__ -DSOLARIS -I../../sys/generic \
-       -I.. ${OSDEFS} ${MACHINEDEFS}
-AFPLIBS=
-ADDLIBS=       -lsocket -lnsl
-
-# Local build stuff.
-
-SRC= linkage.c tpi.c dlpi.c ioc.c if.c aarp.c ddp.c sock.c rt.c
-OBJ= linkage.o tpi.o dlpi.o ioc.o if.o aarp.o ddp.o sock.o rt.o
-HEADERS= if.h ioc.h rt.h sock.h
-EXTRA_DIST= ddp.conf Makefile
-
-INCPATH=       -I../../include -I../netatalk -I../..
-CFLAGS=        ${DEFS} ${OPTOPTS} ${INCPATH} ${KCFLAGS} 
-
-ALL=   ../../libatalk ../../include ../../bin ../../etc ../../man
-
-oops:
-       @echo "Read README again.  Don't type 'make' here."
-       @exit 1
-
-all :  kernel ${ALL}
-
-kernel :       FRC
-       @case `uname -p` in \
-           i386) \
-               PROCESSOR=i386; \
-               KGCCFLAGS=""; \
-               ;; \
-           sparc) \
-               PROCESSOR=sparc; \
-               KGCCFLAGS="-mno-app-regs -munaligned-doubles \
-                       -fpcc-struct-return" \
-               ;; \
-           *) echo "Unknown processor type..."; exit 1 \
-               ;; \
-       esac; \
-       if [ x"${OSVERSION}" != x"5.5.1" ]; then \
-               OSDEFS=-D_ISOC9X_SOURCE; \
-       fi; \
-       echo "Making $@ for $$PROCESSOR..."; \
-       ${MAKE} -f Makefile.kernel ${MFLAGS} \
-           SBINDIR="${sbindir}" BINDIR="${bindir}" RESDIR="${RESDIR}"\
-           ETCDIR="${sysconfdir}" LIBDIR="${LIBDIR}" INCDIR="${INCDIR}" \
-           MANDIR="${MANDIR}" DESTDIR="${DESTDIR}" AFSDIR="${AFSDIR}" \
-           KRBDIR="${KRBDIR}" OSDEFS="$${OSDEFS}" \
-           MACHINEDEFS="$${MACHINEDEFS}" \
-           AFPLIBS="${AFPLIBS}" KGCCFLAGS="$${KGCCFLAGS}" ddp
-
-FRC: 
-
-ddp :  ${OBJ}
-       ${LD} -r -o ddp ${OBJ}
-
-linkage.o : linkage.c
-       ${CC} ${CFLAGS} -DVERSION=\"`cat ../../VERSION`\" -c linkage.c
-
-../../bin ../../etc:   ../../libatalk
-
-${ALL}:        FRC
-       if [ x"${OSVERSION}" != x"5.5.1" ]; then \
-         OSDEFS=-D_ISOC9X_SOURCE; \
-       fi; \
-       cd $@; ${MAKE} ${MFLAGS} CC="${CC}" \
-           ADDLIBS="${ADDLIBS}" DEFS="${DEFS} $${OSDEFS}" \
-           OPTOPTS="${OPTOPTS}" \
-           SBINDIR="${sbindir}" BINDIR="${bindir}" RESDIR="${RESDIR}" \
-           ETCDIR="${sysconfdir}" LIBDIR="${LIBDIR}" INCDIR="${INCDIR}" \
-           DESTDIR="${DESTDIR}" AFSDIR="${AFSDIR}" KRBDIR="${KRBDIR}" \
-           AFPLIBS="${AFPLIBS}" LDSHARED="${LDSHARED}" \
-           LDFLAGS_EXPORT="${LDFLAGS_EXPORT}" \
-           LDSHAREDFLAGS="${LDSHAREDFLAGS}" CSHAREDFLAGS="${CSHAREDFLAGS}" \
-           LIBSHARED="${LIBSHARED}" USE_CRYPTLIB="${USE_CRYPTLIB}" \
-           OSDEFS="$${OSDEFS}" MACHINEDEFS="$${MACHINEDEFS}" \
-           all
-
-FRC:
-
-kuninstall : FRC
-       rm -f /etc/rc2.d/S79atalk /etc/rc0.d/K79atalk
-       if [ x"${SPARC64}" != x ] ; then \
-               ${RM} /usr/kernel/drv/sparcv9/ddp; \
-               ${RM} /usr/kernel/strmod/sparcv9/ddp; \
-       else \
-               ${RM} /usr/kernel/drv/ddp; \
-               ${RM} /usr/kernel/strmod/ddp; \
-       fi
-       ${RM} /usr/kernel/drv/ddp.conf
-       -rem_drv ddp
-       sync;sync;sync
-
-kinstall : kernel kuninstall
-       if [ x"${SPARC64}" != x ]; then \
-               ${INSTALL} -c ddp /usr/kernel/drv/sparcv9/ddp; \
-               ln /usr/kernel/drv/sparcv9/ddp /usr/kernel/strmod/sparcv9/ddp; \
-       else \
-               ${INSTALL} -c ddp /usr/kernel/drv/ddp; \
-               ln /usr/kernel/drv/ddp /usr/kernel/strmod/ddp; \
-       fi
-       ${INSTALL} -c ddp.conf /usr/kernel/drv/ddp.conf
-       add_drv -m '* 0666 root sys' ddp
-       sync;sync;sync
-       if [ -f /etc/init.d/atalk ]; then \
-               echo "Preserving existing /etc/init.d/atalk settings."; \
-       else \
-       sed -e s@:DESTDIR:@${DESTDIR}@ -e s@:SBINDIR:@${sbindir}@ \
-               -e s@:BINDIR:@${bindir}@ -e s@:RESDIR:@${RESDIR}@ \
-               -e s@:ETCDIR:@${sysconfdir}@ -e s@:LIBDIR:@${LIBDIR}@ \
-               -e s@:INCDIR:@${INCDIR}@ \
-           < ../../distrib/initscripts/rc.atalk.sysv > /etc/init.d/atalk; \
-       fi
-       chmod 744 /etc/init.d/atalk
-       -ln -s ../init.d/atalk /etc/rc2.d/S79atalk
-       -ln -s ../init.d/atalk /etc/rc0.d/K79atalk
-
-install :
-       -mkdir ${DESTDIR}${sbindir} ${DESTDIR}${bindir} ${DESTDIR}${sysconfdir} \
-               ${DESTDIR}${libdir}
-       sed -e s@:BINDIR:@${prefix}/bin@ < ../../contrib/shell_utils/lp2pap.sh > ${DESTDIR}${RESDIR}/lp2pap.sh
-       chmod 744 ${DESTDIR}${sysconfdir}/lp2pap.sh
-       for i in ${ALL}; \
-           do (cd $$i; ${MAKE} ${MFLAGS} CC="${CC}" \
-               ADDLIBS="${ADDLIBS}" DEFS="${DEFS}" OPTOPTS="${OPTOPTS}" \
-               SBINDIR="${sbindir}" BINDIR="${bindir}" RESDIR="${RESDIR}" \
-               ETCDIR="${ETCDIR}" LIBDIR="${LIBDIR}" INCDIR="${INCDIR}" \
-               AFSDIR="${AFSDIR}" KRBDIR="${KRBDIR}" \
-               AFPLIBS="${AFPLIBS}" \
-               LDSHARED="${LDSHARED}" LDFLAGS_EXPORT="${LDFLAGS_EXPORT}" \
-               LDSHAREDFLAGS="${LDSHAREDFLAGS}" \
-               CSHAREDFLAGS="${CSHAREDFLAGS}" LIBSHARED="${LIBSHARED}" \
-               OSDEFS="$${OSDEFS}" MACHINEDEFS="$${MACHINEDEFS}" \
-               INSTALL="${INSTALL}" $@); \
-       done
-       if [ -f ${DESTDIR}${sysconfdir}/afpd.conf ]; then \
-               echo "Retaining old afpd.conf file.";  \
-       else \
-               sed -e s@:DESTDIR:@${DESTDIR}@ -e s@:SBINDIR:@${sbindir}@ \
-                       -e s@:BINDIR:@${bindir}@ -e s@:RESDIR:@${RESDIR}@ \
-                       -e s@:ETCDIR:@${sysconfdir}@ -e s@:LIBDIR:@${LIBDIR}@ \
-                       -e s@:INCDIR:@${INCDIR}@ \
-                       < ../../config/afpd.conf > ${sysconfdir}/afpd.conf; \
-       fi
-       @echo
-       @echo "Install is done.  Don't forget to add lines from"
-       @echo "services.atalk to /etc/services and to call rc.atalk"
-       @echo "in /etc/rc.  See README and README.SOLARIS for more"
-       @echo "information."
-
-distdir :
-
-clean : sysclean
-       for i in ${ALL}; \
-           do (cd $$i; ${MAKE} ${MFLAGS} clean); \
-       done
-
-klean sysclean :
-       rm -f a.out core* *.o *.bak *[Ee]rrs tags
-       rm -f ddp
-
-depend :
-       for i in ${ALL}; \
-           do (cd $$i; ${MAKE} ${MFLAGS} DEFS="${DEFS}" depend); \
-       done
-
-# DO NOT DELETE THIS LINE
-
index 9383ecfb92766d1891ba8701acd679ed9bcc8ef1..ea3cf6758adfa9c3337652ed9d6837092c7628d9 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: aarp.c,v 1.3 2002-01-17 06:13:02 srittau Exp $
+ * $Id: aarp.c,v 1.4 2005-04-28 20:50:07 bfernhomberg Exp $
  */
 
 #ifdef HAVE_CONFIG_H
@@ -124,8 +124,9 @@ aarp_free( struct atif_data *aid, struct aarplist *aal )
 }
 
     void
-aarp_timeout( struct atif_data *aid )
+aarp_timeout( void *ptr )
 {
+    struct atif_data   *aid = (struct atif_data *) ptr;
     struct aarplist    *aal, *p;
 
     aid->aid_aarptimeo = qtimeout( aid->aid_q, aarp_timeout,
index 922c6023eba76124d9891bf9ea8aa42bccdfd337..7e0918ffb8714200668de55cf5cf85ecbc78922d 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: if.c,v 1.2 2002-01-17 07:11:13 srittau Exp $
+/* $Id: if.c,v 1.3 2005-04-28 20:50:07 bfernhomberg Exp $
  */
 
 #ifdef HAVE_CONFIG_H
@@ -163,8 +163,10 @@ if_addmulti( queue_t *q, mblk_t *m, char *name, struct sockaddr *sa )
 }
 
     void
-if_pickaddr( struct atif_data *aid )
+if_pickaddr( void *ptr )
 {
+    struct atif_data *aid = (struct atif_data*) ptr;
+
     if ( aid->aid_c.c_type != SIOCSIFADDR ) {
        cmn_err( CE_NOTE, "if_pickaddr context %x\n", aid->aid_c.c_type );
        return;
index f1ed708935df6e09ddc970b2997990604d6877fd..0348d104fd46e9fc87979bef03f8886e8b5615b2 100644 (file)
@@ -11,7 +11,11 @@ struct atif_data {
     /* solaris 7 wants timeout_id_t, but solaris 2.6 doesn't have that.
      * so, we compromise with an unsigned long as we know that's big
      * enough to hold a pointer. */
+#ifdef HAVE_TIMEOUT_ID_T
+    timeout_id_t       aid_aarptimeo;
+#else
     unsigned long      aid_aarptimeo;
+#endif
     /*
      * A little bit of cleverness, to overcome the inability of
      * streams to sleep.  The type of context must be checked before
index 84b1586167666c37dceeb2f8cabbfc8ba67edc68..4a53f9a9d5a3f6b32c30cb72886ab76841bc592a 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: ioc.c,v 1.2 2002-01-17 07:11:13 srittau Exp $
+/* $Id: ioc.c,v 1.3 2005-04-28 20:50:07 bfernhomberg Exp $
  */
 
 #ifdef HAVE_CONFIG_H
@@ -84,7 +84,7 @@ ioc_copyin( queue_t *q, mblk_t *m, mblk_t *private, caddr_t addr, uint size )
        freemsg( m );
        return;
     }
-#endif notdef
+#endif /* notdef */
     m->b_datap->db_type = M_COPYIN;
     m->b_wptr = m->b_rptr + sizeof( struct copyreq );
     cq = (struct copyreq *)m->b_rptr;
@@ -114,7 +114,7 @@ ioc_copyout( queue_t *q, mblk_t *m, mblk_t *private, caddr_t data,
        freemsg( m );
        return;
     }
-#endif notdef
+#endif /* notdef */
     if (( m0 = allocb( size, BPRI_MED )) == NULL ) {
        cmn_err( CE_CONT, "ioc_copyout nomem\n" );
        freemsg( m );
index 078ebe5c0a54062402508fa0dad8c60888bf4ed1..60bac2b4c36c870d8bcaf61b92bf422312ec07ce 100644 (file)
@@ -1,3 +1,6 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
 #include <sys/types.h>
 #include <sys/kmem.h>
 #include <sys/conf.h>
@@ -36,7 +39,11 @@ tpi_getinfo( dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **resultp )
     static int
 tpi_identify( dev_info_t *dip )
 {
-    if ( strcmp( ddi_get_name( dip ), "ddp" ) == 0 ) {
+    char *tmp;
+
+    /* don't use strcmp under Solaris 9, problem loading kernel module */
+    tmp = ddi_get_name( dip );
+    if ((tmp[0]== 'd') && (tmp[1]=='d') && (tmp[2]=='p') && tmp[3]==0) {
        return( DDI_IDENTIFIED );
     } else {
        return( DDI_NOT_IDENTIFIED );
@@ -344,7 +351,7 @@ cmn_err( CE_CONT, "tpi_wput T_UNITDATA_REQ mblk size %X %X\n", m->b_rptr + tl->u
                freemsg( m );
                break;
            }
-#endif notdef
+#endif /* notdef */
 
            sat = *(struct sockaddr_at *)(m->b_rptr +
                    tl->unitdata_req.DEST_offset );