]> arthur.barton.de Git - netatalk.git/commitdiff
Merge 2-1
authorFrank Lahm <franklahm@googlemail.com>
Wed, 2 Mar 2011 10:35:41 +0000 (11:35 +0100)
committerFrank Lahm <franklahm@googlemail.com>
Wed, 2 Mar 2011 10:35:41 +0000 (11:35 +0100)
253 files changed:
Makefile.am
NEWS
README [deleted file]
TODO [deleted file]
VERSION
bin/Makefile.am
bin/ad/.gitignore [new file with mode: 0644]
bin/ad/Makefile.am [new file with mode: 0644]
bin/ad/ad.c [new file with mode: 0644]
bin/ad/ad.h [new file with mode: 0644]
bin/ad/ad_cp.c [new file with mode: 0644]
bin/ad/ad_find.c [new file with mode: 0644]
bin/ad/ad_ls.c [new file with mode: 0644]
bin/ad/ad_mv.c [new file with mode: 0644]
bin/ad/ad_rm.c [new file with mode: 0644]
bin/ad/ad_util.c [new file with mode: 0644]
bin/afile/Makefile.am [deleted file]
bin/afile/achfile.c [deleted file]
bin/afile/afile.c [deleted file]
bin/afile/common.c [deleted file]
bin/afile/common.h [deleted file]
bin/cnid/Makefile.am
bin/cnid/ad.c [deleted file]
bin/cnid/ad.h [deleted file]
bin/cnid/ad_cp.c [deleted file]
bin/cnid/ad_ls.c [deleted file]
bin/cnid/ad_util.c [deleted file]
bin/misc/.gitignore
bin/misc/Makefile.am
bin/misc/logger_test.c [new file with mode: 0644]
bin/misc/uuidtest.c
config/AppleVolumes.default.tmpl
config/Makefile.am
config/afpd.conf.tmpl
config/netatalk.conf
configure.in
contrib/ICDumpSuffixMap [deleted file]
contrib/Makefile.am
contrib/misc/make-precompose.h.pl [changed mode: 0644->0755]
contrib/patches/README [deleted file]
contrib/patches/patch.afp_vfs [deleted file]
contrib/patches/patch.mangled_trash_with_ip [deleted file]
contrib/patches/patch.samba.3.0.5pre2-SVN [deleted file]
contrib/patches/patch.samba.3.0a20 [deleted file]
contrib/patches/patch.vfs [deleted file]
contrib/permtest/add_permtest.patch [deleted file]
contrib/permtest/permtest.cfg [deleted file]
contrib/permtest/permtest.pl.in [deleted file]
contrib/shell_utils/Makefile.am
contrib/shell_utils/apple_cp.in [deleted file]
contrib/shell_utils/apple_mv.in [deleted file]
contrib/shell_utils/apple_rm.in [deleted file]
contrib/shell_utils/asip-status.pl.in
distrib/debian/README.Debian [deleted file]
distrib/debian/changelog [deleted file]
distrib/debian/control [deleted file]
distrib/debian/copyright [deleted file]
distrib/debian/cvs2deb.sh [deleted file]
distrib/debian/logcheck/ignore.d.server [deleted file]
distrib/debian/logcheck/violations.ignore.d [deleted file]
distrib/debian/netatalk-dev.docs [deleted file]
distrib/debian/netatalk-dev.files [deleted file]
distrib/debian/netatalk.dirs [deleted file]
distrib/debian/netatalk.docs [deleted file]
distrib/debian/netatalk.examples [deleted file]
distrib/debian/netatalk.files [deleted file]
distrib/debian/netatalk.init [deleted file]
distrib/debian/netatalk.links [deleted file]
distrib/debian/netatalk.undocumented [deleted file]
distrib/debian/patches/add_printer.patch [deleted file]
distrib/debian/patches/etc2ps.sh.patch [deleted file]
distrib/debian/patches/filterdir.patch [deleted file]
distrib/debian/patches/netatalk.conf.patch [deleted file]
distrib/debian/patches/netatalk.pamd.patch [deleted file]
distrib/debian/patches/psf.8.patch [deleted file]
distrib/debian/rules [deleted file]
distrib/initscripts/Makefile.am
distrib/initscripts/rc.atalk.bsd.tmpl
distrib/initscripts/rc.atalk.debian.tmpl
distrib/initscripts/rc.atalk.gentoo.tmpl
distrib/initscripts/rc.atalk.redhat.tmpl
distrib/initscripts/rc.atalk.suse.tmpl
distrib/initscripts/rc.atalk.sysv.tmpl
distrib/rpm/buildrpm [deleted file]
distrib/rpm/netatalk-asun.spec.old [deleted file]
distrib/rpm/netatalk-fedora.spec [deleted file]
distrib/rpm/netatalk-mandrake.spec [deleted file]
distrib/rpm/netatalk-redhat.spec [deleted file]
distrib/rpm/netatalk-rpmbuild.patch [deleted file]
doc/DEVELOPER
doc/FAQ [deleted file]
doc/Makefile.am
doc/README.ACLs [deleted file]
doc/README.documentation [deleted file]
doc/README.hidden-items [deleted file]
doc/README.ids [deleted file]
doc/TODO2.1 [deleted file]
etc/Makefile.am
etc/afpd/Makefile.am
etc/afpd/acl_mappings.h
etc/afpd/acls.c
etc/afpd/acls.h
etc/afpd/afp_avahi.c [new file with mode: 0644]
etc/afpd/afp_avahi.h [new file with mode: 0644]
etc/afpd/afp_config.c
etc/afpd/afp_config.h
etc/afpd/afp_dsi.c
etc/afpd/afp_options.c
etc/afpd/afp_zeroconf.c [new file with mode: 0644]
etc/afpd/afp_zeroconf.h [new file with mode: 0644]
etc/afpd/appl.c
etc/afpd/auth.c
etc/afpd/catsearch.c
etc/afpd/desktop.c
etc/afpd/dircache.c [new file with mode: 0644]
etc/afpd/dircache.h [new file with mode: 0644]
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/ofork.c
etc/afpd/status.c
etc/afpd/switch.c
etc/afpd/uam.c
etc/afpd/unix.c
etc/afpd/volume.c
etc/afpd/volume.h
etc/cnid_dbd/Makefile.am
etc/cnid_dbd/cmd_dbd.c
etc/cnid_dbd/cmd_dbd.h
etc/cnid_dbd/cmd_dbd_scanvol.c
etc/cnid_dbd/cnid_metad.c
etc/cnid_dbd/comm.c
etc/cnid_dbd/comm.h
etc/cnid_dbd/db_param.c
etc/cnid_dbd/db_param.h
etc/cnid_dbd/dbd.h
etc/cnid_dbd/dbd_add.c
etc/cnid_dbd/dbd_getstamp.c
etc/cnid_dbd/dbd_resolve.c
etc/cnid_dbd/dbd_search.c [new file with mode: 0644]
etc/cnid_dbd/dbif.c
etc/cnid_dbd/dbif.h
etc/cnid_dbd/main.c
etc/cnid_dbd/pack.c
etc/cnid_dbd/pack.h
etc/cnid_dbd/usockfd.c
include/atalk/Makefile.am
include/atalk/acl.h
include/atalk/adouble.h
include/atalk/afp.h
include/atalk/bstradd.h [new file with mode: 0644]
include/atalk/bstrlib.h [new file with mode: 0644]
include/atalk/cnid.h
include/atalk/cnid_dbd_private.h
include/atalk/cnid_private.h
include/atalk/directory.h
include/atalk/dsi.h
include/atalk/ea.h
include/atalk/errchk.h [new file with mode: 0644]
include/atalk/ftw.h [new file with mode: 0644]
include/atalk/ldapconfig.h
include/atalk/queue.h [new file with mode: 0644]
include/atalk/server_child.h
include/atalk/server_ipc.h
include/atalk/util.h
include/atalk/uuid.h
include/atalk/vfs.h
include/atalk/volinfo.h
include/atalk/volume.h
libatalk/Makefile.am
libatalk/acl/Makefile.am
libatalk/acl/aclldap.h
libatalk/acl/cache.c
libatalk/acl/ldap.c
libatalk/acl/ldap_config.c
libatalk/acl/unix.c
libatalk/acl/uuid.c
libatalk/asp/asp_getsess.c
libatalk/bstring/.gitignore [new file with mode: 0644]
libatalk/bstring/Makefile.am [new file with mode: 0644]
libatalk/bstring/bstradd.c [new file with mode: 0644]
libatalk/bstring/bstrlib.c [new file with mode: 0644]
libatalk/cnid/cdb/Makefile.am
libatalk/cnid/cdb/cnid_cdb_open.c
libatalk/cnid/cnid.c
libatalk/cnid/dbd/cnid_dbd.c
libatalk/cnid/dbd/cnid_dbd.h
libatalk/compat/pselect.c
libatalk/dsi/dsi_attn.c
libatalk/dsi/dsi_close.c
libatalk/dsi/dsi_getsess.c
libatalk/dsi/dsi_opensess.c
libatalk/dsi/dsi_read.c
libatalk/dsi/dsi_stream.c
libatalk/dsi/dsi_tcp.c
libatalk/dsi/dsi_tickle.c
libatalk/unicode/precompose.h
libatalk/unicode/utf8.c
libatalk/unicode/util_unistr.c
libatalk/util/Makefile.am
libatalk/util/fault.c
libatalk/util/ftw.c [new file with mode: 0644]
libatalk/util/queue.c [new file with mode: 0644]
libatalk/util/server_child.c
libatalk/util/server_ipc.c
libatalk/util/socket.c
libatalk/util/test/.gitignore [deleted file]
libatalk/util/test/Makefile.am [deleted file]
libatalk/util/test/logger_test.c [deleted file]
libatalk/util/unix.c
libatalk/util/volinfo.c
libatalk/vfs/Makefile.am
libatalk/vfs/acl.c
libatalk/vfs/unix.c
libatalk/vfs/vfs.c
macros/db3-check.m4
macros/summary.m4
macros/zeroconf.m4 [new file with mode: 0644]
man/man1/Makefile.am
man/man1/achfile.1 [deleted file]
man/man1/ad.1
man/man1/apple_cp.1.tmpl [deleted file]
man/man1/apple_mv.1.tmpl [deleted file]
man/man1/apple_rm.1.tmpl [deleted file]
man/man1/dbd.1
man/man3/Makefile.am
man/man4/Makefile.am
man/man5/AppleVolumes.default.5.tmpl
man/man5/Makefile.am
man/man5/afpd.conf.5.tmpl
man/man5/netatalk.conf.5.tmpl
man/man8/Makefile.am
man/man8/afp_acls.8.tmpl [deleted file]
man/man8/cnid_dbd.8.tmpl
test/.gitignore [new file with mode: 0644]
test/Makefile.am [new file with mode: 0644]
test/afpd/.gitignore [new file with mode: 0644]
test/afpd/Makefile.am [new file with mode: 0644]
test/afpd/afpfunc_helpers.c [new file with mode: 0644]
test/afpd/afpfunc_helpers.h [new file with mode: 0644]
test/afpd/subtests.c [new file with mode: 0644]
test/afpd/subtests.h [new file with mode: 0644]
test/afpd/test.c [new file with mode: 0644]
test/afpd/test.h [new file with mode: 0644]
test/afpd/test.sh [new file with mode: 0755]

index 44ac045379515e1f79b5a26cf098127308ebf3c8..1203023118901ebe8c00249ef3cc2889222fe104 100644 (file)
@@ -1,9 +1,8 @@
 # Makefile.am for top level of netatalk package
 
-SUBDIRS = libatalk bin config etc man contrib distrib include sys doc macros
+SUBDIRS = libatalk bin config etc man contrib distrib include sys doc macros test
 
-EXTRA_DIST = CONTRIBUTORS COPYRIGHT COPYING NEWS\
-       TODO VERSION services.atalk
+EXTRA_DIST = CONTRIBUTORS COPYRIGHT COPYING NEWS VERSION services.atalk
 
 ACLOCAL_AMFLAGS = -I macros
 AUTOMAKE_OPTIONS = foreign
diff --git a/NEWS b/NEWS
index 13dac554a6fb6c1bbfc5a5bba311f5a89fbf26b5..f40686f5fdb3814126437f72b66fb6e4eab2818b 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,71 @@
+Changes in 2.2beta2
+====================
+
+* NEW: afpd: AFP 3.3
+* UPD: afpd: AFP 3.x can't be disabled
+
+Changes in 2.2beta1
+====================
+
+* FIX: composition of Surrogate Pair
+* UPD: gentoo,suse,cobalt,tru64: inistscript name is "netatalk", not "atalk"
+* UPD: gentoo: rc-update install don't hook in the Makefile
+
+Changes in 2.2alpha5
+====================
+
+* UPD: afpd: new option "searchdb" which enables fast catalog searches
+       using the CNID db.
+* UPD: Case-insensitive fast search with the CNID db
+* UPD: cnid_dbd: afpd now passes the volume path, not the db path when
+       connecting for a volume. cnid_dbd will read the
+       ".AppleDesktop/.volinfo" file of the volume in order to figure
+       out the CNID db path and the volume charset encoding.
+
+Changes in 2.2alpha4
+====================
+
+* NEW: Enhanced CNID "dbd" database for fast name search support.
+       Important: this makes cnidscheme "cdb" incompatible with "dbd".
+* NEW: afpd: support for fast catalog searches
+* NEW: ad utility: ad find
+* UPD: afpd: CNID database versioning check for "cdb" scheme
+* UPD: cnid_dbd: CNID database versioning and upgrading. Additional
+       CNID database index for fast name searches.
+
+Changes in 2.2alpha3
+====================
+
+* FIX: afpd: various fixes
+* FIX: Any daemon did not run if atalkd doesn't exist (redhat/debian)
+
+Changes in 2.2alpha2
+====================
+
+* FIX: afpd: fix compilation error when ACL support is not available
+* FIX: Ensure Appletalk manpages and config files are distributed
+
+Changes in 2.2alpha1
+====================
+
+* NEW: ad utility: ad cp
+* NEW: ad utility: ad rm
+* NEW: ad utility: ad mv
+* NEW: afpd: dynamic directoy and CNID cache (new config option -dircachesize)
+* NEW: afpd: POSIX 1e ACL support
+* NEW: afpd: automagic Zeroconf registration with avahi, registering both
+       the service _afpovertcp._tcp and TimeMachine volumes with _adisk._tcp.
+* UPD: afpd: ACLs usable (though not visible on the client side) without common
+       directory service, by mapping ACLs to UARight
+* UPD: afpd: performance improvements for ACL access calculations
+* UPD: AppleTalk is disabled by default at configuration time. If needed
+       use configure switch --enable-ddp.
+* FIX: afpd: Solaris 10 compatibilty fix: don't use SO_SNDTIMEO/SO_RCVTIMEO,
+       use non-blocking IO and select instead.
+* FIX: cnid_dbd: Solaris 10 compatibilty fix: don't use SO_SNDTIMEO/SO_RCVTIMEO,
+       use non-blocking IO and select instead.
+* REM: afile/achfile/apple_cp/apple_mv/apple_rm: use ad
+
 Changes in 2.1.6
 ================
 
@@ -32,7 +100,7 @@ Changes in 2.1.4
 * FIX: afpd: Better handling of symlinks in combination with ACLs and EAs.
        Fixes bug 3074076.
 * FIX: dbd: Adding a file with the CNID from it's adouble file did
-       not work in case that CNID was alread occupied in the database
+       not work in case that CNID was already occupied in the database
 * FIX: macusers: add support for Solaris
 * NEW: cnid_metad: use a PID lockfile
 * NEW: afpd: prevent log flooding
@@ -84,6 +152,7 @@ Changes in 2.1-release
 
 Changes in 2.1-beta2
 ====================
+
 * NEW: afpd: static generated AFP signature stored in afp_signature.conf,
        cf man 5 afp_signature.conf
 * NEW: afpd: clustering support: new per volume option "cnidserver".
diff --git a/README b/README
deleted file mode 100644 (file)
index 5d09f07..0000000
--- a/README
+++ /dev/null
@@ -1,16 +0,0 @@
-The documentation for Netatalk is arranged as follows:
-
-* doc/Netatalk-Manual(.pdf|.txt)
-  the Netatalk manual
-* doc/DEVELOPER 
-  information for developers and additional requirements for compiling
-* doc/FAQ
-  FAQ in progress
-* doc/README.AppleTalk
-  additional instructions for AppleTalk on various operating systems.
-* doc/README.hidden-items
-  documents the various special files created by netatalk in file shares
-
-This should be all you need to get netatalk running.
-
-        - The Netatalk Team
diff --git a/TODO b/TODO
deleted file mode 100644 (file)
index 2c9540c..0000000
--- a/TODO
+++ /dev/null
@@ -1,84 +0,0 @@
-desired features (in no particular order):
-    afpd:
-        return the right version-specific error codes
-        honor the readonly/deleteinhibit/renameinhibit/copyprotect bits.
-        via a database (that handles ro media, -db <path>):
-               Add afp_fileid capabilities - done
-               Add afp_catalogue
-               afp_enumerate optimization
-        server messages in useful places 
-       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
-               database for non-hfs volumes. i think mmapping a
-               bitmap with dids at the root level should work.
-               also, v2 gets us much better prodos support and
-               provides for shortname support. - done 
-       various toggles to afpd.conf (-timeout, etc.)
-       figure out more ways of optimizing things. current places
-               of interest:
-               1) reading/writing. currently there's character 
-                  replacement. we should have a better way of doing
-                  it that speeds things up the no-replacement case.
-                  i've already done that for the crlf case.
-               2) use of mmap where appropriate. NOTE: this will only
-                   be a win if we mmap heavily used files. likely
-                  candidates include file-based databases. mmapping 
-                  header files is actually pretty slow under linux.
-               3) change lookup algorithms where appropriate. 
-       ability to interact with hfs desktop databases (either by
-               changing hfs or changing afpd).
-        utmp/wtmp support
-               
-    papd:
-       DHX authenticated printing logins (does a real Appleshare server
-               do this?)
-       Change to samba-style config file.       
-
-    autoconf/automake system:
-       Need to separate out the flags and libraries for different
-               applications, so that we aren't having them all linked with
-               every library, etc.
-        
-things to fix:
-        cleaner separation of layers.
-       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
-                can fiddle with this file. in addition, we need to be
-               able to still change permissions on a directory with u-a
-               set. finally, we need to adjust the offspring count
-               for directories based upon what permissions they
-               have. i.e., search -> can see directories. 
-                           read -> can see files.
-               we need to map permissions so that these semantics get
-                followed.
-        support picking up items from dropboxes without linux-side superuser
-                intervention
-        support for system-wide messages; send the main afpd process SIGUSR2
-                and each of the children should send out the same message.
-        replacement of a linefeed with the appropriate Macintosh character in
-                server messaging (currently replaces with a space)
-
-added features:
-       sped up of_findname and of_dealloc.
-        nfs quota support
-       solaris beta STREAMS driver added.
-       64-bit cleanup
-       cleaner startup/takedown
-        added debug messages to dsi_write areas.
-       fixed server info unexpected disconnects (due to OT bug).
-        afp/ddp and afp/tcp cohabitation. afp/ddp and afp/tcp can
-       operate separately now (-T turns off tcp, -D turns off ddp).
-       incorporated the netbsd patches 
-               [source: wrstuden@loki.stanford.edu (Bill Studenmund)]
-       casefolding on a per volume basis.
-       added "generic" platform support for AFP/tcp.
-       :ETCDIR:/afppasswd file for randnum passwds
-       AppleVolumes variable substitions
-       atalkd: zones on single interfaces and the ability to control
-               which interfaces get routes between them.
-       papd:   cleartext and noauth logins using Print Server Security
-               Protocol
-               CAP-style authenticated printing
-               fixed errors when spooling to lpr 0.46 queue
diff --git a/VERSION b/VERSION
index b6545a2755827b1af31eb2aca89270e4de2c178b..1b6bd7a95eb7204ddac6728aede66219eeb867b3 100644 (file)
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-2.1.6dev
\ No newline at end of file
+2.2beta2
\ No newline at end of file
index d23a5e5e2dd8af358672e56ec114c0af66a70f5e..423e7e84621bca9bc9a667bc7e1046352c0c8418 100644 (file)
@@ -1,3 +1,7 @@
 # Makefile.am for bin/
 
-SUBDIRS = adv1tov2 aecho afile afppasswd cnid getzones megatron nbp pap psorder uniconv misc
+SUBDIRS = ad adv1tov2 afppasswd cnid megatron uniconv misc
+
+if USE_APPLETALK
+SUBDIRS += aecho getzones nbp pap psorder
+endif
diff --git a/bin/ad/.gitignore b/bin/ad/.gitignore
new file mode 100644 (file)
index 0000000..28432ec
--- /dev/null
@@ -0,0 +1,6 @@
+Makefile
+Makefile.in
+ad
+.deps
+.libs
+*.o
diff --git a/bin/ad/Makefile.am b/bin/ad/Makefile.am
new file mode 100644 (file)
index 0000000..7e6fe92
--- /dev/null
@@ -0,0 +1,24 @@
+# Makefile.am for bin/ad/
+
+noinst_HEADERS = ad.h
+
+if USE_BDB
+bin_PROGRAMS = ad
+
+ad_SOURCES = \
+       ad.c \
+       ad_find.c \
+       ad_util.c \
+       ad_ls.c \
+       ad_cp.c \
+       ad_mv.c \
+       ad_rm.c
+
+ad_CFLAGS = -D_PATH_AD=\"$(bindir)/ad\"
+
+ad_LDADD = \
+       $(top_builddir)/libatalk/cnid/libcnid.la \
+       $(top_builddir)/libatalk/libatalk.la \
+       @ACL_LIBS@
+
+endif
diff --git a/bin/ad/ad.c b/bin/ad/ad.c
new file mode 100644 (file)
index 0000000..71a0f74
--- /dev/null
@@ -0,0 +1,66 @@
+/* 
+   Copyright (c) 2009 Frank Lahm <franklahm@gmail.com>
+   
+   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.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <limits.h>
+#include <signal.h>
+#include <string.h>
+#include <errno.h>
+
+#include <atalk/cnid.h>
+#include <atalk/volinfo.h>
+#include <atalk/logger.h>
+#include <atalk/util.h>
+
+#include "ad.h"
+
+static void usage_main(void)
+{
+    printf("Usage: ad ls|cp|rm|mv|find [file|dir, ...]\n");
+}
+
+int main(int argc, char **argv)
+{
+    setuplog("default log_note /dev/tty");
+
+    if (argc < 2) {
+        usage_main();
+        return 1;
+    }
+
+    if (STRCMP(argv[1], ==, "ls"))
+        return ad_ls(argc - 1, argv + 1);
+    else if (STRCMP(argv[1], ==, "cp"))
+        return ad_cp(argc - 1, argv + 1);
+    else if (STRCMP(argv[1], ==, "rm"))
+        return ad_rm(argc - 1, argv + 1);
+    else if (STRCMP(argv[1], ==, "mv"))
+        return ad_mv(argc, argv);
+    else if (STRCMP(argv[1], ==, "find"))
+        return ad_find(argc, argv);
+    else {
+        usage_main();
+        return 1;
+    }
+
+    return 0;
+}
diff --git a/bin/ad/ad.h b/bin/ad/ad.h
new file mode 100644 (file)
index 0000000..1b484e6
--- /dev/null
@@ -0,0 +1,80 @@
+/* 
+   Copyright (c) 2009 Frank Lahm <franklahm@gmail.com>
+   
+   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.
+*/
+
+#ifndef AD_H
+#define AD_H
+
+#define _XOPEN_SOURCE 600
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <signal.h>
+
+#include <atalk/ftw.h>
+#include <atalk/volinfo.h>
+#include <atalk/cnid.h>
+
+#define DIR_DOT_OR_DOTDOT(a) \
+        ((strcmp(a, ".") == 0) || (strcmp(a, "..") == 0))
+
+#ifndef TIMESPEC_TO_TIMEVAL
+#define TIMESPEC_TO_TIMEVAL(tv, ts) { \
+    (tv)->tv_sec = (ts)->tv_sec; \
+    (tv)->tv_usec = (ts)->tv_nsec / 1000; \
+    }
+#endif
+
+enum logtype {STD, DBG};
+
+#define SLOG(...)                             \
+    _log(STD, __VA_ARGS__)
+
+#define ERROR(...)                              \
+    do {                                        \
+        _log(STD, __VA_ARGS__);                 \
+        exit(1);                                \
+    } while (0)
+
+typedef struct {
+    struct volinfo volinfo;
+    struct vol     volume;
+    char           db_stamp[ADEDLEN_PRIVSYN];
+} afpvol_t;
+
+extern int log_verbose;             /* Logging flag */
+extern void _log(enum logtype lt, char *fmt, ...);
+
+extern int ad_ls(int argc, char **argv);
+extern int ad_cp(int argc, char **argv);
+extern int ad_rm(int argc, char **argv);
+extern int ad_mv(int argc, char **argv);
+
+/* ad_util.c */
+extern int openvol(const char *path, afpvol_t *vol);
+extern void closevol(afpvol_t *vol);
+extern cnid_t cnid_for_path(const afpvol_t *vol, const char *path, cnid_t *did);
+extern cnid_t cnid_for_paths_parent(const afpvol_t *vol, const char *path, cnid_t *did);
+extern char *utompath(const struct volinfo *volinfo, const char *upath);
+extern int convert_dots_encoding(const afpvol_t *svol, const afpvol_t *dvol, char *path, size_t buflen);
+
+typedef struct {
+    char *p_end;/* pointer to NULL at end of path */
+    char *target_end;/* pointer to end of target base */
+    char p_path[MAXPATHLEN + 2];/* pointer to the start of a path */
+} PATH_T;
+
+extern PATH_T to;
+extern int fflag, iflag, lflag, nflag, pflag, vflag;
+
+#endif /* AD_H */
diff --git a/bin/ad/ad_cp.c b/bin/ad/ad_cp.c
new file mode 100644 (file)
index 0000000..97b3061
--- /dev/null
@@ -0,0 +1,1030 @@
+/*
+ * Copyright (c) 2010, Frank Lahm <franklahm@googlemail.com>
+ * Copyright (c) 1988, 1993, 1994
+ * The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * David Hitz of Auspex Systems Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Cp copies source files to target files.
+ *
+ * The global PATH_T structure "to" always contains the path to the
+ * current target file.  Since fts(3) does not change directories,
+ * this path can be either absolute or dot-relative.
+ *
+ * The basic algorithm is to initialize "to" and use fts(3) to traverse
+ * the file hierarchy rooted in the argument list.  A trivial case is the
+ * case of 'cp file1 file2'.  The more interesting case is the case of
+ * 'cp file1 file2 ... fileN dir' where the hierarchy is traversed and the
+ * path (relative to the root of the traversal) is appended to dir (stored
+ * in "to") to form the final target path.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <libgen.h>
+
+#include <atalk/ftw.h>
+#include <atalk/adouble.h>
+#include <atalk/vfs.h>
+#include <atalk/util.h>
+#include <atalk/unix.h>
+#include <atalk/volume.h>
+#include <atalk/volinfo.h>
+#include <atalk/bstrlib.h>
+#include <atalk/bstradd.h>
+#include <atalk/queue.h>
+
+#include "ad.h"
+
+#define STRIP_TRAILING_SLASH(p) {                                   \
+        while ((p).p_end > (p).p_path + 1 && (p).p_end[-1] == '/')  \
+            *--(p).p_end = 0;                                       \
+    }
+
+static char emptystring[] = "";
+
+PATH_T to = { to.p_path, emptystring, "" };
+enum op { FILE_TO_FILE, FILE_TO_DIR, DIR_TO_DNE };
+
+int fflag, iflag, nflag, pflag, vflag;
+mode_t mask;
+
+cnid_t ppdid, pdid, did; /* current dir CNID and parent did*/
+
+static afpvol_t svolume, dvolume;
+static enum op type;
+static int Rflag;
+static volatile sig_atomic_t alarmed;
+static int badcp, rval;
+static int ftw_options = FTW_MOUNT | FTW_PHYS | FTW_ACTIONRETVAL;
+
+static char           *netatalk_dirs[] = {
+    ".AppleDouble",
+    ".AppleDB",
+    ".AppleDesktop",
+    NULL
+};
+
+/* Forward declarations */
+static int copy(const char *fpath, const struct stat *sb, int tflag, struct FTW *ftwbuf);
+static int ftw_copy_file(const struct FTW *, const char *, const struct stat *, int);
+static int ftw_copy_link(const struct FTW *, const char *, const struct stat *, int);
+static int setfile(const struct stat *, int);
+static int preserve_dir_acls(const struct stat *, char *, char *);
+static int preserve_fd_acls(int, int);
+
+/*
+  Check for netatalk special folders e.g. ".AppleDB" or ".AppleDesktop"
+  Returns pointer to name or NULL.
+*/
+static const char *check_netatalk_dirs(const char *name)
+{
+    int c;
+
+    for (c=0; netatalk_dirs[c]; c++) {
+        if ((strcmp(name, netatalk_dirs[c])) == 0)
+            return netatalk_dirs[c];
+    }
+    return NULL;
+}
+
+static void upfunc(void)
+{
+    did = pdid;
+    pdid = ppdid;
+}
+
+/*
+  SIGNAL handling:
+  catch SIGINT and SIGTERM which cause clean exit. Ignore anything else.
+*/
+
+static void sig_handler(int signo)
+{
+    alarmed = 1;
+    return;
+}
+
+static void set_signal(void)
+{
+    struct sigaction sv;
+
+    sv.sa_handler = sig_handler;
+    sv.sa_flags = SA_RESTART;
+    sigemptyset(&sv.sa_mask);
+    if (sigaction(SIGTERM, &sv, NULL) < 0)
+        ERROR("error in sigaction(SIGTERM): %s", strerror(errno));
+
+    if (sigaction(SIGINT, &sv, NULL) < 0)
+        ERROR("error in sigaction(SIGINT): %s", strerror(errno));
+
+    memset(&sv, 0, sizeof(struct sigaction));
+    sv.sa_handler = SIG_IGN;
+    sigemptyset(&sv.sa_mask);
+
+    if (sigaction(SIGABRT, &sv, NULL) < 0)
+        ERROR("error in sigaction(SIGABRT): %s", strerror(errno));
+
+    if (sigaction(SIGHUP, &sv, NULL) < 0)
+        ERROR("error in sigaction(SIGHUP): %s", strerror(errno));
+
+    if (sigaction(SIGQUIT, &sv, NULL) < 0)
+        ERROR("error in sigaction(SIGQUIT): %s", strerror(errno));
+}
+
+static void usage_cp(void)
+{
+    printf(
+        "Usage: ad cp [-R] [-aipvf] <source_file> <target_file>\n"
+        "       ad cp [-R] [-aipvfx] <source_file [source_file ...]> <target_directory>\n\n"
+        "In the first synopsis form, the cp utility copies the contents of the source_file to the\n"
+        "target_file.  In the second synopsis form, the contents of each named source_file is copied to the\n"
+        "destination target_directory.  The names of the files themselves are not changed.  If cp detects an\n"
+        "attempt to copy a file to itself, the copy will fail.\n\n"
+        "Netatalk AFP volumes are detected by means of their \".AppleDesktop\" directory\n"
+        "which is located in their volume root. When a copy targetting an AFP volume\n"
+        "is detected, its CNID database daemon is connected and all copies will also\n"
+        "go through the CNID database.\n"
+        "AppleDouble files are also copied and created as needed when the target is\n"
+        "an AFP volume.\n\n"
+        "The following options are available:\n\n"
+        "     -a    Archive mode.  Same as -Rp.\n\n"
+        "     -f    For each existing destination pathname, remove it and create a new\n"
+        "           file, without prompting for confirmation regardless of its permis-\n"
+        "           sions.  (The -f option overrides any previous -i or -n options.)\n\n"
+        "     -i    Cause cp to write a prompt to the standard error output before\n"
+        "           copying a file that would overwrite an existing file.  If the\n"
+        "           response from the standard input begins with the character 'y' or\n"
+        "           'Y', the file copy is attempted.  (The -i option overrides any pre-\n"
+        "           vious -f or -n options.)\n\n"
+        "     -n    Do not overwrite an existing file.  (The -n option overrides any\n"
+        "           previous -f or -i options.)\n\n"
+        "     -p    Cause cp to preserve the following attributes of each source file\n"
+        "           in the copy: modification time, access time, file flags, file mode,\n"
+        "           user ID, and group ID, as allowed by permissions.\n"
+        "           If the user ID and group ID cannot be preserved, no error message\n"
+        "           is displayed and the exit value is not altered.\n\n"
+        "     -R    If source_file designates a directory, cp copies the directory and\n"
+        "           the entire subtree connected at that point.If the source_file\n"
+        "           ends in a /, the contents of the directory are copied rather than\n"
+        "           the directory itself.\n\n"
+        "     -v    Cause cp to be verbose, showing files as they are copied.\n\n"
+        "     -x    File system mount points are not traversed.\n\n"
+        );
+    exit(EXIT_FAILURE);
+}
+
+int ad_cp(int argc, char *argv[])
+{
+    struct stat to_stat, tmp_stat;
+    int r, ch, have_trailing_slash;
+    char *target;
+#if 0
+    afpvol_t srcvol;
+    afpvol_t dstvol;
+#endif
+
+    ppdid = pdid = htonl(1);
+    did = htonl(2);
+
+    while ((ch = getopt(argc, argv, "afinpRvx")) != -1)
+        switch (ch) {
+        case 'a':
+            pflag = 1;
+            Rflag = 1;
+            break;
+        case 'f':
+            fflag = 1;
+            iflag = nflag = 0;
+            break;
+        case 'i':
+            iflag = 1;
+            fflag = nflag = 0;
+            break;
+        case 'n':
+            nflag = 1;
+            fflag = iflag = 0;
+            break;
+        case 'p':
+            pflag = 1;
+            break;
+        case 'R':
+            Rflag = 1;
+            break;
+        case 'v':
+            vflag = 1;
+            break;
+        case 'x':
+            ftw_options |= FTW_MOUNT;
+            break;
+        default:
+            usage_cp();
+            break;
+        }
+    argc -= optind;
+    argv += optind;
+
+    if (argc < 2)
+        usage_cp();
+
+    set_signal();
+    cnid_init();
+
+    /* Save the target base in "to". */
+    target = argv[--argc];
+    if ((strlcpy(to.p_path, target, PATH_MAX)) >= PATH_MAX)
+        ERROR("%s: name too long", target);
+
+    to.p_end = to.p_path + strlen(to.p_path);
+    if (to.p_path == to.p_end) {
+        *to.p_end++ = '.';
+        *to.p_end = 0;
+    }
+    have_trailing_slash = (to.p_end[-1] == '/');
+    if (have_trailing_slash)
+        STRIP_TRAILING_SLASH(to);
+    to.target_end = to.p_end;
+
+    /* Set end of argument list */
+    argv[argc] = NULL;
+
+    /*
+     * Cp has two distinct cases:
+     *
+     * cp [-R] source target
+     * cp [-R] source1 ... sourceN directory
+     *
+     * In both cases, source can be either a file or a directory.
+     *
+     * In (1), the target becomes a copy of the source. That is, if the
+     * source is a file, the target will be a file, and likewise for
+     * directories.
+     *
+     * In (2), the real target is not directory, but "directory/source".
+     */
+    r = stat(to.p_path, &to_stat);
+    if (r == -1 && errno != ENOENT)
+        ERROR("%s", to.p_path);
+    if (r == -1 || !S_ISDIR(to_stat.st_mode)) {
+        /*
+         * Case (1).  Target is not a directory.
+         */
+        if (argc > 1)
+            ERROR("%s is not a directory", to.p_path);
+
+        /*
+         * Need to detect the case:
+         *cp -R dir foo
+         * Where dir is a directory and foo does not exist, where
+         * we want pathname concatenations turned on but not for
+         * the initial mkdir().
+         */
+        if (r == -1) {
+            lstat(*argv, &tmp_stat);
+
+            if (S_ISDIR(tmp_stat.st_mode) && Rflag)
+                type = DIR_TO_DNE;
+            else
+                type = FILE_TO_FILE;
+        } else
+            type = FILE_TO_FILE;
+
+        if (have_trailing_slash && type == FILE_TO_FILE) {
+            if (r == -1)
+                ERROR("directory %s does not exist", to.p_path);
+            else
+                ERROR("%s is not a directory", to.p_path);
+        }
+    } else
+        /*
+         * Case (2).  Target is a directory.
+         */
+        type = FILE_TO_DIR;
+
+    /*
+     * Keep an inverted copy of the umask, for use in correcting
+     * permissions on created directories when not using -p.
+     */
+    mask = ~umask(0777);
+    umask(~mask);
+
+#if 0
+    /* Inhereting perms in ad_mkdir etc requires this */
+    ad_setfuid(0);
+#endif
+
+    /* Load .volinfo file for destination*/
+    openvol(to.p_path, &dvolume);
+
+    for (int i = 0; argv[i] != NULL; i++) {
+        /* Load .volinfo file for source */
+        openvol(argv[i], &svolume);
+
+        if (nftw(argv[i], copy, upfunc, 20, ftw_options) == -1) {
+            if (alarmed) {
+                SLOG("...break");
+            } else {
+                SLOG("Error: %s: %s", argv[i], strerror(errno));
+            }
+            closevol(&svolume);
+            closevol(&dvolume);
+        }
+    }
+    return rval;
+}
+
+static int copy(const char *path,
+                const struct stat *statp,
+                int tflag,
+                struct FTW *ftw)
+{
+    static int base = 0;
+
+    struct stat to_stat;
+    int dne;
+    size_t nlen;
+    const char *p;
+    char *target_mid;
+
+    if (alarmed)
+        return -1;
+
+    const char *dir = strrchr(path, '/');
+    if (dir == NULL)
+        dir = path;
+    else
+        dir++;
+    if (check_netatalk_dirs(dir) != NULL)
+        return FTW_SKIP_SUBTREE;
+
+    /*
+     * If we are in case (2) above, we need to append the
+     * source name to the target name.
+     */
+    if (type != FILE_TO_FILE) {
+        /*
+         * Need to remember the roots of traversals to create
+         * correct pathnames.  If there's a directory being
+         * copied to a non-existent directory, e.g.
+         *     cp -R a/dir noexist
+         * the resulting path name should be noexist/foo, not
+         * noexist/dir/foo (where foo is a file in dir), which
+         * is the case where the target exists.
+         *
+         * Also, check for "..".  This is for correct path
+         * concatenation for paths ending in "..", e.g.
+         *     cp -R .. /tmp
+         * Paths ending in ".." are changed to ".".  This is
+         * tricky, but seems the easiest way to fix the problem.
+         *
+         * XXX
+         * Since the first level MUST be FTS_ROOTLEVEL, base
+         * is always initialized.
+         */
+        if (ftw->level == 0) {
+            if (type != DIR_TO_DNE) {
+                base = ftw->base;
+
+                if (strcmp(&path[base], "..") == 0)
+                    base += 1;
+            } else
+                base = strlen(path);
+        }
+
+        p = &path[base];
+        nlen = strlen(path) - base;
+        target_mid = to.target_end;
+        if (*p != '/' && target_mid[-1] != '/')
+            *target_mid++ = '/';
+        *target_mid = 0;
+        if (target_mid - to.p_path + nlen >= PATH_MAX) {
+            SLOG("%s%s: name too long (not copied)", to.p_path, p);
+            badcp = rval = 1;
+            return 0;
+        }
+        (void)strncat(target_mid, p, nlen);
+        to.p_end = target_mid + nlen;
+        *to.p_end = 0;
+        STRIP_TRAILING_SLASH(to);
+    }
+
+    /* Not an error but need to remember it happened */
+    if (stat(to.p_path, &to_stat) == -1)
+        dne = 1;
+    else {
+        if (to_stat.st_dev == statp->st_dev &&
+            to_stat.st_ino == statp->st_ino) {
+            SLOG("%s and %s are identical (not copied).", to.p_path, path);
+            badcp = rval = 1;
+            if (S_ISDIR(statp->st_mode))
+                /* without using glibc extension FTW_ACTIONRETVAL cant handle this */
+                return FTW_SKIP_SUBTREE;
+            return 0;
+        }
+        if (!S_ISDIR(statp->st_mode) &&
+            S_ISDIR(to_stat.st_mode)) {
+            SLOG("cannot overwrite directory %s with "
+                 "non-directory %s",
+                 to.p_path, path);
+            badcp = rval = 1;
+            return 0;
+        }
+        dne = 0;
+    }
+
+    /* Convert basename to appropiate volume encoding */
+    if (dvolume.volinfo.v_path) {
+        if ((convert_dots_encoding(&svolume, &dvolume, to.p_path, MAXPATHLEN)) == -1) {
+            SLOG("Error converting name for %s", to.p_path);
+            badcp = rval = 1;
+            return -1;
+        }
+    }
+
+    switch (statp->st_mode & S_IFMT) {
+    case S_IFLNK:
+        if (ftw_copy_link(ftw, path, statp, !dne))
+            badcp = rval = 1;
+        break;
+    case S_IFDIR:
+        if (!Rflag) {
+            SLOG("%s is a directory", path);
+            badcp = rval = 1;
+            return -1;
+        }
+        /*
+         * If the directory doesn't exist, create the new
+         * one with the from file mode plus owner RWX bits,
+         * modified by the umask.  Trade-off between being
+         * able to write the directory (if from directory is
+         * 555) and not causing a permissions race.  If the
+         * umask blocks owner writes, we fail..
+         */
+        if (dne) {
+            if (mkdir(to.p_path, statp->st_mode | S_IRWXU) < 0)
+                ERROR("mkdir: %s: %s", to.p_path, strerror(errno));
+        } else if (!S_ISDIR(to_stat.st_mode)) {
+            errno = ENOTDIR;
+            ERROR("%s", to.p_path);
+        }
+
+        /* Create ad dir and copy ".Parent" */
+        if (dvolume.volinfo.v_path && dvolume.volinfo.v_adouble == AD_VERSION2) {
+
+            /* Create ".AppleDouble" dir */
+            mode_t omask = umask(0);
+            bstring addir = bfromcstr(to.p_path);
+            bcatcstr(addir, "/.AppleDouble");
+            mkdir(cfrombstr(addir), 02777);
+            bdestroy(addir);
+
+            if (svolume.volinfo.v_path && svolume.volinfo.v_adouble == AD_VERSION2) {
+                /* copy ".Parent" file */
+                if (dvolume.volume.vfs->vfs_copyfile(&dvolume.volume, -1, path, to.p_path)) {
+                    SLOG("Error copying adouble for %s -> %s", path, to.p_path);
+                    badcp = rval = 1;
+                    break;
+                }
+            }
+
+            /* Get CNID of Parent and add new childir to CNID database */
+            ppdid = pdid;
+            if ((did = cnid_for_path(&dvolume, to.p_path, &pdid)) == CNID_INVALID) {
+                SLOG("Error resolving CNID for %s", to.p_path);
+                badcp = rval = 1;
+                return -1;
+            }
+
+            struct adouble ad;
+            struct stat st;
+            if (lstat(to.p_path, &st) != 0) {
+                badcp = rval = 1;
+                break;
+            }
+            ad_init(&ad, dvolume.volinfo.v_adouble, dvolume.volinfo.v_ad_options);
+            if (ad_open_metadata(to.p_path, ADFLAGS_DIR, O_RDWR | O_CREAT, &ad) != 0) {
+                ERROR("Error opening adouble for: %s", to.p_path);
+            }
+            ad_setid( &ad, st.st_dev, st.st_ino, did, pdid, dvolume.db_stamp);
+            ad_setname(&ad, utompath(&dvolume.volinfo, basename(to.p_path)));
+            ad_setdate(&ad, AD_DATE_CREATE | AD_DATE_UNIX, st.st_mtime);
+            ad_setdate(&ad, AD_DATE_MODIFY | AD_DATE_UNIX, st.st_mtime);
+            ad_setdate(&ad, AD_DATE_ACCESS | AD_DATE_UNIX, st.st_mtime);
+            ad_setdate(&ad, AD_DATE_BACKUP, AD_DATE_START);
+            ad_flush(&ad);
+            ad_close_metadata(&ad);
+
+            umask(omask);
+        }
+
+        if (pflag) {
+            if (setfile(statp, -1))
+                rval = 1;
+#if 0
+            if (preserve_dir_acls(statp, curr->fts_accpath, to.p_path) != 0)
+                rval = 1;
+#endif
+        }
+        break;
+
+    case S_IFBLK:
+    case S_IFCHR:
+        SLOG("%s is a device file (not copied).", path);
+        break;
+    case S_IFSOCK:
+        SLOG("%s is a socket (not copied).", path);
+        break;
+    case S_IFIFO:
+        SLOG("%s is a FIFO (not copied).", path);
+        break;
+    default:
+        if (ftw_copy_file(ftw, path, statp, dne))
+            badcp = rval = 1;
+
+        if (dvolume.volinfo.v_path && dvolume.volinfo.v_adouble == AD_VERSION2) {
+
+            mode_t omask = umask(0);
+            if (svolume.volinfo.v_path && svolume.volinfo.v_adouble == AD_VERSION2) {
+                /* copy ad-file */
+                if (dvolume.volume.vfs->vfs_copyfile(&dvolume.volume, -1, path, to.p_path)) {
+                    SLOG("Error copying adouble for %s -> %s", path, to.p_path);
+                    badcp = rval = 1;
+                    break;
+                }
+            }
+
+            /* Get CNID of Parent and add new childir to CNID database */
+            pdid = did;
+            cnid_t cnid;
+            if ((cnid = cnid_for_path(&dvolume, to.p_path, &did)) == CNID_INVALID) {
+                SLOG("Error resolving CNID for %s", to.p_path);
+                badcp = rval = 1;
+                return -1;
+            }
+
+            struct adouble ad;
+            struct stat st;
+            if (lstat(to.p_path, &st) != 0) {
+                badcp = rval = 1;
+                break;
+            }
+            ad_init(&ad, dvolume.volinfo.v_adouble, dvolume.volinfo.v_ad_options);
+            if (ad_open_metadata(to.p_path, 0, O_RDWR | O_CREAT, &ad) != 0) {
+                ERROR("Error opening adouble for: %s", to.p_path);
+            }
+            ad_setid( &ad, st.st_dev, st.st_ino, cnid, did, dvolume.db_stamp);
+            ad_setname(&ad, utompath(&dvolume.volinfo, basename(to.p_path)));
+            ad_setdate(&ad, AD_DATE_CREATE | AD_DATE_UNIX, st.st_mtime);
+            ad_setdate(&ad, AD_DATE_MODIFY | AD_DATE_UNIX, st.st_mtime);
+            ad_setdate(&ad, AD_DATE_ACCESS | AD_DATE_UNIX, st.st_mtime);
+            ad_setdate(&ad, AD_DATE_BACKUP, AD_DATE_START);
+            ad_flush(&ad);
+            ad_close_metadata(&ad);
+            umask(omask);
+        }
+        break;
+    }
+    if (vflag && !badcp)
+        (void)printf("%s -> %s\n", path, to.p_path);
+
+    return 0;
+}
+
+/* Memory strategy threshold, in pages: if physmem is larger then this, use a large buffer */
+#define PHYSPAGES_THRESHOLD (32*1024)
+
+/* Maximum buffer size in bytes - do not allow it to grow larger than this */
+#define BUFSIZE_MAX (2*1024*1024)
+
+/* Small (default) buffer size in bytes. It's inefficient for this to be smaller than MAXPHYS */
+#define MAXPHYS (64 * 1024)
+#define BUFSIZE_SMALL (MAXPHYS)
+
+static int ftw_copy_file(const struct FTW *entp,
+                         const char *spath,
+                         const struct stat *sp,
+                         int dne)
+{
+    static char *buf = NULL;
+    static size_t bufsize;
+    ssize_t wcount;
+    size_t wresid;
+    off_t wtotal;
+    int ch, checkch, from_fd = 0, rcount, rval, to_fd = 0;
+    char *bufp;
+    char *p;
+
+    if ((from_fd = open(spath, O_RDONLY, 0)) == -1) {
+        SLOG("%s: %s", spath, strerror(errno));
+        return (1);
+    }
+
+    /*
+     * If the file exists and we're interactive, verify with the user.
+     * If the file DNE, set the mode to be the from file, minus setuid
+     * bits, modified by the umask; arguably wrong, but it makes copying
+     * executables work right and it's been that way forever.  (The
+     * other choice is 666 or'ed with the execute bits on the from file
+     * modified by the umask.)
+     */
+    if (!dne) {
+#define YESNO "(y/n [n]) "
+        if (nflag) {
+            if (vflag)
+                printf("%s not overwritten\n", to.p_path);
+            (void)close(from_fd);
+            return (0);
+        } else if (iflag) {
+            (void)fprintf(stderr, "overwrite %s? %s",
+                          to.p_path, YESNO);
+            checkch = ch = getchar();
+            while (ch != '\n' && ch != EOF)
+                ch = getchar();
+            if (checkch != 'y' && checkch != 'Y') {
+                (void)close(from_fd);
+                (void)fprintf(stderr, "not overwritten\n");
+                return (1);
+            }
+        }
+
+        if (fflag) {
+            /* remove existing destination file name,
+             * create a new file  */
+            (void)unlink(to.p_path);
+            (void)dvolume.volume.vfs->vfs_deletefile(&dvolume.volume, -1, to.p_path);
+            to_fd = open(to.p_path, O_WRONLY | O_TRUNC | O_CREAT,
+                         sp->st_mode & ~(S_ISUID | S_ISGID));
+        } else {
+            /* overwrite existing destination file name */
+            to_fd = open(to.p_path, O_WRONLY | O_TRUNC, 0);
+        }
+    } else {
+        to_fd = open(to.p_path, O_WRONLY | O_TRUNC | O_CREAT,
+                     sp->st_mode & ~(S_ISUID | S_ISGID));
+    }
+
+    if (to_fd == -1) {
+        SLOG("%s: %s", to.p_path, strerror(errno));
+        (void)close(from_fd);
+        return (1);
+    }
+
+    rval = 0;
+
+    /*
+     * Mmap and write if less than 8M (the limit is so we don't totally
+     * trash memory on big files.  This is really a minor hack, but it
+     * wins some CPU back.
+     * Some filesystems, such as smbnetfs, don't support mmap,
+     * so this is a best-effort attempt.
+     */
+
+    if (S_ISREG(sp->st_mode) && sp->st_size > 0 &&
+        sp->st_size <= 8 * 1024 * 1024 &&
+        (p = mmap(NULL, (size_t)sp->st_size, PROT_READ,
+                  MAP_SHARED, from_fd, (off_t)0)) != MAP_FAILED) {
+        wtotal = 0;
+        for (bufp = p, wresid = sp->st_size; ;
+             bufp += wcount, wresid -= (size_t)wcount) {
+            wcount = write(to_fd, bufp, wresid);
+            if (wcount <= 0)
+                break;
+            wtotal += wcount;
+            if (wcount >= (ssize_t)wresid)
+                break;
+        }
+        if (wcount != (ssize_t)wresid) {
+            SLOG("%s: %s", to.p_path, strerror(errno));
+            rval = 1;
+        }
+        /* Some systems don't unmap on close(2). */
+        if (munmap(p, sp->st_size) < 0) {
+            SLOG("%s: %s", spath, strerror(errno));
+            rval = 1;
+        }
+    } else {
+        if (buf == NULL) {
+            /*
+             * Note that buf and bufsize are static. If
+             * malloc() fails, it will fail at the start
+             * and not copy only some files.
+             */
+            if (sysconf(_SC_PHYS_PAGES) >
+                PHYSPAGES_THRESHOLD)
+                bufsize = MIN(BUFSIZE_MAX, MAXPHYS * 8);
+            else
+                bufsize = BUFSIZE_SMALL;
+            buf = malloc(bufsize);
+            if (buf == NULL)
+                ERROR("Not enough memory");
+
+        }
+        wtotal = 0;
+        while ((rcount = read(from_fd, buf, bufsize)) > 0) {
+            for (bufp = buf, wresid = rcount; ;
+                 bufp += wcount, wresid -= wcount) {
+                wcount = write(to_fd, bufp, wresid);
+                if (wcount <= 0)
+                    break;
+                wtotal += wcount;
+                if (wcount >= (ssize_t)wresid)
+                    break;
+            }
+            if (wcount != (ssize_t)wresid) {
+                SLOG("%s: %s", to.p_path, strerror(errno));
+                rval = 1;
+                break;
+            }
+        }
+        if (rcount < 0) {
+            SLOG("%s: %s", spath, strerror(errno));
+            rval = 1;
+        }
+    }
+
+    /*
+     * Don't remove the target even after an error.  The target might
+     * not be a regular file, or its attributes might be important,
+     * or its contents might be irreplaceable.  It would only be safe
+     * to remove it if we created it and its length is 0.
+     */
+
+    if (pflag && setfile(sp, to_fd))
+        rval = 1;
+    if (pflag && preserve_fd_acls(from_fd, to_fd) != 0)
+        rval = 1;
+    if (close(to_fd)) {
+        SLOG("%s: %s", to.p_path, strerror(errno));
+        rval = 1;
+    }
+
+    (void)close(from_fd);
+
+    return (rval);
+}
+
+static int ftw_copy_link(const struct FTW *p,
+                         const char *spath,
+                         const struct stat *sstp,
+                         int exists)
+{
+    int len;
+    char llink[PATH_MAX];
+
+    if ((len = readlink(spath, llink, sizeof(llink) - 1)) == -1) {
+        SLOG("readlink: %s: %s", spath, strerror(errno));
+        return (1);
+    }
+    llink[len] = '\0';
+    if (exists && unlink(to.p_path)) {
+        SLOG("unlink: %s: %s", to.p_path, strerror(errno));
+        return (1);
+    }
+    if (symlink(llink, to.p_path)) {
+        SLOG("symlink: %s: %s", llink, strerror(errno));
+        return (1);
+    }
+    return (pflag ? setfile(sstp, -1) : 0);
+}
+
+static int setfile(const struct stat *fs, int fd)
+{
+    static struct timeval tv[2];
+    struct stat ts;
+    int rval, gotstat, islink, fdval;
+    mode_t mode;
+
+    rval = 0;
+    fdval = fd != -1;
+    islink = !fdval && S_ISLNK(fs->st_mode);
+    mode = fs->st_mode & (S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO);
+
+    TIMESPEC_TO_TIMEVAL(&tv[0], &fs->st_atim);
+    TIMESPEC_TO_TIMEVAL(&tv[1], &fs->st_mtim);
+    if (utimes(to.p_path, tv)) {
+        SLOG("utimes: %s", to.p_path);
+        rval = 1;
+    }
+    if (fdval ? fstat(fd, &ts) :
+        (islink ? lstat(to.p_path, &ts) : stat(to.p_path, &ts)))
+        gotstat = 0;
+    else {
+        gotstat = 1;
+        ts.st_mode &= S_ISUID | S_ISGID | S_ISVTX |
+            S_IRWXU | S_IRWXG | S_IRWXO;
+    }
+    /*
+     * Changing the ownership probably won't succeed, unless we're root
+     * or POSIX_CHOWN_RESTRICTED is not set.  Set uid/gid before setting
+     * the mode; current BSD behavior is to remove all setuid bits on
+     * chown.  If chown fails, lose setuid/setgid bits.
+     */
+    if (!gotstat || fs->st_uid != ts.st_uid || fs->st_gid != ts.st_gid)
+        if (fdval ? fchown(fd, fs->st_uid, fs->st_gid) :
+            (islink ? lchown(to.p_path, fs->st_uid, fs->st_gid) :
+             chown(to.p_path, fs->st_uid, fs->st_gid))) {
+            if (errno != EPERM) {
+                SLOG("chown: %s: %s", to.p_path, strerror(errno));
+                rval = 1;
+            }
+            mode &= ~(S_ISUID | S_ISGID);
+        }
+
+    if (!gotstat || mode != ts.st_mode)
+        if (fdval ? fchmod(fd, mode) : chmod(to.p_path, mode)) {
+            SLOG("chmod: %s: %s", to.p_path, strerror(errno));
+            rval = 1;
+        }
+
+#ifdef HAVE_ST_FLAGS
+    if (!gotstat || fs->st_flags != ts.st_flags)
+        if (fdval ?
+            fchflags(fd, fs->st_flags) :
+            (islink ? lchflags(to.p_path, fs->st_flags) :
+             chflags(to.p_path, fs->st_flags))) {
+            SLOG("chflags: %s: %s", to.p_path, strerror(errno));
+            rval = 1;
+        }
+#endif
+
+    return (rval);
+}
+
+static int preserve_fd_acls(int source_fd, int dest_fd)
+{
+#if 0
+    acl_t acl;
+    acl_type_t acl_type;
+    int acl_supported = 0, ret, trivial;
+
+    ret = fpathconf(source_fd, _PC_ACL_NFS4);
+    if (ret > 0 ) {
+        acl_supported = 1;
+        acl_type = ACL_TYPE_NFS4;
+    } else if (ret < 0 && errno != EINVAL) {
+        warn("fpathconf(..., _PC_ACL_NFS4) failed for %s", to.p_path);
+        return (1);
+    }
+    if (acl_supported == 0) {
+        ret = fpathconf(source_fd, _PC_ACL_EXTENDED);
+        if (ret > 0 ) {
+            acl_supported = 1;
+            acl_type = ACL_TYPE_ACCESS;
+        } else if (ret < 0 && errno != EINVAL) {
+            warn("fpathconf(..., _PC_ACL_EXTENDED) failed for %s",
+                 to.p_path);
+            return (1);
+        }
+    }
+    if (acl_supported == 0)
+        return (0);
+
+    acl = acl_get_fd_np(source_fd, acl_type);
+    if (acl == NULL) {
+        warn("failed to get acl entries while setting %s", to.p_path);
+        return (1);
+    }
+    if (acl_is_trivial_np(acl, &trivial)) {
+        warn("acl_is_trivial() failed for %s", to.p_path);
+        acl_free(acl);
+        return (1);
+    }
+    if (trivial) {
+        acl_free(acl);
+        return (0);
+    }
+    if (acl_set_fd_np(dest_fd, acl, acl_type) < 0) {
+        warn("failed to set acl entries for %s", to.p_path);
+        acl_free(acl);
+        return (1);
+    }
+    acl_free(acl);
+#endif
+    return (0);
+}
+
+static int preserve_dir_acls(const struct stat *fs, char *source_dir, char *dest_dir)
+{
+#if 0
+    acl_t (*aclgetf)(const char *, acl_type_t);
+    int (*aclsetf)(const char *, acl_type_t, acl_t);
+    struct acl *aclp;
+    acl_t acl;
+    acl_type_t acl_type;
+    int acl_supported = 0, ret, trivial;
+
+    ret = pathconf(source_dir, _PC_ACL_NFS4);
+    if (ret > 0) {
+        acl_supported = 1;
+        acl_type = ACL_TYPE_NFS4;
+    } else if (ret < 0 && errno != EINVAL) {
+        warn("fpathconf(..., _PC_ACL_NFS4) failed for %s", source_dir);
+        return (1);
+    }
+    if (acl_supported == 0) {
+        ret = pathconf(source_dir, _PC_ACL_EXTENDED);
+        if (ret > 0) {
+            acl_supported = 1;
+            acl_type = ACL_TYPE_ACCESS;
+        } else if (ret < 0 && errno != EINVAL) {
+            warn("fpathconf(..., _PC_ACL_EXTENDED) failed for %s",
+                 source_dir);
+            return (1);
+        }
+    }
+    if (acl_supported == 0)
+        return (0);
+
+    /*
+     * If the file is a link we will not follow it
+     */
+    if (S_ISLNK(fs->st_mode)) {
+        aclgetf = acl_get_link_np;
+        aclsetf = acl_set_link_np;
+    } else {
+        aclgetf = acl_get_file;
+        aclsetf = acl_set_file;
+    }
+    if (acl_type == ACL_TYPE_ACCESS) {
+        /*
+         * Even if there is no ACL_TYPE_DEFAULT entry here, a zero
+         * size ACL will be returned. So it is not safe to simply
+         * check the pointer to see if the default ACL is present.
+         */
+        acl = aclgetf(source_dir, ACL_TYPE_DEFAULT);
+        if (acl == NULL) {
+            warn("failed to get default acl entries on %s",
+                 source_dir);
+            return (1);
+        }
+        aclp = &acl->ats_acl;
+        if (aclp->acl_cnt != 0 && aclsetf(dest_dir,
+                                          ACL_TYPE_DEFAULT, acl) < 0) {
+            warn("failed to set default acl entries on %s",
+                 dest_dir);
+            acl_free(acl);
+            return (1);
+        }
+        acl_free(acl);
+    }
+    acl = aclgetf(source_dir, acl_type);
+    if (acl == NULL) {
+        warn("failed to get acl entries on %s", source_dir);
+        return (1);
+    }
+    if (acl_is_trivial_np(acl, &trivial)) {
+        warn("acl_is_trivial() failed on %s", source_dir);
+        acl_free(acl);
+        return (1);
+    }
+    if (trivial) {
+        acl_free(acl);
+        return (0);
+    }
+    if (aclsetf(dest_dir, acl_type, acl) < 0) {
+        warn("failed to set acl entries on %s", dest_dir);
+        acl_free(acl);
+        return (1);
+    }
+    acl_free(acl);
+#endif
+    return (0);
+}
diff --git a/bin/ad/ad_find.c b/bin/ad/ad_find.c
new file mode 100644 (file)
index 0000000..8501500
--- /dev/null
@@ -0,0 +1,177 @@
+/* 
+   Copyright (c) 2010 Frank Lahm <franklahm@gmail.com>
+   
+   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.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <limits.h>
+#include <string.h>
+#include <errno.h>
+
+#include <atalk/adouble.h>
+#include <atalk/cnid.h>
+#include <atalk/cnid_dbd_private.h>
+#include <atalk/volinfo.h>
+#include <atalk/bstrlib.h>
+#include <atalk/bstradd.h>
+#include <atalk/directory.h>
+#include <atalk/util.h>
+#include <atalk/unicode.h>
+#include "ad.h"
+
+static volatile sig_atomic_t alarmed;
+
+/*
+  SIGNAL handling:
+  catch SIGINT and SIGTERM which cause clean exit. Ignore anything else.
+*/
+
+static void sig_handler(int signo)
+{
+    alarmed = 1;
+    return;
+}
+
+static void set_signal(void)
+{
+    struct sigaction sv;
+
+    sv.sa_handler = sig_handler;
+    sv.sa_flags = SA_RESTART;
+    sigemptyset(&sv.sa_mask);
+    if (sigaction(SIGTERM, &sv, NULL) < 0)
+        ERROR("error in sigaction(SIGTERM): %s", strerror(errno));
+
+    if (sigaction(SIGINT, &sv, NULL) < 0)
+        ERROR("error in sigaction(SIGINT): %s", strerror(errno));
+
+    memset(&sv, 0, sizeof(struct sigaction));
+    sv.sa_handler = SIG_IGN;
+    sigemptyset(&sv.sa_mask);
+
+    if (sigaction(SIGABRT, &sv, NULL) < 0)
+        ERROR("error in sigaction(SIGABRT): %s", strerror(errno));
+
+    if (sigaction(SIGHUP, &sv, NULL) < 0)
+        ERROR("error in sigaction(SIGHUP): %s", strerror(errno));
+
+    if (sigaction(SIGQUIT, &sv, NULL) < 0)
+        ERROR("error in sigaction(SIGQUIT): %s", strerror(errno));
+}
+
+static void usage_find(void)
+{
+    printf(
+        "Usage: ad find [-v VOLUME_PATH] NAME\n"
+        );
+}
+
+int ad_find(int argc, char **argv)
+{
+    int c, ret;
+    afpvol_t vol;
+    const char *srchvol = getcwdpath();
+
+    while ((c = getopt(argc-1, &argv[1], ":v:")) != -1) {
+        switch(c) {
+        case 'v':
+            srchvol = strdup(optarg);
+            break;
+        case ':':
+        case '?':
+            usage_find();
+            return -1;
+            break;
+        }
+
+    }
+    optind++;
+
+    if ((argc - optind) != 1) {
+        usage_find();
+        exit(1);
+    }
+
+    set_signal();
+    cnid_init();
+
+    if (openvol(srchvol, &vol) != 0)
+        ERROR("Cant open volume \"%s\"", srchvol);
+
+    uint16_t flags = CONV_TOLOWER;
+    char namebuf[MAXPATHLEN + 1];
+    if (convert_charset(vol.volinfo.v_volcharset,
+                        vol.volinfo.v_volcharset,
+                        vol.volinfo.v_maccharset,
+                        argv[optind],
+                        strlen(argv[optind]),
+                        namebuf,
+                        MAXPATHLEN,
+                        &flags) == (size_t)-1) {
+        ERROR("conversion error");
+    }
+
+    int count;
+    char resbuf[DBD_MAX_SRCH_RSLTS * sizeof(cnid_t)];
+    if ((count = cnid_find(vol.volume.v_cdb,
+                           namebuf,
+                           strlen(namebuf),
+                           resbuf,
+                           sizeof(resbuf))) < 1) {
+        ret = 1;
+    } else {
+        ret = 0;
+        cnid_t cnid;
+        char *bufp = resbuf;
+        bstring sep = bfromcstr("/");
+        while (count--) {
+            memcpy(&cnid, bufp, sizeof(cnid_t));
+            bufp += sizeof(cnid_t);
+
+            bstring path = NULL;
+            bstring volpath = bfromcstr(vol.volinfo.v_path);
+            BSTRING_STRIP_SLASH(volpath);
+            char buffer[12 + MAXPATHLEN + 1];
+            int buflen = 12 + MAXPATHLEN + 1;
+            char *name;
+            cnid_t did = cnid;
+            struct bstrList *pathlist = bstrListCreateMin(32);
+
+            while (did != DIRDID_ROOT) {
+                if ((name = cnid_resolve(vol.volume.v_cdb, &did, buffer, buflen)) == NULL)
+                    goto next;
+                bstrListPush(pathlist, bfromcstr(name));
+            }
+            bstrListPush(pathlist, volpath);
+            path = bjoinInv(pathlist, sep);
+            
+            printf("%s\n", cfrombstr(path));
+
+        next:
+            bstrListDestroy(pathlist);
+            bdestroy(path);
+        }
+        bdestroy(sep);
+    }
+
+    closevol(&vol);
+
+    return ret;
+}
diff --git a/bin/ad/ad_ls.c b/bin/ad/ad_ls.c
new file mode 100644 (file)
index 0000000..63226a3
--- /dev/null
@@ -0,0 +1,688 @@
+/* 
+   Copyright (c) 2009 Frank Lahm <franklahm@gmail.com>
+   
+   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.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <limits.h>
+#include <string.h>
+#include <errno.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <pwd.h>
+#include <grp.h>
+#include <time.h>
+
+#include <atalk/adouble.h>
+#include <atalk/cnid.h>
+#include <atalk/volinfo.h>
+#include "ad.h"
+
+#define ADv2_DIRNAME ".AppleDouble"
+
+#define DIR_DOT_OR_DOTDOT(a) \
+        ((strcmp(a, ".") == 0) || (strcmp(a, "..") == 0))
+
+static volatile sig_atomic_t alarmed;
+
+/* ls options */
+static int ls_a;
+static int ls_l;
+static int ls_R;
+static int ls_d;
+static int ls_u;
+
+/* Used for pretty printing */
+static int first = 1;
+static int recursion;
+
+static char           *netatalk_dirs[] = {
+    ADv2_DIRNAME,
+    ".AppleDB",
+    ".AppleDesktop",
+    NULL
+};
+
+static char *labels[] = {
+    "---",
+    "gry",
+    "gre",
+    "vio",
+    "blu",
+    "yel",
+    "red",
+    "ora"
+};
+
+/*
+  SIGNAL handling:
+  catch SIGINT and SIGTERM which cause clean exit. Ignore anything else.
+*/
+
+static void sig_handler(int signo)
+{
+    alarmed = 1;
+    return;
+}
+
+static void set_signal(void)
+{
+    struct sigaction sv;
+
+    sv.sa_handler = sig_handler;
+    sv.sa_flags = SA_RESTART;
+    sigemptyset(&sv.sa_mask);
+    if (sigaction(SIGTERM, &sv, NULL) < 0)
+        ERROR("error in sigaction(SIGTERM): %s", strerror(errno));
+
+    if (sigaction(SIGINT, &sv, NULL) < 0)
+        ERROR("error in sigaction(SIGINT): %s", strerror(errno));
+
+    memset(&sv, 0, sizeof(struct sigaction));
+    sv.sa_handler = SIG_IGN;
+    sigemptyset(&sv.sa_mask);
+
+    if (sigaction(SIGABRT, &sv, NULL) < 0)
+        ERROR("error in sigaction(SIGABRT): %s", strerror(errno));
+
+    if (sigaction(SIGHUP, &sv, NULL) < 0)
+        ERROR("error in sigaction(SIGHUP): %s", strerror(errno));
+
+    if (sigaction(SIGQUIT, &sv, NULL) < 0)
+        ERROR("error in sigaction(SIGQUIT): %s", strerror(errno));
+}
+
+/*
+  Check for netatalk special folders e.g. ".AppleDB" or ".AppleDesktop"
+  Returns pointer to name or NULL.
+*/
+static const char *check_netatalk_dirs(const char *name)
+{
+    int c;
+
+    for (c=0; netatalk_dirs[c]; c++) {
+        if ((strcmp(name, netatalk_dirs[c])) == 0)
+            return netatalk_dirs[c];
+    }
+    return NULL;
+}
+
+
+static void usage_ls(void)
+{
+    printf(
+        "Usage: ad ls [-dRl[u]] [file|dir, ...]\n\n"
+        "  -l Long Output [-u: unix info]:\n"
+        "     <unixinfo ...> <FinderFlags> <AFPAttributes> <Color> <Type> <Creator> <CNID from AppleDouble> <name>\n\n"
+        "     FinderFlags (valid for (f)ile and/or (d)irectory):\n"
+        "       d = On Desktop (f/d)\n"
+        "       e = Hidden extension (f/d)\n"
+        "       m = Shared (can run multiple times) (f)\n"
+        "       n = No INIT resources (f)\n"
+        "       i = Inited (f/d)\n"
+        "       c = Custom icon (f/d)\n"
+        "       t = Stationery (f)\n"
+        "       s = Name locked (f/d)\n"
+        "       b = Bundle (f/d)\n"
+        "       v = Invisible (f/d)\n"
+        "       a = Alias file (f/d)\n\n"
+        "     AFPAttributes:\n"
+        "       y = System (f/d)\n"
+        "       w = No write (f)\n"
+        "       p = Needs backup (f/d)\n"
+        "       r = No rename (f/d)\n"
+        "       l = No delete (f/d)\n"
+        "       o = No copy (f)\n\n"
+        "     Note: any letter appearing in uppercase means the flag is set\n"
+        "           but it's a directory for which the flag is not allowed.\n"
+        );
+}
+
+static void print_numlinks(const struct stat *statp)
+{
+    printf("%5ld", (long)statp->st_nlink);
+}
+
+static void print_owner(const struct stat *statp)
+{
+    struct passwd *pwd = getpwuid(statp->st_uid);
+
+    if (pwd == NULL)
+        printf(" %-8ld", (long)statp->st_uid);
+    else
+        printf(" %-8s", pwd->pw_name);
+}
+
+static void print_group(const struct stat *statp)
+{
+    struct group *grp = getgrgid(statp->st_gid);
+
+    if (grp == NULL)
+        printf(" %-8ld", (long)statp->st_gid);
+    else
+        printf(" %-8s", grp->gr_name);
+}
+
+static void print_size(const struct stat *statp)
+{
+    switch (statp->st_mode & S_IFMT) {
+    case S_IFCHR:
+    case S_IFBLK:
+        printf("%4u,%4u", (unsigned)(statp->st_rdev >> 8),
+               (unsigned)(statp->st_rdev & 0xFF));
+        break;
+    default:
+        printf("%9lu", (unsigned long)statp->st_size);
+    }
+}
+
+static void print_date(const struct stat *statp)
+{
+    time_t now;
+    double diff;
+    char buf[100], *fmt;
+
+    if (time(&now) == -1) {
+        printf(" ????????????");
+        return;
+    }
+    diff = difftime(now, statp->st_mtime);
+    if (diff < 0 || diff > 60 * 60 * 24 * 182.5)
+        fmt = "%b %e  %Y";
+    else
+        fmt = "%b %e %H:%M";
+    strftime(buf, sizeof(buf), fmt, localtime(&statp->st_mtime));
+    printf(" %s", buf);
+}
+
+static void print_flags(char *path, afpvol_t *vol, const struct stat *st)
+{
+    int adflags = 0;
+    struct adouble ad;
+    char *FinderInfo;
+    uint16_t FinderFlags;
+    uint16_t AFPattributes;
+    char type[5] = "----";
+    char creator[5] = "----";
+    int i;
+    uint32_t cnid;
+
+    if (S_ISDIR(st->st_mode))
+        adflags = ADFLAGS_DIR;
+
+    if (vol->volinfo.v_path == NULL)
+        return;
+
+    ad_init(&ad, vol->volinfo.v_adouble, vol->volinfo.v_ad_options);
+
+    if ( ad_metadata(path, adflags, &ad) < 0 )
+        return;
+
+    FinderInfo = ad_entry(&ad, ADEID_FINDERI);
+
+    memcpy(&FinderFlags, FinderInfo + 8, 2);
+    FinderFlags = ntohs(FinderFlags);
+
+    memcpy(type, FinderInfo, 4);
+    memcpy(creator, FinderInfo + 4, 4);
+
+    ad_getattr(&ad, &AFPattributes);
+    AFPattributes = ntohs(AFPattributes);
+
+    /*
+      Finder flags. Lowercase means valid, uppercase means invalid because
+      object is a dir and flag is only valid for files.
+    */
+    putchar(' ');
+    if (FinderFlags & FINDERINFO_ISONDESK)
+        putchar('d');
+    else
+        putchar('-');
+
+    if (FinderFlags & FINDERINFO_HIDEEXT)
+        putchar('e');
+    else
+        putchar('-');
+
+    if (FinderFlags & FINDERINFO_ISHARED) {
+        if (adflags & ADFLAGS_DIR)
+            putchar('M');
+        else
+            putchar('m');
+    } else
+        putchar('-');
+
+    if (FinderFlags & FINDERINFO_HASNOINITS) {
+        if (adflags & ADFLAGS_DIR)
+            putchar('N');
+        else
+            putchar('n');
+    } else
+        putchar('-');
+
+    if (FinderFlags & FINDERINFO_HASBEENINITED)
+        putchar('i');
+    else
+        putchar('-');
+
+    if (FinderFlags & FINDERINFO_HASCUSTOMICON)
+        putchar('c');
+    else
+        putchar('-');
+
+    if (FinderFlags & FINDERINFO_ISSTATIONNERY) {
+        if (adflags & ADFLAGS_DIR)
+            putchar('T');
+        else
+            putchar('t');
+    } else
+        putchar('-');
+
+    if (FinderFlags & FINDERINFO_NAMELOCKED)
+        putchar('s');
+    else
+        putchar('-');
+
+    if (FinderFlags & FINDERINFO_HASBUNDLE)
+        putchar('b');
+    else
+        putchar('-');
+
+    if (FinderFlags & FINDERINFO_INVISIBLE)
+        putchar('v');
+    else
+        putchar('-');
+
+    if (FinderFlags & FINDERINFO_ISALIAS)
+        putchar('a');
+    else
+        putchar('-');
+
+    putchar(' ');
+
+    /* AFP attributes */
+    if (AFPattributes & ATTRBIT_SYSTEM)
+        putchar('y');
+    else
+        putchar('-');
+
+    if (AFPattributes & ATTRBIT_NOWRITE) {
+        if (adflags & ADFLAGS_DIR)
+            putchar('W');
+        else
+            putchar('w');
+    } else
+        putchar('-');
+
+    if (AFPattributes & ATTRBIT_BACKUP)
+        putchar('p');
+    else
+        putchar('-');
+
+    if (AFPattributes & ATTRBIT_NORENAME)
+        putchar('r');
+    else
+        putchar('-');
+
+    if (AFPattributes & ATTRBIT_NODELETE)
+        putchar('l');
+    else
+        putchar('-');
+
+    if (AFPattributes & ATTRBIT_NOCOPY) {
+        if (adflags & ADFLAGS_DIR)
+            putchar('O');
+        else
+            putchar('o');                
+    } else
+        putchar('-');
+
+    /* Color */
+    printf(" %s ", labels[(FinderFlags & FINDERINFO_COLOR) >> 1]);
+
+    /* Type & Creator */
+    for(i=0; i<4; i++) {
+        if (isalnum(type[i]))
+            putchar(type[i]);
+        else
+            putchar('-');
+    }
+    putchar(' '); 
+    for(i=0; i<4; i++) {
+        if (isalnum(creator[i]))
+            putchar(creator[i]);
+        else
+            putchar('-');
+    }
+    putchar(' '); 
+
+    /* CNID */
+    cnid = ad_forcegetid(&ad);
+    if (cnid)
+        printf(" %10u ", ntohl(cnid));
+    else
+        printf(" !ADVOL_CACHE ");
+
+    ad_close_metadata(&ad);
+}
+
+#define TYPE(b) ((st->st_mode & (S_IFMT)) == (b))
+#define MODE(b) ((st->st_mode & (b)) == (b))
+
+static void print_mode(const struct stat *st)
+{
+    if (TYPE(S_IFBLK))
+        putchar('b');
+    else if (TYPE(S_IFCHR))
+        putchar('c');
+    else if (TYPE(S_IFDIR))
+        putchar('d');
+    else if (TYPE(S_IFIFO))
+        putchar('p');
+    else if (TYPE(S_IFREG))
+        putchar('-');
+    else if (TYPE(S_IFLNK))
+        putchar('l');
+    else if (TYPE(S_IFSOCK))
+        putchar('s');
+    else
+        putchar('?');
+    putchar(MODE(S_IRUSR) ? 'r' : '-');
+    putchar(MODE(S_IWUSR) ? 'w' : '-');
+    if (MODE(S_ISUID)) {
+        if (MODE(S_IXUSR))
+            putchar('s');
+        else
+            putchar('S');
+    }
+    else if (MODE(S_IXUSR))
+        putchar('x');
+    else
+        putchar('-');
+    putchar(MODE(S_IRGRP) ? 'r' : '-');
+    putchar(MODE(S_IWGRP) ? 'w' : '-');
+    if (MODE(S_ISGID)) {
+        if (MODE(S_IXGRP))
+            putchar('s');
+        else
+            putchar('S');
+    }
+    else if (MODE(S_IXGRP))
+        putchar('x');
+    else
+        putchar('-');
+    putchar(MODE(S_IROTH) ? 'r' : '-');
+    putchar(MODE(S_IWOTH) ? 'w' : '-');
+    if (MODE(S_IFDIR) && MODE(S_ISVTX)) {
+        if (MODE(S_IXOTH))
+            putchar('t');
+        else
+            putchar('T');
+    }
+    else if (MODE(S_IXOTH))
+        putchar('x');
+    else
+        putchar('-');
+}
+#undef TYPE
+#undef MODE
+
+static int ad_print(char *path, const struct stat *st, afpvol_t *vol)
+{
+    if ( ! ls_l) {
+        printf("%s  ", path);
+        if (ls_d)
+            printf("\n");
+        return 0;
+    }
+
+    /* Long output */
+    if (ls_u) {
+        print_mode(st);
+        print_numlinks(st);
+        print_owner(st);
+        print_group(st);
+        print_size(st);
+        print_date(st);
+    }
+    print_flags(path, vol, st);
+    printf("  %s\n", path);    
+
+
+    return 0;
+}
+
+static int ad_ls_r(char *path, afpvol_t *vol)
+{
+    int ret = 0, cwd, dirprinted = 0, dirempty;
+    const char *name;
+    char *tmp;
+    static char cwdpath[MAXPATHLEN+1];
+    DIR *dp;
+    struct dirent *ep;
+    static struct stat st;      /* Save some stack space */
+
+    if ( first)
+        cwdpath[0] = 0;
+    else
+        strcat(cwdpath, "/");
+
+    strcat(cwdpath, path);
+    first = 0;
+
+    if (lstat(path, &st) < 0) {
+        perror("Can't stat");
+        return -1;
+    }
+    /* If its a file or a dir with -d option call ad_print and return */
+    if (S_ISREG(st.st_mode) || ls_d)
+        return ad_print(path, &st, vol);
+
+    /* Its a dir: chdir to it remembering where we started */
+    if ((cwd = open(".", O_RDONLY)) == -1) {
+        perror("Cant open .");
+        return -1;
+    }
+    if (chdir(path) != 0) {
+        perror("Cant chdir");
+        close(cwd);
+        return -1;
+    }
+
+    if ((dp = opendir (".")) == NULL) {
+        perror("Couldn't opendir .");
+        return -1;
+    }
+
+    /* First run: print everything */
+    dirempty = 1;
+    while ((ep = readdir (dp))) {
+        if (alarmed) {
+            ret = -1;
+            goto exit;
+        }
+
+        /* Check if its "." or ".." */
+        if (DIR_DOT_OR_DOTDOT(ep->d_name))
+            continue;
+
+        /* Check for netatalk special folders e.g. ".AppleDB" or ".AppleDesktop" */
+        if ((name = check_netatalk_dirs(ep->d_name)) != NULL)
+            continue;
+
+        if ((ep->d_name[0] == '.') && ! ls_a)
+            continue;
+
+        dirempty = 0;
+
+        if (recursion && ! dirprinted) {
+            printf("\n%s:\n", cwdpath);
+            dirprinted = 1;
+        }
+
+        if (lstat(ep->d_name, &st) < 0) {
+            perror("Can't stat");
+            return -1;
+        }
+
+        ret = ad_print(ep->d_name, &st, vol);
+        if (ret != 0)
+            goto exit;
+    }
+
+    if (! ls_l && ! dirempty)
+        printf("\n");
+
+    /* Second run: recurse to dirs */
+    if (ls_R) {
+        rewinddir(dp);
+        while ((ep = readdir (dp))) {
+            if (alarmed) {
+                ret = -1;
+                goto exit;
+            }
+
+            /* Check if its "." or ".." */
+            if (DIR_DOT_OR_DOTDOT(ep->d_name))
+                continue;
+
+            /* Check for netatalk special folders e.g. ".AppleDB" or ".AppleDesktop" */
+            if ((name = check_netatalk_dirs(ep->d_name)) != NULL)
+                continue;
+
+            if ((ret = lstat(ep->d_name, &st)) < 0) {
+                perror("Can't stat");
+                goto exit;
+            }
+
+            /* Recursion */
+            if (S_ISDIR(st.st_mode)) {
+                recursion = 1;
+                ret = ad_ls_r(ep->d_name, vol);
+            }
+            if (ret != 0)
+                goto exit;
+        }
+    }
+
+exit:
+    closedir(dp);
+    fchdir(cwd);
+    close(cwd);
+
+    tmp = strrchr(cwdpath, '/');
+    if (tmp)
+        *tmp = 0;
+
+    return ret;
+}
+
+int ad_ls(int argc, char **argv)
+{
+    int c, firstarg;
+    afpvol_t vol;
+    struct stat st;
+
+    while ((c = getopt(argc, argv, ":adlRu")) != -1) {
+        switch(c) {
+        case 'a':
+            ls_a = 1;
+            break;
+        case 'd':
+            ls_d = 1;
+            break;
+        case 'l':
+            ls_l = 1;
+            break;
+        case 'R':
+            ls_R = 1;
+            break;
+        case 'u':
+            ls_u = 1;
+            break;
+        case ':':
+        case '?':
+            usage_ls();
+            return -1;
+            break;
+        }
+
+    }
+
+    set_signal();
+    cnid_init();
+
+    if ((argc - optind) == 0) {
+        openvol(".", &vol);
+        ad_ls_r(".", &vol);
+        closevol(&vol);
+    }
+    else {
+        int havefile = 0;
+
+        firstarg = optind;
+
+        /* First run: only print files from argv paths */
+        while(optind < argc) {
+            if (stat(argv[optind], &st) != 0)
+                goto next;
+            if (S_ISDIR(st.st_mode))
+                goto next;
+
+            havefile = 1;
+            first = 1;
+            recursion = 0;
+
+            openvol(argv[optind], &vol);
+            ad_ls_r(argv[optind], &vol);
+            closevol(&vol);
+        next:
+            optind++;
+        }
+        if (havefile && (! ls_l))
+            printf("\n");
+
+        /* Second run: print dirs */
+        optind = firstarg;
+        while(optind < argc) {
+            if (stat(argv[optind], &st) != 0)
+                goto next2;
+            if ( ! S_ISDIR(st.st_mode))
+                goto next2;
+            if ((optind > firstarg) || havefile)
+                printf("\n%s:\n", argv[optind]);
+
+            first = 1;
+            recursion = 0;
+
+            openvol(argv[optind], &vol);
+            ad_ls_r(argv[optind], &vol);
+            closevol(&vol);
+
+        next2:
+            optind++;
+        }
+
+
+    }
+
+    return 0;
+}
diff --git a/bin/ad/ad_mv.c b/bin/ad/ad_mv.c
new file mode 100644 (file)
index 0000000..342f222
--- /dev/null
@@ -0,0 +1,480 @@
+/*
+ * Copyright (c) 2010, Frank Lahm <franklahm@googlemail.com>
+ *
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <libgen.h>
+
+#include <atalk/ftw.h>
+#include <atalk/adouble.h>
+#include <atalk/vfs.h>
+#include <atalk/util.h>
+#include <atalk/unix.h>
+#include <atalk/volume.h>
+#include <atalk/volinfo.h>
+#include <atalk/bstrlib.h>
+#include <atalk/bstradd.h>
+#include <atalk/queue.h>
+
+#include "ad.h"
+
+#define STRIP_TRAILING_SLASH(p) {                                   \
+        while ((p).p_end > (p).p_path + 1 && (p).p_end[-1] == '/')  \
+            *--(p).p_end = 0;                                       \
+    }
+
+static int fflg, iflg, nflg, vflg;
+
+static afpvol_t svolume, dvolume;
+static cnid_t did, pdid;
+static volatile sig_atomic_t alarmed;
+static char           *netatalk_dirs[] = {
+    ".AppleDouble",
+    ".AppleDB",
+    ".AppleDesktop",
+    NULL
+};
+
+static int copy(const char *, const char *);
+static int do_move(const char *, const char *);
+static void preserve_fd_acls(int source_fd, int dest_fd, const char *source_path,
+                             const char *dest_path);
+/*
+  Check for netatalk special folders e.g. ".AppleDB" or ".AppleDesktop"
+  Returns pointer to name or NULL.
+*/
+static const char *check_netatalk_dirs(const char *name)
+{
+    int c;
+
+    for (c=0; netatalk_dirs[c]; c++) {
+        if ((strcmp(name, netatalk_dirs[c])) == 0)
+            return netatalk_dirs[c];
+    }
+    return NULL;
+}
+
+/*
+  SIGNAL handling:
+  catch SIGINT and SIGTERM which cause clean exit. Ignore anything else.
+*/
+
+static void sig_handler(int signo)
+{
+    alarmed = 1;
+    return;
+}
+
+static void set_signal(void)
+{
+    struct sigaction sv;
+
+    sv.sa_handler = sig_handler;
+    sv.sa_flags = SA_RESTART;
+    sigemptyset(&sv.sa_mask);
+    if (sigaction(SIGTERM, &sv, NULL) < 0)
+        ERROR("error in sigaction(SIGTERM): %s", strerror(errno));
+
+    if (sigaction(SIGINT, &sv, NULL) < 0)
+        ERROR("error in sigaction(SIGINT): %s", strerror(errno));
+
+    memset(&sv, 0, sizeof(struct sigaction));
+    sv.sa_handler = SIG_IGN;
+    sigemptyset(&sv.sa_mask);
+
+    if (sigaction(SIGABRT, &sv, NULL) < 0)
+        ERROR("error in sigaction(SIGABRT): %s", strerror(errno));
+
+    if (sigaction(SIGHUP, &sv, NULL) < 0)
+        ERROR("error in sigaction(SIGHUP): %s", strerror(errno));
+
+    if (sigaction(SIGQUIT, &sv, NULL) < 0)
+        ERROR("error in sigaction(SIGQUIT): %s", strerror(errno));
+}
+
+static void usage_mv(void)
+{
+    printf(
+        "Usage: ad mv [-f | -i | -n] [-v] source target\n"
+        "       ad mv [-f | -i | -n] [-v] source ... directory\n\n"
+        "Move files around within an AFP volume, updating the CNID\n"
+        "database as needed. If either:\n"
+        " - source or destination is not an AFP volume\n"
+        " - source volume != destinatio volume\n"
+        "the files are copied and removed from the source.\n\n"
+        "The following options are available:\n\n"
+        "   -f   Do not prompt for confirmation before overwriting the destination\n"
+        "        path.  (The -f option overrides any previous -i or -n options.)\n"
+        "   -i   Cause mv to write a prompt to standard error before moving a file\n"
+        "        that would overwrite an existing file.  If the response from the\n"
+        "        standard input begins with the character `y' or `Y', the move is\n"
+        "        attempted.  (The -i option overrides any previous -f or -n\n"
+        "        options.)\n"
+        "   -n   Do not overwrite an existing file.  (The -n option overrides any\n"
+        "        previous -f or -i options.)\n"
+        "   -v   Cause mv to be verbose, showing files after they are moved.\n"
+        );
+    exit(EXIT_FAILURE);
+}
+
+int ad_mv(int argc, char *argv[])
+{
+    size_t baselen, len;
+    int rval;
+    char *p, *endp;
+    struct stat sb;
+    int ch;
+    char path[MAXPATHLEN];
+
+
+    pdid = htonl(1);
+    did = htonl(2);
+
+    argc--;
+    argv++;
+
+    while ((ch = getopt(argc, argv, "finv")) != -1)
+        switch (ch) {
+        case 'i':
+            iflg = 1;
+            fflg = nflg = 0;
+            break;
+        case 'f':
+            fflg = 1;
+            iflg = nflg = 0;
+            break;
+        case 'n':
+            nflg = 1;
+            fflg = iflg = 0;
+            break;
+        case 'v':
+            vflg = 1;
+            break;
+        default:
+            usage_mv();
+        }
+
+    argc -= optind;
+    argv += optind;
+
+    if (argc < 2)
+        usage_mv();
+
+    set_signal();
+    cnid_init();
+    if (openvol(argv[argc - 1], &dvolume) != 0) {
+        SLOG("Error opening CNID database for %s: ", argv[argc - 1]);
+        return 1;
+    }
+
+    /*
+     * If the stat on the target fails or the target isn't a directory,
+     * try the move.  More than 2 arguments is an error in this case.
+     */
+    if (stat(argv[argc - 1], &sb) || !S_ISDIR(sb.st_mode)) {
+        if (argc > 2)
+            usage_mv();
+        if (openvol(argv[0], &svolume) != 0) {
+            SLOG("Error opening CNID database for %s: ", argv[0]);
+            return 1;
+        }
+        rval = do_move(argv[0], argv[1]);
+        closevol(&svolume);
+        closevol(&dvolume);
+        return 1;
+    }
+
+    /* It's a directory, move each file into it. */
+    if (strlen(argv[argc - 1]) > sizeof(path) - 1)
+        ERROR("%s: destination pathname too long", *argv);
+
+    (void)strcpy(path, argv[argc - 1]);
+    baselen = strlen(path);
+    endp = &path[baselen];
+    if (!baselen || *(endp - 1) != '/') {
+        *endp++ = '/';
+        ++baselen;
+    }
+
+    for (rval = 0; --argc; ++argv) {
+        /*
+         * Find the last component of the source pathname.  It
+         * may have trailing slashes.
+         */
+        p = *argv + strlen(*argv);
+        while (p != *argv && p[-1] == '/')
+            --p;
+        while (p != *argv && p[-1] != '/')
+            --p;
+
+        if ((baselen + (len = strlen(p))) >= PATH_MAX) {
+            SLOG("%s: destination pathname too long", *argv);
+            rval = 1;
+        } else {
+            memmove(endp, p, (size_t)len + 1);
+            if (openvol(*argv, &svolume) != 0) {
+                SLOG("Error opening CNID database for %s: ", argv[0]);
+                rval = 1;
+                goto exit;
+            }
+            if (do_move(*argv, path))
+                rval = 1;
+            closevol(&svolume);
+        }
+    }
+
+exit:
+    closevol(&dvolume);
+    return rval;
+}
+
+static int do_move(const char *from, const char *to)
+{
+    struct stat sb;
+    int ask, ch, first;
+
+    /*
+     * Check access.  If interactive and file exists, ask user if it
+     * should be replaced.  Otherwise if file exists but isn't writable
+     * make sure the user wants to clobber it.
+     */
+    if (!fflg && !access(to, F_OK)) {
+
+        /* prompt only if source exist */
+        if (lstat(from, &sb) == -1) {
+            SLOG("%s: %s", from, strerror(errno));
+            return (1);
+        }
+
+        ask = 0;
+        if (nflg) {
+            if (vflg)
+                printf("%s not overwritten\n", to);
+            return (0);
+        } else if (iflg) {
+            (void)fprintf(stderr, "overwrite %s? (y/n [n]) ", to);
+            ask = 1;
+        } else if (access(to, W_OK) && !stat(to, &sb)) {
+            (void)fprintf(stderr, "override for %s? (y/n [n]) ", to);
+            ask = 1;
+        }
+        if (ask) {
+            first = ch = getchar();
+            while (ch != '\n' && ch != EOF)
+                ch = getchar();
+            if (first != 'y' && first != 'Y') {
+                (void)fprintf(stderr, "not overwritten\n");
+                return (0);
+            }
+        }
+    }
+
+    int mustcopy = 0;
+    /* 
+     * Besides the usual EXDEV we copy instead of moving if
+     * 1) source AFP volume != dest AFP volume
+     * 2) either source or dest isn't even an AFP volume
+     */
+    if (!svolume.volinfo.v_path
+        || !dvolume.volinfo.v_path
+        || strcmp(svolume.volinfo.v_path, dvolume.volinfo.v_path) != 0)
+        mustcopy = 1;
+    
+    cnid_t cnid = 0;
+    if (!mustcopy) {
+        if ((cnid = cnid_for_path(&svolume, from, &did)) == CNID_INVALID) {
+            SLOG("Couldn't resolve CNID for %s", from);
+            return -1;
+        }
+
+        if (stat(from, &sb) != 0) {
+            SLOG("Cant stat %s: %s", to, strerror(errno));
+            return -1;
+        }
+
+        if (rename(from, to) != 0) {
+            if (errno == EXDEV) {
+                mustcopy = 1;
+                char path[MAXPATHLEN];
+
+                /*
+                 * If the source is a symbolic link and is on another
+                 * filesystem, it can be recreated at the destination.
+                 */
+                if (lstat(from, &sb) == -1) {
+                    SLOG("%s: %s", from, strerror(errno));
+                    return (-1);
+                }
+                if (!S_ISLNK(sb.st_mode)) {
+                    /* Can't mv(1) a mount point. */
+                    if (realpath(from, path) == NULL) {
+                        SLOG("cannot resolve %s: %s: %s", from, path, strerror(errno));
+                        return (1);
+                    }
+                }
+            } else { /* != EXDEV */
+                SLOG("rename %s to %s: %s", from, to, strerror(errno));
+                return (1);
+            }
+        } /* rename != 0*/
+        
+        switch (sb.st_mode & S_IFMT) {
+        case S_IFREG:
+            if (dvolume.volume.vfs->vfs_renamefile(&dvolume.volume, -1, from, to) != 0) {
+                SLOG("Error moving adouble file for %s", from);
+                return -1;
+            }
+            break;
+        case S_IFDIR:
+            break;
+        default:
+            SLOG("Not a file or dir: %s", from);
+            return -1;
+        }
+    
+        /* get CNID of new parent dir */
+        cnid_t newpdid, newdid;
+        if ((newdid = cnid_for_paths_parent(&dvolume, to, &newpdid)) == CNID_INVALID) {
+            SLOG("Couldn't resolve CNID for parent of %s", to);
+            return -1;
+        }
+
+        if (stat(to, &sb) != 0) {
+            SLOG("Cant stat %s: %s", to, strerror(errno));
+            return 1;
+        }
+
+        char *p = strdup(to);
+        char *name = basename(p);
+        if (cnid_update(dvolume.volume.v_cdb, cnid, &sb, newdid, name, strlen(name)) != 0) {
+            SLOG("Cant update CNID for: %s", to);
+            return 1;
+        }
+        free(p);
+
+        struct adouble ad;
+        ad_init(&ad, dvolume.volinfo.v_adouble, dvolume.volinfo.v_ad_options);
+        if (ad_open_metadata(to, S_ISDIR(sb.st_mode) ? ADFLAGS_DIR : 0, O_RDWR, &ad) != 0) {
+            SLOG("Error opening adouble for: %s", to);
+            return 1;
+        }
+        ad_setid(&ad, sb.st_dev, sb.st_ino, cnid, newdid, dvolume.db_stamp);
+        ad_flush(&ad);
+        ad_close_metadata(&ad);
+
+        if (vflg)
+            printf("%s -> %s\n", from, to);
+        return (0);
+    }
+    
+    if (mustcopy)
+        return copy(from, to);
+
+    /* If we get here it's an error */
+    return -1;
+}
+
+static int copy(const char *from, const char *to)
+{
+    struct stat sb;
+    int pid, status;
+
+    if (lstat(to, &sb) == 0) {
+        /* Destination path exists. */
+        if (S_ISDIR(sb.st_mode)) {
+            if (rmdir(to) != 0) {
+                SLOG("rmdir %s: %s", to, strerror(errno));
+                return (1);
+            }
+        } else {
+            if (unlink(to) != 0) {
+                SLOG("unlink %s: %s", to, strerror(errno));
+                return (1);
+            }
+        }
+    } else if (errno != ENOENT) {
+        SLOG("%s: %s", to, strerror(errno));
+        return (1);
+    }
+
+    /* Copy source to destination. */
+    if (!(pid = fork())) {
+        execl(_PATH_AD, "ad", "cp", vflg ? "-Rpv" : "-Rp", from, to, (char *)NULL);
+        _exit(1);
+    }
+    while ((waitpid(pid, &status, 0)) == -1) {
+        if (errno == EINTR)
+            continue;
+        SLOG("%s cp -R %s %s: waitpid: %s", _PATH_AD, from, to, strerror(errno));
+        return (1);
+    }
+    if (!WIFEXITED(status)) {
+        SLOG("%s cp -R %s %s: did not terminate normally", _PATH_AD, from, to);
+        return (1);
+    }
+    switch (WEXITSTATUS(status)) {
+    case 0:
+        break;
+    default:
+        SLOG("%s cp -R %s %s: terminated with %d (non-zero) status",
+             _PATH_AD, from, to, WEXITSTATUS(status));
+        return (1);
+    }
+
+    /* Delete the source. */
+    if (!(pid = fork())) {
+        execl(_PATH_AD, "ad", "rm", "-R", from, (char *)NULL);
+        _exit(1);
+    }
+    while ((waitpid(pid, &status, 0)) == -1) {
+        if (errno == EINTR)
+            continue;
+        SLOG("%s rm -R %s: waitpid: %s", _PATH_AD, from, strerror(errno));
+        return (1);
+    }
+    if (!WIFEXITED(status)) {
+        SLOG("%s rm -R %s: did not terminate normally", _PATH_AD, from);
+        return (1);
+    }
+    switch (WEXITSTATUS(status)) {
+    case 0:
+        break;
+    default:
+        SLOG("%s rm -R %s: terminated with %d (non-zero) status",
+              _PATH_AD, from, WEXITSTATUS(status));
+        return (1);
+    }
+    return 0;
+}
+
+static void
+preserve_fd_acls(int source_fd,
+                 int dest_fd,
+                 const char *source_path,
+                 const char *dest_path)
+{
+    ;
+}
diff --git a/bin/ad/ad_rm.c b/bin/ad/ad_rm.c
new file mode 100644 (file)
index 0000000..b9ef2c3
--- /dev/null
@@ -0,0 +1,322 @@
+/*
+ * Copyright (c) 2010, Frank Lahm <franklahm@googlemail.com>
+ *
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <atalk/ftw.h>
+#include <atalk/adouble.h>
+#include <atalk/vfs.h>
+#include <atalk/util.h>
+#include <atalk/unix.h>
+#include <atalk/volume.h>
+#include <atalk/volinfo.h>
+#include <atalk/bstrlib.h>
+#include <atalk/bstradd.h>
+#include <atalk/queue.h>
+
+#include "ad.h"
+
+#define STRIP_TRAILING_SLASH(p) {                                   \
+        while ((p).p_end > (p).p_path + 1 && (p).p_end[-1] == '/')  \
+            *--(p).p_end = 0;                                       \
+    }
+
+static afpvol_t volume;
+
+static cnid_t did, pdid;
+static int Rflag;
+static volatile sig_atomic_t alarmed;
+static int badrm, rval;
+
+static char           *netatalk_dirs[] = {
+    ".AppleDB",
+    ".AppleDesktop",
+    NULL
+};
+
+/* Forward declarations */
+static int rm(const char *fpath, const struct stat *sb, int tflag, struct FTW *ftwbuf);
+
+/*
+  Check for netatalk special folders e.g. ".AppleDB" or ".AppleDesktop"
+  Returns pointer to name or NULL.
+*/
+static const char *check_netatalk_dirs(const char *name)
+{
+    int c;
+
+    for (c=0; netatalk_dirs[c]; c++) {
+        if ((strcmp(name, netatalk_dirs[c])) == 0)
+            return netatalk_dirs[c];
+    }
+    return NULL;
+}
+
+static void upfunc(void)
+{
+    did = pdid;
+}
+
+/*
+  SIGNAL handling:
+  catch SIGINT and SIGTERM which cause clean exit. Ignore anything else.
+*/
+
+static void sig_handler(int signo)
+{
+    alarmed = 1;
+    return;
+}
+
+static void set_signal(void)
+{
+    struct sigaction sv;
+
+    sv.sa_handler = sig_handler;
+    sv.sa_flags = SA_RESTART;
+    sigemptyset(&sv.sa_mask);
+    if (sigaction(SIGTERM, &sv, NULL) < 0)
+        ERROR("error in sigaction(SIGTERM): %s", strerror(errno));
+
+    if (sigaction(SIGINT, &sv, NULL) < 0)
+        ERROR("error in sigaction(SIGINT): %s", strerror(errno));
+
+    memset(&sv, 0, sizeof(struct sigaction));
+    sv.sa_handler = SIG_IGN;
+    sigemptyset(&sv.sa_mask);
+
+    if (sigaction(SIGABRT, &sv, NULL) < 0)
+        ERROR("error in sigaction(SIGABRT): %s", strerror(errno));
+
+    if (sigaction(SIGHUP, &sv, NULL) < 0)
+        ERROR("error in sigaction(SIGHUP): %s", strerror(errno));
+
+    if (sigaction(SIGQUIT, &sv, NULL) < 0)
+        ERROR("error in sigaction(SIGQUIT): %s", strerror(errno));
+}
+
+static void usage_rm(void)
+{
+    printf(
+        "Usage: ad rm [-vR] <file|dir> [<file|dir> ...]\n\n"
+        "The rm utility attempts to remove the non-directory type files specified\n"
+        "on the command line.\n"
+        "If the files and directories reside on an AFP volume, the corresponding\n"
+        "CNIDs are deleted from the volumes database.\n\n"
+        "The options are as follows:\n\n"
+        "   -R   Attempt to remove the file hierarchy rooted in each file argument.\n"
+        "   -v   Be verbose when deleting files, showing them as they are removed.\n"
+        );
+    exit(EXIT_FAILURE);
+}
+
+int ad_rm(int argc, char *argv[])
+{
+    int ch;
+
+    pdid = htonl(1);
+    did = htonl(2);
+
+    while ((ch = getopt(argc, argv, "vR")) != -1)
+        switch (ch) {
+        case 'R':
+            Rflag = 1;
+            break;
+        case 'v':
+            vflag = 1;
+            break;
+        default:
+            usage_rm();
+            break;
+        }
+    argc -= optind;
+    argv += optind;
+
+    if (argc < 1)
+        usage_rm();
+
+    set_signal();
+    cnid_init();
+
+    /* Set end of argument list */
+    argv[argc] = NULL;
+
+    for (int i = 0; argv[i] != NULL; i++) {
+        /* Load .volinfo file for source */
+        openvol(argv[i], &volume);
+
+        if (nftw(argv[i], rm, upfunc, 20, FTW_DEPTH | FTW_PHYS) == -1) {
+            if (alarmed) {
+                SLOG("...break");
+            } else {
+                SLOG("Error: %s", argv[i]);
+            }
+            closevol(&volume);
+        }
+    }
+    return rval;
+}
+
+static int rm(const char *path,
+              const struct stat *statp,
+              int tflag,
+              struct FTW *ftw)
+{
+    cnid_t cnid;
+
+    if (alarmed)
+        return -1;
+
+    const char *dir = strrchr(path, '/');
+    if (dir == NULL)
+        dir = path;
+    else
+        dir++;
+    if (check_netatalk_dirs(dir) != NULL)
+        return FTW_SKIP_SUBTREE;
+
+    switch (statp->st_mode & S_IFMT) {
+
+    case S_IFLNK:
+        if (volume.volinfo.v_path) {
+            if ((volume.volinfo.v_adouble == AD_VERSION2)
+                && (strstr(path, ".AppleDouble") != NULL)) {
+                /* symlink inside adouble dir */
+                if (unlink(path) != 0)
+                    badrm = rval = 1;
+                break;
+            }
+
+            /* Get CNID of Parent and add new childir to CNID database */
+            pdid = did;
+            if ((cnid = cnid_for_path(&volume, path, &did)) == CNID_INVALID) {
+                SLOG("Error resolving CNID for %s", path);
+                return -1;
+            }
+            if (cnid_delete(volume.volume.v_cdb, cnid) != 0) {
+                SLOG("Error removing CNID %u for %s", ntohl(cnid), path);
+                return -1;
+            }
+        }
+
+        if (unlink(path) != 0) {
+            badrm = rval = 1;
+            break;
+        }
+
+        break;
+
+    case S_IFDIR:
+        if (!Rflag) {
+            SLOG("%s is a directory", path);
+            return FTW_SKIP_SUBTREE;
+        }
+
+        if (volume.volinfo.v_path) {
+            if ((volume.volinfo.v_adouble == AD_VERSION2)
+                && (strstr(path, ".AppleDouble") != NULL)) {
+                /* should be adouble dir itself */
+                if (rmdir(path) != 0) {
+                    SLOG("Error removing dir \"%s\": %s", path, strerror(errno));
+                    badrm = rval = 1;
+                    return -1;
+                }
+                break;
+            }
+
+            /* Get CNID of Parent and add new childir to CNID database */
+            if ((did = cnid_for_path(&volume, path, &pdid)) == CNID_INVALID) {
+                SLOG("Error resolving CNID for %s", path);
+                return -1;
+            }
+            if (cnid_delete(volume.volume.v_cdb, did) != 0) {
+                SLOG("Error removing CNID %u for %s", ntohl(did), path);
+                return -1;
+            }
+        }
+
+        if (rmdir(path) != 0) {
+            SLOG("Error removing dir \"%s\": %s", path, strerror(errno));
+            badrm = rval = 1;
+            return -1;
+        }
+
+        break;
+
+    case S_IFBLK:
+    case S_IFCHR:
+        SLOG("%s is a device file.", path);
+        badrm = rval = 1;
+        break;
+
+    case S_IFSOCK:
+        SLOG("%s is a socket.", path);
+        badrm = rval = 1;
+        break;
+
+    case S_IFIFO:
+        SLOG("%s is a FIFO.", path);
+        badrm = rval = 1;
+        break;
+
+    default:
+        if (volume.volinfo.v_path) {
+            if ((volume.volinfo.v_adouble == AD_VERSION2)
+                && (strstr(path, ".AppleDouble") != NULL)) {
+                /* file in adouble dir */
+                if (unlink(path) != 0)
+                    badrm = rval = 1;
+                break;
+            }
+
+            /* Get CNID of Parent and add new childir to CNID database */
+            pdid = did;
+            if ((cnid = cnid_for_path(&volume, path, &did)) == CNID_INVALID) {
+                SLOG("Error resolving CNID for %s", path);
+                return -1;
+            }
+            if (cnid_delete(volume.volume.v_cdb, cnid) != 0) {
+                SLOG("Error removing CNID %u for %s", ntohl(cnid), path);
+                return -1;
+            }
+
+            /* Ignore errors, because with -R adouble stuff is always alread gone */
+            volume.volume.vfs->vfs_deletefile(&volume.volume, -1, path);
+        }
+
+        if (unlink(path) != 0) {
+            badrm = rval = 1;
+            break;
+        }
+
+        break;
+    }
+
+    if (vflag && !badrm)
+        (void)printf("%s\n", path);
+
+    return 0;
+}
diff --git a/bin/ad/ad_util.c b/bin/ad/ad_util.c
new file mode 100644 (file)
index 0000000..5a9b097
--- /dev/null
@@ -0,0 +1,454 @@
+/*
+ * Copyright (c) 2009 Frank Lahm <franklahm@gmail.com>
+ * Copyright (c) 1991, 1993, 1994
+ * The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sysexits.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <string.h>
+#include <libgen.h>
+
+#ifdef HAVE_SOLARIS_ACLS
+#include <sys/acl.h>
+#endif  /* HAVE_SOLARIS_ACLS */
+
+#ifdef HAVE_POSIX_ACLS
+#include <sys/types.h>
+#include <sys/acl.h>
+#endif /* HAVE_POSIX_ACLS */
+
+#include <atalk/util.h>
+#include <atalk/cnid.h>
+#include <atalk/volinfo.h>
+#include <atalk/bstrlib.h>
+#include <atalk/bstradd.h>
+#include <atalk/logger.h>
+#include <atalk/errchk.h>
+#include <atalk/unicode.h>
+
+#include "ad.h"
+
+int log_verbose;             /* Logging flag */
+
+void _log(enum logtype lt, char *fmt, ...)
+{
+    int len;
+    static char logbuffer[1024];
+    va_list args;
+
+    if ( (lt == STD) || (log_verbose == 1)) {
+        va_start(args, fmt);
+        len = vsnprintf(logbuffer, 1023, fmt, args);
+        va_end(args);
+        logbuffer[1023] = 0;
+
+        printf("%s\n", logbuffer);
+    }
+}
+
+/*!
+ * Load volinfo and initialize struct vol
+ *
+ * Only opens "dbd" volumes !
+ *
+ * @param path   (r)  path to evaluate
+ * @param vol    (rw) structure to initialize
+ *
+ * @returns 0 on success, exits on error
+ */
+int openvol(const char *path, afpvol_t *vol)
+{
+    int flags = 0;
+
+    memset(vol, 0, sizeof(afpvol_t));
+
+    /* try to find a .AppleDesktop/.volinfo */
+    if (loadvolinfo((char *)path, &vol->volinfo) != 0)
+        return -1;
+
+    if (STRCMP(vol->volinfo.v_cnidscheme, != , "dbd"))
+        ERROR("\"%s\" isn't a \"dbd\" CNID volume!", vol->volinfo.v_path);
+
+    if (vol_load_charsets(&vol->volinfo) == -1)
+        ERROR("Error loading charsets!");
+
+    /* Sanity checks to ensure we can touch this volume */
+    if (vol->volinfo.v_adouble != AD_VERSION2)
+        ERROR("Unsupported adouble versions: %u", vol->volinfo.v_adouble);
+
+    if (vol->volinfo.v_vfs_ea != AFPVOL_EA_SYS)
+        ERROR("Unsupported Extended Attributes option: %u", vol->volinfo.v_vfs_ea);
+
+    /* initialize sufficient struct vol for VFS initialisation */
+    vol->volume.v_adouble = AD_VERSION2;
+    vol->volume.v_vfs_ea = AFPVOL_EA_SYS;
+    initvol_vfs(&vol->volume);
+
+    if ((vol->volinfo.v_flags & AFPVOL_NODEV))
+        flags |= CNID_FLAG_NODEV;
+
+    if ((vol->volume.v_cdb = cnid_open(vol->volinfo.v_path,
+                                       0000,
+                                       "dbd",
+                                       flags,
+                                       vol->volinfo.v_dbd_host,
+                                       vol->volinfo.v_dbd_port)) == NULL)
+        ERROR("Cant initialize CNID database connection for %s", vol->volinfo.v_path);
+
+    cnid_getstamp(vol->volume.v_cdb,
+                  vol->db_stamp,
+                  sizeof(vol->db_stamp));
+    
+    return 0;
+}
+
+void closevol(afpvol_t *vol)
+{
+    if (vol->volume.v_cdb)
+        cnid_close(vol->volume.v_cdb);
+
+    memset(vol, 0, sizeof(afpvol_t));
+}
+
+/*
+  Taken form afpd/desktop.c
+*/
+char *utompath(const struct volinfo *volinfo, const char *upath)
+{
+    static char  mpath[ MAXPATHLEN + 2]; /* for convert_charset dest_len parameter +2 */
+    char         *m;
+    const char   *u;
+    uint16_t     flags = CONV_IGNORE | CONV_UNESCAPEHEX;
+    size_t       outlen;
+
+    if (!upath)
+        return NULL;
+
+    m = mpath;
+    u = upath;
+    outlen = strlen(upath);
+
+    if ((volinfo->v_casefold & AFPVOL_UTOMUPPER))
+        flags |= CONV_TOUPPER;
+    else if ((volinfo->v_casefold & AFPVOL_UTOMLOWER))
+        flags |= CONV_TOLOWER;
+
+    if ((volinfo->v_flags & AFPVOL_EILSEQ)) {
+        flags |= CONV__EILSEQ;
+    }
+
+    /* convert charsets */
+    if ((size_t)-1 == ( outlen = convert_charset(volinfo->v_volcharset,
+                                                 CH_UTF8_MAC,
+                                                 volinfo->v_maccharset,
+                                                 u, outlen, mpath, MAXPATHLEN, &flags)) ) {
+        SLOG("Conversion from %s to %s for %s failed.",
+             volinfo->v_volcodepage, volinfo->v_maccodepage, u);
+        return NULL;
+    }
+
+    return(m);
+}
+
+/*!
+ * Build path relativ to volume root
+ *
+ * path might be:
+ * (a) relative:
+ *     "dir/subdir" with cwd: "/afp_volume/topdir"
+ * (b) absolute:
+ *     "/afp_volume/dir/subdir"
+ *
+ * @param path     (r) path relative to cwd() or absolute
+ * @param volpath  (r) volume path that path is a subdir of (has been computed in volinfo funcs)
+ *
+ * @returns relative path in new bstring, caller must bdestroy it
+ */
+static bstring rel_path_in_vol(const char *path, const char *volpath)
+{
+    EC_INIT;
+    int cwd = -1;
+    bstring fpath = NULL;
+    char *dname = NULL;
+    struct stat st;
+
+    if (path == NULL || volpath == NULL)
+        return NULL;
+
+    EC_NEG1_LOG(cwd = open(".", O_RDONLY));
+
+    EC_ZERO_LOGSTR(lstat(path, &st), "lstat(%s): %s", path, strerror(errno));
+    switch (S_IFMT & st.st_mode) {
+
+    case S_IFREG:
+    case S_IFLNK:
+        EC_NULL_LOG(dname = strdup(path));
+        EC_ZERO_LOGSTR(chdir(dirname(dname)), "chdir(%s): %s", dirname, strerror(errno));
+        free(dname);
+        dname = NULL;
+        EC_NULL(fpath = bfromcstr(getcwdpath()));
+        BSTRING_STRIP_SLASH(fpath);
+        EC_ZERO(bcatcstr(fpath, "/"));
+        EC_NULL_LOG(dname = strdup(path));
+        EC_ZERO(bcatcstr(fpath, basename(dname)));
+        break;
+
+    case S_IFDIR:
+        EC_ZERO_LOGSTR(chdir(path), "chdir(%s): %s", path, strerror(errno));
+        EC_NULL(fpath = bfromcstr(getcwdpath()));
+        break;
+
+    default:
+        SLOG("special: %s", path);
+        EC_FAIL;
+    }
+
+    BSTRING_STRIP_SLASH(fpath);
+
+    /*
+     * Now we have eg:
+     *   fpath:   /Volume/netatalk/dir/bla
+     *   volpath: /Volume/netatalk/
+     * we want: "dir/bla"
+     */
+    EC_ZERO(bdelete(fpath, 0, strlen(volpath)));
+
+EC_CLEANUP:
+    if (dname) free(dname);
+    if (cwd != -1) {
+        fchdir(cwd);
+        close(cwd);
+    }
+    if (ret != 0)
+        return NULL;
+    return fpath;
+}
+
+/*!
+ * Convert dot encoding of basename _in place_
+ *
+ * path arg can be "[/][dir/ | ...]filename". It will be converted in place
+ * possible encoding ".file" as ":2efile" which means the result will be
+ * longer then the original which means provide a big enough buffer.
+ *
+ * @param svol   (r)  source volume
+ * @param dvol   (r)  destinatio volume
+ * @param path   (rw) path to convert _in place_
+ * @param buflen (r)  size of path buffer (max strlen == buflen -1)
+ *
+ * @returns 0 on sucess, -1 on error
+ */
+int convert_dots_encoding(const afpvol_t *svol, const afpvol_t *dvol, char *path, size_t buflen)
+{
+    static charset_t from = (charset_t) -1;
+    static char buf[MAXPATHLEN+2];
+    char *bname = stripped_slashes_basename(path);
+    int pos = bname - path;
+    uint16_t flags = 0;
+
+    if ( ! svol->volinfo.v_path) {
+        /* no source volume: escape special chars (eg ':') */
+        from = dvol->volinfo.v_volcharset; /* src = dst charset */
+        flags |= CONV_ESCAPEHEX;
+    } else {
+        from = svol->volinfo.v_volcharset;
+    }
+
+    if ( (svol->volinfo.v_path)
+         && ! (svol->volinfo.v_flags & AFPVOL_USEDOTS)
+         && (dvol->volinfo.v_flags & AFPVOL_USEDOTS)) {
+        /* source is without dots, destination is with */
+        flags |= CONV_UNESCAPEHEX;
+    } else if (! (dvol->volinfo.v_flags & AFPVOL_USEDOTS)) {
+        flags |= CONV_ESCAPEDOTS;
+    }
+
+    int len = convert_charset(from,
+                              dvol->volinfo.v_volcharset,
+                              dvol->volinfo.v_maccharset,
+                              bname, strlen(bname),
+                              buf, MAXPATHLEN,
+                              &flags);
+    if (len == -1)
+        return -1;
+
+    if (strlcpy(bname, buf, MAXPATHLEN - pos) > MAXPATHLEN - pos)
+        return -1;
+    return 0;
+}
+
+/*!
+ * ResolvesCNID of a given paths
+ *
+ * path might be:
+ * (a) relative:
+ *     "dir/subdir" with cwd: "/afp_volume/topdir"
+ * (b) absolute:
+ *     "/afp_volume/dir/subdir"
+ *
+ * path MUST be pointing inside vol, this is usually the case as vol has been build from
+ * path using loadvolinfo and friends.
+ *
+ * @param vol  (r) pointer to afpvol_t
+ * @param path (r) path, see above
+ * @param did  (rw) parent CNID of returned CNID
+ *
+ * @returns CNID of path
+ */
+cnid_t cnid_for_path(const afpvol_t *vol,
+                     const char *path,
+                     cnid_t *did)
+{
+    EC_INIT;
+
+    cnid_t cnid;
+    bstring rpath = NULL;
+    bstring statpath = NULL;
+    struct bstrList *l = NULL;
+    struct stat st;
+
+    *did = htonl(1);
+    cnid = htonl(2);
+
+    EC_NULL(rpath = rel_path_in_vol(path, vol->volinfo.v_path));
+    EC_NULL(statpath = bfromcstr(vol->volinfo.v_path));
+
+    l = bsplit(rpath, '/');
+    for (int i = 0; i < l->qty ; i++) {
+        *did = cnid;
+        EC_ZERO(bconcat(statpath, l->entry[i]));
+        EC_ZERO_LOGSTR(lstat(cfrombstr(statpath), &st),
+                       "lstat(rpath: %s, elem: %s): %s: %s",
+                       cfrombstr(rpath), cfrombstr(l->entry[i]),
+                       cfrombstr(statpath), strerror(errno));
+
+        if ((cnid = cnid_add(vol->volume.v_cdb,
+                             &st,
+                             *did,
+                             cfrombstr(l->entry[i]),
+                             blength(l->entry[i]),
+                             0)) == CNID_INVALID) {
+            EC_FAIL;
+        }
+        EC_ZERO(bcatcstr(statpath, "/"));
+    }
+
+EC_CLEANUP:
+    bdestroy(rpath);
+    bstrListDestroy(l);
+    bdestroy(statpath);
+    if (ret != 0)
+        return CNID_INVALID;
+
+    return cnid;
+}
+
+/*!
+ * Resolves CNID of a given paths parent directory
+ *
+ * path might be:
+ * (a) relative:
+ *     "dir/subdir" with cwd: "/afp_volume/topdir"
+ * (b) absolute:
+ *     "/afp_volume/dir/subdir"
+ *
+ * path MUST be pointing inside vol, this is usually the case as vol has been build from
+ * path using loadvolinfo and friends.
+ *
+ * @param vol  (r) pointer to afpvol_t
+ * @param path (r) path, see above
+ * @param did  (rw) parent CNID of returned CNID
+ *
+ * @returns CNID of path
+ */
+cnid_t cnid_for_paths_parent(const afpvol_t *vol,
+                             const char *path,
+                             cnid_t *did)
+{
+    EC_INIT;
+
+    cnid_t cnid;
+    bstring rpath = NULL;
+    bstring statpath = NULL;
+    struct bstrList *l = NULL;
+    struct stat st;
+
+    *did = htonl(1);
+    cnid = htonl(2);
+
+    EC_NULL(rpath = rel_path_in_vol(path, vol->volinfo.v_path));
+    EC_NULL(statpath = bfromcstr(vol->volinfo.v_path));
+
+    l = bsplit(rpath, '/');
+    if (l->qty == 1)
+        /* only one path element, means parent dir cnid is volume root = 2 */
+        goto EC_CLEANUP;
+    for (int i = 0; i < (l->qty - 1); i++) {
+        *did = cnid;
+        EC_ZERO(bconcat(statpath, l->entry[i]));
+        EC_ZERO_LOGSTR(lstat(cfrombstr(statpath), &st),
+                       "lstat(rpath: %s, elem: %s): %s: %s",
+                       cfrombstr(rpath), cfrombstr(l->entry[i]),
+                       cfrombstr(statpath), strerror(errno));
+
+        if ((cnid = cnid_add(vol->volume.v_cdb,
+                             &st,
+                             *did,
+                             cfrombstr(l->entry[i]),
+                             blength(l->entry[i]),
+                             0)) == CNID_INVALID) {
+            EC_FAIL;
+        }
+        EC_ZERO(bcatcstr(statpath, "/"));
+    }
+
+EC_CLEANUP:
+    bdestroy(rpath);
+    bstrListDestroy(l);
+    bdestroy(statpath);
+    if (ret != 0)
+        return CNID_INVALID;
+
+    return cnid;
+}
+
diff --git a/bin/afile/Makefile.am b/bin/afile/Makefile.am
deleted file mode 100644 (file)
index 376eab6..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-# Makefile.am for bin/afile/
-
-INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/sys
-
-bin_PROGRAMS = afile achfile
-
-afile_SOURCES = afile.c common.c common.h
-achfile_SOURCES = achfile.c common.c common.h
diff --git a/bin/afile/achfile.c b/bin/afile/achfile.c
deleted file mode 100644 (file)
index 99133cc..0000000
+++ /dev/null
@@ -1,272 +0,0 @@
-/*
- * $Id: achfile.c,v 1.7 2009-10-14 01:38:28 didg Exp $
- *
-    afile - determine the MacOS creator/type of files
-
-    Copyright (C) 2001 Sebastian Rittau.
-    All rights reserved.
-
-    This file may be distributed and/or modfied under the terms of the
-    following license:
-
-    Redistribution and use in source and binary forms, with or without
-    modification, are permitted provided that the following conditions
-    are met:
-    1. Redistributions of source code must retain the above copyright
-       notice, this list of conditions and the following disclaimer.
-    2. Redistributions in binary form must reproduce the above copyright
-       notice, this list of conditions and the following disclaimer in the
-       documentation and/or other materials provided with the distribution.
-    3. Neither the name of the author nor the names of its contributors
-       may be used to endorse or promote products derived from this software
-       without specific prior written permission.
-
-    THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
-    ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-    ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
-    FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-    DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
-    OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-    HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-    LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
-    OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-    SUCH DAMAGE.
-*/
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif /* HAVE_CONFIG_H */
-
-#include <stdio.h>
-#include <string.h>
-#include <errno.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/adouble.h>
-
-#include "common.h"
-
-/* Global Variables */
-static const char *type    = NULL;
-static const char *creator = NULL;
-
-
-/* Print usage information. */
-static void usage(char *prog)
-{
-  fprintf(stderr, "Usage: %s [-t TYPE] [-c CREATOR] FILE ...\n", prog);
-}
-
-/* Print extensive help. */
-static void help(char *prog)
-{
-  usage(prog);
-  fprintf(stderr,
-         "\n"
-         "Change the MacOS creator/type of FILEs.\n"
-         "\n"
-         "  -t, --type=TYPE        choose type\n"
-         "  -c, --creator=CREATOR  choose creator\n"
-         "  -h, --help             show this help and exit\n"
-         "  -v, --version          show version information and exit\n");
-}
-
-/* Print the version. */
-static void version(void)
-{
-  fprintf(stderr, "achfile (netatalk " VERSION ")\n");
-}
-
-/* Argument Handling
- * known options: -t, -c, -h, -v
- * known long options: --help, --version
- */
-#define OPTSTRING "t:c:hv-:"
-static const char *get_long_arg(int argc, char *argv[], const char *arg, const char *oa) {
-  switch (*oa) {
-  case '=':
-    return &oa[1];
-  case '\0':
-    if (optind == argc) {
-      fprintf(stderr, "%s: option \'%s\' requires an argument\n", argv[0], arg);
-      return NULL;
-    }
-    return argv[optind++];
-  default:
-    fprintf(stderr, "%s: unrecognized option \'%s\'\n", argv[0], arg);
-    usage(argv[0]);
-    return NULL;
-  }
-}
-
-static int parse_args(int argc, char *argv[])
-{
-  int c;
-  const char *longarg;
-
-  /* iterate through the command line */
-  while ((c = getopt(argc, argv, OPTSTRING)) != -1) {
-    switch (c) {
-    case 'h':
-      help(argv[0]);
-      exit(0);
-    case 'v':
-      version();
-      exit(0);
-    case 't':
-      type = optarg;
-      break;
-    case 'c':
-      creator = optarg;
-      break;
-    case '-':
-      if (strcmp(optarg, "help") == 0) {
-       help(argv[0]);
-       exit(0);
-      }
-      if (strcmp(optarg, "version") == 0) {
-       version();
-       exit(0);
-      }
-      if (strncmp(optarg, "type", 4) == 0) {
-       longarg = get_long_arg(argc, argv, "type", &optarg[4]);
-       if (!longarg)
-         return -1;
-       type = longarg;
-      } else if (strncmp(optarg, "creator", 7) == 0) {
-       longarg = get_long_arg(argc, argv, "creator", &optarg[7]);
-       if (!longarg)
-         return -1;
-       creator = longarg;
-      }
-      break;
-    default:
-      usage(argv[0]);
-      return -1;
-    }
-  }
-
-  /* At least one file argument is required. */
-  if (argc == optind) {
-    usage(argv[0]);
-    return -1;
-  }
-
-  /* Either type or creator is required. */
-  if (!type && !creator) {
-    fprintf(stderr, "achfile: either type or creator must be specified\n");
-    return -1;
-  }
-
-  /* Type and creator must be exactly four characters long. */
-  if ((type && strlen(type) != 4) || (creator && strlen(creator) != 4)) {
-    fprintf(stderr, "achfile: type and creator must be four character IDs\n");
-    return -1;
-  }
-
-  return 0;
-}
-
-
-/* Change the owner/creator of each file specified on the command line. */
-static int handle_file(const char *filename)
-{
-  int fd;
-  struct stat statbuf;
-  char *adname;
-  ssize_t sz;
-  char buf[AD_DATASZ];
-  struct adouble *ad = (struct adouble *) &buf;
-
-  if (stat(filename, &statbuf) == -1) {
-    fprintf(stderr, "achfile:%s: %s\n", filename, strerror(errno));
-    return -1;
-  }
-
-  adname = dataname_to_adname(filename);
-  fd = open(adname, O_RDWR, 0);
-  if (fd == -1) {
-    if (errno == ENOENT)
-      fprintf(stderr, "achfile:%s: no resource fork\n", filename);
-    else
-      fprintf(stderr, "achfile:%s: %s\n", adname, strerror(errno));
-    free(adname);
-    return -1;
-  }
-  sz = read(fd, buf, AD_DATASZ);
-  if (sz == -1) {
-    fprintf(stderr, "achfile:%s: %s\n", adname, strerror(errno));
-    free(adname);
-    close(fd);
-    return -1;
-  } else if (sz < AD_DATASZ) {
-    fprintf(stderr, "achfile:%s: corrupt resource fork\n", filename);
-    free(adname);
-    close(fd);
-    return -1;
-  }
-  if ( ntohl(ad->ad_magic) != AD_MAGIC) {
-    fprintf(stderr, "achfile:%s: corrupt resource fork\n", filename);
-    free(adname);
-    close(fd);
-    return -1;
-  }
-
-  /* Change Type */
-  if (type) {
-    buf[ADEDOFF_FINDERI + 0] = type[0];
-    buf[ADEDOFF_FINDERI + 1] = type[1];
-    buf[ADEDOFF_FINDERI + 2] = type[2];
-    buf[ADEDOFF_FINDERI + 3] = type[3];
- }
-
-  /* Change Creator */
-  if (creator) {
-    buf[ADEDOFF_FINDERI + 4] = creator[0];
-    buf[ADEDOFF_FINDERI + 5] = creator[1];
-    buf[ADEDOFF_FINDERI + 6] = creator[2];
-    buf[ADEDOFF_FINDERI + 7] = creator[3];
- }
-
-  /* Write file back to disk. */
-  if (lseek(fd, 0, SEEK_SET) == -1) {
-    fprintf(stderr, "achfile:%s: %s\n", adname, strerror(errno));
-    free(adname);
-    close(fd);
-    return -1;
-  }
-  if (write(fd, &buf, AD_DATASZ) < AD_DATASZ) {
-    fprintf(stderr, "achfile:%s: %s\n", adname, strerror(errno));
-    free(adname);
-    close(fd);
-    return -1;
-  }
-
-  /* Clean Up */
-  free(adname);
-  close(fd);
-
-  return 0;
-}
-
-
-int main(int argc, char *argv[])
-{
-  /* argument handling */
-  if (parse_args(argc, argv) == -1)
-    return 1;
-
-  while (optind < argc)
-    handle_file(argv[optind++]);
-
-  return 0;
-}
diff --git a/bin/afile/afile.c b/bin/afile/afile.c
deleted file mode 100644 (file)
index e70c850..0000000
+++ /dev/null
@@ -1,260 +0,0 @@
-/*
- * $Id: afile.c,v 1.7 2009-10-14 01:38:28 didg Exp $
- *
-    afile - determine the MacOS creator/type of files
-
-    Copyright (C) 2001 Sebastian Rittau.
-    All rights reserved.
-
-    This file may be distributed and/or modfied under the terms of the
-    following license:
-
-    Redistribution and use in source and binary forms, with or without
-    modification, are permitted provided that the following conditions
-    are met:
-    1. Redistributions of source code must retain the above copyright
-       notice, this list of conditions and the following disclaimer.
-    2. Redistributions in binary form must reproduce the above copyright
-       notice, this list of conditions and the following disclaimer in the
-       documentation and/or other materials provided with the distribution.
-    3. Neither the name of the author nor the names of its contributors
-       may be used to endorse or promote products derived from this software
-       without specific prior written permission.
-
-    THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
-    ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-    ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
-    FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-    DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
-    OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-    HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-    LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
-    OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-    SUCH DAMAGE.
-*/
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif /* HAVE_CONFIG_H */
-
-#include <stdio.h>
-#include <string.h>
-#include <errno.h>
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif /* HAVE_UNISTD_H */
-
-#include <atalk/adouble.h>
-
-#include "common.h"
-
-/* Possible return types. These are taken from the original afile for
- * compatibility.
- */
-#define RET_OK                0 /* everything went fine */
-#define RET_NO_SUCH_FILE      1 /* file doesn't exist */
-#define RET_UNREADABLE        2 /* file is unreadable */
-#define RET_IS_DIR            3 /* file is a directory */
-#define RET_NO_DF             4 /* there is no corresponding data fork */
-#define RET_INVALID_DF        5 /* data fork exists but can't be read */
-#define RET_NO_AD             6 /* AppleDouble file doesn't exist */
-#define RET_INVALID_AD        7 /* AppleDouble file exists but can't be read */
-#define RET_SHORT_AD          8 /* AppleDouble file is too short */
-#define RET_BAD_MAGIC         9 /* AppleDouble file has a bad magic value */
-#define RET_BAD_ARGS         99 /* bad command line options */
-
-
-/* Global Variables */
-static int showall = 0;
-
-
-/* Print usage information. */
-static void usage(char *prog)
-{
-  fprintf(stderr, "Usage: %s [-a] FILE ...\n", prog);
-}
-
-/* Print extensive help. */
-static void help(char *prog)
-{
-  usage(prog);
-  fprintf(stderr,
-         "\n"
-         "Determine the MacOS creator/type of FILEs.\n"
-         "\n"
-         "  -a, --show-all    also show unknown files and directories\n"
-         "  -h, --help        show this help and exit\n"
-         "  -v, --version     show version information and exit\n");
-}
-
-/* Print the version. */
-static void version(void)
-{
-  fprintf(stderr, "afile (netatalk " VERSION ")\n");
-}
-
-/* Argument Handling
- * known options: -a, -h, -v
- * known long options: --show-all, --help, --version
- */
-#define OPTSTRING "ahv-:"
-static int parse_args(int argc, char *argv[])
-{
-  int c;
-
-  /* iterate through the command line */
-  while ((c = getopt(argc, argv, OPTSTRING)) != -1) {
-    switch (c) {
-    case 'h':
-      help(argv[0]);
-      exit(0);
-    case 'v':
-      version();
-      exit(0);
-    case 'a':
-      showall = 1;
-      break;
-    case '-':
-      if (strcmp(optarg, "help") == 0) {
-       help(argv[0]);
-       exit(0);
-      }
-      if (strcmp(optarg, "version") == 0) {
-       version();
-       exit(0);
-      }
-      if (strcmp(optarg, "show-all") == 0)
-       showall = 1;
-      break;
-    default:
-      usage(argv[0]);
-      return -1;
-    }
-  }
-
-  /* At least one file argument is required. */
-  if (argc == optind) {
-    usage(argv[0]);
-    return -1;
-  }
-
-  return 0;
-}
-
-
-/* Print the creator/type as taken from the supplied character stream, which
- * must be a AppleDouble file header.
- */
-static void print_type(const char *filename, const char *creator, const char *type)
-{
-  printf("%4.4s %4.4s %s\n", creator, type, filename);
-}
-
-
-static int handle_ad(struct AFile *rfile)
-{
-  int fd;
-  char *dataname;
-
-  dataname = adname_to_dataname(afile_filename(rfile));
-
-  /* Try to open data file. */
-  fd = open(dataname, O_RDONLY);
-  free(dataname);
-  if (fd == -1) {
-    if (errno == ENOENT)
-      return RET_NO_DF;      /* There is no data fork. */
-    else
-      return RET_INVALID_DF; /* The data fork can't be read. */
-  }
-  /* FIXME: stat */
-
-  close(fd);
-
-  return RET_OK;
-}
-
-
-static int handle_datafile(struct AFile *datafile)
-{
-  int ret;
-  char *adname;
-  struct AFile *rfile;
-
-  /* Try to load AppleDouble file. */
-  adname = dataname_to_adname(afile_filename(datafile));
-  rfile = afile_new(adname);
-  if (!rfile) {
-    if (errno == ENOENT) {
-      free(adname);
-      if (showall)
-       printf("unknown %s\n", afile_filename(datafile));
-      return RET_NO_AD;
-    }
-    fprintf(stderr, "afile:%s: %s\n", adname, strerror(errno));
-    free(adname);
-    return RET_INVALID_AD;
-  }
-  free(adname);
-
-  /* Check if this is really an AppleDouble file. */
-  if (afile_is_ad(rfile)) {
-    print_type(afile_filename(datafile),
-              afile_creator(rfile), afile_type(rfile));
-    if (afile_mode(datafile) != afile_mode(rfile))
-      fprintf(stderr, "afile:%s: mode does not match", afile_filename(datafile));
-    ret = RET_OK;
-  } else
-    ret = RET_INVALID_AD;
-
-  afile_delete(rfile);
-
-  return ret;
-}
-
-
-/* Parse a file and its resource fork. Output the file's creator/type. */
-static int parse_file(char *filename)
-{
-  int ret;
-  struct AFile *afile;
-
-  afile = afile_new(filename);
-  if (!afile) {
-    fprintf(stderr, "afile:%s: %s\n", filename, strerror(errno));
-    return errno == ENOENT ? RET_NO_SUCH_FILE : RET_UNREADABLE;
-  }
-
-  if (afile_is_dir(afile)) {
-    if (showall)
-      printf("directory %s\n", filename);
-    ret = RET_IS_DIR;
-  } else if (afile_is_ad(afile))
-    ret = handle_ad(afile);
-  else
-    ret = handle_datafile(afile);
-
-  afile_delete(afile);
-
-  return ret;
-}
-
-
-int main(int argc, char *argv[])
-{
-  int ret = RET_OK;
-
-  /* argument handling */
-  if (parse_args(argc, argv) == -1)
-    return RET_BAD_ARGS;
-
-  /* iterate through all files specified as arguments */
-  while (optind < argc)
-    ret = parse_file(argv[optind++]);
-
-  return ret;
-}
diff --git a/bin/afile/common.c b/bin/afile/common.c
deleted file mode 100644 (file)
index 6ec68a5..0000000
+++ /dev/null
@@ -1,217 +0,0 @@
-/*
- * $Id: common.c,v 1.3 2001-06-29 14:14:46 rufustfirefly Exp $
- *
-    common functions, defines, and structures for afile, achfile, and acleandir
-
-    Copyright (C) 2001 Sebastian Rittau.
-    All rights reserved.
-
-    This file may be distributed and/or modfied under the terms of the
-    following license:
-
-    Redistribution and use in source and binary forms, with or without
-    modification, are permitted provided that the following conditions
-    are met:
-    1. Redistributions of source code must retain the above copyright
-       notice, this list of conditions and the following disclaimer.
-    2. Redistributions in binary form must reproduce the above copyright
-       notice, this list of conditions and the following disclaimer in the
-       documentation and/or other materials provided with the distribution.
-    3. Neither the name of the author nor the names of its contributors
-       may be used to endorse or promote products derived from this software
-       without specific prior written permission.
-
-    THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
-    ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-    ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
-    FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-    DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
-    OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-    HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-    LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
-    OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-    SUCH DAMAGE.
-*/
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif /* HAVE_CONFIG_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/adouble.h>
-#include <netatalk/endian.h>
-
-#include "common.h"
-
-
-#define AD_PREFIX ".AppleDouble/"
-#define PARENT_PREFIX "../"
-
-
-char *dataname_to_adname(const char *dataname)
-{
-  const char *filepart;
-  char *adname;
-  size_t adlen = strlen(AD_PREFIX);
-  size_t dirlen;
-
-  /* Construct the AppleDouble file name from data fork file name. */
-  adname = calloc(adlen + strlen(dataname) + 1, sizeof(char));
-  filepart = rindex(dataname, '/');
-  if (filepart == NULL) {
-    /* Filename doesn't contain a path. */
-    strcpy(adname, AD_PREFIX);
-    strcpy(adname + adlen, dataname);
-  } else {
-    /* Filename does contain a path. */
-    dirlen = (size_t) (filepart - dataname);
-    strncpy(adname, dataname, dirlen + 1);
-    strcpy(adname + dirlen + 1, AD_PREFIX);
-    strcpy(adname + dirlen + adlen + 1, filepart + 1);
-  }
-
-  return adname;
-}
-
-char *adname_to_dataname(const char *adname)
-{
-  const char *filepart;
-  char *dataname;
-  size_t plen = strlen(PARENT_PREFIX);
-  size_t dirlen;
-
-  /* Construct the data file name from the AppleDouble file name. */
-  dataname = calloc(strlen(adname) + plen + 1, sizeof(char));
-  filepart = rindex(adname, '/');
-  if (filepart == NULL) {
-    strcpy(dataname, PARENT_PREFIX);
-    strcpy(dataname + plen, adname);
-  } else {
-    dirlen = (size_t) (filepart - adname);
-    strncpy(dataname, adname, dirlen + 1);
-    strcpy(dataname + dirlen + 1, PARENT_PREFIX);
-    strcpy(dataname + dirlen + plen + 1, filepart + 1);
-  }
-
-  return dataname;
-}
-
-
-#define FLAG_NONE 0x0000
-#define FLAG_AD   0x0001
-#define FLAG_DIR  0x0002
-
-
-struct AFile *afile_new(const char *filename)
-{
-  struct stat fdstat;
-  char adbuf[AD_DATASZ];
-  ssize_t sz;
-  struct stat statbuf;
-
-  struct AFile *afile = (struct AFile *) calloc(sizeof(struct AFile), 1);
-  afile->filename     = filename;
-  afile->fd           = open(filename, O_RDONLY);
-  afile->flags        = FLAG_NONE;
-
-  /* Try to open file. */
-  if (afile->fd == -1) {
-    free(afile);
-    return NULL;
-  }
-
-  fstat(afile->fd, &statbuf);
-  afile->mode = statbuf.st_mode;
-
-  /* Try to determine if this file is a regular file, a directory, or
-   * something else.
-   */
-  fstat(afile->fd, &fdstat);
-  if (S_ISREG(fdstat.st_mode)) {                     /* it is a regular file */
-    /* Check if the opened file is the resource fork. */
-    sz = read(afile->fd, adbuf, AD_DATASZ);
-    if (sz >= 0) {
-      /* If we can't read a whole AppleDouble header, this can't be a valid
-       * AppleDouble file.
-       */
-      if (sz == AD_DATASZ) {
-       /* ... but as we could, maybe this is. Now if only the magic number
-        * would be correct ...
-        */
-       if (ntohl(((unsigned int *) adbuf)[0]) == AD_MAGIC)
-         /* Great! It obviously is a AppleDouble file. */
-         afile->flags |= FLAG_AD;
-         afile->creator[0] = adbuf[ADEDOFF_FINDERI + 0];
-         afile->creator[1] = adbuf[ADEDOFF_FINDERI + 1];
-         afile->creator[2] = adbuf[ADEDOFF_FINDERI + 2];
-         afile->creator[3] = adbuf[ADEDOFF_FINDERI + 3];
-         afile->type   [0] = adbuf[ADEDOFF_FINDERI + 4];
-         afile->type   [1] = adbuf[ADEDOFF_FINDERI + 5];
-         afile->type   [2] = adbuf[ADEDOFF_FINDERI + 6];
-         afile->type   [3] = adbuf[ADEDOFF_FINDERI + 7];
-      }
-    } else {
-      afile_delete(afile);
-      return NULL;
-    }
-    
-  } else if (S_ISDIR(fdstat.st_mode))                /* it is a directory */
-    afile->flags |= FLAG_DIR;
-  else {                                             /* it is neither */
-    afile_delete(afile);
-    return NULL;
-  }
-
-  return afile;
-}
-
-
-void afile_delete(struct AFile *afile)
-{
-  close(afile->fd);
-  free(afile);
-}
-
-
-const char *afile_filename(struct AFile *afile)
-{
-  return afile->filename;
-}
-
-int afile_is_ad(struct AFile *afile)
-{
-  return afile->flags & FLAG_AD;
-}
-
-int afile_is_dir(struct AFile *afile)
-{
-  return afile->flags & FLAG_DIR;
-}
-
-mode_t afile_mode(struct AFile *afile)
-{
-  return afile->mode;
-}
-
-const char *afile_creator(const struct AFile *afile)
-{
-  return afile->creator;
-}
-
-const char *afile_type(const struct AFile *afile)
-{
-  return afile->type;
-}
diff --git a/bin/afile/common.h b/bin/afile/common.h
deleted file mode 100644 (file)
index 8368909..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * $Id: common.h,v 1.2 2001-06-29 14:14:46 rufustfirefly Exp $
- *
-    common functions, defines, and structures for afile, achfile, and acleandir
-
-    Copyright (C) 2001 Sebastian Rittau.
-    All rights reserved.
-
-    This file may be distributed and/or modfied under the terms of the
-    following license:
-
-    Redistribution and use in source and binary forms, with or without
-    modification, are permitted provided that the following conditions
-    are met:
-    1. Redistributions of source code must retain the above copyright
-       notice, this list of conditions and the following disclaimer.
-    2. Redistributions in binary form must reproduce the above copyright
-       notice, this list of conditions and the following disclaimer in the
-       documentation and/or other materials provided with the distribution.
-    3. Neither the name of the author nor the names of its contributors
-       may be used to endorse or promote products derived from this software
-       without specific prior written permission.
-
-    THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
-    ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-    ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
-    FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-    DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
-    OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-    HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-    LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
-    OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-    SUCH DAMAGE.
-*/
-
-#include <stdlib.h>
-
-
-char *dataname_to_adname(const char *dataname);
-char *adname_to_dataname(const char *adname);
-
-/* Class for handling data and AppleDouble files. Don't access directly.
- * Instead, use the methods provided below.
- */
-struct AFile {
-  const char *filename;
-  int fd;
-  mode_t mode;
-  unsigned short flags;
-  char creator[4], type[4];
-};
-
-
-/* Constructor */
-struct AFile *afile_new(const char *filename);
-/* Destructor */
-void afile_delete(struct AFile *afile);
-/* Accessor Methods */
-const char *afile_filename(struct AFile *afile);
-int afile_is_ad(struct AFile *afile);
-int afile_is_dir(struct AFile *afile);
-mode_t afile_mode(struct AFile *afile);
-/* The following two methods are only valid if afile_is_ad yields true. */
-const char *afile_creator(const struct AFile *afile);
-const char *afile_type(const struct AFile *afile);
index 3aa59e933c9dc53f240a87ca9bbf3a91a6b2523a..2ade6f5dfa4ddefda2d13e1017364967619e59eb 100644 (file)
@@ -1,15 +1,7 @@
 # Makefile.am for bin/cnid/
 
 EXTRA_DIST = cnid2_create.in
-noinst_HEADERS = ad.h
 
 if USE_BDB
-bin_PROGRAMS = ad
 bin_SCRIPTS = cnid2_create
-
-ad_SOURCES = ad.c ad_util.c \
-       ad_ls.c \
-       ad_cp.c
-
-ad_LDADD = $(top_builddir)/libatalk/libatalk.la
 endif
diff --git a/bin/cnid/ad.c b/bin/cnid/ad.c
deleted file mode 100644 (file)
index 95faece..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-/* 
-   $Id: ad.c,v 1.2 2009-10-13 22:55:36 didg Exp $
-
-   Copyright (c) 2009 Frank Lahm <franklahm@gmail.com>
-   
-   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.
-*/
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif /* HAVE_CONFIG_H */
-
-#include <unistd.h>
-#include <sys/types.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <stdarg.h>
-#include <limits.h>
-#include <signal.h>
-#include <string.h>
-#include <errno.h>
-
-#include <atalk/cnid.h>
-#include <atalk/volinfo.h>
-#include "ad.h"
-
-static void usage_main(void)
-{
-/*
-    printf("Usage: ad ls|rm|cp|mv|set [file|dir, ...]\n");
-*/
-    printf("Usage: ad ls [file|dir, ...]\n");
-}
-
-int main(int argc, char **argv)
-{
-    if (argc < 2) {
-        usage_main();
-        return 1;
-    }
-
-    if (STRCMP(argv[1], ==, "ls"))
-        return ad_ls(argc - 1, argv + 1);
-    else if (STRCMP(argv[1], ==, "cp"))
-        return ad_cp(argc - 1, argv + 1);
-    else {
-        usage_main();
-        return 1;
-    }
-
-    return 0;
-}
diff --git a/bin/cnid/ad.h b/bin/cnid/ad.h
deleted file mode 100644 (file)
index bb08085..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-/* 
-   $Id: ad.h,v 1.1 2009-09-01 14:28:07 franklahm Exp $
-
-   Copyright (c) 2009 Frank Lahm <franklahm@gmail.com>
-   
-   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.
-*/
-
-#ifndef AD_H
-#define AD_H
-
-#include <atalk/volinfo.h>
-
-#define STRCMP(a,b,c) (strcmp(a,c) b 0)
-
-#define DIR_DOT_OR_DOTDOT(a) \
-        ((strcmp(a, ".") == 0) || (strcmp(a, "..") == 0))
-
-typedef struct {
-    struct volinfo volinfo;
-//    char *dirname;
-//    char *basename;
-//    int adflags;                /* file:0, dir:ADFLAGS_DIR */
-} afpvol_t;
-
-
-extern int newvol(const char *path, afpvol_t *vol);
-extern void freevol(afpvol_t *vol);
-
-extern int ad_ls(int argc, char **argv);
-extern int ad_cp(int argc, char **argv);
-
-#endif /* AD_H */
diff --git a/bin/cnid/ad_cp.c b/bin/cnid/ad_cp.c
deleted file mode 100644 (file)
index 938ce1b..0000000
+++ /dev/null
@@ -1,300 +0,0 @@
-/* 
-   Copyright (c) 2009 Frank Lahm <franklahm@gmail.com>
-   
-   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.
-*/
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif /* HAVE_CONFIG_H */
-
-#include <unistd.h>
-#include <sys/types.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <stdarg.h>
-#include <limits.h>
-#include <string.h>
-#include <errno.h>
-#include <dirent.h>
-#include <fcntl.h>
-#include <ctype.h>
-#include <pwd.h>
-#include <grp.h>
-#include <time.h>
-#include <libgen.h>
-
-#include <atalk/adouble.h>
-#include <atalk/cnid.h>
-#include <atalk/volinfo.h>
-#include <atalk/util.h>
-#include "ad.h"
-
-#define ADv2_DIRNAME ".AppleDouble"
-
-/* options */
-static int cp_R;
-static int cp_L;
-static int cp_P;
-static int cp_n;
-static int cp_p;
-static int cp_v;
-
-static char           *netatalk_dirs[] = {
-    ADv2_DIRNAME,
-    ".AppleDB",
-    ".AppleDesktop",
-    NULL
-};
-
-/*
-  Check for netatalk special folders e.g. ".AppleDB" or ".AppleDesktop"
-  Returns pointer to name or NULL.
-*/
-static const char *check_netatalk_dirs(const char *name)
-{
-    int c;
-
-    for (c=0; netatalk_dirs[c]; c++) {
-        if ((strcmp(name, netatalk_dirs[c])) == 0)
-            return netatalk_dirs[c];
-    }
-    return NULL;
-}
-
-
-static void usage_cp(void)
-{
-    printf(
-        "Usage: ad cp [-R [-L | -P]] [-pv] <source_file> <target_file>\n"
-        "Usage: ad cp [-R [-L | -P]] [-pv] <source_file [source_file ...]> <target_directory>\n"
-        );
-}
-
-static int ad_cp_copy(const afpvol_t *srcvol, const afpvol_t *dstvol,
-                      char *srcfile, char *dstfile, struct stat *st)
-{
-    printf("copy: '%s' -> '%s'\n", srcfile, dstfile);
-    return 0;
-}
-
-static int ad_cp_r(const afpvol_t *srcvol, const afpvol_t *dstvol, char *srcdir, char *dstdir)
-{
-    int ret = 0, dirprinted = 0, dirempty;
-    static char srcpath[MAXPATHLEN+1];
-    static char dstpath[MAXPATHLEN+1];
-    char *tmp;
-    DIR *dp = NULL;
-    struct dirent *ep;
-    static struct stat st;      /* Save some stack space */
-
-    strlcat(srcpath, srcdir, sizeof(srcpath));
-    strlcat(dstpath, dstdir, sizeof(dstpath));
-
-    if ((dp = opendir (srcdir)) == NULL) {
-        perror("Couldn't opendir .");
-        return -1;
-    }
-
-    /* First run: copy files */
-    while ((ep = readdir (dp))) {
-        /* Check if its "." or ".." */
-        if (DIR_DOT_OR_DOTDOT(ep->d_name))
-            continue;
-
-        /* Check for netatalk special folders e.g. ".AppleDB" or ".AppleDesktop" */
-        if ((check_netatalk_dirs(ep->d_name)) != NULL)
-            continue;
-
-        if (lstat(ep->d_name, &st) < 0) {
-            perror("Can't stat");
-            return -1;
-        }
-
-        /* Build paths, copy, strip name */
-        strlcat(srcpath, "/", sizeof(srcpath));
-        strlcat(dstpath, "/", sizeof(dstpath));
-        strlcat(srcpath, ep->d_name, sizeof(srcpath));
-        strlcat(dstpath, ep->d_name, sizeof(dstpath));
-
-        ret = ad_cp_copy(srcvol, dstvol, srcpath, dstpath, &st);
-
-        if ((tmp = strrchr(srcpath, '/')))
-            *tmp = 0;
-        if ((tmp = strrchr(dstpath, '/')))
-            *tmp = 0;
-
-        if (ret != 0)
-            goto exit;
-    }
-
-    /* Second run: recurse to dirs */
-    rewinddir(dp);
-    while ((ep = readdir (dp))) {
-        /* Check if its "." or ".." */
-        if (DIR_DOT_OR_DOTDOT(ep->d_name))
-            continue;
-        
-        /* Check for netatalk special folders e.g. ".AppleDB" or ".AppleDesktop" */
-        if (check_netatalk_dirs(ep->d_name) != NULL)
-            continue;
-        
-        if (lstat(ep->d_name, &st) < 0) {
-            perror("Can't stat");
-            return -1;
-        }
-        
-        /* Recursion */
-        if (S_ISDIR(st.st_mode)) {
-            strlcat(srcpath, "/", sizeof(srcpath));
-            strlcat(dstpath, "/", sizeof(dstpath));
-            ret = ad_cp_r(srcvol, dstvol, ep->d_name, ep->d_name);
-        }
-        if (ret != 0)
-            goto exit;
-    }
-
-exit:
-    if (dp)
-        closedir(dp);
-    if ((tmp = strrchr(srcpath, '/')))
-        *tmp = 0;
-    if ((tmp = strrchr(dstpath, '/')))
-        *tmp = 0;
-
-    return ret;
-}
-
-int ad_cp(int argc, char **argv)
-{
-    int c, numpaths;
-    afpvol_t srcvvol;
-    struct stat sst;
-    struct stat dst;
-    afpvol_t srcvol;
-    afpvol_t dstvol;
-    char *srcfile = NULL;
-    char *srcdir = NULL;    
-    char *dstfile = NULL;
-    char *dstdir = NULL;
-    char path[MAXPATHLEN+1];
-    char *basenametmp;
-
-    while ((c = getopt(argc, argv, ":npvLPR")) != -1) {
-        switch(c) {
-        case 'n':
-            cp_n = 1;
-            break;
-        case 'p':
-            cp_p = 1;
-            break;
-        case 'v':
-            cp_v = 1;
-            break;
-        case 'L':
-            cp_L = 1;
-            break;
-        case 'P':
-            cp_P = 1;
-            break;
-        case 'R':
-            cp_R = 1;
-            break;
-        case ':':
-        case '?':
-            usage_cp();
-            return -1;
-            break;
-        }
-    }
-
-    /* How many pathnames do we have */
-    numpaths = argc - optind;
-    printf("Number of paths: %u\n", numpaths);
-    if (numpaths < 2) {
-        usage_cp();
-        exit(EXIT_FAILURE);
-    }
-
-    while ( argv[argc-1][(strlen(argv[argc-1]) - 1)] == '/')
-        argv[argc-1][(strlen(argv[argc-1]) - 1)] = 0;
-    printf("Destination is: %s\n", argv[argc-1]);
-
-    /* Create vol for destination */
-    newvol(argv[argc-1], &dstvol);
-
-    if (numpaths == 2) {
-        /* Case 1: 2 paths */
-        if (stat(argv[optind], &sst) != 0)
-            goto next;
-        if (S_ISREG(sst.st_mode)) {
-            /* Either file to file or file to dir copy */
-            newvol(argv[optind], &srcvol);
-            ad_cp_copy(&srcvol, &dstvol, srcfile, path, &sst);
-            freevol(&srcvol);
-            freevol(&dstvol);
-            
-        } else if (S_ISDIR(sst.st_mode)) {
-            /* dir to dir copy. Check if -R is requested */
-            if (!cp_R) {
-                usage_cp();
-                exit(EXIT_FAILURE);
-            }
-        }
-
-    } else {
-        /* Case 2: >2 paths */
-        while (optind < (argc-1)) {
-            printf("Source is: %s\n", argv[optind]);
-            newvol(argv[optind], &srcvol);
-            if (stat(argv[optind], &sst) != 0)
-                goto next;
-            if (S_ISDIR(sst.st_mode)) {
-                /* Source is a directory */
-                if (!cp_R) {
-                    printf("Source %s is a directory\n", argv[optind]);
-                    goto next;
-                }
-                srcdir = argv[optind];
-                dstdir = argv[argc-1];
-                
-                ad_cp_r(&srcvol, &dstvol, srcdir, dstdir);
-                freevol(&srcvol);
-            } else {
-                /* Source is a file */
-                srcfile = argv[optind];
-                if (numpaths != 2 && !dstdir) {
-                    usage_cp();
-                    exit(EXIT_FAILURE);
-                }
-                path[0] = 0;
-                strlcat(path, dstdir, sizeof(path));
-                basenametmp = strdup(srcfile);
-                strlcat(path, basename(basenametmp), sizeof(path));
-                free(basenametmp);
-                printf("%s %s\n", srcfile, path);
-                if (ad_cp_copy(&srcvol, &dstvol, srcfile, path, &sst) != 0) {
-                    freevol(&srcvol);
-                    freevol(&dstvol);
-                    exit(EXIT_FAILURE);
-                }
-            } /* else */
-        next:
-            optind++;
-        } /* while */
-    } /* else (numpath>2) */
-
-    freevol(&dstvol);
-
-    return 0;
-
-}
diff --git a/bin/cnid/ad_ls.c b/bin/cnid/ad_ls.c
deleted file mode 100644 (file)
index cd6545e..0000000
+++ /dev/null
@@ -1,637 +0,0 @@
-/* 
-   $Id: ad_ls.c,v 1.4 2009-10-14 01:38:28 didg Exp $
-
-   Copyright (c) 2009 Frank Lahm <franklahm@gmail.com>
-   
-   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.
-*/
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif /* HAVE_CONFIG_H */
-
-#include <unistd.h>
-#include <sys/types.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <stdarg.h>
-#include <limits.h>
-#include <string.h>
-#include <errno.h>
-#include <dirent.h>
-#include <fcntl.h>
-#include <ctype.h>
-#include <pwd.h>
-#include <grp.h>
-#include <time.h>
-
-#include <atalk/adouble.h>
-#include <atalk/cnid.h>
-#include <atalk/volinfo.h>
-#include "ad.h"
-
-#define ADv2_DIRNAME ".AppleDouble"
-
-#define DIR_DOT_OR_DOTDOT(a) \
-        ((strcmp(a, ".") == 0) || (strcmp(a, "..") == 0))
-
-/* ls options */
-static int ls_a;
-static int ls_l;
-static int ls_R;
-static int ls_d;
-static int ls_u;
-
-/* Used for pretty printing */
-static int first = 1;
-static int recursion;
-
-static char           *netatalk_dirs[] = {
-    ADv2_DIRNAME,
-    ".AppleDB",
-    ".AppleDesktop",
-    NULL
-};
-
-static char *labels[] = {
-    "---",
-    "gry",
-    "gre",
-    "vio",
-    "blu",
-    "yel",
-    "red",
-    "ora"
-};
-
-/*
-  Check for netatalk special folders e.g. ".AppleDB" or ".AppleDesktop"
-  Returns pointer to name or NULL.
-*/
-static const char *check_netatalk_dirs(const char *name)
-{
-    int c;
-
-    for (c=0; netatalk_dirs[c]; c++) {
-        if ((strcmp(name, netatalk_dirs[c])) == 0)
-            return netatalk_dirs[c];
-    }
-    return NULL;
-}
-
-
-static void usage_ls(void)
-{
-    printf(
-        "Usage: ad ls [-dRl[u]] [file|dir, ...]\n\n"
-        "  -l Long Output [-u: unix info]:\n"
-        "     <unixinfo ...> <FinderFlags> <AFPAttributes> <Color> <Type> <Creator> <CNID from AppleDouble> <name>\n\n"
-        "     FinderFlags (valid for (f)ile and/or (d)irectory):\n"
-        "       d = On Desktop (f/d)\n"
-        "       e = Hidden extension (f/d)\n"
-        "       m = Shared (can run multiple times) (f)\n"
-        "       n = No INIT resources (f)\n"
-        "       i = Inited (f/d)\n"
-        "       c = Custom icon (f/d)\n"
-        "       t = Stationery (f)\n"
-        "       s = Name locked (f/d)\n"
-        "       b = Bundle (f/d)\n"
-        "       v = Invisible (f/d)\n"
-        "       a = Alias file (f/d)\n\n"
-        "     AFPAttributes:\n"
-        "       y = System (f/d)\n"
-        "       w = No write (f)\n"
-        "       p = Needs backup (f/d)\n"
-        "       r = No rename (f/d)\n"
-        "       l = No delete (f/d)\n"
-        "       o = No copy (f)\n\n"
-        "     Note: any letter appearing in uppercase means the flag is set\n"
-        "           but it's a directory for which the flag is not allowed.\n"
-        );
-}
-
-static void print_numlinks(const struct stat *statp)
-{
-    printf("%5ld", (long)statp->st_nlink);
-}
-
-static void print_owner(const struct stat *statp)
-{
-    struct passwd *pwd = getpwuid(statp->st_uid);
-
-    if (pwd == NULL)
-        printf(" %-8ld", (long)statp->st_uid);
-    else
-        printf(" %-8s", pwd->pw_name);
-}
-
-static void print_group(const struct stat *statp)
-{
-    struct group *grp = getgrgid(statp->st_gid);
-
-    if (grp == NULL)
-        printf(" %-8ld", (long)statp->st_gid);
-    else
-        printf(" %-8s", grp->gr_name);
-}
-
-static void print_size(const struct stat *statp)
-{
-    switch (statp->st_mode & S_IFMT) {
-    case S_IFCHR:
-    case S_IFBLK:
-        printf("%4u,%4u", (unsigned)(statp->st_rdev >> 8),
-               (unsigned)(statp->st_rdev & 0xFF));
-        break;
-    default:
-        printf("%9lu", (unsigned long)statp->st_size);
-    }
-}
-
-static void print_date(const struct stat *statp)
-{
-    time_t now;
-    double diff;
-    char buf[100], *fmt;
-
-    if (time(&now) == -1) {
-        printf(" ????????????");
-        return;
-    }
-    diff = difftime(now, statp->st_mtime);
-    if (diff < 0 || diff > 60 * 60 * 24 * 182.5)
-        fmt = "%b %e  %Y";
-    else
-        fmt = "%b %e %H:%M";
-    strftime(buf, sizeof(buf), fmt, localtime(&statp->st_mtime));
-    printf(" %s", buf);
-}
-
-static void print_flags(char *path, afpvol_t *vol, const struct stat *st)
-{
-    int adflags = 0;
-    struct adouble ad;
-    char *FinderInfo;
-    uint16_t FinderFlags;
-    uint16_t AFPattributes;
-    char type[5] = "----";
-    char creator[5] = "----";
-    int i;
-    uint32_t cnid;
-
-    if (S_ISDIR(st->st_mode))
-        adflags = ADFLAGS_DIR;
-
-    if (vol->volinfo.v_path == NULL)
-        return;
-
-    ad_init(&ad, vol->volinfo.v_adouble, vol->volinfo.v_ad_options);
-
-    if ( ad_metadata(path, adflags, &ad) < 0 )
-        return;
-
-    FinderInfo = ad_entry(&ad, ADEID_FINDERI);
-
-    memcpy(&FinderFlags, FinderInfo + 8, 2);
-    FinderFlags = ntohs(FinderFlags);
-
-    memcpy(type, FinderInfo, 4);
-    memcpy(creator, FinderInfo + 4, 4);
-
-    ad_getattr(&ad, &AFPattributes);
-    AFPattributes = ntohs(AFPattributes);
-
-    /*
-      Finder flags. Lowercase means valid, uppercase means invalid because
-      object is a dir and flag is only valid for files.
-    */
-    putchar(' ');
-    if (FinderFlags & FINDERINFO_ISONDESK)
-        putchar('d');
-    else
-        putchar('-');
-
-    if (FinderFlags & FINDERINFO_HIDEEXT)
-        putchar('e');
-    else
-        putchar('-');
-
-    if (FinderFlags & FINDERINFO_ISHARED) {
-        if (adflags & ADFLAGS_DIR)
-            putchar('M');
-        else
-            putchar('m');
-    } else
-        putchar('-');
-
-    if (FinderFlags & FINDERINFO_HASNOINITS) {
-        if (adflags & ADFLAGS_DIR)
-            putchar('N');
-        else
-            putchar('n');
-    } else
-        putchar('-');
-
-    if (FinderFlags & FINDERINFO_HASBEENINITED)
-        putchar('i');
-    else
-        putchar('-');
-
-    if (FinderFlags & FINDERINFO_HASCUSTOMICON)
-        putchar('c');
-    else
-        putchar('-');
-
-    if (FinderFlags & FINDERINFO_ISSTATIONNERY) {
-        if (adflags & ADFLAGS_DIR)
-            putchar('T');
-        else
-            putchar('t');
-    } else
-        putchar('-');
-
-    if (FinderFlags & FINDERINFO_NAMELOCKED)
-        putchar('s');
-    else
-        putchar('-');
-
-    if (FinderFlags & FINDERINFO_HASBUNDLE)
-        putchar('b');
-    else
-        putchar('-');
-
-    if (FinderFlags & FINDERINFO_INVISIBLE)
-        putchar('v');
-    else
-        putchar('-');
-
-    if (FinderFlags & FINDERINFO_ISALIAS)
-        putchar('a');
-    else
-        putchar('-');
-
-    putchar(' ');
-
-    /* AFP attributes */
-    if (AFPattributes & ATTRBIT_SYSTEM)
-        putchar('y');
-    else
-        putchar('-');
-
-    if (AFPattributes & ATTRBIT_NOWRITE) {
-        if (adflags & ADFLAGS_DIR)
-            putchar('W');
-        else
-            putchar('w');
-    } else
-        putchar('-');
-
-    if (AFPattributes & ATTRBIT_BACKUP)
-        putchar('p');
-    else
-        putchar('-');
-
-    if (AFPattributes & ATTRBIT_NORENAME)
-        putchar('r');
-    else
-        putchar('-');
-
-    if (AFPattributes & ATTRBIT_NODELETE)
-        putchar('l');
-    else
-        putchar('-');
-
-    if (AFPattributes & ATTRBIT_NOCOPY) {
-        if (adflags & ADFLAGS_DIR)
-            putchar('O');
-        else
-            putchar('o');                
-    } else
-        putchar('-');
-
-    /* Color */
-    printf(" %s ", labels[(FinderFlags & FINDERINFO_COLOR) >> 1]);
-
-    /* Type & Creator */
-    for(i=0; i<4; i++) {
-        if (isalnum(type[i]))
-            putchar(type[i]);
-        else
-            putchar('-');
-    }
-    putchar(' '); 
-    for(i=0; i<4; i++) {
-        if (isalnum(creator[i]))
-            putchar(creator[i]);
-        else
-            putchar('-');
-    }
-    putchar(' '); 
-
-    /* CNID */
-    cnid = ad_forcegetid(&ad);
-    if (cnid)
-        printf(" %10u ", ntohl(cnid));
-    else
-        printf(" !ADVOL_CACHE ");
-
-    ad_close_metadata(&ad);
-}
-
-#define TYPE(b) ((st->st_mode & (S_IFMT)) == (b))
-#define MODE(b) ((st->st_mode & (b)) == (b))
-
-static void print_mode(const struct stat *st)
-{
-    if (TYPE(S_IFBLK))
-        putchar('b');
-    else if (TYPE(S_IFCHR))
-        putchar('c');
-    else if (TYPE(S_IFDIR))
-        putchar('d');
-    else if (TYPE(S_IFIFO))
-        putchar('p');
-    else if (TYPE(S_IFREG))
-        putchar('-');
-    else if (TYPE(S_IFLNK))
-        putchar('l');
-    else if (TYPE(S_IFSOCK))
-        putchar('s');
-    else
-        putchar('?');
-    putchar(MODE(S_IRUSR) ? 'r' : '-');
-    putchar(MODE(S_IWUSR) ? 'w' : '-');
-    if (MODE(S_ISUID)) {
-        if (MODE(S_IXUSR))
-            putchar('s');
-        else
-            putchar('S');
-    }
-    else if (MODE(S_IXUSR))
-        putchar('x');
-    else
-        putchar('-');
-    putchar(MODE(S_IRGRP) ? 'r' : '-');
-    putchar(MODE(S_IWGRP) ? 'w' : '-');
-    if (MODE(S_ISGID)) {
-        if (MODE(S_IXGRP))
-            putchar('s');
-        else
-            putchar('S');
-    }
-    else if (MODE(S_IXGRP))
-        putchar('x');
-    else
-        putchar('-');
-    putchar(MODE(S_IROTH) ? 'r' : '-');
-    putchar(MODE(S_IWOTH) ? 'w' : '-');
-    if (MODE(S_IFDIR) && MODE(S_ISVTX)) {
-        if (MODE(S_IXOTH))
-            putchar('t');
-        else
-            putchar('T');
-    }
-    else if (MODE(S_IXOTH))
-        putchar('x');
-    else
-        putchar('-');
-}
-#undef TYPE
-#undef MODE
-
-static int ad_print(char *path, const struct stat *st, afpvol_t *vol)
-{
-    if ( ! ls_l) {
-        printf("%s  ", path);
-        if (ls_d)
-            printf("\n");
-        return 0;
-    }
-
-    /* Long output */
-    if (ls_u) {
-        print_mode(st);
-        print_numlinks(st);
-        print_owner(st);
-        print_group(st);
-        print_size(st);
-        print_date(st);
-    }
-    print_flags(path, vol, st);
-    printf("  %s\n", path);    
-
-
-    return 0;
-}
-
-static int ad_ls_r(char *path, afpvol_t *vol)
-{
-    int ret = 0, cwd, dirprinted = 0, dirempty;
-    const char *name;
-    char *tmp;
-    static char cwdpath[MAXPATHLEN+1];
-    DIR *dp;
-    struct dirent *ep;
-    static struct stat st;      /* Save some stack space */
-
-    if ( first)
-        cwdpath[0] = 0;
-    else
-        strcat(cwdpath, "/");
-
-    strcat(cwdpath, path);
-    first = 0;
-
-    if (lstat(path, &st) < 0) {
-        perror("Can't stat");
-        return -1;
-    }
-    /* If its a file or a dir with -d option call ad_print and return */
-    if (S_ISREG(st.st_mode) || ls_d)
-        return ad_print(path, &st, vol);
-
-    /* Its a dir: chdir to it remembering where we started */
-    if ((cwd = open(".", O_RDONLY)) == -1) {
-        perror("Cant open .");
-        return -1;
-    }
-    if (chdir(path) != 0) {
-        perror("Cant chdir");
-        close(cwd);
-        return -1;
-    }
-
-    if ((dp = opendir (".")) == NULL) {
-        perror("Couldn't opendir .");
-        return -1;
-    }
-
-    /* First run: print everything */
-    dirempty = 1;
-    while ((ep = readdir (dp))) {
-        /* Check if its "." or ".." */
-        if (DIR_DOT_OR_DOTDOT(ep->d_name))
-            continue;
-
-        /* Check for netatalk special folders e.g. ".AppleDB" or ".AppleDesktop" */
-        if ((name = check_netatalk_dirs(ep->d_name)) != NULL)
-            continue;
-
-        if ((ep->d_name[0] == '.') && ! ls_a)
-            continue;
-
-        dirempty = 0;
-
-        if (recursion && ! dirprinted) {
-            printf("\n%s:\n", cwdpath);
-            dirprinted = 1;
-        }
-
-        if (lstat(ep->d_name, &st) < 0) {
-            perror("Can't stat");
-            return -1;
-        }
-
-        ret = ad_print(ep->d_name, &st, vol);
-        if (ret != 0)
-            goto exit;
-    }
-
-    if (! ls_l && ! dirempty)
-        printf("\n");
-
-    /* Second run: recurse to dirs */
-    if (ls_R) {
-        rewinddir(dp);
-        while ((ep = readdir (dp))) {
-            /* Check if its "." or ".." */
-            if (DIR_DOT_OR_DOTDOT(ep->d_name))
-                continue;
-
-            /* Check for netatalk special folders e.g. ".AppleDB" or ".AppleDesktop" */
-            if ((name = check_netatalk_dirs(ep->d_name)) != NULL)
-                continue;
-
-            if ((ret = lstat(ep->d_name, &st)) < 0) {
-                perror("Can't stat");
-                goto exit;
-            }
-
-            /* Recursion */
-            if (S_ISDIR(st.st_mode)) {
-                recursion = 1;
-                ret = ad_ls_r(ep->d_name, vol);
-            }
-            if (ret != 0)
-                goto exit;
-        }
-    }
-
-exit:
-    closedir(dp);
-    fchdir(cwd);
-    close(cwd);
-
-    tmp = strrchr(cwdpath, '/');
-    if (tmp)
-        *tmp = 0;
-
-    return ret;
-}
-
-int ad_ls(int argc, char **argv)
-{
-    int c, firstarg;
-    afpvol_t vol;
-    struct stat st;
-
-    while ((c = getopt(argc, argv, ":adlRu")) != -1) {
-        switch(c) {
-        case 'a':
-            ls_a = 1;
-            break;
-        case 'd':
-            ls_d = 1;
-            break;
-        case 'l':
-            ls_l = 1;
-            break;
-        case 'R':
-            ls_R = 1;
-            break;
-        case 'u':
-            ls_u = 1;
-            break;
-        case ':':
-        case '?':
-            usage_ls();
-            return -1;
-            break;
-        }
-
-    }
-
-    if ((argc - optind) == 0) {
-        newvol(".", &vol);
-        ad_ls_r(".", &vol);
-        freevol(&vol);
-    }
-    else {
-        int havefile = 0;
-
-        firstarg = optind;
-
-        /* First run: only print files from argv paths */
-        while(optind < argc) {
-            if (stat(argv[optind], &st) != 0)
-                goto next;
-            if (S_ISDIR(st.st_mode))
-                goto next;
-
-            havefile = 1;
-            first = 1;
-            recursion = 0;
-
-            newvol(argv[optind], &vol);
-            ad_ls_r(argv[optind], &vol);
-            freevol(&vol);
-        next:
-            optind++;
-        }
-        if (havefile && (! ls_l))
-            printf("\n");
-
-        /* Second run: print dirs */
-        optind = firstarg;
-        while(optind < argc) {
-            if (stat(argv[optind], &st) != 0)
-                goto next2;
-            if ( ! S_ISDIR(st.st_mode))
-                goto next2;
-            if ((optind > firstarg) || havefile)
-                printf("\n%s:\n", argv[optind]);
-
-            first = 1;
-            recursion = 0;
-
-            newvol(argv[optind], &vol);
-            ad_ls_r(argv[optind], &vol);
-            freevol(&vol);
-
-        next2:
-            optind++;
-        }
-
-
-    }
-
-    return 0;
-}
diff --git a/bin/cnid/ad_util.c b/bin/cnid/ad_util.c
deleted file mode 100644 (file)
index 339a72b..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-/* 
-   $Id: ad_util.c,v 1.2 2009-10-14 02:30:42 didg Exp $
-
-   Copyright (c) 2009 Frank Lahm <franklahm@gmail.com>
-   
-   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.
-*/
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif /* HAVE_CONFIG_H */
-
-#include <unistd.h>
-#include <sys/types.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <stdarg.h>
-#include <string.h>
-#include <errno.h>
-#include <libgen.h>
-
-#include <atalk/cnid.h>
-#include <atalk/volinfo.h>
-#include "ad.h"
-
-
-int newvol(const char *path, afpvol_t *vol)
-{
-//    char *pathdup;
-
-    memset(vol, 0, sizeof(afpvol_t));
-
-//    pathdup = strdup(path);
-//    vol->dirname = strdup(dirname(pathdup));
-//    free(pathdup);
-
-//    pathdup = strdup(path);
-//    vol->basename = strdup(basename(pathdup));
-//    free(pathdup);
-
-    loadvolinfo((char *)path, &vol->volinfo);
-
-    return 0;
-}
-
-void freevol(afpvol_t *vol)
-{
-#if 0
-    if (vol->dirname) {
-        free(vol->dirname);
-        vol->dirname = NULL;
-    }
-    if (vol->basename) {
-        free(vol->basename);
-        vol->basename = NULL;
-    }
-#endif
-}
index 15f4cd1a3254accb1b4e6365a1ff16f311e6e708..2bff10ed3a1d944593ad9ff8cea65d8cbecbe84d 100644 (file)
@@ -1,9 +1,10 @@
 Makefile
 Makefile.in
 netacnv
+afpldaptest
+logger_test
 .deps
 .libs
 *.o
-afpldaptest
-.gitignore
-netacnv.o
+
+
index 9b55ee3621fe40a12364623c764b4e387fa1bd93..04a53e23e8b72fa1c59ff0af9944890f9a6188af 100644 (file)
@@ -1,16 +1,18 @@
 # Makefile.am for bin/misc
 
-bin_PROGRAMS = netacnv
+pkgconfdir = @PKGCONFDIR@
+bin_PROGRAMS =
+
+noinst_PROGRAMS = netacnv logger_test
 
 netacnv_SOURCES = netacnv.c
 netacnv_LDADD = $(top_builddir)/libatalk/libatalk.la
-pkgconfdir = @PKGCONFDIR@
 
-if USE_NFSv4_ACLS
-bin_PROGRAMS += afpldaptest
+logger_test_SOURCES = logger_test.c
+logger_test_LDADD = $(top_builddir)/libatalk/libatalk.la
 
+bin_PROGRAMS += afpldaptest
 afpldaptest_SOURCES = uuidtest.c
+afpldaptest_CFLAGS = -D_PATH_ACL_LDAPCONF=\"$(pkgconfdir)/afp_ldap.conf\"
 afpldaptest_LDADD =  $(top_builddir)/libatalk/libatalk.la
 
-AM_CFLAGS = -D_PATH_ACL_LDAPCONF=\"$(pkgconfdir)/afp_ldap.conf\"
-endif
diff --git a/bin/misc/logger_test.c b/bin/misc/logger_test.c
new file mode 100644 (file)
index 0000000..a968cce
--- /dev/null
@@ -0,0 +1,94 @@
+#include <stdio.h>
+
+#include <atalk/boolean.h>
+#include <atalk/logger.h>
+
+int main(int argc, char *argv[])
+{
+  set_processname("logger_Test");
+#if 0
+  LOG(log_severe, logtype_logger, "Logging Test starting: this should only log to syslog");
+
+  /* syslog testing */
+  LOG(log_severe, logtype_logger, "Disabling syslog logging.");
+  unsetuplog("Default");
+  LOG(log_error, logtype_default, "This shouldn't log to syslog: LOG(log_error, logtype_default).");
+  LOG(log_error, logtype_logger, "This shouldn't log to syslog: LOG(log_error, logtype_logger).");
+  setuplog("Default LOG_INFO");
+  LOG(log_info, logtype_logger, "Set syslog logging to 'log_info', so this should log again. LOG(log_info, logtype_logger).");
+  LOG(log_error, logtype_logger, "This should log to syslog: LOG(log_error, logtype_logger).");
+  LOG(log_error, logtype_default, "This should log to syslog. LOG(log_error, logtype_default).");
+  LOG(log_debug, logtype_logger, "This shouldn't log to syslog. LOG(log_debug, logtype_logger).");
+  LOG(log_debug, logtype_default, "This shouldn't log to syslog. LOG(log_debug, logtype_default).");
+  LOG(log_severe, logtype_logger, "Disabling syslog logging.");
+  unsetuplog("Default");
+#endif
+  /* filelog testing */
+
+  setuplog("DSI log_maxdebug test.log");
+  LOG(log_info, logtype_dsi, "This should log.");
+  LOG(log_error, logtype_default, "This should not log.");
+
+  setuplog("Default log_debug test.log");
+  LOG(log_debug, logtype_default, "This should log.");
+  LOG(log_maxdebug, logtype_default, "This should not log.");
+
+  LOG(log_maxdebug, logtype_dsi, "This should still log.");
+
+  /* flooding prevention check */
+  LOG(log_debug, logtype_default, "Flooding 3x");
+  for (int i = 0; i < 3; i++) {
+      LOG(log_debug, logtype_default, "Flooding...");
+  }
+  /* wipe the array */
+  LOG(log_debug, logtype_default, "1"); LOG(log_debug, logtype_default, "2"); LOG(log_debug, logtype_default, "3");
+
+  LOG(log_debug, logtype_default, "-============");
+  LOG(log_debug, logtype_default, "Flooding 5x");
+  for (int i = 0; i < 5; i++) {
+      LOG(log_debug, logtype_default, "Flooding...");
+  }
+  LOG(log_debug, logtype_default, "1"); LOG(log_debug, logtype_default, "2"); LOG(log_debug, logtype_default, "3");
+
+  LOG(log_debug, logtype_default, "o============");
+  LOG(log_debug, logtype_default, "Flooding 2005x");
+  for (int i = 0; i < 2005; i++) {
+      LOG(log_debug, logtype_default, "Flooding...");
+  }
+  LOG(log_debug, logtype_default, "1"); LOG(log_debug, logtype_default, "2"); LOG(log_debug, logtype_default, "3");
+
+  LOG(log_debug, logtype_default, "0============");
+  LOG(log_debug, logtype_default, "Flooding 11x1");
+  for (int i = 0; i < 11; i++) {
+      LOG(log_error, logtype_default, "flooding 11x1 1");
+  }
+
+  LOG(log_debug, logtype_default, "1============");
+  LOG(log_debug, logtype_default, "Flooding 11x2");
+  for (int i = 0; i < 11; i++) {
+      LOG(log_error, logtype_default, "flooding 11x2 1");
+      LOG(log_error, logtype_default, "flooding 11x2 2");
+  }
+
+  LOG(log_debug, logtype_default, "2============");
+  LOG(log_debug, logtype_default, "Flooding 11x3");
+  for (int i = 0; i < 11; i++) {
+      LOG(log_error, logtype_default, "flooding 11x3 1");
+      LOG(log_error, logtype_default, "flooding 11x3 2");
+      LOG(log_error, logtype_default, "flooding 11x3 3");
+  }
+
+  LOG(log_debug, logtype_default, "3============");
+  LOG(log_debug, logtype_default, "Flooding 11x4");
+  for (int i = 0; i < 11; i++) {
+      LOG(log_error, logtype_default, "flooding 11x4 1");
+      LOG(log_error, logtype_default, "flooding 11x4 2");
+      LOG(log_error, logtype_default, "flooding 11x4 3");
+      LOG(log_error, logtype_default, "flooding 11x4 4");
+  }
+
+
+  return 0;
+}
+
+
index 77a7fa793bfb744b276ebb1313f076d454659076..b12585ee9b7e57a2a7e57fdff81330d7e3de218f 100644 (file)
@@ -1,5 +1,4 @@
 /*
-  $Id: uuidtest.c,v 1.3 2009-11-28 12:27:24 franklahm Exp $
   Copyright (c) 2008,2009 Frank Lahm <franklahm@gmail.com>
 
   This program is free software; you can redistribute it and/or modify
 #include "config.h"
 #endif /* HAVE_CONFIG_H */
 
-#ifdef HAVE_NFSv4_ACLS
-
 #include <unistd.h>
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
 #include <stdarg.h>
+
+#ifdef HAVE_LDAP
+#define LDAP_DEPRECATED 1
 #include <ldap.h>
+#endif
 
 #include <atalk/ldapconfig.h>
 #include <atalk/uuid.h>
@@ -42,6 +43,7 @@ static void parse_ldapconf()
     static int inited = 0;
 
     if (! inited) {
+#ifdef HAVE_LDAP
         /* Parse afp_ldap.conf */
         printf("Start parsing afp_ldap.conf\n");
         acl_ldap_readconfig(_PATH_ACL_LDAPCONF);
@@ -57,21 +59,22 @@ static void parse_ldapconf()
                 exit(EXIT_FAILURE);
             }
         } else {
-            printf("afp_ldap.conf is not ok.\n");
-            exit(EXIT_FAILURE);
+            printf("afp_ldap.conf is not ok, not using LDAP. Only local UUID testing available.\n");
         }
+#else
+        printf("Built without LDAP support, only local UUID testing available.\n");
+#endif
         inited = 1;
     }
 }
 
 int main( int argc, char **argv)
 {
-    int ret, i, c;
+    int ret, c;
     int verbose = 0;
+    atalk_uuid_t uuid;
     int logsetup = 0;
-    uuid_t uuid;
     uuidtype_t type;
-    char *uuidstring = NULL;
     char *name = NULL;
 
     while ((c = getopt(argc, argv, ":vu:g:i:")) != -1) {
@@ -92,9 +95,7 @@ int main( int argc, char **argv)
             printf("Searching user: %s\n", optarg);
             ret = getuuidfromname( optarg, UUID_USER, uuid);
             if (ret == 0) {
-                uuid_bin2string( uuid, &uuidstring);
-                printf("User: %s ==> UUID: %s\n", optarg, uuidstring);
-                free(uuidstring);
+                printf("User: %s ==> UUID: %s\n", optarg, uuid_bin2string(uuid));
             } else {
                 printf("User %s not found.\n", optarg);
             }
@@ -107,9 +108,7 @@ int main( int argc, char **argv)
             printf("Searching group: %s\n", optarg);
             ret = getuuidfromname( optarg, UUID_GROUP, uuid);
             if (ret == 0) {
-                uuid_bin2string( uuid, &uuidstring);
-                printf("Group: %s ==> UUID: %s\n", optarg, uuidstring);
-                free(uuidstring);
+                printf("Group: %s ==> UUID: %s\n", optarg, uuid_bin2string(uuid));
             } else {
                 printf("Group %s not found.\n", optarg);
             }
@@ -123,10 +122,17 @@ int main( int argc, char **argv)
             uuid_string2bin(optarg, uuid);
             ret = getnamefromuuid( uuid, &name, &type);
             if (ret == 0) {
-                if (type == UUID_USER)
+                switch (type) {
+                case UUID_LOCAL:
+                    printf("local UUID: %s\n", optarg);
+                    break;
+                case UUID_USER:
                     printf("UUID: %s ==> User: %s\n", optarg, name);
-                else
+                    break;
+                case UUID_GROUP:
                     printf("UUID: %s ==> Group: %s\n", optarg, name);
+                    break;
+                }
                 free(name);
             } else {
                 printf("UUID: %s not found.\n", optarg);
@@ -144,4 +150,3 @@ int main( int argc, char **argv)
     return 0;
 }
 
-#endif  /* HAVE_NFSv4_ACLS */
index d4453a70fac615573447571e95d5a41bfdd6d639..945672cc3d7880723e2781fbd397c3adb40bfc92 100644 (file)
 # illegalseq          -> encode illegal sequence in filename asis,
 #                        ex "\217-", which is not a valid SHIFT-JIS char,
 #                        is encoded  as U\217 -
-# acls                -> Enable ACLs on this volume. Requires a NFSv4 ACLs
-#                        compatible filesystem (e.g. ZFS) and an ACL API
-#                        compatible to *Solaris. In other words: this requires
-#                        Solaris, Opensolaris or a derived distribution.
 # nocnidcache         -> Don't store and read CNID to/from AppleDouble file.
 #                        This should not be used as it also prevents a CNID
 #                        database rebuild with `dbd`!
index f527aab99f10365ad4b63929dfd16c4c612ff6bd..8fbfddebf416965b02241f71329d9c92e8fe1950 100644 (file)
@@ -3,22 +3,33 @@
 SUBDIRS = pam
 SUFFIXES = .tmpl .
 
-GENFILES = afpd.conf AppleVolumes.default
 TMPLFILES = afpd.conf.tmpl AppleVolumes.default.tmpl
+GENFILES = afpd.conf AppleVolumes.default
+CLEANFILES = $(GENFILES)
+EXTRA_DIST = \
+       AppleVolumes.default.tmpl \
+       AppleVolumes.system \
+       afp_ldap.conf \
+       afpd.conf.tmpl \
+       atalkd.conf \
+       netatalk.conf \
+       papd.conf
+
+OVERWRITE_CONFIG = @OVERWRITE_CONFIG@
 
 if USE_DEBIAN
-CONFFILES = AppleVolumes.system atalkd.conf papd.conf
+CONFFILES = AppleVolumes.system
 else
-CONFFILES = AppleVolumes.system atalkd.conf papd.conf netatalk.conf
+CONFFILES = AppleVolumes.system netatalk.conf
 endif
 
-if USE_NFSv4_ACLS
+if HAVE_ACLS
 CONFFILES += afp_ldap.conf
 endif
 
-OVERWRITE_CONFIG = @OVERWRITE_CONFIG@
-EXTRA_DIST = $(CONFFILES) $(TMPLFILES) afp_ldap.conf
-CLEANFILES = $(GENFILES)
+if USE_APPLETALK
+CONFFILES += atalkd.conf papd.conf
+endif
 
 pkgconfdir = @PKGCONFDIR@
 webminpath = @WEBMIN_PATH@
index 4c9ea98dbfa9243565069cdb968bfa0204c8d58f..377592120173b11d26a6d580bf016042fa5f9c19 100644 (file)
@@ -69,6 +69,8 @@
 #                         string.
 #     -slp                Register this server with the Service Location
 #                         Protocol (if SLP support was compiled in).
+#     -nozeroconf         Don't register this server with the Multicats
+#                         DNS Protocol.
 #     -advertise_ssh      Allows Mac OS X clients (10.3.3-10.4) to
 #                         automagically establish a tunneled AFP connection
 #                         through SSH. This option is not so significant
index ea893433b50e507e313c0eb402afb473659b24bc..b8c1e67b731325483351384e5f7a87c5c631efc9 100644 (file)
@@ -1,43 +1,60 @@
 # Netatalk configuration
-# Change this to increase the maximum number of clients that can connect:
-AFPD_MAX_CLIENTS=20
 
-# Change this to set the machine's atalk name and zone.
-# NOTE: if your zone has spaces in it, you're better off specifying
-#       it in afpd.conf
-#ATALK_ZONE=@zone
-ATALK_NAME=`echo ${HOSTNAME}|cut -d. -f1`
+#########################################################################
+# Global configuration
+#########################################################################
 
-# specify the Mac and unix charsets to be used
-ATALK_MAC_CHARSET='MAC_ROMAN'
+#### machine's AFPserver/AppleTalk name.
+#ATALK_NAME=machinename
+
+#### server (unix) and legacy client (<= Mac OS 9) charsets
 ATALK_UNIX_CHARSET='LOCALE'
+ATALK_MAC_CHARSET='MAC_ROMAN'
+
+#### Don't Edit. export the charsets, read form ENV by apps
+export ATALK_UNIX_CHARSET
+export ATALK_MAC_CHARSET
+
+#########################################################################
+# AFP specific configuration
+#########################################################################
 
-# specify the UAMs to enable
-# available options: uams_guest.so, uams_clrtxt.so, uams_randnum.so, 
-#                           uams_dhx.so, uams_dhx2.so
-# AFPD_UAMLIST="-U uams_dhx.so,uams_dhx2.so"
-
-# Change this to set the id of the guest user
-AFPD_GUEST=nobody
-
-# Set which daemons to run.
-# If you need legacy AppleTalk, run atalkd.
-# papd, timelord and a2boot are dependent upon atalkd.
-# If you use "AFP over TCP" server only, run only cnid_metad and afpd.
-ATALKD_RUN=no
-PAPD_RUN=no
-TIMELORD_RUN=no
-A2BOOT_RUN=no
+#### Set which daemons to run.
+#### If you use AFP file server, run both cnid_metad and afpd.
 CNID_METAD_RUN=yes
 AFPD_RUN=yes
 
-# Control whether the daemons are started in the background.
-# If it is dissatisfied that atalkd starts slowly, set "yes".
-ATALK_BGROUND=no
+#### maximum number of clients that can connect:
+#AFPD_MAX_CLIENTS=20
 
-# export the charsets, read form ENV by apps
-export ATALK_MAC_CHARSET
-export ATALK_UNIX_CHARSET
+#### UAMs (User Authentication Modules)
+#### available options: uams_dhx.so, uams_dhx2.so, uams_guest.so,
+####                    uams_clrtxt.so(legacy), uams_randnum.so(legacy)
+#AFPD_UAMLIST="-U uams_dhx.so,uams_dhx2.so"
+
+#### Set the id of the guest user when using uams_guest.so
+#AFPD_GUEST=nobody
+
+#### config for cnid_metad. Default log config:
+#CNID_CONFIG="-l log_note"
 
-# config for cnid_metad. Default log config:
-# CNID_CONFIG="-l log_note"
+#########################################################################
+# AppleTalk specific configuration (legacy)
+#########################################################################
+
+#### Set which legacy daemons to run.
+#### If you need AppleTalk, run atalkd.
+#### papd, timelord and a2boot are dependent upon atalkd.
+#ATALKD_RUN=no
+#PAPD_RUN=no
+#TIMELORD_RUN=no
+#A2BOOT_RUN=no
+
+#### Control whether the daemons are started in the background.
+#### If it is dissatisfied that legacy atalkd starts slowly, set "yes".
+#ATALK_BGROUND=no
+
+#### Set the AppleTalk Zone name.
+#### NOTE: if your zone has spaces in it, you're better off specifying
+####       it in afpd.conf
+#ATALK_ZONE=@zone
index 125f51fb498359031a32969f961d72a92cc8accd..5bce2794280061f2070215b0edb1e872fce6a0b6 100644 (file)
@@ -1,4 +1,3 @@
-dnl $Id: configure.in,v 1.244 2010-04-13 08:05:06 franklahm Exp $
 dnl configure.in for netatalk
 
 AC_INIT(etc/afpd/main.c)
@@ -25,71 +24,11 @@ AC_PROG_PS
 
 AM_PROG_CC_C_O
 
-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:
-dnl 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 not the right stuff but should be enough for now
-AC_CHECK_FUNC(gethostbyname,,[AC_CHECK_LIB(nsl,gethostbyname)])
-AC_CHECK_FUNC(connect,,[AC_CHECK_LIB(socket,connect)])
-
-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 -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 Checks for header files.
 AC_HEADER_DIRENT
 AC_HEADER_STDC
 AC_HEADER_SYS_WAIT
-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_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 langinfo.h locale.h sys/filio.h)
 AC_CHECK_HEADER(sys/cdefs.h,,
        AC_MSG_RESULT([enabling generic cdefs.h from tree])
        CFLAGS="-I\$(top_srcdir)/sys/generic $CFLAGS"
@@ -100,8 +39,6 @@ AC_CHECK_HEADERS([sys/mount.h], , ,
 #endif
 ])
 
-AC_CHECK_HEADERS(langinfo.h locale.h sys/filio.h)
-
 dnl Checks for typedefs, structures, and compiler characteristics.
 AC_C_CONST
 AC_TYPE_UID_T
@@ -124,7 +61,6 @@ if test x"$libltdl_cv_need_uscore" = xyes; then
     AC_DEFINE(DLSYM_PREPEND_UNDERSCORE, 1, [BSD compatibility macro])
 fi
 
-
 dnl Checks for library functions.
 AC_TYPE_GETGROUPS
 AC_PROG_GCC_TRADITIONAL
@@ -135,10 +71,20 @@ 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 setlocale nl_langinfo strlcpy strlcat setlinebuf dirfd pselect)
+AC_CHECK_FUNCS(backtrace_symbols setlocale nl_langinfo strlcpy strlcat setlinebuf dirfd pselect access pread pwrite)
 AC_CHECK_FUNCS(waitpid getcwd strdup strndup strnlen strtoul strerror chown fchown chmod fchmod chroot link mknod mknod64)
 AC_CHECK_FUNC(renameat, AC_DEFINE([_ATFILE_SOURCE], 1, AT file source)) 
 AC_CHECK_MEMBERS(struct tm.tm_gmtoff,,, [#include <time.h>])
+
+AC_CHECK_FUNC(gethostbyname,,[AC_CHECK_LIB(nsl,gethostbyname)])
+AC_CHECK_FUNC(connect,,[AC_CHECK_LIB(socket,connect)])
+dnl search for necessary libs for libpthread stuff
+AC_SEARCH_LIBS(pthread_sigmask, pthread,, 
+               [AC_MSG_ERROR([cannot find pthread_sigmask in libc or libpthread])])
+if test x"$ac_cv_search_pthread_sigmask" != x"none required" ; then
+   PTHREAD_LIBS=$ac_cv_search_pthread_sigmask
+fi
+AC_SUBST(PTHREAD_LIBS)
 AC_CACHE_SAVE
 
 dnl Checks for (v)snprintf
@@ -149,36 +95,34 @@ 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
+# Test if the compiler is in 64bit mode
+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 FIXME: Do we need something like this for Solaris 64bit?
-dnl
+fi
+rm -rf conftest*
 
 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])
-  ;;
+powerpc64:yes | s390x:yes | sparc*:yes | x86_64:yes | i386:yes)
+    AC_MSG_RESULT([yes])
+    case $target_os in
+    solaris2*)
+        atalk_libname="lib/64"
+        ;;
+    *)
+        atalk_libname="lib64"
+        ;;
+    esac
+    ;;
 *:*)
-  atalk_libname="lib"
-  AC_MSG_RESULT([no])
-  ;;
+    AC_MSG_RESULT([no])
+    atalk_libname="lib"
+    ;;
 esac
 
 dnl --------------------------------------------------------------------------
@@ -232,19 +176,20 @@ AC_ARG_WITH(cracklib,
 AC_MSG_CHECKING([for cracklib support])
 AC_MSG_RESULT([$netatalk_cv_with_cracklib])
 
-netatalk_cv_ddp_enabled=yes
+netatalk_cv_ddp_enabled=no
 AC_MSG_CHECKING([whether to enable DDP])
 AC_ARG_ENABLE(ddp,
-       [  --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
+       [  --enable-ddp            enable DDP (AppleTalk)],[
+       if test "$enableval" = "yes"; then 
+               AC_MSG_RESULT([yes])
+               netatalk_cv_ddp_enabled=yes
        else
                AC_MSG_RESULT([yes])
+               AC_DEFINE(NO_DDP, 1, [Define if DDP should be disabled])
        fi
        ],[
-               AC_MSG_RESULT([yes])
+               AC_MSG_RESULT([no])
+               AC_DEFINE(NO_DDP, 1, [Define if DDP should be disabled])
        ]
 )
 
@@ -278,9 +223,11 @@ AC_ARG_ENABLE(debug,
                AC_MSG_RESULT([yes])
        else
                AC_MSG_RESULT([no])
+        AC_DEFINE(NDEBUG, 1, [Disable assertions])
        fi
        ],[
                AC_MSG_RESULT([no])
+        AC_DEFINE(NDEBUG, 1, [Disable assertions])
        ]
 )
 
@@ -302,39 +249,7 @@ AC_ARG_ENABLE(debugging,
        ]
 )
 
-
-afp3=no
-afp3set=no
-AC_MSG_CHECKING([whether AFP 3.x calls should be enabled])
-AC_ARG_ENABLE(afp3,
-       [  --disable-afp3          disable AFP 3.x calls],
-       [
-           if test x"$enableval" != x"no"; then
-               afp3set=yes
-               afp3=yes
-               AC_MSG_RESULT([yes])
-           else
-               AC_MSG_RESULT([no])
-           fi
-       ],[
-           AC_MSG_RESULT([yes])
-           afp3=yes
-       ]
-)
-
-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_SYS_LARGEFILE([], AC_MSG_ERROR([AFP 3.x support requires Large File Support.]))
 AC_CHECK_ICONV
 
 dnl ----------- A NOTE ABOUT DROPKLUDGE
@@ -387,6 +302,9 @@ AC_CHECK_QUOTA
 dnl Check for optional server location protocol support (used by MacOS X)
 NETATALK_SRVLOC
 
+dnl Check for optional Zeroconf support
+NETATALK_ZEROCONF
+
 dnl Check for PAM libs
 netatalk_cv_use_pam=no
 AC_PATH_PAM([
@@ -1022,49 +940,153 @@ AC_ARG_ENABLE(overwrite,
 )
 AC_MSG_RESULT([$OVERWRITE_CONFIG])
 
-dnl --------------------- check for ACL support
-AC_MSG_CHECKING([if NFSv4 ACL Support should be enabled])
-AC_ARG_ENABLE(nfsv4acls,
-       [  --enable-nfsv4acls      enable NFSv4 ACL Support (auto)],[
-       if test x"$enableval" = x"yes"; then
-          AC_MSG_RESULT([yes])
-          neta_cv_nfsv4acl="yes"
-       else
-          AC_MSG_RESULT([no])
-          neta_cv_nfsv4acl="no"
-       fi],[
-          AC_MSG_RESULT([auto])
-          neta_cv_nfsv4acl="yes"
-       ]
-)
+dnl --------------------- check for LDAP support, for client-side ACL visibility
+AC_MSG_CHECKING(for LDAP (necessary for client-side ACL visibility))
+AC_ARG_WITH(ldap,
+    [AS_HELP_STRING([--with-ldap],
+        [LDAP support (default=auto)])],
+    [ case "$withval" in
+      yes|no)
+          with_ldap="$withval"
+                 ;;
+      *)
+          with_ldap=auto
+          ;;
+      esac ])
+AC_MSG_RESULT($with_ldap)
+
+if test x"$with_ldap" != x"no" ; then
+       AC_CHECK_HEADER([ldap.h], with_ldap=yes,
+        [ if test x"$with_ldap" = x"yes" ; then
+            AC_MSG_ERROR([Missing LDAP headers])
+        fi
+               with_ldap=no
+        ])
+       AC_CHECK_LIB(ldap, ldap_init, with_ldap=yes,
+        [ if test x"$with_ldap" = x"yes" ; then
+            AC_MSG_ERROR([Missing LDAP library])
+        fi
+               with_ldap=no
+        ])
+fi
 
-if test x"$this_os" != x"solaris" && test x"$neta_cv_nfsv4acl" = x"yes" ; then
-               AC_MSG_NOTICE([NFSv4 ACL Support only available on (Open)Solaris])
-        neta_cv_nfsv4acl="no"
+if test x"$with_ldap" = x"yes"; then
+       AC_DEFINE(HAVE_LDAP,1,[Whether LDAP is available])
 fi
 
-if test x$neta_cv_nfsv4acl = xyes; then
-       AC_CHECK_HEADER([ldap.h],,[
-               AC_MSG_ERROR([ACL Support need the LDAP client headers not found.])
-               neta_cv_nfsv4acl=no
-               ]
-       )
-       AC_CHECK_LIB(ldap,ldap_init,neta_cv_nfsv4acl=yes,neta_cv_nfsv4acl=no)
+dnl --------------------- check for ACL support
+AC_MSG_CHECKING(whether to support ACLs)
+AC_ARG_WITH(acls,
+    [AS_HELP_STRING([--with-acls],
+        [Include ACL support (default=auto)])],
+    [ case "$withval" in
+      yes|no)
+          with_acl_support="$withval"
+                 ;;
+      *)
+          with_acl_support=auto
+          ;;
+      esac ],
+    [with_acl_support=auto])
+AC_MSG_RESULT($with_acl_support)
+
+if test x"$with_acl_support" = x"no"; then
+       AC_MSG_RESULT(Disabling ACL support)
+       AC_DEFINE(HAVE_NO_ACLS,1,[Whether no ACLs support should be built in])
+else
+    with_acl_support=yes
 fi
-if test x$neta_cv_nfsv4acl = xyes; then
-       AC_CHECK_HEADER([sys/acl.h],[
-               AC_DEFINE([HAVE_NFSv4_ACLS], 1, [Enable ACL code])
-               AC_MSG_NOTICE([Enabling ACL support])
-               ],
-               neta_cv_nfsv4acl=no
-       )
+
+if test x"$with_acl_support" = x"yes" ; then
+       AC_MSG_NOTICE(checking whether ACL support is available:)
+       case "$host_os" in
+       *sysv5*)
+               AC_MSG_NOTICE(Using UnixWare ACLs)
+               AC_DEFINE(HAVE_UNIXWARE_ACLS,1,[Whether UnixWare ACLs are available])
+               ;;
+       *solaris*)
+               AC_MSG_NOTICE(Using solaris ACLs)
+               AC_DEFINE(HAVE_SOLARIS_ACLS,1,[Whether solaris ACLs are available])
+               ACL_LIBS="$ACL_LIBS -lsec"
+               ;;
+       *hpux*)
+               AC_MSG_NOTICE(Using HPUX ACLs)
+               AC_DEFINE(HAVE_HPUX_ACLS,1,[Whether HPUX ACLs are available])
+               ;;
+       *irix*)
+               AC_MSG_NOTICE(Using IRIX ACLs)
+               AC_DEFINE(HAVE_IRIX_ACLS,1,[Whether IRIX ACLs are available])
+               ;;
+       *aix*)
+               AC_MSG_NOTICE(Using AIX ACLs)
+               AC_DEFINE(HAVE_AIX_ACLS,1,[Whether AIX ACLs are available])
+               ;;
+       *osf*)
+               AC_MSG_NOTICE(Using Tru64 ACLs)
+               AC_DEFINE(HAVE_TRU64_ACLS,1,[Whether Tru64 ACLs are available])
+               ACL_LIBS="$ACL_LIBS -lpacl"
+               ;;
+       *darwin*)
+               AC_MSG_NOTICE(ACLs on Darwin currently not supported)
+               AC_DEFINE(HAVE_NO_ACLS,1,[Whether no ACLs support is available])
+               ;;
+       *)
+               AC_CHECK_LIB(acl,acl_get_file,[ACL_LIBS="$ACL_LIBS -lacl"])
+               case "$host_os" in
+               *linux*)
+                       AC_CHECK_LIB(attr,getxattr,[ACL_LIBS="$ACL_LIBS -lattr"])
+                       ;;
+               esac
+               AC_CACHE_CHECK([for POSIX ACL support],netatalk_cv_HAVE_POSIX_ACLS,[
+                       acl_LIBS=$LIBS
+                       LIBS="$LIBS $ACL_LIBS"
+                       AC_TRY_LINK([
+                               #include <sys/types.h>
+                               #include <sys/acl.h>
+                       ],[
+                               acl_t acl;
+                               int entry_id;
+                               acl_entry_t *entry_p;
+                               return acl_get_entry(acl, entry_id, entry_p);
+                       ],
+                       [netatalk_cv_HAVE_POSIX_ACLS=yes],
+                       [netatalk_cv_HAVE_POSIX_ACLS=no
+                with_acl_support=no])
+                       LIBS=$acl_LIBS
+               ])
+               if test x"$netatalk_cv_HAVE_POSIX_ACLS" = x"yes"; then
+                       AC_MSG_NOTICE(Using POSIX ACLs)
+                       AC_DEFINE(HAVE_POSIX_ACLS,1,[Whether POSIX ACLs are available])
+                       AC_CACHE_CHECK([for acl_get_perm_np],netatalk_cv_HAVE_ACL_GET_PERM_NP,[
+                               acl_LIBS=$LIBS
+                               LIBS="$LIBS $ACL_LIBS"
+                               AC_TRY_LINK([
+                                       #include <sys/types.h>
+                                       #include <sys/acl.h>
+                               ],[
+                                       acl_permset_t permset_d;
+                                       acl_perm_t perm;
+                                       return acl_get_perm_np(permset_d, perm);
+                               ],
+                               [samba_cv_HAVE_ACL_GET_PERM_NP=yes],
+                               [samba_cv_HAVE_ACL_GET_PERM_NP=no])
+                               LIBS=$acl_LIBS
+                       ])
+                       if test x"netatalk_cv_HAVE_ACL_GET_PERM_NP" = x"yes"; then
+                               AC_DEFINE(HAVE_ACL_GET_PERM_NP,1,[Whether acl_get_perm_np() is available])
+                       fi
+               else
+                       AC_MSG_NOTICE(ACL support is not avaliable)
+                       AC_DEFINE(HAVE_NO_ACLS,1,[Whether no ACLs support is available])
+               fi
+               ;;
+    esac
 fi
-if test x$neta_cv_nfsv4acl = xyes; then
-       LIBATALK_ACLS="acl/libacl.la"
-else
-       LIBATALK_ACLS=""
+
+if test x"$with_acl_support" = x"yes" ; then
+    AC_DEFINE(HAVE_ACLS,1,[Whether ACLs support is available])
+    AC_SUBST(ACL_LIBS)
 fi
-AC_SUBST(LIBATALK_ACLS)
 
 dnl --------------------- check for Extended Attributes support
 neta_cv_eas="ad"
@@ -1166,6 +1188,7 @@ if test "x$neta_cv_eas_sys_found" = "xyes" ; then
       neta_cv_eas="$neta_cv_eas | sys"
    fi
 fi
+AC_DEFINE_UNQUOTED(EA_MODULES,["$neta_cv_eas"],[Available Extended Attributes modules])
 
 dnl --------------------- Check if realpath() takes NULL
 AC_CACHE_CHECK([if the realpath function allows a NULL argument],
@@ -1210,7 +1233,8 @@ AM_CONDITIONAL(COMPILE_TIMELORD, test x$compile_timelord = xyes)
 AM_CONDITIONAL(COMPILE_A2BOOT, test x$compile_a2boot = xyes)
 AM_CONDITIONAL(HAVE_LIBGCRYPT, test x$neta_cv_have_libgcrypt = xyes)
 AM_CONDITIONAL(HAVE_OPENSSL, test x$neta_cv_have_openssl = xyes)
-AM_CONDITIONAL(USE_NFSv4_ACLS, test x$neta_cv_nfsv4acl = xyes)
+AM_CONDITIONAL(HAVE_ACLS, test x"$with_acl_support" = x"yes")
+AM_CONDITIONAL(HAVE_LDAP, test x"$with_ldap" = x"yes")
 AM_CONDITIONAL(USE_DHX, test x$neta_cv_compile_dhx = xyes)
 AM_CONDITIONAL(USE_DHX2, test x$neta_cv_compile_dhx2 = xyes)
 AM_CONDITIONAL(USE_RANDNUM, test x$neta_cv_have_openssl = xyes)
@@ -1231,14 +1255,15 @@ 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)
 AM_CONDITIONAL(USE_BDB, test x$bdb_required = xyes)
+AM_CONDITIONAL(USE_APPLETALK, test x$netatalk_cv_ddp_enabled = xyes)
 
 dnl --------------------- generate files
 
 AC_OUTPUT([Makefile
        bin/Makefile
+       bin/ad/Makefile
        bin/adv1tov2/Makefile
        bin/aecho/Makefile
-       bin/afile/Makefile
        bin/afppasswd/Makefile
        bin/cnid/Makefile
        bin/cnid/cnid2_create
@@ -1257,10 +1282,7 @@ AC_OUTPUT([Makefile
        contrib/printing/Makefile
        contrib/shell_utils/Makefile
        contrib/shell_utils/afpd-mtab.pl
-       contrib/shell_utils/apple_cp
     contrib/shell_utils/apple_dump
-       contrib/shell_utils/apple_mv
-       contrib/shell_utils/apple_rm
        contrib/shell_utils/asip-status.pl
        contrib/timelord/Makefile
        contrib/a2boot/Makefile
@@ -1285,6 +1307,7 @@ AC_OUTPUT([Makefile
        libatalk/adouble/Makefile
        libatalk/asp/Makefile
        libatalk/atp/Makefile
+       libatalk/bstring/Makefile
        libatalk/cnid/Makefile
        libatalk/cnid/cdb/Makefile
        libatalk/cnid/last/Makefile
@@ -1295,7 +1318,6 @@ AC_OUTPUT([Makefile
        libatalk/nbp/Makefile
        libatalk/netddp/Makefile
        libatalk/util/Makefile
-       libatalk/util/test/Makefile
        libatalk/tdb/Makefile
        libatalk/unicode/Makefile
        libatalk/unicode/charsets/Makefile
@@ -1316,6 +1338,8 @@ AC_OUTPUT([Makefile
        sys/solaris/Makefile
        sys/sunos/Makefile
        sys/ultrix/Makefile
+       test/Makefile
+       test/afpd/Makefile
        ],
        [chmod a+x distrib/config/netatalk-config contrib/shell_utils/apple_*]
 )
diff --git a/contrib/ICDumpSuffixMap b/contrib/ICDumpSuffixMap
deleted file mode 100644 (file)
index 3a8283f..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#!perl\r#\r# ICDumpMap\r#     ---  Dump suffix mappings from your Internet Config extension.\r#\r# iNOUE Koich! <inoue@ma.ns.musashi-tech.ac.jp>\r#\r\ruse Mac::InternetConfig;\r\ropen MAP, ">AppleVolumes";\rprintf MAP "%-9s \"%4s\"  \"%4s\"      %-30s %-25s %-15s\n\n",\r".", "TEXT", "ttxt", "ASCII Text", "SimpleText", "text/plain";\rprint MAP "\# The following lines are extracted from Internet Config Preference.\n\n";\rfor my $entry (keys %InternetConfigMap) {\r   next unless $entry->extension =~ /^\./;\r   $_ = sprintf "%-9s \"%4s\"  \"%4s\"      %-30s %-25s %-15s",\r      $entry->extension, $entry->file_type, $entry->file_creator,\r      $entry->entry_name, $entry->creator_app_name,\r      $entry->MIME_type;\r   s/\s*$/\n/;\r   print MAP;\r}\rclose MAP;\r
\ No newline at end of file
index ae0ea4f003f6226870b7cda5e8766b5fbaaad15e..5652b1bb74d2ad283927a2c398cc40cba3b43da9 100644 (file)
@@ -1,17 +1,15 @@
 # Makefile.am for contrib/
 
+SUBDIRS = macusers shell_utils
+
 if COMPILE_TIMELORD
-TIMELORD = timelord
-else
-TIMELORD =
+SUBDIRS += timelord
 endif
 
 if COMPILE_A2BOOT
-A2BOOT = a2boot
-else
-A2BOOT =
+SUBDIRS += a2boot
 endif
 
-SUBDIRS = macusers printing shell_utils ${TIMELORD} ${A2BOOT}
-
-EXTRA_DIST = ICDumpSuffixMap
+if USE_APPLETALK
+SUBDIRS += printing
+endif
old mode 100644 (file)
new mode 100755 (executable)
index 9e85815..11cb8d9
@@ -1,6 +1,19 @@
 #!/usr/bin/perl
-
+#
 # usage: make-precompose.h.pl UnicodeData.txt > precompose.h
+#
+# (c) 2008-2011 by HAT <hat@fa2.so-net.ne.jp>
+#
+#  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.
+# 
 
 # See
 # http://www.unicode.org/Public/UNIDATA/UCD.html
 # http://www.unicode.org/Public/UNIDATA/UnicodeData.txt
 
 
-# table for binary search --------------------------------------------------
+# temp files for binary search (compose.TEMP, compose_sp.TEMP) -------------
 
 open(UNICODEDATA, "<$ARGV[0]");
-open(PRECOMPOSETEMP, ">precompose.TEMP");
-open( DECOMPOSETEMP, ">decompose.TEMP");
 
-while (<UNICODEDATA>){
+open(COMPOSE_TEMP, ">compose.TEMP");
+open(COMPOSE_SP_TEMP, ">compose_sp.TEMP");
+
+while (<UNICODEDATA>) {
     chop;
     (
      $code0,
@@ -33,48 +47,168 @@ while (<UNICODEDATA>){
      $Simple_Uppercase_Mapping12,
      $Simple_Lowercase_Mapping13,
      $Simple_Titlecase_Mapping14
-     ) = split(/\;/);
+    ) = split(/\;/);
 
     if (($Decomposition_Mapping5 ne "") && ($Decomposition_Mapping5 !~ /\</) && ($Decomposition_Mapping5 =~ / /)) {
        ($base, $comb) = split(/ /,$Decomposition_Mapping5);
-       
+
        $leftbracket  = "  { ";
        $rightbracket =" },     ";
 
-       if (hex($code0) > 0xFFFF) {           # DELETE THIS LINE  IF INTERNAL CODE IS UCS4
-           $leftbracket  = "\/\*{ ";         # DELETE THIS LINE  IF INTERNAL CODE IS UCS4
-           $rightbracket =" },\*\/   ";      # DELETE THIS LINE  IF INTERNAL CODE IS UCS4
-       }                                     # DELETE THIS LINE  IF INTERNAL CODE IS UCS4
-       
        # AFP 3.x Spec
        if ( ((0x2000  <= hex($code0)) && (hex($code0) <=  0x2FFF))
-         || ((0xFE30  <= hex($code0)) && (hex($code0) <=  0xFE4F))
-          || ((0x2F800 <= hex($code0)) && (hex($code0) <= 0x2FA1F))) {
+            || ((0xFE30  <= hex($code0)) && (hex($code0) <=  0xFE4F))
+            || ((0x2F800 <= hex($code0)) && (hex($code0) <= 0x2FA1F))) {
+           $leftbracket  = "\/\*{ ";
+           $rightbracket =" },\*\/   ";
+       }
+
+       if (hex($code0) > 0xFFFF) {
+
+           $code0_sp_hi = 0xD800 - (0x10000 >> 10) + (hex($code0) >> 10);
+           $code0_sp_lo = 0xDC00 + (hex($code0) & 0x3FF);
+
+           $base_sp_hi = 0xD800 - (0x10000 >> 10) + (hex($base) >> 10);
+           $base_sp_lo = 0xDC00 + (hex($base) & 0x3FF);
+
+           $comb_sp_hi = 0xD800 - (0x10000 >> 10) + (hex($comb) >> 10);
+           $comb_sp_lo = 0xDC00 + (hex($comb) & 0x3FF);
+
+           printf(COMPOSE_SP_TEMP "%s0x%04X%04X, 0x%04X%04X, 0x%04X%04X%s\/\* %s \*\/\n",
+                  $leftbracket, $code0_sp_hi ,$code0_sp_lo, $base_sp_hi, $base_sp_lo, $comb_sp_hi, $comb_sp_lo, $rightbracket, $Name1);
+
            $leftbracket  = "\/\*{ ";
            $rightbracket =" },\*\/   ";
        }
-       
-       printf(PRECOMPOSETEMP "%s0x%08X, 0x%08X, 0x%08X%s\/\* %s \*\/\n", $leftbracket, hex($code0), hex($base), hex($comb), $rightbracket, $Name1);
 
-       printf( DECOMPOSETEMP "%s0x%08X, 0x%08X, 0x%08X%s\/\* %s \*\/\n", $leftbracket, hex($code0), hex($base), hex($comb), $rightbracket, $Name1);
-       
+       printf(COMPOSE_TEMP "%s0x%08X, 0x%08X, 0x%08X%s\/\* %s \*\/\n", $leftbracket, hex($code0), hex($base), hex($comb), $rightbracket, $Name1);
+
+    }
+}
+
+close(UNICODEDATA);
+
+close(COMPOSE_TEMP);
+close(COMPOSE_SP_TEMP);
+
+# macros for BMP (PRECOMP_COUNT, DECOMP_COUNT, MAXCOMBLEN) ----------------
+
+open(COMPOSE_TEMP, "<compose.TEMP");
+
+@comp_table = ();
+$comp_count = 0;
+
+while (<COMPOSE_TEMP>) {
+    if (m/^\/\*/) {
+       next;
+    }
+    $comp_table[$comp_count][0] = substr($_, 4, 10);
+    $comp_table[$comp_count][1] = substr($_, 16, 10);
+    $comp_count++;
+}
+
+$maxcomblen = 2;      # Hangul's maxcomblen is already 2. That is, VT.
+
+for ($i = 0 ; $i < $comp_count ; $i++) {
+    $base = $comp_table[$i][1];
+    $comblen = 1;
+    $j = 0;
+    while ($j < $comp_count) {
+       if ($base ne $comp_table[$j][0]) {
+           $j++;
+           next;
+       } else {
+           $comblen++;
+           $base =  $comp_table[$j][1];
+           $j = 0;
+       }
+    }
+    $maxcomblen = ($maxcomblen > $comblen) ? $maxcomblen : $comblen;
+}
+
+close(COMPOSE_TEMP);
+
+# macros for SP (PRECOMP_SP_COUNT,DECOMP_SP_COUNT, MAXCOMBSPLEN) -----------
+
+open(COMPOSE_SP_TEMP, "<compose_sp.TEMP");
+
+@comp_sp_table = ();
+$comp_sp_count = 0;
+
+while (<COMPOSE_SP_TEMP>) {
+    if (m/^\/\*/) {
+       next;
+    }
+    $comp_sp_table[$comp_sp_count][0] = substr($_, 4, 10);
+    $comp_sp_table[$comp_sp_count][1] = substr($_, 16, 10);
+    $comp_sp_count++;
+}
+
+$maxcombsplen = 2;     # one char have 2 codepoints, like a D8xx DCxx.
+
+for ($i = 0 ; $i < $comp_sp_count ; $i++) {
+    $base_sp = $comp_sp_table[$i][1];
+    $comblen = 2;
+    $j = 0;
+    while ($j < $comp_sp_count) {
+       if ($base_sp ne $comp_sp_table[$j][0]) {
+           $j++;
+           next;
+       } else {
+           $comblen += 2;
+           $base_sp =  $comp_sp_table[$j][1];
+           $j = 0;
+       }
     }
+    $maxcombsplen = ($maxcombsplen > $comblen) ? $maxcombsplen : $comblen;
 }
 
+close(COMPOSE_SP_TEMP);
+
+# macro for buffer length (COMBBUFLEN) -------------------------------------
+
+$combbuflen = ($maxcomblen > $maxcombsplen) ? $maxcomblen : $maxcombsplen;
+
 # sort ---------------------------------------------------------------------
 
-system("sort -k 3 precompose.TEMP \> precompose.SORT");
-system("sort -k 2  decompose.TEMP \>  decompose.SORT");
+system("sort -k 3 compose.TEMP \> precompose.SORT");
+system("sort -k 2 compose.TEMP \>  decompose.SORT");
+
+system("sort -k 3 compose_sp.TEMP \> precompose_sp.SORT");
+system("sort -k 2 compose_sp.TEMP \>  decompose_sp.SORT");
 
 # print  -------------------------------------------------------------------
 
-printf ("\/\* This file is generated by contrib/misc/make-precompose.h.pl %s \*\/\n", $ARGV[0]);
 print ("\/\* DO NOT EDIT BY HAND\!\!\!                                           \*\/\n");
+print ("\/\* This file is generated by                                        \*\/\n");
+printf ("\/\*              contrib/misc/make-precompose.h.pl %s   \*\/\n", $ARGV[0]);
 print ("\n");
 printf ("\/\* %s is got from                                      \*\/\n", $ARGV[0]);
 print ("\/\* http\:\/\/www.unicode.org\/Public\/UNIDATA\/UnicodeData.txt            \*\/\n");
 print ("\n");
 
+print ("\#define SBASE 0xAC00\n");
+print ("\#define LBASE 0x1100\n");
+print ("\#define VBASE 0x1161\n");
+print ("\#define TBASE 0x11A7\n");
+print ("\#define LCOUNT 19\n");
+print ("\#define VCOUNT 21\n");
+print ("\#define TCOUNT 28\n");
+print ("\#define NCOUNT 588     \/\* (VCOUNT \* TCOUNT) \*\/\n");
+print ("\#define SCOUNT 11172   \/\* (LCOUNT \* NCOUNT) \*\/\n");
+print ("\n");
+
+printf ("\#define PRECOMP_COUNT %d\n", $comp_count);
+printf ("\#define DECOMP_COUNT %d\n", $comp_count);
+printf ("\#define MAXCOMBLEN %d\n", $maxcomblen);
+print ("\n");
+printf ("\#define PRECOMP_SP_COUNT %d\n", $comp_sp_count);
+printf ("\#define DECOMP_SP_COUNT %d\n", $comp_sp_count);
+printf ("\#define MAXCOMBSPLEN %d\n", $maxcombsplen);
+print ("\n");
+printf ("\#define COMBBUFLEN %d  \/\* max\(MAXCOMBLEN\,MAXCOMBSPLEN\) \*\/\n", $combbuflen);
+print ("\n");
+
 print ("static const struct \{\n");
 print ("  unsigned int replacement\;\n");
 print ("  unsigned int base\;\n");
@@ -97,6 +231,30 @@ system("cat decompose.SORT");
 print ("\}\;\n");
 print ("\n");
 
+
+
+print ("static const struct \{\n");
+print ("  unsigned int replacement_sp\;\n");
+print ("  unsigned int base_sp\;\n");
+print ("  unsigned int comb_sp\;\n");
+print ("\} precompositions_sp\[\] \= \{\n");
+
+system("cat precompose_sp.SORT");
+
+print ("\}\;\n");
+print ("\n");
+
+print ("static const struct \{\n");
+print ("  unsigned int replacement_sp\;\n");
+print ("  unsigned int base_sp\;\n");
+print ("  unsigned int comb_sp\;\n");
+print ("\} decompositions_sp\[\] \= \{\n");
+
+system("cat decompose_sp.SORT");
+
+print ("\}\;\n");
+print ("\n");
+
 print ("\/\* EOF \*\/\n");
 
 # EOF
diff --git a/contrib/patches/README b/contrib/patches/README
deleted file mode 100644 (file)
index 731933b..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-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
deleted file mode 100644 (file)
index f2c08ee..0000000
+++ /dev/null
@@ -1,1678 +0,0 @@
-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
deleted file mode 100644 (file)
index 38976fc..0000000
+++ /dev/null
@@ -1,252 +0,0 @@
-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
deleted file mode 100644 (file)
index 8b17608..0000000
+++ /dev/null
@@ -1,453 +0,0 @@
-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
deleted file mode 100644 (file)
index 6d84621..0000000
+++ /dev/null
@@ -1,407 +0,0 @@
-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
deleted file mode 100644 (file)
index 06295d0..0000000
+++ /dev/null
@@ -1,1115 +0,0 @@
-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
diff --git a/contrib/permtest/add_permtest.patch b/contrib/permtest/add_permtest.patch
deleted file mode 100644 (file)
index 6fdf38c..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-Index: configure.in
-===================================================================
-RCS file: /cvsroot/netatalk/netatalk/configure.in,v
-retrieving revision 1.205
-diff -u -w -b -r1.205 configure.in
---- configure.in       9 Sep 2006 04:30:01 -0000       1.205
-+++ configure.in       25 Jul 2008 13:48:05 -0000
-@@ -1053,6 +1053,7 @@
-       contrib/shell_utils/apple_rm
-       contrib/shell_utils/asip-status.pl
-       contrib/shell_utils/cleanappledouble.pl
-+      contrib/shell_utils/permtest.pl
-       contrib/timelord/Makefile
-       contrib/a2boot/Makefile
-       distrib/Makefile
-Index: contrib/shell_utils/Makefile.am
-===================================================================
-RCS file: /cvsroot/netatalk/netatalk/contrib/shell_utils/Makefile.am,v
-retrieving revision 1.16
-diff -u -w -b -r1.16 Makefile.am
---- contrib/shell_utils/Makefile.am    28 Apr 2005 20:49:36 -0000      1.16
-+++ contrib/shell_utils/Makefile.am    25 Jul 2008 13:48:05 -0000
-@@ -9,6 +9,9 @@
-       apple_cp apple_mv apple_rm      \
-       cleanappledouble.pl             \
-       asip-status.pl
-+EXTRASCRIPTS = \
-+      permtest.pl \
-+      permtest.cfg
- SUFFIXES = .tmpl .
-@@ -22,4 +25,4 @@
- bin_SCRIPTS = $(PERLSCRIPTS) $(GENERATED_FILES)
--EXTRA_DIST = $(PERLSCRIPTS) $(TEMPLATE_FILES)
-+EXTRA_DIST = $(PERLSCRIPTS) $(TEMPLATE_FILES) $(EXTRASCRIPTS)
diff --git a/contrib/permtest/permtest.cfg b/contrib/permtest/permtest.cfg
deleted file mode 100644 (file)
index 941d4e6..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-# Exactly follow this layout! Don't put extra white space in config lines !!
-# Order doesn't matter.
-
-# We use a ssh executed stat command to verify uid,gid and mode. Therefore ssh access with
-# PKI authentication must be setup and working!
-sshLogin = USER@HOST
-
-# self explaining
-mountAFPVolume = afp://USER:PASSWORD@HOST/VOLUME
-
-# These files will be created
-createFile = PATH_TO_FILE_ON_CLIENT
-
-# These files will be stat'ed. You can use different server-side paths here for files
-# created with "createFile" directive
-testFile = PATH_TO_FILE_ON_SERVER,user=USERNAME,group=GROUPNAME,mode=MODE
-
-# These dirs will be created
-createDir = PATH_TO_DIR_ON_CLIENT
-
-# These will be verified.
-testDir = PATH_TO_DIR_ON_CLIENT,user=USERNAME,group=GROUPNAME,mode=MODE
-
-# EOF. Leave this as a last line. We delibaretly chop in perl which might otherwise truncate
-# your last "testDir" definition.
\ No newline at end of file
diff --git a/contrib/permtest/permtest.pl.in b/contrib/permtest/permtest.pl.in
deleted file mode 100755 (executable)
index 87de19a..0000000
+++ /dev/null
@@ -1,224 +0,0 @@
-#!@PERL@ -w
-
-###########################################################################
-#
-# Characterization testing netatalks permission model
-#
-# (c) 2008 by Frank Lahm <franklahm@googlemail.com>
-#
-#   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.
-# 
-###########################################################################
-
-###########################################################################
-#
-# Usage:
-#
-#  "permtest.cfg" must be in your CWD. Must be run on a OS X host. Tested
-#  with 10.4.11. Uses Applescript through system("osascript ...") to mount
-#  AFP Volumes. Uses `ssh LOGIN@HOST stat FILE|DIR`. Therefor PKI
-#  authentication must be setup and working!
-#  See "permtest.cfg" for more details, it's pretty much self-explaining.
-# 
-###########################################################################
-
-use strict;
-
-my $DEBUG = 0;
-
-###########################################################################
-
-sub parseConfig;
-sub mountAPFVols;
-sub createTestFiles;
-sub createTestDirs;
-sub verifyTestFiles;
-sub verifyTestDirs;
-sub unmountAfp;
-
-my ($sshLogin, $sshResult, %sshStat, @AFPVols, @createFiles, @createDirs, @testFiles, @testDirs);
-my ($dir, $file, $user, $group, $perms, $mode, $cmd);
-
-parseConfig();
-mountAPFVols();
-createTestFiles();
-createTestDirs();
-print "\n";
-verifyTestFiles();
-verifyTestDirs();
-unmountAfp();
-
-exit 0;
-
-###########################################################################
-
-# parse config file
-sub parseConfig
-{
-       open CFG, "permtest.cfg" or die "Config file not found!";
-       while (<CFG>) {
-               chop;
-           if (/^#/) { next; };
-           if (/^sshLogin/) {
-                       $sshLogin = $_;
-                       $sshLogin =~ s/^sshLogin ?= ?// ;
-                       next;
-               }
-               if (/^mountAFPVolume/) {
-                       s/^mountAFPVolume ?= ?// ;
-                       print "Found AFP Volume Definition \"$_\"\n" if $DEBUG;
-                       push @AFPVols, $_;
-                       next;
-               }
-           if (/^createFile/) {
-                       s/^createFile ?= ?// ;
-                       push @createFiles, $_;
-                       next;
-               }
-               if (/^createDir/) {
-                       s/^createDir ?= ?// ;
-                       push @createDirs, $_;
-                       next;
-               }
-               if (/^testFile/) {
-                       push @testFiles, $_;
-                       next;
-               }
-               if (/^testDir/) {
-                       push @testDirs, $_;
-                       next;
-               }
-       }
-       close CFG;
-}
-
-# mount AFP Volumes
-sub mountAPFVols
-{
-       foreach (@AFPVols) {
-               print "Mounting AFP Volume \"$_\"\n";
-               $cmd = "osascript -e 'tell application \"Finder\"' -e 'mount volume \"$_\"' -e 'end tell' &> /dev/null";
-               print "Going to run the following Applescript:\n" . $cmd . "\n\n" if $DEBUG;
-               system($cmd);
-               if ($? != 0) { die "Error mounting \"$_\"\n"; }
-       }
-}
-
-# Create test files
-sub createTestFiles
-{
-       foreach (@createFiles) {
-               s/^createFile ?= ?// ;
-               system("rm \"$_\" &> /dev/null");
-               print "Creating file: \"$_\"\n";
-               system("touch \"$_\"");
-               if ($? != 0) { die "Error creating file \"$_\"\n"; }
-       }
-}
-
-# Create test dirs
-sub createTestDirs
-{
-       foreach (@createDirs) {
-               s/^createDir ?= ?// ;
-               system("rmdir \"$_\" &> /dev/null");
-               print "Creating dir: \"$_\"\n";
-               system("mkdir \"$_\"");
-               if ($? != 0) { die "Error creating dir \"$_\"\n"; }
-       }
-}
-
-# Verify files and dirs
-sub verifyTestFiles
-{
-       foreach (@testFiles) {
-               my @line = split(",");
-               foreach (@line) {
-                       if (/^testFile/) {
-                               $file = $_;
-                               $file =~ s/^testFile ?= ?//;
-                       }
-                       elsif (/^user/) {
-                               $user = $_;
-                               $user =~ s/^user ?= ?//;
-                       }
-                       elsif (/^group/) {
-                               $group = $_;
-                               $group =~ s/^group ?= ?//;
-                       }
-                       elsif (/^mode/) {
-                               $mode = $_;
-                               $mode =~ s/^mode ?= ?//;
-                       }
-               } # foreach (@elems)
-               print "File: $file, User: $user, Group: $group, Perms: $perms\n" if $DEBUG;
-       
-               $sshResult = `ssh $sshLogin stat -c \"user,%U,group,%G,mode,0%a\" \"$file\"`;
-               if ($? != 0) { die "Error stat'ing file \"$file\"\n"; }
-               chop $sshResult;
-               print "ssh stat $file gave us: $sshResult\n" if $DEBUG;
-       
-               %sshStat = split(",", $sshResult);
-               if ( ($sshStat{user} ne $user) or ($sshStat{group} ne $group) or ($sshStat{mode} ne $mode) ) {
-                       print "Creatin error for: \"$file\"!\nExpected:\t$user, $group, $mode.\nGot:\t\t$sshStat{user}, $sshStat{group}, $sshStat{mode}.\n\n";
-               }
-               system("rm \"$file\"");
-               if ($? != 0) { die "Couldn't delete \"$file\"\n"; }
-       }
-}
-
-sub verifyTestDirs
-{
-       foreach (@testDirs) {
-               my @line = split(",");
-               foreach (@line) {
-                       if (/^testDir/) {
-                               $dir = $_;
-                               $dir =~ s/^testDir ?= ?//;
-                       }
-                       elsif (/^user/) {
-                               $user = $_;
-                               $user =~ s/^user ?= ?//;
-                       }
-                       elsif (/^group/) {
-                               $group = $_;
-                               $group =~ s/^group ?= ?//;
-                       }
-                       elsif (/^mode/) {
-                               $mode = $_;
-                               $mode =~ s/^mode ?= ?//;
-                       }
-               } # foreach (@elems)
-               print "Dir: $dir, User: $user, Group: $group, Perms: $perms\n" if $DEBUG;
-       
-               $sshResult = `ssh $sshLogin stat -c \"user,%U,group,%G,mode,0%a\" \"$dir\"`;
-               if ($? != 0) { die "Error stat'ing file \"$dir\"\n"; }
-               chop $sshResult;
-               print "ssh stat $dir gave us: $sshResult\n" if $DEBUG;
-       
-               %sshStat = split(",", $sshResult);
-               if ( ($sshStat{user} ne $user) or ($sshStat{group} ne $group) or ($sshStat{mode} ne $mode) ) {
-                       print "Creatin error for: \"$dir\"!\nExpected:\t$user, $group, $mode.\nGot:\t\t$sshStat{user}, $sshStat{group}, $sshStat{mode}.\n\n";
-               }
-               system("rmdir \"$dir\""); if ($? != 0) { die "Couldn't delete \"$dir\"\n"; }
-       }
-}
-
-sub unmountAfp
-{
-       foreach (@AFPVols) {
-               print "Goint to eject Volume \"$_\"\n";
-               s#^(.*/)## ;
-               $cmd = "osascript -e 'tell application \"Finder\"' -e 'eject \"$_\"' -e 'end tell' &> /dev/null";
-               print "Going to run the following Applescript:\n" . $cmd . "\n\n" if $DEBUG;
-               system($cmd);
-       }
-}
index bb2f1496f10b47705e87f11d169f5343ca0ca203..c8cefe1e8ef8c8d0520b3c673e79474f43db1601 100644 (file)
@@ -6,7 +6,6 @@ GENERATED_FILES = lp2pap.sh
 TEMPLATE_FILES = lp2pap.sh.tmpl
 PERLSCRIPTS = \
        afpd-mtab.pl \
-       apple_cp apple_mv apple_rm  \
        asip-status.pl \
        apple_dump
 
diff --git a/contrib/shell_utils/apple_cp.in b/contrib/shell_utils/apple_cp.in
deleted file mode 100755 (executable)
index b8a75ab..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-#!@PERL@
-# 
-# $Id: apple_cp.in,v 1.1 2002-01-17 05:59:25 srittau Exp $
-
-$USAGE = <<USAGE;
-Usage: $0 filename1 filename2
-       $0 filename ...  directory
-Do an apple copy, copying the resource fork as well
-USAGE
-
-die $USAGE if @ARGV < 2;
-
-@from = @ARGV; pop(@from);
-$to = $ARGV[-1];
-
-if (-f $to && @from > 1) { die $USAGE; }
-
-foreach $from (@from) {
-    if (!-f $from) {   
-       print STDERR "file $from does not exist\n";
-       die $USAGE;
-    }
-    
-    if (!-d $to && @from >1) {
-       print STDERR "directory $to does not exist\nCan't copy multiple files into one file.\n";
-       die $USAGE;
-    }
-    
-    $cmd = "cp '$from' '$to'";
-    system $cmd || die "error executing $cmd";
-    
-    ($from_dir, $from_file) = split_dir_file($from);
-
-    if (-d $to) {
-       if (!-d "$to/.AppleDouble") {
-           mkdir("$to/.AppleDouble", 0777);
-       }       
-       $cmd = "cp '$from_dir/.AppleDouble/$from_file' '$to/.AppleDouble/$from_file'";
-    } else {
-       ($to_dir, $to_file) = split_dir_file($to);
-       if (!-d "$to_dir/.AppleDouble") {
-           mkdir("$to_dir/.AppleDouble", 0777);
-       }       
-       $cmd = "cp '$from_dir/.AppleDouble/$from_file' '$to_dir/.AppleDouble/$to_file'";
-    }
-
-    system $cmd || die "error executing $cmd";
-}
-
-# split a file path into a directory and file name.
-sub split_dir_file {
-    my $path = shift;
-
-    @path_elems = split(/\//, $path);
-
-    my $file = pop(@path_elems);
-    my $dir;
-    if (!@path_elems) {
-       $dir = '.';
-    } else {
-       $dir = join('/', @path_elems);
-    }
-
-    $dir, $file;
-}
-
-
diff --git a/contrib/shell_utils/apple_mv.in b/contrib/shell_utils/apple_mv.in
deleted file mode 100755 (executable)
index 79cf579..0000000
+++ /dev/null
@@ -1,79 +0,0 @@
-#!@PERL@
-# 
-# $Id: apple_mv.in,v 1.1 2002-01-17 05:59:25 srittau Exp $
-
-$USAGE = <<USAGE;
-Usage: $0 filename1 filename2
-       $0 filename ...  directory
-Do an apple move, moving the resource fork as well
-USAGE
-
-@from = @ARGV; pop(@from);
-$to = $ARGV[-1];
-
-if (-f $to && @from > 1) { die $USAGE; }
-
-foreach $from (@from) {
-    if (!-f $from) {   
-       print STDERR "file $from does not exist\n";
-       die $USAGE;
-    }
-
-    if (!-d $to && @from >1) {
-       print STDERR "directory $to does not exist\nCan't move multiple files into one file.\n";
-       die $USAGE;
-    }
-    
-    $from = escape_bad_chars($from);
-    $to = escape_bad_chars($to);
-    $cmd = "mv $from $to";
-    system $cmd || die "error executing $cmd";
-    
-    ($from_dir, $from_file) = split_dir_file($from);
-
-    if (-d $to) {
-       if (!-d "$to/.AppleDouble") {
-           mkdir("$to/.AppleDouble", 0777);
-       }
-       $cmd = "mv $from_dir/.AppleDouble/$from_file $to/.AppleDouble/$from_file";
-    } else {
-       ($to_dir, $to_file) = split_dir_file($to);
-
-       if (!-d $to_dir) {
-           print STDERR "directory $to does not exist\n";
-           die $USAGE;
-       }
-    
-       if (!-d "$to_dir/.AppleDouble") {
-           mkdir("$to_dir/.AppleDouble", 0777);
-       }
-       $cmd = "mv $from_dir/.AppleDouble/$from_file $to_dir/.AppleDouble/$to_file";
-    }
-
-    system $cmd || die "error executing $cmd";
-}
-
-sub escape_bad_chars {
-    my($file) = @_;
-    $file=~s/([^a-zA-Z0-9.-_])/\\$1/;
-    return $file;
-}
-
-# split a file path into a directory and file name.
-sub split_dir_file {
-    my $path = shift;
-
-    @path_elems = split(/\//, $path);
-
-    my $file = pop(@path_elems);
-    my $dir;
-    if (!@path_elems) {
-       $dir = '.';
-    } else {
-       $dir = join('/', @path_elems);
-    }
-
-    $dir, $file;
-}
-
-
diff --git a/contrib/shell_utils/apple_rm.in b/contrib/shell_utils/apple_rm.in
deleted file mode 100755 (executable)
index 6595937..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-#!@PERL@
-# 
-# $Id: apple_rm.in,v 1.1 2002-01-17 05:59:25 srittau Exp $
-
-$USAGE = <<USAGE;
-Usage: $0 filename ...
-Do an apple remove, remove the resource fork as well
-USAGE
-
-die $USAGE if @ARGV < 1;
-
-foreach $path (@ARGV) {
-    if (!-f $path) {
-       print STDERR "file $path does not exist\n";
-       die $USAGE;
-    }
-
-    ($dir, $file) = &split_dir_file($path);
-
-    $cmd = "rm '$path'";
-    system $cmd || die "error executing $cmd";
-    
-    $cmd = "rm '$dir/.AppleDouble/$file'";
-    system $cmd || die "error executing $cmd";
-}
-
-# split a file path into a directory and file name.
-sub split_dir_file {
-    my $path = shift;
-
-    @path_elems = split(/\//, $path);
-
-    my $file = pop(@path_elems);
-    my $dir;
-    if (!@path_elems) {
-       $dir = '.';
-    } else {
-       $dir = join('/', @path_elems);
-    }
-
-    $dir, $file;
-}
index 226ec9e9d7d94eb76c942f635fad5871010fcfcd..4fc195df3ffcf94c0121a51c61b08f803944ed5c 100755 (executable)
@@ -391,6 +391,7 @@ sub parse_afp_flags
        push (@flags, "SupportsReconnect") if ($flags & (1<<7));
        push (@flags, "SupportsOpenDirectory") if ($flags & (1<<8));
        push (@flags, "SupportsUTF8Servername") if ($flags & (1<<9));
+       push (@flags, "SupportsUUIDs") if ($flags & (1<<10));
        push (@flags, "SupportsSuperClient") if ($flags & (1<<15));
 
        return @flags;
diff --git a/distrib/debian/README.Debian b/distrib/debian/README.Debian
deleted file mode 100644 (file)
index c51ccce..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-This is the pre-packaged Debian version of the Netatalk protocol suite.
-To find out more about netatalk, visit http://netatalk.sourceforge.net/
-
-This package was originally put together by Klee Dienes <klee@debian.org>
-and was later maintained by late Joel Klecker <espy@debian.org> and
-David Huggins-Daines <dhd@debian.org>. It was repackaged by its current
-maintainer Sebastian Rittau <srittau@debian.org>.
-
-                                 OpenSSL
-                                 =======
-
-Netatalk supports OpenSSL to provide a secure means for authentication.
-Unfortunately it's currently not possible for Debian to distribute
-Netatalk with SSL support enabled, since OpenSSL's license is incompatible
-with the GPL used by Netatalk.
-
-But it's possible to build Netatalk with SSL support locally:
-
-1. Make sure that the package libssl-dev is installed:
-
-  apt-get install libssl-dev
-
-2. Make sure all other build dependencies are fulfilled:
-
-  apt-get build-dep netatalk
-
-3. Download the Netatalk sources:
-
-  apt-get source netatalk
-
-4. Edit the rules file to enable SSL compilation:
-
-  cd netatalk-1.5pre8 && \
-  cp debian/rules debian/rules.bak && \
-  sed -e 's/^#USE_SSL=yes/USE_SSL=yes/' debian/rules.bak >debian/rules
-
-  (You may need to substitute the directory name netatalk-1.5pre8 with the
-  proper one.)
-
-5. Build the package:
-
-  dpkg-buildpackage -rfakeroot
diff --git a/distrib/debian/changelog b/distrib/debian/changelog
deleted file mode 100644 (file)
index d194da8..0000000
+++ /dev/null
@@ -1,576 +0,0 @@
-netatalk (1.5pre8cvs-0) unstable; urgency=low
-
-  * Unofficial CVS release.
-  * Correct included docs, since all platform specific docs were merged.
-  * Upstream does now have manpages for apple_cp(1), apple_mv(1), and
-    apple_rm(1), written by Lance Levsen <l.levsen@printwest.com>.
-    Removed the links to undocumented(7).
-  * Don't supply --with-did=last anymore, since this is now the default.
-  * Added cnid_didname_verify(1) to list of undocumented binaries.
-
- -- Sebastian Rittau <srittau@debian.org>  Mon, 10 Dec 2001 13:46:14 +0100
-
-netatalk (1.5pre8-5) unstable; urgency=low
-
-  * Appletalk -> AppleTalk in package short descriptions. Thanks to Matt
-    Zimmerman and his spell checking effort for pointing this out.
-  * Really install README.Debian this time.
-  * Removed afppasswd and afppasswd(1) from Debian distribution, since
-    they are of no use when SSL support is not compiled in.
-
- -- Sebastian Rittau <srittau@debian.org>  Sun, 18 Nov 2001 15:13:53 +0100
-
-netatalk (1.5pre8-4) unstable; urgency=low
-
-  * Fixed uams_pam.so. (Closes: #118889)
-  * Explain why we don't link against OpenSSL in README.Debian.
-  * Modified debian/rules so that setting a variable called USE_SSL to
-    "yes" enables SSL support. This should ease the local compilation of
-    SSL-enabled netatalk packages.
-
- -- Sebastian Rittau <srittau@debian.org>  Sat, 10 Nov 2001 19:05:12 +0100
-
-netatalk (1.5pre8-3) unstable; urgency=low
-
-  * Corrected upstream version number (pre8 instead of pre7). This corrects
-    afpd -v and similar commands.
-  * Raised default number of allowed afpd clients. Suggestion by Jonas
-    Smedegaard.
-  * Small logcheck fix by Jonas.
-  * Removed ATALK_BACKGROUND description from netatalk.conf(5).
-  * Removed obsolete --with-config-dir configure option.
-
- -- Sebastian Rittau <srittau@debian.org>  Sat, 27 Oct 2001 15:36:30 +0200
-
-netatalk (1.5pre8-2) unstable; urgency=low
-
-  * Work around the fact that upstream includes sym-links to mkinstalldirs and
-    missing instead of verbatim copies. We do that by including our own copies
-    in debian and copy them before running the build. (Closes: #114915)
-
- -- Sebastian Rittau <srittau@debian.org>  Wed, 10 Oct 2001 14:03:34 +0200
-
-netatalk (1.5pre8-1) unstable; urgency=low
-
-  * New upstream version, containing most Debian patches.
-  * Added a patch to configure.in that fixes PAM detection and compilation.
-
- -- Sebastian Rittau <srittau@debian.org>  Sun,  7 Oct 2001 12:46:15 +0200
-
-netatalk (1.5pre7-5) unstable; urgency=low
-
-  * More patches by Jonas Smedegaard <dr@jones.dk>:
-    + 001_logcheck_fix_typo_and_optimize...
-      Logcheck fixes and improvements. (Closes: #114448)
-    + 005_visible_home_dir_in_config_(again!)
-      Name user home directories "Home Directory" by default to make them
-      appear in the MacOS chooser. (Patch had already been applied in
-      1.5pre7-2, but had been lost since.)
-    + Jonas made more patches, which I haven't applied yet, but either
-      committed upstream or sent upstream for discussion.
-      
- -- Sebastian Rittau <srittau@debian.org>  Thu,  4 Oct 2001 22:31:50 +0200
-
-netatalk (1.5pre7-4) unstable; urgency=low
-
-  * Fixed Build-Dependencies. (pam-cracklib -> cracklib2-dev) (Closes: #113356)
-  * Restored symlinks in /usr/lib/atalk/filters and other directories.
-    (Closes: #113746)
-  * Patches by Jonas Smedegaard <dr@jones.dk>:
-    + 002_correctly_calculate_perl_depends
-    + 003_remove_cap_line_from_logcheck
-      Small logcheck change.
-    + 004_add_misc_logcheck_lines
-      Another logcheck change.
-    + 011_strip_pam_paths
-      Not applied, but patched config/netatalk.pamd to strip /lib/security
-      from its path.
-
- -- Sebastian Rittau <srittau@debian.org>  Mon,  1 Oct 2001 08:30:17 +0200
-
-netatalk (1.5pre7-3) unstable; urgency=low
-
-  * Fixed a stupid typo I made in the new init script.
-  * Put add_netatalk_printer and netatalkshorternamelinks.pl in the
-    examples directory instead of /usr/bin. Suggestion from Jonas
-    Smedegaard.
-
- -- Sebastian Rittau <srittau@debian.org>  Sun, 23 Sep 2001 19:08:43 +0200
-
-netatalk (1.5pre7-2) unstable; urgency=low
-
-  * Integrated a lot of patches by Jonas Smedegaard <dr@jones.dk>:
-    + 001_etc2ps paths
-      Correct paths in etc2ps and suggest tetex-base.
-    + 005_visible_home_dir_in_config
-      Name user home directories "Home Directory" by default to make them
-      appear in the MacOS chooser.
-    + 007_logcheck
-      Support for the logcheck log file checking package.
-    + 011_avoid_symlinks_and_force_using_autoconf_2.50
-      Partly applied: Patch configure.in so that the use of autoconf 2.50
-      is forced. (Debian autoconf hack workaround.)
-    + 012_netatalk.conf
-      Improved init script. Also, make use of netatalk.conf again.
-      I patched the patch so that netatalk.conf is placed in /etc/default.
-    + 015_recommend_lsof_(for_macusers)_and_suggest_quota
-      Recommend lsof and suggest quota.
-    + 021_enable_ssl_and_cracklib_and_correct_pam_paths
-      Partly applied: Enable cracklib support.
-  * Fixed paths in add_netatalk_printer.
-  * Removed lp2pap.sh since it's of no use on Debian systems.
-  * Removed test_parse_mtab and afpd-mtab.pl because we are not using
-    the mtab DID scheme.
-  * Comparison operator is '=', not '==' in the 'test' command. Fixed
-    my patch.
-  * Removed netatalk.conf.5 as well, since we don't install netatalk.conf
-    anymore.
-  * Removed superfluous file /etc/netatalk/netatalk.pamd.
-  * Moved all *.la and *.a files to netatalk-dev. Added appropriate
-    conflicts and replaces.
-  * debian/rules: Do not copy files to package build directories instead of
-    removing them afterwards.
-
- -- Sebastian Rittau <srittau@debian.org>  Sun, 23 Sep 2001 14:04:06 +0200
-
-netatalk (1.5pre7-1) unstable; urgency=medium
-
-  * New upstream version. Most patches were applied upstream.
-  * This release uses libtool for UAM stuff. Also, the correct flag
-    for dynamic linking is supplied, so the problems with unresolved
-    symbols should be gone now. (Closes: #95399)
-  * Non-DSFG free code was removed. Copyright notice was changed accordingly.
-  * Use ./configure --sysconfdir instead of --with-config-dir.
-  * Upstream package does now install PAM file in the correct directory.
-    Removed rule, correcting this from Debian rules file.
-  * Added man pages for netatalk-config(1) and timelord(8). (Upstream
-    does now also include a man page for timeout(1), but since we're not
-    distributing it anymore, we don't care.)
-  * Some doc files were removed, others were added.
-  * Use debhelper compatibility level 3 and performed general packaging
-    cleanups at the same time.
-  * Standards-Version 3.5.6.0. No changes needed.
-  * Netatalk is now GPL'ed. Added a note stating that to copyright.
-    Also, we can't link against libssl anymore. Removed SSL stuff.
-    I had to patch configure.in to do that.
-  * Removed emacs stuff from changelog.
-  * Applied a patch to getiface.c for a problem that could lead to
-    segfaults. Thanks to Kai Henningsen <kaih@khms.westfalen.de>
-    for actually being affected by this bug, and - more importantly -
-    finding the problem. (Closes: #109310)
-
- -- Sebastian Rittau <srittau@debian.org>  Thu, 30 Aug 2001 02:02:17 +0200
-
-netatalk (1.5pre6-7) unstable; urgency=low
-
-  * Cleaned up CFLAGS handling in ./configure call.
-  * Updated config.{sub,guess} again, just to make sure ...
-  * Depend on the timeout package from tct. Also, don't distribute
-    /usr/bin/timeout and remove the timeout(1) link to undocumented(7).
-    Make preparations to remove the proper timeout(1) man page that will
-    get distributed with netatalk 1.5pre7.
-
- -- Sebastian Rittau <srittau@debian.org>  Sun, 19 Aug 2001 18:05:55 +0200
-
-netatalk (1.5pre6-6) unstable; urgency=medium
-
-  * ./configure --with-did=last
-    This should fix errors with MacOS X.
-  * Fixed typo in add_netatalk_printer. (Closes: #104192)
-  * Removed /etc/netatalk/netatalk.conf, since it's not used by Debian's
-    init script. (Closes: #103539)
-  * Disabled pam_guest module by default. (Closes: #106637)
-
- -- Sebastian Rittau <srittau@debian.org>  Sat, 28 Jul 2001 14:49:15 +0200
-
-netatalk (1.5pre6-5) unstable; urgency=low
-
-  * Removed --without-ssl option from ./configure invocation. Not
-    that it had any effect before.
-  * Updated config.{sub,guess} (manually for now). I will switch to
-    dh_autotools if and when this is available. (Closes: #102861)
-
- -- Sebastian Rittau <srittau@debian.org>  Fri,  6 Jul 2001 00:46:18 +0200
-
-netatalk (1.5pre6-4) unstable; urgency=low
-
-  * Changed section of netatalk-dev to non-US, too.
-  * Make netatalk-dev depend on netatalk.
-
- -- Sebastian Rittau <srittau@debian.org>  Tue, 19 Jun 2001 01:40:07 +0200
-
-netatalk (1.5pre6-3) unstable; urgency=low
-
-  * Thanks to my former sponsor Michael 'grisu' Bramer for his efforts.
-  * Changed maintainer address to <srittau@debian.org>.
-  * Moved to section non-US and link against libssl. Changed Build-Depends
-    accordingly.
-  * Link against libdb3 instead of libdb2. Changed Build-Depends
-    accordingly.
-  * Sources were not obtained from CVS, and are available by HTTP.
-  * Removed patch to contrib/Makefile.* to enable compilation of timelord.
-    Instead, use configure option --with-timelord.
-  * Added symlinks to megatron. Use patch from upstream CVS. (Closes: #95944)
-  * Clean up patch for etc/psf/Makefile.am.
-  * Added DEB_BUILD_OPTIONS handling. (Closes: #99705)
-  * Added links to undocumented(7) from binheader(1) and nadheader(1).
-  * Standards-Version: 3.5.5.0.
-
- -- Sebastian Rittau <srittau@debian.org>  Sun, 17 Jun 2001 15:50:13 +0200
-
-netatalk (1.5pre6-2) unstable; urgency=low
-
-  * This version will hopefully clean up the version mess, I created.
-  * Conforms to standards-version 3.5.3.0 (no changes needed).
-  * Link cleanappledouble.pl(1) to undocumented(7).
-  * Removed all hand-crafted {pre,post}{inst,rm} files.
-  * Give files in /etc/netatalk/nls a mode of 0644, instead of 0755. Fixes
-    lintian warnings.
-  * Build-Depends on libdb2-dev do exist since -1. (Closes: #92774)
-  * Distribute missing pagecount.ps. (Closes: #95117)
-  * Compile timelord.
-  * Use --enable-fhs instead of --with-fhs. Should fix some paths.
-  * Compile with shadow support. (Closes: #95186)
-  * Use the pam_unix.so module instead of pam_pwdb.so in /etc/pam.d/netatalk.
-
- -- Sebastian Rittau <srittau@jroger.in-berlin.de>  Tue,  1 May 2001 03:38:57 +0200
-
-netatalk (1.5pre6-1) unstable; urgency=low
-
-  * New upstream release.
-  * Re-added changes made in 1.4b2+asun2.1.3-8.
-  * Added --prefix=/usr to ./configure options.
-
- -- Sebastian Rittau <srittau@jroger.in-berlin.de>  Fri, 13 Apr 2001 00:27:47 +0200
-
-netatalk (1.5pre5-3) unstable; urgency=low
-
-  * Re-added changes made in 1.4b2+asun2.1.3-8.
-
- -- Sebastian Rittau <srittau@jroger.in-berlin.de>  Fri,  6 Apr 2001 23:44:47 +0200
-
-netatalk (1.5pre5-2) unstable; urgency=low
-
-  * Added copyright of University of Newcastle upon Tyne to debian/copyright.
-  * Removed patches/uams_dhx_pam.c.patch as it was applied upstream.
-  * Some documentation files were moved into the doc subdirectory.
-  * Added more documentation files.
-  * Added some temporary build fixes.
-
- -- Sebastian Rittau <srittau@jroger.in-berlin.de>  Wed,  8 Mar 2001 00:03:30 +0100
-
-netatalk (1.5pre5-1) unstable; urgency=low
-
-  * New upstream version.
-
- -- Sebastian Rittau <srittau@jroger.in-berlin.de>  Fri, 23 Feb 2001 21:07:18 +0100
-
-netatalk (1.5pre4-1) unstable; urgency=low
-
-  * New upstream version.
-  * Some reorganisations to allow building directly from CVS.
-  * Debian packaging is now included in upstream CVS.
-  * Modified debian/copyright to include CVS instructions.
-  * Call ./configure with --with-fhs and removed --with-uams-path option.
-  * Removed patches/paths.h.patch as this is now supported by --with-fhs.
-  * Removed various build patches now included upstream.
-  * Use dh_installman from debhelper v3. Updated build dependencies
-    accordingly.
-  * Removed comment about Debian specific changes from debian/copyright.
-  * Build with libssl support. (Closes: #48871)
-  * Added libssl096-dev to Build-Depends.
-  * Ship FAQ in /usr/share/doc/netatalk
-
- -- Sebastian Rittau <srittau@jroger.in-berlin.de>  Thu, 22 Feb 2001 20:44:41 +0100
-
-netatalk (1.5pre3-1) unstable; urgency=low
-
-  * New upstream version from netatalk.sourceforge.net.
-    (Closes: #69232, #78781)
-  * Repackaged using debhelper.
-  * Conforms to policy version 3.5.1.0.
-  * Removed some Debian specific patches integrated upstream.
-  * Updated debian/copyright.
-  * Changed priority from optional to extra.
-
- -- Sebastian Rittau <srittau@jroger.in-berlin.de>  Thu, 22 Feb 2001 10:18:07 +0100
-
-netatalk (1.4b2+asun2.1.3-8) unstable; urgency=low
-
-  * Added libdb2-dev to build-depends. (Closes: #92774)
-  * Complies with Debian policy version 3.5.2.0.
-  * Added netatalk homepage and current maintainer to debian/copyright.
-
- -- Sebastian Rittau <srittau@jroger.in-berlin.de>  Tue,  3 Apr 2001 23:59:38 +0200
-
-netatalk (1.4b2+asun2.1.3-7) unstable; urgency=low
-
-  * New maintainer. (Closes: #82386)
-  * Fixed a build problem.
-  * Strip .note and .comment sections from /usr/lib/atalk/psa.
-  * Added debhelper as build-dependency.
-  * Complies with Debian policy version 3.2.1.0.
-
- -- Sebastian Rittau <srittau@jroger.in-berlin.de>  Sun, 21 Jan 2001 15:49:11 +0100
-
-netatalk (1.4b2+asun2.1.3-6) unstable; urgency=low
-
-  * The "looks like I picked the wrong week to quit sniffing glue" release.
-  * Update the maintainer name in the control file.
-  * Move psa and etc2ps to /usr/lib/atalk, as they are not user binaries
-    (this also shuts lintian up).
-
- -- David Huggins-Daines <dhd@debian.org>  Fri, 14 Jan 2000 21:04:24 -0500
-
-netatalk (1.4b2+asun2.1.3-5) unstable; urgency=low
-
-  * New maintainer.
-  * Compensate for stupid new 'install -s' behaviour. (closes:Bug#51423)
-  * Fix psf(8) manpage. (closes:Bug#30839)
-  * Updated Standards-Version.
-  * Fixed symlinks to be relative, as per lintian's warnings.
-  * Added /usr/doc symlinks in the postinst/prerm.
-
- -- David Huggins-Daines <dhd@debian.org>  Wed, 22 Dec 1999 20:24:26 -0500
-
-netatalk (1.4b2+asun2.1.3-4) unstable; urgency=low
-
-  * Fix init script to always kill papd even if ENABLE_PAP=no (closes:Bug#48783).
-
- -- Joel Klecker <espy@debian.org>  Sun, 31 Oct 1999 07:43:29 -0800
-
-netatalk (1.4b2+asun2.1.3-3) unstable; urgency=low
-
-  * Remove libatalk1 and libatalk1-dev (I think it is a mistake to "fork" a
-    shared version of a library in Debian, if the library is static upstream
-    then upstream isn't gonna be careful with the ABI).
-  * Create netatalk-dev.
-  * netatalk.init: Use $() instead of ``.
-    Use /bin/hostname explicitly.
-    s/daemons/Daemons/g.
-    Remove module fiddling (closes:Bug#44767,#43319).
-  * Remove "glibc 2.1 fix" it's no longer needed.
-  * Compile with sendfile support.
-  * Use /usr/share/doc.
-  * Cleanup bashisms in debian/rules.
-
- -- Joel Klecker <espy@debian.org>  Sat, 23 Oct 1999 20:59:24 -0700
-
-netatalk (1.4b2+asun2.1.3-2) unstable; urgency=low
-
-  * (netatalk): Make /etc/netatalk/afpd.conf a conffile (closes:Bug#37628).
-
- -- Joel Klecker <espy@debian.org>  Thu, 13 May 1999 10:54:37 -0700
-
-netatalk (1.4b2+asun2.1.3-1) unstable; urgency=low
-
-  * New upstream release (closes:Bug#33982).
-  * Correct paths in psf.8 (closes:Bug#30839).
-  * There is now a different way to control CRLF translation on a
-    per-volume basis upstream so I have removed the patch that
-    provides the -e option to afpd.
-  * (netatalk): Depend on libpam-modules.
-  * Put man pages in /usr/share/man.
-
- -- Joel Klecker <espy@debian.org>  Tue, 30 Mar 1999 12:17:36 -0800
-
-netatalk (1.4b2+asun2.1.1-2) frozen unstable; urgency=low
-
-  * Incorporated glibc 2.1 fixes from Christian Meder.
-  * Remove explicit add-log-mailing-address from debian/changelog.
-
- -- Joel Klecker <espy@debian.org>  Fri, 15 Jan 1999 07:28:11 -0800
-
-netatalk (1.4b2+asun2.1.1-1.1) frozen unstable; urgency=low
-
-  * non maintainer, sparc only upload
-  * fix #includes for glibc2.1
-
- -- Christian Meder <meder@isr.uni-stuttgart.de>  Mon,  4 Jan 1999 12:37:13 +0100
-
-netatalk (1.4b2+asun2.1.1-1) frozen unstable; urgency=low
-
-  * New upstream bugfix release.
-  * Recompile against libc6 2.0.7u-7 to get rid of versioned
-    libc6 dependency.
-
- -- Joel Klecker <espy@debian.org>  Thu,  3 Dec 1998 07:45:42 -0800
-
-netatalk (1.4b2+asun2.1.0-5) frozen unstable; urgency=high
-
-  * [libatalk/atp/atp_rsel.c] Minor change for libnatali compatibility
-    (closes:Bug#30092).
-  * Rebuild with libc6 2.0.7u-6 for i386.
-
- -- Joel Klecker <espy@debian.org>  Fri, 27 Nov 1998 22:58:11 -0800
-
-netatalk (1.4b2+asun2.1.0-4) frozen unstable; urgency=low
-
-  * binary-arch target now depends on pre-binary (closes:Bug#29508)
-
- -- Joel Klecker <espy@debian.org>  Tue, 17 Nov 1998 04:46:50 -0800
-
-netatalk (1.4b2+asun2.1.0-3) frozen unstable; urgency=low
-
-  * Now installs /usr/lib/atalk/pagecount.ps (closes:Bug#29323)
-
- -- Joel Klecker <espy@debian.org>  Thu, 12 Nov 1998 00:30:53 -0800
-
-netatalk (1.4b2+asun2.1.0-2) frozen unstable; urgency=low
-
-  * Should build from freshly unpacked source now (Bug#28810)
-
- -- Joel Klecker <espy@debian.org>  Sun,  1 Nov 1998 19:34:52 -0800
-
-netatalk (1.4b2+asun2.1.0-1) unstable; urgency=low
-  
-  * New upstream release.
-  * Incorporate megatron patch from Rob Browning (Bug#25598).
-  * Don't install /usr/include/netatalk on glibc 2.1 architectures.
-  * Fix paths in /etc/pam.d/netatalk file.
-
- -- Joel Klecker <espy@debian.org>  Thu, 29 Oct 1998 23:54:13 -0800
-
-netatalk (1.4b2+asun2.0a18.2-1) frozen unstable; urgency=low
-
-  * New "upstream" release.
-  * This does add new features, however, it also fixes at
-    least one nasty bug (Bug#13973).
-  * Applied patch which adds a command-line option to disable
-    CR/LF translation (thanks to Davide Welton and Jon Nelson).
-    (Note to release manager: this patch is applied so this
-     package has the exact functionality of netatalk-asun)
-  * Renamed libatalk-dev to libatalk1-dev.
-  * Symlinked /usr/man/man1/nbpunrgstr.1.gz to /usr/man/man1/nbprgstr.1.gz
-    to keep lintian happy.
-  * Changed the "lock directory" to /var/run and the names of the "lock files" to <foo>.pid,
-    since what the source calls locks are really the same as the .pid files other daemons
-    put in /var/run.
-  * This package provides all the functionality of netatalk-asun, and
-    it will replace netatalk-asun in the distribution.
-
- -- Joel Klecker <jk@espy.org>  Tue, 12 May 1998 19:31:54 -0700
-
-netatalk (1.4b2-5) frozen unstable; urgency=low
-
-  * New Maintainer (I can finally close bugs
-    I fixed in previous releases ;).
-  * Changed library package names again.
-  * Upgraded to Debian Policy 2.4.0.0.
-  * Moved conffiles to /etc/netatalk.
-  * Fixes almost all lintian warnings/errors.
-  * Cleaned up changelog.
-
- -- Joel Klecker <jk@espy.org>  Sun, 22 Mar 1998 21:50:00 -0800
-
-netatalk (1.4b2-4.5) unstable; urgency=low
-
-  * Non-maintainer release (again :>)
-  * Made libatalk14g-dev conflict with libc5-dev to fix overlap
-    (Bug:#17848)
-
- -- Joel Klecker <jk@espy.org>  Thu, 5 Feb 1998 20:42:51 -0800
-
-netatalk (1.4b2-4.4) unstable; urgency=low
-
-  * Yet Another non-maintainer release.
-  * Added patch to fix "dancing icon" problems with Macs running Mac OS 8.
-  * Changed comment in /etc/AppleVolumes.default (Bug:#15279)
-  * Implemented variable for "server name" in init script
-    (as suggested in Bug:#12024)
-  * Added a kluge to /etc/init.d/netatalk to remove kernel appletalk
-    module (if there is one) at stop and reinsert it at start, this
-    is needed or else netatalk will not start once stopped (Bug:#12142,11349)
-
- -- Joel Klecker <jk@espy.org>  Fri, 30 Jan 1998 07:50:00 -0800
-
-netatalk (1.4b2-4.3) unstable; urgency=low
-
-  * Non-maintainer release.
-  * Fixed dependencies.
-
- -- Joel Klecker <jk@espy.org>  Thu, 8 Jan 1998 16:14:17 -0800
-
-netatalk (1.4b2-4.2) unstable; urgency=low
-  
-  * Non-maintainer release.
-  * Changed library package names.
-
- -- Joel Klecker <jk@espy.org>  Wed, 7 Jan 1998 00:00:00 -0800
-
-netatalk (1.4b2-4.1) unstable; urgency=low
-
-  * Non-maintainer libc6 compile.
-
- -- Joel Klecker <jk@espy.org>  Tue, 6 Jan 1998 00:00:00 -0800
-
-netatalk (1.4b2-4) unstable; urgency=low
-
-  * Recompiled against newer PAM libraries.
-  * Added /etc/pam.d/samba.
-
- -- Klee Dienes <klee@debian.org>  Sat, 8 Mar 1997 01:17:09 -0500
-
-netatalk (1.4b2-3) unstable; urgency=low
-
-  * Added PAM support.
-  * Split into libatalk, libatalk-dev, and netatalk.
-  * Added patch from Randy Gobbel <gobbel@cogsci.ucsd.edu> to allow case
-    translation to be specified at config-time rather than compile time.
-    Note that configuration files that make use of this feature may not
-    work with other releases of netatalk, and that this feature may be
-    removed in the future if UMich rejects the patch or implements it
-    differently.
-  * Startup messages now conform to 'Standard for Console Messages' (fixes
-    #5399).
-  * No longer creates new subdirectories (to appease dpkg-buildpackage).
-
- -- Klee Dienes <klee@debian.org>  Wed, 26 Feb 1997 21:02:02 -0500
-
-netatalk (1.4b2-2) unstable; urgency=low
-
-  * Resend_request made external for libnatali.
-  * Added shared libraries.
-  * Next revision will split into libatalk, libatalk-dev, and netatalk.
-
- -- Klee Dienes <klee@debian.org>  Fri, 24 Jan 1997 22:37:22 -0500
-
-netatalk (1.4b2-1) unstable; urgency=low
-
-  * Updated to upstream version 1.4b2.
-  * Added preliminary PAM support (currently disabled).
-  * Made /etc/init.d/netatalk a conffile.
-  * Changed /etc/init.d/netatalk to complete only once appletalk services
-    are running.  Configurating an Appletalk interface can take many (> 15)
-    seconds, so the previous version would fork a process to configure the
-    interface and then start up the other Appletalk services.  Although
-    possibly controversial, this change is necessary so that packages like
-    ppr can be ensured that netatalk will be started before they run
-    without undue complication.
-
- -- Klee Dienes <klee@debian.org>  Sat, 2 Nov 1996 19:42:04 -0700
-
-netatalk (1.4b1-1) unstable; urgency=low
-
-  * Updated to new upstream version.
-  * Updated to new packaging format.
-
- -- Klee Dienes <klee@debian.org>  Wed, 2 Oct 1996 10:18:14 -0700
-
-netatalk (1.3.3-3);
-
-  * Fixed location of include files.
-
- -- Klee Dienes <klee@mit.edu>  Mon Jan  8 10:46:52 MST 1996
-
-netatalk (1.3.3-2);
-
-  * Fixed bug in postrm script.
-
- -- Klee Dienes <klee@mit.edu>  Thu Dec 21 08:22:24 MST 1995
-
-netatalk (1.3.3-1);
-
-  * Initial Release.
-
- -- Klee Dienes <klee@mit.edu>  Wed Dec 13 22:58:31 MST 1995
diff --git a/distrib/debian/control b/distrib/debian/control
deleted file mode 100644 (file)
index fa3de94..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-Source: netatalk
-Section: non-US
-Priority: extra
-Maintainer: Sebastian Rittau <srittau@debian.org>
-Standards-Version: 3.5.6.0
-Build-Depends: debhelper (>= 3.0.0), libdb3-dev, libwrap0-dev, libpam0g-dev, cracklib2-dev
-
-Package: netatalk
-Architecture: any
-Depends: netbase, timeout, libpam-modules, ${shlibs:Depends}, ${perl:Depends}
-Recommends: lsof, libpam-cracklib
-Suggests: tetex-base, quota
-Conflicts: netatalk-asun, libatalk14g, libatalk1
-Replaces: netatalk-asun, libatalk14, libatalk1
-Description: AppleTalk user binaries
- Netatalk is an implementation of the AppleTalk Protocol Suite for
- BSD-derived systems.  The current release contains support for
- EtherTalk Phase I and II, DDP, RTMP, NBP, ZIP, AEP, ATP, PAP, ASP, and
- AFP.
-
-Package: netatalk-dev
-Architecture: any
-Depends: netatalk (>= 1.5)
-Conflicts: netatalk (<< 1.5pre7-2), libatalk14g-dev, libatalk14-dev, netatalk-asun, libatalk1-dev
-Replaces: netatalk (<< 1.5pre7-2), libatalk14g-dev, libatalk14-dev, netatalk-asun, libatalk1-dev
-Description: AppleTalk library and development files
- Netatalk is an implementation of the AppleTalk Protocol Suite for
- BSD-derived systems.  The current release contains support for
- EtherTalk Phase I and II, DDP, RTMP, NBP, ZIP, AEP, ATP, PAP, ASP, and
- AFP.
-
diff --git a/distrib/debian/copyright b/distrib/debian/copyright
deleted file mode 100644 (file)
index c284410..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-This is the Debian GNU/Linux prepackaged version of netatalk.
-
-This package was originally put together by Joel 'epsy' Klecker.
-Current maintainer is Sebastian Rittau <srittau@debian.org>.
-
-The sources were obtained from CVS: cvs.netatalk.sourceforge.net.
-See the Netatalk homepage at <http://netatalk.sourceforge.net/> for
-anonymous CVS instructions.
-
-The following copyrights/licenses apply to this software:
-
-The GNU General Public License (GPL). See /usr/share/common-licenses/GPL
-for more information.
-
-This software includes software developed by the University of Michigan.
-
-Copyright (c) 1990,1996 Regents of The University of Michigan.
-All Rights Reserved.
-
-    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 appears in all copies and
-    that both that copyright notice and this permission notice appear
-    in supporting documentation, and that the name of The University
-    of Michigan not be used in advertising or publicity pertaining to
-    distribution of the software without specific, written prior
-    permission. This software is supplied as is without expressed or
-    implied warranties of any kind.
-
-This product includes software developed by the University of
-California, Berkeley and its contributors.
-
-Solaris code is encumbered by the following:
-    Copyright (C) 1996 by Sun Microsystems Computer Co.
-    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.  This software is
-    provided "as is" without express or implied warranty.
-
-Modifications for Appleshare IP and other files copyrighted by Adrian
-Sun are under the following copyright:
-
-    Copyright (c) 1997,1998,1999,2000 Adrian Sun (asun@cobalt.com)
-    All Rights Reserved.
-
-    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 appears in all copies and
-    that both that copyright notice and this permission notice appear
-    in supporting documentation. This software is supplied as is
-    without expressed or implied warranties of any kind.
-
-Research Systems Unix Group
-The University of Michigan
-c/o Wesley Craig
-535 W. William Street
-Ann Arbor, Michigan
-+1-313-764-2278
-netatalk@umich.edu
diff --git a/distrib/debian/cvs2deb.sh b/distrib/debian/cvs2deb.sh
deleted file mode 100755 (executable)
index 699131f..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-#!/bin/sh
-
-# Execute this script from the main netatalk source directory.
-
-set -e
-
-debiandir=distrib/debian
-
-if test ! -d libatalk; then
-  echo "Not in netatalk directory"
-  exit 1
-fi
-
-VERSION=`cat VERSION`
-DEBVERSION="${VERSION}cvs"
-DISTDIR="netatalk-$VERSION"
-DISTTGZ="netatalk_$DEBVERSION.orig.tar.gz"
-
-if test ! -f INSTALL; then
-  if test -e INSTALL; then
-    echo "INSTALL is in the way, please move it away"
-    exit 1
-  fi
-  touch INSTALL
-fi
-
-if test ! -x configure; then
-  ./autogen.sh
-fi
-
-if test ! -e Makefile; then
-  if test -x config.status; then
-    ./config.status
-  else
-    ./configure
-  fi
-fi
-
-make dist
-
-mv "netatalk-$VERSION.tar.gz" "$DISTTGZ"
-rm -rf "$DISTDIR" || true
-tar xzf "$DISTTGZ"
-
-for FILE in `find $debiandir/patches/*.patch`; do
-  patch --dir="$DISTDIR" --strip=1 <$FILE
-done
-
-cp -a "$debiandir" "$DISTDIR"
-rm -r "$DISTDIR/debian/CVS"
-rm -r "$DISTDIR/debian/patches"
-rm -r "$DISTDIR/debian/split-init"
-rm    "$DISTDIR/debian/cvs2deb.sh"
-
-cd $DISTDIR
-
-touch INSTALL
-
-automake
-
-dpkg-buildpackage -rfakeroot
-
-cd ..
-rm -r "$DISTDIR"
-rm INSTALL
diff --git a/distrib/debian/logcheck/ignore.d.server b/distrib/debian/logcheck/ignore.d.server
deleted file mode 100644 (file)
index bf7b562..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-afpd\[.*\]: ((dhx|dhx2) )?login: [[:alnum:]]+
-afpd\[.*\]: (server_child\[[[:digit:]]+\] [[:digit:]]+ )?(done|exited 1)
-afpd\[.*\]: [\.[:alnum:]]+ read, [\.[:alnum:]]+ written
-afpd\[.*\]: .*: Broken pipe
-afpd\[.*\]: .*: Connection reset by peer
-afpd\[.*\]: .*: Connection timed out
-afpd\[.*\]: .*: No route to host
-afpd\[.*\]: .*: No such file or directory
-afpd\[.*\]: .*: Permission denied
-afpd\[.*\]: .*: child timed out
-afpd\[.*\]: ASIP session:[[:digit:]]+\([[:digit:]]+\) from [\.:[:digit:]]+\([[:digit:]]+\)
-afpd\[.*\]: Connection terminated
-afpd\[.*\]: afp_openfork: ad_open: File Exists
-afpd\[.*\]: asp_alrm: [[:digit:]]+ timed out
-afpd\[.*\]: login [[:alnum:]]+ \(uid [[:digit:]]+, gid [[:digit:]]+\)
-afpd\[.*\]: login noauth
-afpd\[.*\]: logout [[:alnum:]]+
-afpd\[.*\]: registering [[:alnum:]]+ \(uid [[:digit:]]+\) on [\.[:digit:]]+ as /.+/net[\.[:digit:]]+node[[:digit:]]+
-afpd\[.*\]: session from [\.:[:digit:]]+ on [\.:[:digit:]]+
-afpd\[.*\]: uams_dhx_pam.c :PAM: PAM (Auth OK!|Success -- Success)
-afpd\[.*\]: uams_dhx2_pam.c :PAM: PAM (Auth OK!|Success -- Success)
-afpd\[.*\]: using codepage directory: /etc/netatalk/nls/maccode\.[\.[:alnum:]-]+
-atalkd\[.*\]: .*: Network is unreachable
-atalkd\[.*\]: zip gnireply from [\.[:digit:]]+ \(.* [[:digit:]]\)
-atalkd\[.*\]: zip ignoring gnireply
-papd\[.*\]: child [[:digit:]]+ for ".+" from [\.[:digit:]]+
-papd\[.*\]: child [[:digit:]]+ done
diff --git a/distrib/debian/logcheck/violations.ignore.d b/distrib/debian/logcheck/violations.ignore.d
deleted file mode 100644 (file)
index 98638a7..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-afpd\[.*\]: afp_die: asp_shutdown: Connection timed out
-afpd\[.*\]: afp_getsrvrparms: stat /.+/: Permission denied
-afpd\[.*\]: dsi_stream_read\([[:digit:]]+\): Permission denied
-afpd\[.*\]: getforkparms: (ad_refresh|of_find): Permission denied
diff --git a/distrib/debian/netatalk-dev.docs b/distrib/debian/netatalk-dev.docs
deleted file mode 100644 (file)
index 976f224..0000000
+++ /dev/null
@@ -1 +0,0 @@
-doc/DEVELOPER
diff --git a/distrib/debian/netatalk-dev.files b/distrib/debian/netatalk-dev.files
deleted file mode 100644 (file)
index a4f3f2b..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-usr/bin/netatalk-config
-usr/include/atalk/adouble.h
-usr/include/atalk/aep.h
-usr/include/atalk/afp.h
-usr/include/atalk/asp.h
-usr/include/atalk/atp.h
-usr/include/atalk/cnid.h
-usr/include/atalk/compat.h
-usr/include/atalk/ddp.h
-usr/include/atalk/dsi.h
-usr/include/atalk/nbp.h
-usr/include/atalk/netddp.h
-usr/include/atalk/pap.h
-usr/include/atalk/paths.h
-usr/include/atalk/rtmp.h
-usr/include/atalk/server_child.h
-usr/include/atalk/uam.h
-usr/include/atalk/util.h
-usr/include/atalk/zip.h
-usr/include/netatalk/aarp.c
-usr/include/netatalk/aarp.h
-usr/include/netatalk/at_control.c
-usr/include/netatalk/at_proto.c
-usr/include/netatalk/at_var.h
-usr/include/netatalk/ddp.h
-usr/include/netatalk/ddp_input.c
-usr/include/netatalk/ddp_output.c
-usr/include/netatalk/ddp_usrreq.c
-usr/include/netatalk/ddp_var.h
-usr/include/netatalk/endian.h
-usr/include/netatalk/phase2.h
-usr/lib/libatalk.a
-usr/lib/libatalk.la
-usr/lib/netatalk/uams_*.la
-usr/lib/netatalk/uams_*.a
-usr/share/aclocal
-usr/share/man/man1/netatalk-config.1
-usr/share/man/man3
-usr/share/man/man4
diff --git a/distrib/debian/netatalk.dirs b/distrib/debian/netatalk.dirs
deleted file mode 100644 (file)
index b8ce978..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-etc/default
-etc/logcheck/ignore.d.server
-etc/logcheck/ignore.d.workstation
-etc/logcheck/violations.ignore.d
diff --git a/distrib/debian/netatalk.docs b/distrib/debian/netatalk.docs
deleted file mode 100644 (file)
index c8a19c9..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-BUGS
-CHANGES
-CONTRIBUTORS
-TODO
-doc/CONFIGURE
-doc/FAQ
-doc/README.hidden-items
-doc/README.platforms
diff --git a/distrib/debian/netatalk.examples b/distrib/debian/netatalk.examples
deleted file mode 100644 (file)
index 43e3fc4..0000000
+++ /dev/null
@@ -1 +0,0 @@
-contrib/printing/add_netatalk_printer
diff --git a/distrib/debian/netatalk.files b/distrib/debian/netatalk.files
deleted file mode 100644 (file)
index 4fddf68..0000000
+++ /dev/null
@@ -1,94 +0,0 @@
-etc/netatalk/AppleVolumes.default
-etc/netatalk/AppleVolumes.system
-etc/netatalk/afpd.conf
-etc/netatalk/atalkd.conf
-etc/netatalk/papd.conf
-etc/netatalk/nls
-etc/pam.d/netatalk
-usr/bin/achfile
-usr/bin/adv1tov2
-usr/bin/aecho
-usr/bin/afile
-usr/bin/apple_cp
-usr/bin/apple_mv
-usr/bin/apple_rm
-usr/bin/cleanappledouble.pl
-usr/bin/getzones
-usr/bin/macusers
-usr/bin/makecode
-usr/bin/megatron
-usr/bin/pap
-usr/bin/papstatus
-usr/bin/parsecode
-usr/bin/psorder
-usr/bin/nbplkup
-usr/bin/nbprgstr
-usr/bin/nbpunrgstr
-usr/bin/nu
-usr/bin/unbin
-usr/bin/unhex
-usr/bin/unsingle
-usr/bin/hqx2bin
-usr/bin/single2bin
-usr/bin/macbinary
-usr/bin/binheader
-usr/bin/nadheader
-usr/lib/atalk/filters/etc2ps.sh
-usr/lib/atalk/filters/ofpap
-usr/lib/atalk/filters/ifpap
-usr/lib/atalk/filters/tfpap
-usr/lib/atalk/filters/ifpaprev
-usr/lib/atalk/filters/tfpaprev
-usr/lib/atalk/filters/ofwpap
-usr/lib/atalk/filters/ifwpap
-usr/lib/atalk/filters/tfwpap
-usr/lib/atalk/filters/ifwpaprev
-usr/lib/atalk/filters/tfwpaprev
-usr/lib/atalk/filters/ofmpap
-usr/lib/atalk/filters/ifmpap
-usr/lib/atalk/filters/tfmpap
-usr/lib/atalk/filters/ifmpaprev
-usr/lib/atalk/filters/tfmpaprev
-usr/lib/atalk/filters/ofwmpap
-usr/lib/atalk/filters/ifwmpap
-usr/lib/atalk/filters/tfwmpap
-usr/lib/atalk/filters/ifwmpaprev
-usr/lib/atalk/filters/tfwmpaprev
-usr/lib/netatalk/uams_*.so
-usr/sbin/afpd
-usr/sbin/atalkd
-usr/sbin/papd
-usr/sbin/psf
-usr/sbin/psa
-usr/sbin/timelord
-usr/share/man/man1/aecho.1
-usr/share/man/man1/afile.1
-usr/share/man/man1/getzones.1
-usr/share/man/man1/megatron.1
-usr/share/man/man1/nbp.1
-usr/share/man/man1/pap.1
-usr/share/man/man1/achfile.1
-usr/share/man/man1/acleandir.1
-usr/share/man/man1/hqx2bin.1
-usr/share/man/man1/macbinary.1
-usr/share/man/man1/nbplkup.1
-usr/share/man/man1/nbprgstr.1
-usr/share/man/man1/nbpunrgstr.1
-usr/share/man/man1/papstatus.1
-usr/share/man/man1/psorder.1
-usr/share/man/man1/single2bin.1
-usr/share/man/man1/unbin.1
-usr/share/man/man1/unhex.1
-usr/share/man/man1/unsingle.1
-usr/share/man/man5/afpd.conf.5
-usr/share/man/man5/atalkd.conf.5
-usr/share/man/man5/papd.conf.5
-usr/share/man/man5/AppleVolumes.default.5
-usr/share/man/man8/pap.8
-usr/share/man/man8/papd.8
-usr/share/man/man8/papstatus.8
-usr/share/man/man8/psf.8
-usr/share/man/man8/timelord.8
-usr/share/man/man8/afpd.8
-usr/share/man/man8/atalkd.8
-usr/share/netatalk
diff --git a/distrib/debian/netatalk.init b/distrib/debian/netatalk.init
deleted file mode 100644 (file)
index fe5e1c7..0000000
+++ /dev/null
@@ -1,89 +0,0 @@
-#!/bin/sh
-
-test -x /usr/sbin/atalkd || exit 0
-
-# Set defaults. Please change these options in /etc/default/netatalk.
-AFPD_UAMLIST="-U uams_clrtxt.so,uams_randnum.so"
-AFPD_GUEST=nobody
-AFPD_MAX_CLIENTS=20
-ATALK_NAME=`/bin/hostname --short`
-
-# Read in netatalk configuration.
-if [ -f /etc/default/netatalk ]; then
-  . /etc/default/netatalk
-fi
-
-OPTIONS_AFP="$AFPD_UAMLIST -g $AFPD_GUEST -c $AFPD_MAX_CLIENTS -n $ATALK_NAME"
-
-case "$1" in
-    start)
-       if [ "$ATALKD_RUN" = "yes" ]; then
-               # Quickly probe for appletalk if it was supposed to be loaded
-               if grep '^appletalk$' /etc/modules; then
-                       /sbin/modprobe appletalk || echo "[could not load appletalk module]"
-               fi
-
-               echo -n "Starting AppleTalk Daemons (this will take a while):"
-               /usr/sbin/atalkd
-               echo -n " atalkd"
-
-               /usr/bin/nbprgstr -p 4 "$ATALK_NAME:Workstation"
-               /usr/bin/nbprgstr -p 4 "$ATALK_NAME:netatalk"
-       fi
-
-       if [ "$AFPD_RUN" = "yes" ]; then
-               /usr/sbin/afpd $OPTIONS_AFP
-               echo -n " afpd"
-       fi
-
-       if [ "$ATALKD_RUN" = "yes" -a "$PAPD_RUN" = "yes" ]; then
-               /usr/sbin/papd
-               echo -n " papd"
-       fi
-
-       if [ "$TIMELORD_RUN" = "yes" ]; then
-               /usr/sbin/timelord
-               echo -n " timelord"
-       fi
-
-       echo "."
-    ;;
-
-    stop)
-       echo -n "Stopping AppleTalk Daemons:"
-       echo -n " afpd"; \
-       start-stop-daemon --stop --quiet --oknodo --exec /usr/sbin/afpd
-
-       echo -n " papd"; \
-       start-stop-daemon --stop --quiet --oknodo --exec /usr/sbin/papd
-
-       echo -n " timelord"; \
-       start-stop-daemon --stop --quiet --oknodo --exec /usr/sbin/timelord
-
-       echo -n " atalkd"; \
-       start-stop-daemon --stop --quiet --oknodo --exec /usr/sbin/atalkd
-
-       echo "."
-    ;;
-    
-    restart)
-       $0 force-reload
-    ;;
-
-    force-reload)
-       echo -n "Restarting AppleTalk Daemons (this will take a while)"
-       /etc/init.d/netatalk stop > /dev/null 2>&1
-       echo -n "."
-       sleep 2
-       echo -n "."
-       if /etc/init.d/netatalk start > /dev/null 2>&1; then
-               echo "done."
-       fi
-    ;;
-  
-    *)
-       echo "Usage: /etc/init.d/netatalk {start|stop|restart|force-reload}" >&2
-       exit 1
-    ;;
-esac
-
diff --git a/distrib/debian/netatalk.links b/distrib/debian/netatalk.links
deleted file mode 100644 (file)
index cc12933..0000000
+++ /dev/null
@@ -1 +0,0 @@
-etc/logcheck/ignore.d.server/netatalk etc/logcheck/ignore.d.workstation/netatalk
diff --git a/distrib/debian/netatalk.undocumented b/distrib/debian/netatalk.undocumented
deleted file mode 100644 (file)
index eb6a7b8..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-binheader.1
-cleanappledouble.pl.1
-cnid_didname_verify.1
-macusers.1
-makecode.1
-nadheader.1
-nu.1
-parsecode.1
-psa.8
diff --git a/distrib/debian/patches/add_printer.patch b/distrib/debian/patches/add_printer.patch
deleted file mode 100644 (file)
index bbfb908..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
---- netatalk.cvs/contrib/printing/add_netatalk_printer
-+++ netatalk.debian/contrib/printing/add_netatalk_printer
-@@ -43,10 +43,10 @@
- # allow for the env NETATALKHOME to override the guessed one from above
--NETATALKHOME=${NETATALKHOME:-$RUNHOME}
-+NETATALKHOME=${NETATALKHOME:-/usr}
- export NETATALKHOME
--PATH=/bin:${PATH}:${NETATALKHOME}/bin:${NETATALKHOME}/etc:${NETATALKHOME}/etc/filters:/usr/lib:/usr/sbin
-+PATH=/bin:${PATH}:${NETATALKHOME}/bin:${NETATALKHOME}/etc:${NETATALKHOME}/lib/atalk/filters:/usr/lib:/usr/sbin
- if [ ! -x ${NETATALKHOME}/bin/pap ]; then
-        echo "OOPS:     I don't see ${NETATALKHOME}/bin/pap ,"
-@@ -66,7 +66,7 @@
- echo ""
- echo "Looking for LaserWriters in Zone ${ZONE} ..."
--$NETATALKHOME/bin/nbplkup ":LaserWriter@${ZONE}"
-+${NETATALKHOME}/bin/nbplkup ":LaserWriter@${ZONE}"
- echo ""
- echo "Enter AppleTalk printer name: \c"
-@@ -80,7 +80,7 @@
- echo "checking nbplkup ${DEST}:LaserWriter@${ZONE}"
- echo ""
--TestDEST=`$NETATALKHOME/bin/nbplkup "${DEST}:LaserWriter@${ZONE}"`
-+TestDEST=`${NETATALKHOME}/bin/nbplkup "${DEST}:LaserWriter@${ZONE}"`
- echo "${TestDEST}"
- echo ""
-@@ -237,7 +237,7 @@
- Printer types: Netatalk
- Printers: any
- Filter type: fast
--Command: ${NETATALKHOME}/etc/filters/ifpap 2>&1 > /dev/null
-+Command: ${NETATALKHOME}/lib/atalk/filters/ifpap 2>&1 > /dev/null
- EOF
-        chown lp:lp /etc/lp/fd/netatalk.fd
-        chmod 664   /etc/lp/fd/netatalk.fd
-@@ -257,7 +257,7 @@
- Printer types: Netatalk-R
- Printers: any
- Filter type: fast
--Command: "/usr/lib/lp/postscript/postreverse | ${NETATALKHOME}/etc/filters/ifpap 2>&1 >/dev/null"
-+Command: "/usr/lib/lp/postscript/postreverse | ${NETATALKHOME}/lib/atalk/filters/ifpap 2>&1 >/dev/null"
- EOF
-        chown lp:lp /etc/lp/fd/netatalk-r.fd
-        chmod 664   /etc/lp/fd/netatalk-r.fd
diff --git a/distrib/debian/patches/etc2ps.sh.patch b/distrib/debian/patches/etc2ps.sh.patch
deleted file mode 100644 (file)
index c9c76d7..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
---- netatalk.cvs/etc/psf/etc2ps.sh
-+++ netatalk.debian/etc/psf/etc2ps.sh
-@@ -9,11 +9,11 @@
- # tag in the case.
- #
--DVIPSPATH=/usr/local/tex/bin
--DVIPS=/usr/local/tex/bin/dvips
-+DVIPSPATH=/usr/bin
-+DVIPS=/usr/bin/dvips
- DVIPSARGS="-f -q"
--TROFF2PS=/usr/local/psroff/troff2/troff2ps
-+TROFF2PS=/usr/bin/troff2ps
- TROFF2PSARGS="-Z -O-.10"
- PATH=/usr/bin:$DVIPSPATH; export PATH
diff --git a/distrib/debian/patches/filterdir.patch b/distrib/debian/patches/filterdir.patch
deleted file mode 100644 (file)
index 65855d9..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
---- netatalk.cvs/etc/psf/Makefile.am
-+++ netatalk.debian/etc/psf/Makefile.am
-@@ -1,8 +1,11 @@
- # Makefile.am for etc/psf/
-+filterdir = $(libdir)/atalk/filters
-+
- sbin_PROGRAMS = psf psa
- pkgdata_DATA = pagecount.ps
-+filter_SCRIPTS = etc2ps.sh
- psf_SOURCES = psf.c
- psa_SOURCES = psa.c
-@@ -26,14 +29,16 @@
- # install sections for links
- #
-+# srittau: We do some dirty hard-coding for Debian to maintain compability.
- install-exec-local:
-+       $(mkinstalldirs) $(DESTDIR)$(filterdir)
-        @list='$(psf_LINKS)'; for l in $$list; do \
--               $(LN_S) -f psf $(DESTDIR)$(sbindir)/$$l;  \
-+               $(LN_S) -f ../../../sbin/psf $(DESTDIR)$(filterdir)/$$l;  \
-        done
- #
diff --git a/distrib/debian/patches/netatalk.conf.patch b/distrib/debian/patches/netatalk.conf.patch
deleted file mode 100644 (file)
index 5487084..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
---- netatalk.cvs/config/netatalk.conf
-+++ netatalk.debian/config/netatalk.conf
-@@ -6,7 +6,7 @@
- # NOTE: if you're zone has spaces in it, you're better off specifying
- #       it in afpd.conf
- #ATALK_ZONE=@zone
--ATALK_NAME=`echo ${HOSTNAME}|cut -d. -f1`
-+ATALK_NAME=`/bin/hostname --short`
- # specify this if you don't want guest, clrtxt, and dhx
- # available options: uams_guest.so, uams_clrtxt.so, uams_dhx.so, 
-@@ -21,6 +21,3 @@
- PAPD_RUN=yes
- AFPD_RUN=yes
- TIMELORD_RUN=no
--
--# Control whether the daemons are started in the background
--ATALK_BGROUND=no
diff --git a/distrib/debian/patches/netatalk.pamd.patch b/distrib/debian/patches/netatalk.pamd.patch
deleted file mode 100644 (file)
index b1758d1..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
---- netatalk.cvs/config/netatalk.pamd
-+++ netatalk.debian/config/netatalk.pamd
-@@ -1,6 +1,6 @@
- #%PAM-1.0
--auth       required    /lib/security/pam_unix.so
--account    required    /lib/security/pam_unix.so 
--#password   required   /lib/security/pam_cracklib.so
--#password   required   /lib/security/pam_unix.so use_authtok
--session    required    /lib/security/pam_unix.so 
-+auth       required    pam_unix.so
-+account    required    pam_unix.so 
-+password   required    pam_cracklib.so
-+password   required    pam_unix.so use_authtok
-+session    required    pam_unix.so 
diff --git a/distrib/debian/patches/psf.8.patch b/distrib/debian/patches/psf.8.patch
deleted file mode 100644 (file)
index 3cc2ab8..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
---- netatalk.cvs/man/man8/psf.8.tmpl
-+++ netatalk.debian/man/man8/psf.8.tmpl
-@@ -90,13 +90,13 @@
- .RS
- .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:\\
--    :of=:LIBDIR:/filters/ofpap:\\
--    :if=:LIBDIR:/filters/ifpaprev:\\
--    :tf=:LIBDIR:/filters/tfpaprev:\\
--    :df=:LIBDIR:/filters/dfpaprev:
-+    :sd=/var/spool/lpd/laser:\\
-+    :lp=/var/spool/lpd/laser/null:\\
-+    :lf=/var/log/lpd-errs:pw#80:hl:\\
-+    :of=:LIBDIR:/atalk/filters/ofpap:\\
-+    :if=:LIBDIR:/atalk/filters/ifpaprev:\\
-+    :tf=:LIBDIR:/atalk/filters/tfpaprev:\\
-+    :df=:LIBDIR:/atalk/filters/dfpaprev:
- .fi
- .RE
- .sp
diff --git a/distrib/debian/rules b/distrib/debian/rules
deleted file mode 100755 (executable)
index 824b41d..0000000
+++ /dev/null
@@ -1,99 +0,0 @@
-#! /usr/bin/make -f
-
-# Uncomment the following line to enable OpenSSL support. (If it's installed.)
-#USE_SSL=yes
-
-# Uncomment this to turn on verbose mode.
-#export DH_VERBOSE=1
-
-# This is the debhelper compatability version to use.
-export DH_COMPAT=3
-
-# support the DEB_BUILD_OPTIONS variable (partly stolen from gnome-utils)
-CFLAGS := -O2
-LDFLAGS :=
-ifneq (,$(findstring debug,$(DEB_BUILD_OPTIONS)))
-  CFLAGS += -g
-  LDFLAGS += -g
-endif
-export CFLAGS
-export LDFLAGS
-
-CONFIGURE_FLAGS = \
-       --with-shadow --enable-fhs --sysconfdir=/etc/netatalk           \
-       --with-tcp-wrappers --mandir=/usr/share/man --prefix=/usr       \
-       --enable-timelord --enable-overwrite                            \
-       --with-cracklib=/var/cache/cracklib/cracklib_dict
-ifneq "x$(USE_SSL)" "xyes"
-CONFIGURE_FLAGS += --without-ssl-dir
-endif
-
-configure: configure-stamp
-configure-stamp:
-       dh_testdir
-
-       ./configure $(CONFIGURE_FLAGS)
-
-       touch configure-stamp
-
-build: configure-stamp build-stamp
-build-stamp:
-       dh_testdir
-
-       $(MAKE)
-
-       touch build-stamp
-
-clean:
-       dh_testdir
-       dh_testroot
-       rm -f build-stamp configure-stamp
-
-       -$(MAKE) distclean
-
-       dh_clean
-
-install: build
-       dh_testdir
-       dh_testroot
-       dh_clean -k
-       dh_installdirs
-
-       $(MAKE) install DESTDIR=$(CURDIR)/debian/tmp
-
-       # Manually move a file that would get installed in the wrong place.
-       mv debian/tmp/etc/netatalk/netatalk.conf debian/netatalk/etc/default/netatalk
-
-       # Install logcheck files
-       install -m 644 debian/logcheck/ignore.d.server debian/netatalk/etc/logcheck/ignore.d.server/netatalk
-       install -m 644 debian/logcheck/violations.ignore.d debian/netatalk/etc/logcheck/violations.ignore.d/netatalk
-
-# Build architecture-independent files here.
-binary-indep: build install
-# We have nothing to do by default.
-
-binary-arch: build install
-       dh_testdir
-       dh_testroot
-       dh_movefiles
-
-       dh_installdocs
-       dh_installexamples
-       dh_installinit --update-rcd-params="defaults 50 50"
-       dh_installman
-       dh_undocumented
-       dh_installchangelogs ChangeLog
-       dh_link
-       dh_strip
-       dh_compress
-       dh_fixperms
-       dh_makeshlibs
-       dh_installdeb
-       dh_shlibdeps
-       dh_perl
-       dh_gencontrol
-       dh_md5sums
-       dh_builddeb
-
-binary: binary-indep binary-arch
-.PHONY: build clean binary-indep binary-arch binary install configure
index ef9ee0ddfaa9a6f2eca475ff8ae4cd171b328046..5ad0d37e4891e430f26160929a79af8324ee4975 100644 (file)
@@ -80,7 +80,7 @@ endif
 if USE_SUSE
 
 sysvdir        = /etc/init.d
-sysv_SCRIPTS = atalk
+sysv_SCRIPTS = netatalk
 
 $(sysv_SCRIPTS): rc.atalk.suse
        cp -f rc.atalk.suse $(sysv_SCRIPTS)
@@ -102,7 +102,7 @@ endif
 if USE_COBALT
 
 sysvdir        = /etc/rc.d/init.d
-sysv_SCRIPTS = atalk
+sysv_SCRIPTS = netatalk
 
 $(sysv_SCRIPTS): rc.atalk.cobalt
        cp -f rc.atalk.cobalt $(sysv_SCRIPTS)
@@ -123,7 +123,7 @@ endif
 if USE_TRU64
 
 sysvdir        = /etc/init.d
-sysv_SCRIPTS = atalk
+sysv_SCRIPTS = netatalk
 
 $(sysv_SCRIPTS): rc.atalk.tru64
        cp -f rc.atalk.tru64 $(sysv_SCRIPTS)
@@ -207,18 +207,18 @@ endif
 if USE_GENTOO
 
 sysvdir = /etc/init.d
-sysv_SCRIPTS = atalk
+sysv_SCRIPTS = netatalk
 
 $(sysv_SCRIPTS): rc.atalk.gentoo
        cp -f rc.atalk.gentoo $(sysv_SCRIPTS)
        chmod a+x $(sysv_SCRIPTS)
 
 install-data-hook:
-       -rc-update add $(sysv_SCRIPTS) default
+#      -rc-update add $(sysv_SCRIPTS) default
 
 uninstall-startup:
-       -rc-update del $(sysv_SCRIPTS) default
-       rm -f $(DESTDIR)$(sysvdir)/$(sysv_SCRIPTS)
+#      -rc-update del $(sysv_SCRIPTS) default
+#      rm -f $(DESTDIR)$(sysvdir)/$(sysv_SCRIPTS)
 
 endif
 
index 05010b7ba320b9b6f3cbfad4b1af6177f8287553..6a0f489a27db73014cf0661c683a1e3f98913f94 100755 (executable)
 ##     /usr/etc/modload -sym :ETCDIR:/netatalk.o;
 ##fi
 
+ATALK_NAME=`hostname|sed 's/\..*$//'`
+ATALK_UNIX_CHARSET='LOCALE'
+ATALK_MAC_CHARSET='MAC_ROMAN'
+
+CNID_METAD_RUN=yes
+AFPD_RUN=yes
+AFPD_MAX_CLIENTS=20
+AFPD_UAMLIST="-U uams_dhx.so,uams_dhx2.so"
+AFPD_GUEST=nobody
+CNID_CONFIG="-l log_note"
+
+ATALKD_RUN=no
+PAPD_RUN=no
+TIMELORD_RUN=no
+#A2BOOT_RUN=no
+ATALK_ZONE=
+#ATALK_BGROUND=no
+
 netatalk_conf=":ETCDIR:/netatalk.conf"
 
 [ -f ${netatalk_conf} ] && . ${netatalk_conf}
@@ -26,8 +44,8 @@ if [ -x :SBINDIR:/atalkd ]; then
 fi
 
 if [ -x :BINDIR:/nbprgstr ]; then
-       :BINDIR:/nbprgstr -p 4 `hostname|sed 's/\..*$//'`:Workstation
-       :BINDIR:/nbprgstr -p 4 `hostname|sed 's/\..*$//'`:netatalk
+       :BINDIR:/nbprgstr -p 4 ${ATALK_NAME}:Workstation
+       :BINDIR:/nbprgstr -p 4 ${ATALK_NAME}:netatalk
        echo -n ' nbprgstr'
 fi
 fi
@@ -37,12 +55,14 @@ if [ -x :SBINDIR:/papd -a X"${PAPD_RUN}" != X"no" ]; then
 fi
 
 if [ -x :SBINDIR:/cnid_metad -a X"${CNID_METAD_RUN}" != X"no" ]; then
-    :SBINDIR:/cnid_metad $CNID_CONFIG
-    echo -n ' cnid_metad'
+       :SBINDIR:/cnid_metad $CNID_CONFIG
+       echo -n ' cnid_metad'
 fi
 
 if [ -x :SBINDIR:/afpd -a X"${AFPD_RUN}" != X"no" ]; then
-       :SBINDIR:/afpd;         echo -n ' afpd'
+       :SBINDIR:/afpd ${AFPD_UAMLIST} -g ${AFPD_GUEST} \
+           -c ${AFPD_MAX_CLIENTS} -n ${ATALK_NAME}${ATALK_ZONE}
+       echo -n ' afpd'
 fi
 
 if [ -x :SBINDIR:/timelord -a X"${TIMELORD_RUN}" != X"no" ]; then
index b9654764c33813f9f69de6491a0f909df8b5bcab..a9fafd1320b8a2e4429b1295dc0bf830102212b9 100644 (file)
@@ -18,22 +18,29 @@ NAME=netatalk
 SCRIPTNAME=/etc/init.d/$NAME
 
 # Guard to prevent execution if netatalk was removed.
-test -x :SBINDIR:/atalkd || exit 0
+test -x :SBINDIR:/afpd || exit 0
 
 # Set defaults. Please change these options in /etc/default/netatalk
+ATALK_NAME=`/bin/hostname --short`
+ATALK_UNIX_CHARSET='LOCALE'
+ATALK_MAC_CHARSET='MAC_ROMAN'
+
+CNID_METAD_RUN=yes
+AFPD_RUN=yes
+AFPD_MAX_CLIENTS=50
 AFPD_UAMLIST="-U uams_dhx2.so"
 AFPD_GUEST=nobody
-AFPD_MAX_CLIENTS=50
+CNID_CONFIG="-l log_note"
+
+ATALKD_RUN=no
+PAPD_RUN=no
+TIMELORD_RUN=no
+#A2BOOT_RUN=no
 ATALK_ZONE=
-ATALK_NAME=`/bin/hostname --short`
 ATALK_BGROUND=no
-CNID_METAD_RUN=yes
-ATALK_MAC_CHARSET='MAC_ROMAN'
-ATALK_UNIX_CHARSET='LOCALE'
 
-# /etc/default/netatalk expects hostname in $HOSTNAME by default
+# old /etc/default/netatalk expected hostname in $HOSTNAME by default
 HOSTNAME=`/bin/hostname`
-# next netatalk 2.2 will not expect $HOSTNAME.
 
 # Read in netatalk configuration.
 if [ -f /etc/default/netatalk ]; then
@@ -46,7 +53,7 @@ atalk_startup() {
 
        # Try to load the AppleTalk kernel module if it was intended.
     if grep -q '^appletalk$' /etc/modules; then
-        /sbin/modprobe appletalk || echo "[could not load appletalk module]"
+               /sbin/modprobe appletalk || echo "[could not load appletalk module]"
     fi
 
        # Start atalkd server.
@@ -86,7 +93,7 @@ atalk_startup() {
 
 case "$1" in
        start)
-               if test "x$ATALK_BGROUND" = "xyes"; then
+               if [ "x$ATALK_BGROUND" = "xyes" -a "x$ATALKD_RUN" = "xyes" ]; then
                        echo "Starting Netatalk services in the background."
                        atalk_startup >/dev/null &
                else
@@ -104,16 +111,20 @@ case "$1" in
                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:/papd; then
+                    echo -n " papd"
+                   start-stop-daemon --stop --quiet --oknodo --exec :SBINDIR:/papd
+               fi
        
                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
+               if test -x :SBINDIR:/atalkd; then
+                    echo -n " atalkd"
+                   start-stop-daemon --stop --quiet --oknodo --exec :SBINDIR:/atalkd
+               fi
        
                echo "."
        ;;
index 200b0c24636e91b0b050fc3a05a37ee50bdd7dcd..5ed475c556acff5b1c9b4ed3a0c83c86d9c6f148 100644 (file)
@@ -5,6 +5,24 @@
 # its data structures must have time to stablize before running the
 # other processes.
 
+ATALK_NAME=`echo ${HOSTNAME}|cut -d. -f1`
+ATALK_UNIX_CHARSET='LOCALE'
+ATALK_MAC_CHARSET='MAC_ROMAN'
+
+CNID_METAD_RUN=yes
+AFPD_RUN=yes
+AFPD_MAX_CLIENTS=20
+AFPD_UAMLIST="-U uams_dhx.so,uams_dhx2.so"
+AFPD_GUEST=nobody
+CNID_CONFIG="-l log_note"
+
+ATALKD_RUN=no
+PAPD_RUN=no
+TIMELORD_RUN=no
+#A2BOOT_RUN=no
+ATALK_ZONE=
+ATALK_BGROUND=no
+
 depend() {
        need net
        use logger dns
@@ -61,7 +79,7 @@ atalk_startup () {
 start () {
        . :ETCDIR:/netatalk.conf
 
-        if [ x"${ATALK_BGROUND}" = x"yes" ]; then
+        if [ x"${ATALK_BGROUND}" = x"yes" -a "${ATALKD_RUN}" != "no" ]; then
             echo "Starting netatalk in the background ... "
             atalk_startup >& /dev/null &
         else
index dfeed4cae5150eb2a2104fb797b5a1c0a331cc1a..79b613bd69b614afb1200af5c1f07c67946ddd52 100644 (file)
@@ -19,6 +19,25 @@ ATALK_SBIN=:SBINDIR:
 # Source networking configuration.
 . /etc/sysconfig/network
 
+# default
+ATALK_NAME=`echo ${HOSTNAME}|cut -d. -f1`
+ATALK_UNIX_CHARSET='LOCALE'
+ATALK_MAC_CHARSET='MAC_ROMAN'
+
+CNID_METAD_RUN=yes
+AFPD_RUN=yes
+AFPD_MAX_CLIENTS=20
+AFPD_UAMLIST="-U uams_dhx.so,uams_dhx2.so"
+AFPD_GUEST=nobody
+CNID_CONFIG="-l log_note"
+
+ATALKD_RUN=no
+PAPD_RUN=no
+TIMELORD_RUN=no
+A2BOOT_RUN=no
+ATALK_ZONE=
+ATALK_BGROUND=no
+
 # read in netatalk configuration
 if [ -f ${ATALK_CONF_DIR}/netatalk.conf ]; then
     . ${ATALK_CONF_DIR}/netatalk.conf
@@ -39,21 +58,16 @@ atalk_startup() {
          exit 1;
     fi
 
-    if [ ! -x ${ATALK_SBIN}/atalkd ]; then
-         # Quickly probe for appletalk and warn if we can't find it
-         #/sbin/modprobe appletalk || echo "[could not load appletalk module]"
-         # Check for IP Encapsulation support
-         #/sbin/modprobe ipddp || echo "[could not load IP encapsulation]"
-         echo "[${ATALK_SBIN}/atalkd not found. Check for permissions]";
-         exit 4;
-    fi
-
     if [ ! -f ${ATALK_CONF_DIR}/netatalk.conf ]; then
          echo "[${ATALK_CONF_DIR}/netatalk.conf not found]";
          exit 6;
     fi
 
-    if [ x"${ATALKD_RUN}" != x"no" ]; then 
+    if [ x"${ATALKD_RUN}" != x"no" -a -x ${ATALK_SBIN}/atalkd ]; then 
+         # Quickly probe for appletalk and warn if we can't find it
+         #/sbin/modprobe appletalk || echo "[could not load appletalk module]"
+         # Check for IP Encapsulation support
+         #/sbin/modprobe ipddp || echo "[could not load IP encapsulation]"
        echo -n "  Starting atalkd:"
        daemon ${ATALK_SBIN}/atalkd
        RETVAL_ATALKD=$?
@@ -125,7 +139,7 @@ atalk_startup() {
 case "$1" in
 'start')
        echo -n 'Starting Netatalk services: '
-       if [ x"${ATALK_BGROUND}" = x"yes" ]; then 
+       if [ x"${ATALK_BGROUND}" = x"yes" -a x"${ATALKD_RUN}" != x"no" ]; then 
            echo -n "(backgrounded)"
            atalk_startup >& /dev/null &
        else
index c9a0bec35039219b4841d3c0b5c3de90bc4d85f9..886591bcd8a98a7067d1f09967df84d3ea3393d8 100755 (executable)
@@ -30,6 +30,25 @@ test -f /etc/rc.status && . /etc/rc.status
 return=$rc_done
 }
 
+ATALK_NAME=`hostname|sed 's/\..*$//'`
+ATALK_UNIX_CHARSET='LOCALE'
+ATALK_MAC_CHARSET='MAC_ROMAN'
+
+CNID_METAD_RUN=yes
+AFPD_RUN=yes
+AFPD_MAX_CLIENTS=20
+AFPD_UAMLIST="-U uams_dhx.so,uams_dhx2.so"
+AFPD_GUEST=nobody
+CNID_CONFIG="-l log_note"
+
+ATALKD_RUN=no
+PAPD_RUN=no
+TIMELORD_RUN=no
+#A2BOOT_RUN=no
+ATALK_ZONE=
+ATALK_BGROUND=no
+
+
 . :ETCDIR:/netatalk.conf
 
 # startup code for everything
@@ -39,8 +58,8 @@ atalk_startup() {
        :SBINDIR:/atalkd
 
        if [ -x :BINDIR:/nbprgstr ]; then       
-           :BINDIR:/nbprgstr -p 4 `hostname|sed 's/\..*$//'`:Workstation
-           :BINDIR:/nbprgstr -p 4 `hostname|sed 's/\..*$//'`:netatalk
+           :BINDIR:/nbprgstr -p 4 ${ATALK_NAME}:Workstation
+           :BINDIR:/nbprgstr -p 4 ${ATALK_NAME}:netatalk
 
        fi      
 
@@ -74,7 +93,7 @@ atalk_startup() {
 
 case "$1" in
     start)
-       if [ x"${ATALK_BGROUND}" = x"yes" ]; then 
+       if [ x"${ATALK_BGROUND}" = x"yes" -a x"${ATALKD_RUN}" != x"no" ]; then 
            echo "Starting netatalk in the background ... "
            atalk_startup >& /dev/null &
        else
index f21c7ec9dff80981b5cae7dd1c6cbbf47f5838d7..85ec0748f5b6add6f72f3522d3b5dd42e41915b2 100755 (executable)
@@ -18,7 +18,26 @@ killproc() {
        [ "$pid" != "" ] && kill $pid
 }
 
-# netatalk.conf expects hostname in $HOSTNAME by default
+# default
+ATALK_NAME=`hostname|cut -d. -f1`
+ATALK_UNIX_CHARSET='LOCALE'
+ATALK_MAC_CHARSET='MAC_ROMAN'
+
+CNID_METAD_RUN=yes
+AFPD_RUN=yes
+AFPD_MAX_CLIENTS=20
+AFPD_UAMLIST="-U uams_dhx.so,uams_dhx2.so"
+AFPD_GUEST=nobody
+CNID_CONFIG="-l log_note"
+
+ATALKD_RUN=no
+PAPD_RUN=no
+TIMELORD_RUN=no
+#A2BOOT_RUN=no
+ATALK_ZONE=
+ATALK_BGROUND=no
+
+# old netatalk.conf expected hostname in $HOSTNAME by default
 HOSTNAME=`hostname`
 
 . :ETCDIR:/netatalk.conf
@@ -67,7 +86,7 @@ atalk_startup() {
 case "$1" in
 
 'start')
-        if [ x"${ATALK_BGROUND}" = x"yes" ]; then
+        if [ x"${ATALK_BGROUND}" = x"yes" -a x"${ATALKD_RUN}" != x"no" ]; then
             echo "Starting netatalk in the background ... "
             atalk_startup > /dev/null &
         else
diff --git a/distrib/rpm/buildrpm b/distrib/rpm/buildrpm
deleted file mode 100755 (executable)
index 5ef90f3..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-#!/bin/sh
-#
-# buildrpm
-# $Id: buildrpm,v 1.3 2003-01-11 17:26:06 jmarcus Exp $
-#
-# automates the process of building the netatalk rpm
-#
-# To properly bootstrap the RPM from a raw CVS pull,
-# place the CVS sandbox under, e.g. /usr/src/redhat/BUILD
-# and name this new directory 'netatalk-$version' (where
-# $version is the contents of the 'VERSION' file under the source
-# root).  Then, cd into the source root and run 'autogen.sh'
-# (with no arguments).  Finally, copy this file to the BUILD
-# directory and run it from there, passing the full name of the
-# source directory as the sole argument.
-#
-if [ "x$1" = "x" ]; then
-    echo "To avoid problems with builds on remote filesystems"
-    echo "please copy this file to your redhat/BUILD directory"
-    echo "and execute as 'buildrpm netatalk-xxy', using the actual"
-    echo "full name (i.e. with version) of the source tree."
-    exit 1
-fi
-
-CVSNAME=$1
-
-REDHAT_DIR=../
-
-VERSION=`cat $CVSNAME/VERSION`
-
-sed -e "s/__VERSION__/$VERSION/" \
-    $CVSNAME/distrib/rpm/netatalk-redhat.spec \
-    > ${REDHAT_DIR}/SPECS/netatalk.spec
-
-cp -f $CVSNAME/distrib/rpm/netatalk-rpmbuild.patch \
-    ${REDHAT_DIR}/SOURCES
-
-# Newer distros use rpmbuild
-if `rpmbuild --version > /dev/null`; then
-    RPM="rpmbuild"
-else
-    RPM="rpm"
-fi
-
-# clean out objects and Makefiles
-(cd $CVSNAME && make distclean)
-
-# tar up the archive
-tar -c -v -z -f ${REDHAT_DIR}/SOURCES/$CVSNAME.tar.gz \
-       --exclude="*/CVS" --exclude="*~" $CVSNAME
-
-# build the SRPM and binary and devel RPMs.
-${RPM} -ba ${REDHAT_DIR}/SPECS/netatalk.spec
diff --git a/distrib/rpm/netatalk-asun.spec.old b/distrib/rpm/netatalk-asun.spec.old
deleted file mode 100644 (file)
index 4e3d992..0000000
+++ /dev/null
@@ -1,297 +0,0 @@
-Summary: AppleTalk networking programs
-Name: netatalk
-Version: 1.4b2+asun2.1.4
-Release: pre39
-Packager: iNOUE Koichi <inoue@ma.ns.musashi-tech.ac.jp>
-Copyright: BSD
-Group: Networking
-Source0: ftp://ftp.cobaltnet.com/pub/users/asun/testing/pre-asun2.1.4-36.tar.gz
-Patch0: netatalk-asun.makefile.patch
-Requires: pam >= 0.56
-BuildRoot: /var/tmp/atalk
-
-%description
-This package enables Linux to talk to Macintosh computers via the
-AppleTalk networking protocol. It includes a daemon to allow Linux
-to act as a file server over AppleTalk or IP for Mac's.
-
-%package devel
-Summary: Headers and static libraries for Appletalk development
-Group: Development/Libraries
-
-%description devel
-This packge contains the header files, and static libraries for building
-Appletalk networking programs.
-
-%prep
-%setup
-%patch0 -p1
-
-%build
-make OPTOPTS="$RPM_OPT_FLAGS -fomit-frame-pointer -fsigned-char" OSVERSION=2.0
-
-%install
-rm -rf $RPM_BUILD_ROOT
-mkdir -p $RPM_BUILD_ROOT/etc/atalk
-mkdir -p $RPM_BUILD_ROOT/etc/pam.d
-mkdir -p $RPM_BUILD_ROOT/etc/rc.d/init.d
-for i in 0 1 2 3 4 5 6; do
-       mkdir -p $RPM_BUILD_ROOT/etc/rc.d/rc$i.d
-done
-mkdir -p $RPM_BUILD_ROOT/usr/lib/atalk
-
-make install INSTALL_PREFIX=$RPM_BUILD_ROOT
-
-for i in aecho getzones megatron nbplkup nbprgstr nbpunrgstr pap \
-       papstatus psorder; do
-       strip $RPM_BUILD_ROOT/usr/bin/$i
-done
-for i in afpd atalkd psf psa papd; do
-       strip $RPM_BUILD_ROOT/usr/sbin/$i
-done
-
-install -m644 config/AppleVolumes.system $RPM_BUILD_ROOT/etc/atalk/AppleVolumes.system
-install -m644 config/AppleVolumes.default $RPM_BUILD_ROOT/etc/atalk/AppleVolumes.default
-install -m644 config/atalkd.conf $RPM_BUILD_ROOT/etc/atalk/atalkd.conf
-install -m644 config/papd.conf $RPM_BUILD_ROOT/etc/atalk/papd.conf
-
-# This is not necessary because chkconfig will make the links.
-for i in 0 1 2 6; do
-       ln -sf ../init.d/atalk $RPM_BUILD_ROOT/etc/rc.d/rc$i.d/K35atalk
-done
-for i in 3 4 5; do
-       ln -sf ../init.d/atalk $RPM_BUILD_ROOT/etc/rc.d/rc$i.d/S91atalk
-done
-
-%clean
-rm -rf $RPM_BUILD_ROOT
-
-%post
-/sbin/chkconfig --add atalk
-ldconfig
-# Do only for the first install
-if [ "$1" = 1 ] ; then
-  # Add the ddp lines to /etc/services
-  if (grep '[0-9][0-9]*/ddp' /etc/services >/dev/null); then
-    cat <<'_EOD1_' >&2
-warning: The DDP services appear to be present in /etc/services.
-warning: Please check them against services.atalk in the documentation.
-_EOD1_
-    true
-  else
-    cat <<'_EOD2_' >>/etc/services
-# start of DDP services
-#
-# Everything between the 'start of DDP services' and 'end of DDP services'
-# lines will be automatically deleted when the netatalk package is removed.
-#
-rtmp           1/ddp           # Routing Table Maintenance Protocol
-nbp            2/ddp           # Name Binding Protocol
-echo           4/ddp           # AppleTalk Echo Protocol
-zip            6/ddp           # Zone Information Protocol
-
-afpovertcp     548/tcp         # AFP over TCP
-afpovertcp     548/udp
-# end of DDP services
-_EOD2_
-  fi
-fi
-
-%postun
-# Do only for the last un-install
-if [ "$1" = 0 ] ; then
-  /sbin/chkconfig --del atalk
-  # remove the ddp lines from /etc/services
-  if (grep '^# start of DDP services$' /etc/services >/dev/null && \
-      grep '^# end of DDP services$' /etc/services >/dev/null ); then
-    sed -e '/^# start of DDP services$/,/^# end of DDP services$/d' \
-       </etc/services >/tmp/services.tmp$$
-    cat /tmp/services.tmp$$ >/etc/services
-    rm /tmp/services.tmp$$
-  else
-    cat <<'_EOD3_' >&2
-warning: Unable to find the lines `# start of DDP services' and
-warning: `# end of DDP services' in the file /etc/services.
-warning: You should remove the DDP services from /etc/service manually.
-_EOD3_
-  fi
-fi
-
-%files
-%doc BUGS CHANGES CONTRIBUTORS COPYRIGHT ChangeLog INSTALL/ README* TODO VERSION contrib/ services.atalk
-%dir /etc/atalk
-%config /etc/atalk/AppleVolumes.default
-%config /etc/atalk/AppleVolumes.system
-%config /etc/atalk/netatalk.conf
-%config /etc/atalk/afpd.conf
-%config /etc/atalk/atalkd.conf
-%config /etc/atalk/papd.conf
-%config /etc/rc.d/init.d/atalk
-%config /etc/pam.d/netatalk
-/etc/rc.d/rc0.d/K35atalk
-/etc/rc.d/rc1.d/K35atalk
-/etc/rc.d/rc2.d/K35atalk
-/etc/rc.d/rc3.d/S91atalk
-/etc/rc.d/rc4.d/S91atalk
-/etc/rc.d/rc5.d/S91atalk
-/etc/rc.d/rc6.d/K35atalk
-/usr/sbin/afpd
-/usr/sbin/atalkd
-/usr/sbin/papd
-/usr/sbin/psa
-/usr/sbin/etc2ps
-/usr/sbin/psf
-/usr/bin/adv1tov2
-/usr/bin/aecho
-/usr/bin/afppasswd
-/usr/bin/binheader
-/usr/bin/getzones
-/usr/bin/hqx2bin
-/usr/bin/macbinary
-/usr/bin/megatron
-/usr/bin/nadheader
-/usr/bin/nbplkup
-/usr/bin/nbprgstr
-/usr/bin/nbpunrgstr
-/usr/bin/pap
-/usr/bin/papstatus
-/usr/bin/psorder
-/usr/bin/single2bin
-/usr/bin/unbin
-/usr/bin/unhex
-/usr/bin/unsingle
-%dir /usr/lib/atalk
-/usr/lib/atalk/filters/
-/usr/lib/atalk/nls/
-/usr/lib/atalk/pagecount.ps
-/usr/lib/atalk/uams/
-/usr/man/man1/aecho.1
-/usr/man/man1/getzones.1
-/usr/man/man1/hqx2bin.1
-/usr/man/man1/macbinary.1
-/usr/man/man1/megatron.1
-/usr/man/man1/nbp.1
-/usr/man/man1/nbplkup.1
-/usr/man/man1/nbprgstr.1
-/usr/man/man1/pap.1
-/usr/man/man1/papstatus.1
-/usr/man/man1/psorder.1
-/usr/man/man1/single2bin.1
-/usr/man/man1/unbin.1
-/usr/man/man1/unhex.1
-/usr/man/man1/unsingle.1
-/usr/man/man3/atalk_aton.3
-/usr/man/man3/nbp_name.3
-/usr/man/man4/atalk.4
-/usr/man/man8/afpd.8
-/usr/man/man8/atalkd.8
-/usr/man/man8/papd.8
-/usr/man/man8/psf.8
-
-%files devel
-/usr/lib/libatalk.a
-/usr/lib/libatalk_p.a
-/usr/include/atalk/
-/usr/include/netatalk/
-
-%changelog
-* Thu Jul 22 1999 iNOUE Koich! <inoue@ma.ns.musashi-tech.ac.jp>
-- /etc/atalk/netatalk.config -> /etc/atalk/netatalk.conf
-  Many parts of patch are merged into the original source code.
-* Tue Jul 13 1999 iNOUE Koich! <inoue@ma.ns.musashi-tech.ac.jp>
-- AppleVolumes.system is merged into the original source code.
-  /etc/atalk/config -> /etc/atalk/netatalk.config.
-  Merge original rc.atalk.redhat and /etc/rc.d/init.d/atalk.
-  Remove last sample line of patched afpd.conf.
-* Fri Jul 9 1999 iNOUE Koich! <inoue@ma.ns.musashi-tech.ac.jp>
-- [pre-asun2.1.4-30]
-* Sun Jun 20 1999 iNOUE Koich! <inoue@ma.ns.musashi-tech.ac.jp>
-- [pre-asun2.1.4-28]
-* Thu Jun 3 1999 iNOUE Koich! <inoue@ma.ns.musashi-tech.ac.jp>
-- [pre-asun2.1.4-22]
-* Wed May 19 1999 iNOUE Koich! <inoue@ma.ns.musashi-tech.ac.jp>
-- [pre-asun2.1.4-15]
-  Make BerkleyDB=/usr.
-* Sun May 2 1999 iNOUE Koich! <inoue@ma.ns.musashi-tech.ac.jp>
-- [pre-asun2.1.4-11]
-  Integrate three patches into netatalk-asun.makefile.patch.
-  Change /etc/uams dir to /usr/lib/atalk/uams.
-  Add configuration line to /etc/atalk/afpd.conf and remove needless 
-  variables from /etc/atalk/config and /etc/rc.d/init.d/atalk.
-* Wed Apr 21 1999 iNOUE Koich! <inoue@ma.ns.musashi-tech.ac.jp>
-- [pre-asun2.1.4-9]
-  Move %chengelog section last.
-* Wed Mar 31 1999 iNOUE Koich! <inoue@ma.ns.musashi-tech.ac.jp>
-- Comment out -DNEED_QUOTA_WRAPPER in sys/linux/Makefile.
-* Sat Mar 20 1999 iNOUE Koich! <inoue@ma.ns.musashi-tech.ac.jp>
-- Correct symbolic links to psf.
-  Remove asciize function from nbplkup so as to display Japanese hostname.
-* Thu Mar 11 1999 iNOUE Koich! <inoue@ma.ns.musashi-tech.ac.jp>
-- Included MacPerl 5 script ICDumpSuffixMap which dumps suffix mapping
-  containd in Internet Config Preference.
-* Tue Mar 2 1999 iNOUE Koich! <inoue@ma.ns.musashi-tech.ac.jp>
-- [asun2.1.3]
-* Mon Feb 15 1999 iNOUE Koich! <inoue@ma.ns.musashi-tech.ac.jp>
-- [pre-asun2.1.2-8]
-* Sun Feb 7 1999 iNOUE Koich! <inoue@ma.ns.musashi-tech.ac.jp>
-- [pre-asun2.1.2-6]
-* Mon Jan 25 1999 iNOUE Koichi <inoue@ma.ns.musashi-tech.ac.jp>
-- [pre-asun2.1.2-3]
-* Thu Dec 17 1998 INOUE Koichi <inoue@ma.ns.musashi-tech.ac.jp>
-- [pre-asun2.1.2]
-  Remove crlf patch. It is now a server's option.
-* Thu Dec 3 1998 INOUE Koichi <inoue@ma.ns.musashi-tech.ac.jp>
-- Use stable version source netatalk-1.4b2+asun2.1.1.tar.gz
-  Add uams directory
-* Sat Nov 28 1998 INOUE Koichi <inoue@ma.ns.musashi-tech.ac.jp>
-- Use pre-asun2.1.1-3 source.
-* Mon Nov 23 1998 INOUE Koichi <inoue@ma.ns.musashi-tech.ac.jp>
-- Use pre-asun2.1.1-2 source.
-* Mon Nov 16 1998 INOUE Koichi <inoue@ma.ns.musashi-tech.ac.jp>
-- Fix rcX.d's symbolic links.
-* Wed Oct 28 1998 INOUE Koichi <inoue@ma.ns.musashi-tech.ac.jp>
-- Use pre-asun2.1.0a-2 source. Remove '%exclusiveos linux' line.
-* Sat Oct 24 1998 INOUE Koichi <inoue@ma.ns.musashi-tech.ac.jp>
-- Use stable version source netatalk-1.4b2+asun2.1.0.tar.gz.
-* Mon Oct 5 1998 INOUE Koichi <inoue@ma.ns.musashi-tech.ac.jp>
-- Use pre-asun2.1.0-10a source.
-* Thu Sep 19 1998 INOUE Koichi <inoue@ma.ns.musashi-tech.ac.jp>
-- Use pre-asun2.1.0-8 source. Add chkconfig support.
-* Sat Sep 12 1998 INOUE Koichi <inoue@ma.ns.musashi-tech.ac.jp>
-- Comment out -DCRLF. Use RPM_OPT_FLAGS.
-* Mon Sep 8 1998 INOUE Koichi <inoue@ma.ns.musashi-tech.ac.jp>
-- Use pre-asun2.1.0-7 source. Rename atalk.init to atalk.
-* Mon Aug 22 1998 INOUE Koichi <inoue@ma.ns.musashi-tech.ac.jp>
-- Use pre-asun2.1.0-6 source.
-* Mon Jul 27 1998 INOUE Koichi <inoue@ma.ns.musashi-tech.ac.jp>
-- Use pre-asun2.1.0-5 source.
-* Tue Jul 21 1998 INOUE Koichi <inoue@ma.ns.musashi-techa.c.jp>
-- Use pre-asun2.1.0-3 source.
-* Tue Jul 7 1998 INOUE Koichi <inoue@ma.ns.musashi-tech.ac.jp>
-- Add afpovertcp entries to /etc/services
-- Remove BuildRoot in man8 pages
-* Mon Jun 29 1998 INOUE Koichi <inoue@ma.ns.musashi-tech.ac.jp>
-- Use modified sources 1.4b2+asun2.1.0 produced by Adrian Sun
-  <asun@saul9.u.washington.edu> to provide an AppleShareIP file server
-- Included AppleVolumes.system file maintained by Johnson
-  <johnson@stpt.usf.edu>
-* Mon Aug 25 1997 David Gibson <D.Gibson@student.anu.edu.au>
-- Used a buildroot
-- Use RPM_OPT_FLAGS
-- Moved configuration parameters/files from atalk.init to /etc/atalk
-- Separated devel package
-- Built with shared libraries
-* Sun Jul 13 1997 Paul H. Hargrove <hargrove@sccm.Stanford.EDU>
-- Updated sources from 1.3.3 to 1.4b2
-- Included endian patch for Linux/SPARC
-- Use all the configuration files supplied in the source.  This has the
-  following advantages over the ones in the previous rpm release:
-       + The printer 'lp' isn't automatically placed in papd.conf
-       + The default file conversion is binary rather than text.
-- Automatically add and remove DDP services from /etc/services
-- Placed the recommended /etc/services in the documentation
-- Changed atalk.init to give daemons a soft kill
-- Changed atalk.init to make configuration easier
-
-* Wed May 28 1997 Mark Cornick <mcornick@zorak.gsfc.nasa.gov>
-Updated for /etc/pam.d
diff --git a/distrib/rpm/netatalk-fedora.spec b/distrib/rpm/netatalk-fedora.spec
deleted file mode 100644 (file)
index ca31a1b..0000000
+++ /dev/null
@@ -1,194 +0,0 @@
-#################################################### VERSIONING INFORMATION
-%define name    netatalk
-%define version 2.0.2
-%define release 2
-
-################################################# BASIC PACKAGE INFORMATION
-Summary: Appletalk and Appleshare/IP services for Linux
-Name: %{name}
-Version: %{version}
-Release: %{release}
-Copyright: BSD
-Group: Networking/Daemons
-Source0: %{name}-%{version}.tar.gz
-URL: http://netatalk.sourceforge.net/
-Packager: dan dickey <dan.dickey@savvis.net>
-
-############################################################## REQUIREMENTS
-Requires: cracklib, openssl, tcp_wrappers, pam
-BuildRequires: openssl-devel
-
-Prefix:    %{_prefix}
-BuildRoot: /var/tmp/%{name}-buildroot
-
-%description
-netatalk is an implementation of the AppleTalk Protocol Suite for Unix/Linux
-systems. The current release contains support for Ethertalk Phase I and II,
-DDP, RTMP, NBP, ZIP, AEP, ATP, PAP, ASP, and AFP. It provides Appletalk file
-printing and routing services on Solaris 2.5, Linux, FreeBSD, SunOS 4.1 and
-Ultrix 4. It also supports AFP 3, 2.2 and 2.1 (Appleshare IP).
-
-%package devel
-Group: Development/Networking
-Summary: Appletalk and Appleshare/IP services for Linux development files
-%description devel
-netatalk is an implementation of the AppleTalk Protocol Suite for Unix/Linux
-systems. The current release contains support for Ethertalk Phase I and II,
-DDP, RTMP, NBP, ZIP, AEP, ATP, PAP, ASP, and AFP. It provides Appletalk file
-printing and routing services on Solaris 2.5, Linux, FreeBSD, SunOS 4.1 and
-Ultrix 4. It also supports AFP 3, 2.2 and 2.1 (Appleshare IP).
-
-This package is required for developing appletalk-based applications.
-
-%prep
-%setup -q -n %{name}-%{version}/
-
-%build
-CFLAGS="$RPM_OPT_FLAGS -fomit-frame-pointer -fsigned-char" ./configure \
-       --prefix=%{prefix} \
-       --libexec=%{prefix}/libexec/netatalk \
-       --with-config-dir=/etc/atalk \
-       --with-pkgconfdir=/etc/atalk \
-       --with-uams-path=/etc/atalk/uams \
-       --with-message-dir=/etc/atalk/msg \
-       --enable-lastdid \
-       --enable-redhat \
-       --with-cracklib \
-       --with-pam \
-       --with-shadow \
-       --with-tcp-wrappers \
-       --with-ssl \
-       --enable-pgp-uam \
-       --enable-a2boot
-make all
-
-%install
-### INSTALL (USING "make install") ###
-mkdir -p $RPM_BUILD_ROOT{%{prefix},/etc/atalk/{uams,msg}}
-make DESTDIR=$RPM_BUILD_ROOT install-strip
-
-%post
-### RUN CHKCONFIG ###
-/sbin/chkconfig --add atalk
-/sbin/ldconfig
-# after the first install only
-if [ "$1" = 1 ]; then
-       # add the ddp lines to /etc/services
-       if (grep '[0-9][0-9]*/ddp' /etc/services >/dev/null); then
-               cat <<'_EOD1_' >&2
-warning: The DDP services appear to be present in /etc/services.
-warning: Please check them against services.atalk in the documentation.
-_EOD1_
-               true
-       else
-               cat <<'_EOD2_' >>/etc/services
-# start of DDP services
-#
-# Everything between the 'start of DDP services' and 'end of DDP services'
-# lines will be automatically deleted when the netatalk package is removed.
-#
-rtmp           1/ddp           # Routing Table Maintenance Protocol
-nbp            2/ddp           # Name Binding Protocol
-echo           4/ddp           # AppleTalk Echo Protocol
-zip            6/ddp           # Zone Information Protocol
-
-afpovertcp     548/tcp         # AFP over TCP
-afpovertcp     548/udp
-# end of DDP services
-_EOD2_
-       fi
-fi
-
-%preun
-### RUN CHKCONFIG ###
-/sbin/chkconfig --del atalk
-
-%postun
-# do only for the last un-install
-if [ "$1" = 0 ]; then
-       # remove the ddp lines from /etc/services
-       if (grep '^# start of DDP services$' /etc/services >/dev/null && \
-           grep '^# end of DDP services$'   /etc/services >/dev/null ); then
-         sed -e '/^# start of DDP services$/,/^# end of DDP services$/d' \
-           </etc/services >/tmp/services.tmp$$
-         cat /tmp/services.tmp$$ >/etc/services
-         rm /tmp/services.tmp$$
-       else
-         cat <<'_EOD3_' >&2
-warning: Unable to find the lines `# start of DDP services` and
-warning: `# end of DDP services` in the file /etc/services.
-warning: You should remove the DDP services from /etc/services manually.
-_EOD3_
-       fi
-fi
-
-%clean
-[ "$RPM_BUILD_ROOT" != "/" ] && rm -rf $RPM_BUILD_ROOT
-
-%files
-%defattr(-,root,root)
-%doc doc/[A-L,N-Z]*
-%config /etc/atalk/Apple*
-%config /etc/atalk/*.conf
-%config /etc/pam.d/netatalk
-%dir /etc/atalk
-%dir /etc/atalk/msg
-%dir /etc/atalk/uams
-/etc/atalk/uams/*.so
-/etc/rc.d/init.d/atalk
-%{prefix}/bin/*
-%{prefix}/sbin/*
-%{prefix}/libexec/*
-%{prefix}/man/man*/*.gz
-%{prefix}/share/netatalk/pagecount.ps
-
-%files devel
-%defattr(-,root,root)
-%{prefix}/lib/*.a
-%{prefix}/lib/*.la
-/etc/atalk/uams/*.a
-/etc/atalk/uams/*.la
-%dir %{prefix}/include/atalk
-%{prefix}/include/atalk/*.h
-%dir %{prefix}/include/netatalk
-%{prefix}/include/netatalk/*.h
-%{prefix}/share/aclocal/netatalk.m4
-
-%changelog
-
-* Thu Apr 28 2005 Dan A. Dickey <dan.dickey@savvis.net>
-  - Modify redhat spec file for Fedora Core.
-
-* Sat Jan 04 2002 Steven N. Hirsch <shirsch@adelphia.net>
-  - Fix RedHat RPM build.
-  - Build Apple2 boot support.
-
-* Thu Apr 12 2001 rufus t firefly <rufus.t.firefly@linux-mandrake.com>
-  - v1.5pre6-1
-  - pre-release 6 for sourceforge
-
-* Wed Mar 07 2001 rufus t firefly <rufus.t.firefly@linux-mandrake.com>
-  - v1.5pre5-1
-  - pre-release 5 for sourceforge
-
-* Fri Feb 23 2001 rufus t firefly <rufus.t.firefly@linux-mandrake.com>
-  - v1.5pre5-0
-  - pre-release 5 for sourceforge (prebuild)
-
-* Tue Feb 20 2001 rufus t firefly <rufus.t.firefly@linux-mandrake.com>
-  - v1.5pre4-1
-  - pre-release 4 for sourceforge
-  - modified/split mandrake spec for redhat 7 build
-
-* Mon Dec 18 2000 rufus t firefly <rufus.t.firefly@linux-mandrake.com>
-  - v1.5pre3-1mdk
-  - pre-release 3 for sourceforge
-  - moved away from 1.4.99 ... 
-
-* Wed Nov 08 2000 rufus t firefly <rufus.t.firefly@linux-mandrake.com>
-  - v1.4.99-0.20001108mdk
-  - pre-release 2 for sourceforge
-
-* Wed Sep 27 2000 rufus t firefly <rufus.t.firefly@linux-mandrake.com>
-  - v1.4.99-0.20000927mdk
-  - pre-release 1 for sourceforge
diff --git a/distrib/rpm/netatalk-mandrake.spec b/distrib/rpm/netatalk-mandrake.spec
deleted file mode 100644 (file)
index caa0cd8..0000000
+++ /dev/null
@@ -1,182 +0,0 @@
-#################################################### VERSIONING INFORMATION
-%define name    netatalk
-%define version 1.5pre6
-%define release 1mdk
-%define tardir %{name}-%{version}
-
-################################################# BASIC PACKAGE INFORMATION
-Summary: Appletalk and Appleshare/IP services for Linux
-Name: %{name}
-Version: %{version}
-Release: %{release}
-Copyright: BSD
-Group: Networking/Daemons
-Source0: %{name}-%{version}.tar.bz2
-URL: http://netatalk.sourceforge.net/
-Packager: rufus t firefly <rufus.t.firefly@linux-mandrake.com>
-Obsoletes: netatalk-1.4b2+asun netatalk-1.4.99
-
-############################################################## REQUIREMENTS
-Requires: cracklib, openssl, tcp_wrappers, pam
-BuildRequires: cracklib-devel, openssl-devel, pam-devel
-
-Prefix:    %{_prefix}
-BuildRoot: %{_tmppath}/%{name}-buildroot
-
-%description
-netatalk is an implementation of the AppleTalk Protocol Suite for Unix/Linux
-systems. The current release contains support for Ethertalk Phase I and II,
-DDP, RTMP, NBP, ZIP, AEP, ATP, PAP, ASP, and AFP. It provides Appletalk file
-printing and routing services on Solaris 2.5, Linux, FreeBSD, SunOS 4.1 and
-Ultrix 4. It also supports AFP 2.1 and 2.2 (Appleshare IP).
-
-%package devel
-Group: Development/Networking
-Summary: Appletalk and Appleshare/IP services for Linux development files
-%description devel
-netatalk is an implementation of the AppleTalk Protocol Suite for Unix/Linux
-systems. The current release contains support for Ethertalk Phase I and II,
-DDP, RTMP, NBP, ZIP, AEP, ATP, PAP, ASP, and AFP. It provides Appletalk file
-printing and routing services on Solaris 2.5, Linux, FreeBSD, SunOS 4.1 and
-Ultrix 4. It also supports AFP 2.1 and 2.2 (Appleshare IP).
-
-This package is required for developing appletalk-based applications.
-
-%changelog
-
-* Thu Apr 12 2001 rufus t firefly <rufus.t.firefly@linux-mandrake.com>
-  - v1.5pre6-1mdk
-  - pre-release 6 for sourceforge
-
-* Wed Mar 07 2001 rufus t firefly <rufus.t.firefly@linux-mandrake.com>
-  - v1.5pre5-1mdk
-  - pre-release 5 for sourceforge
-  - sync with redhat package
-
-* Mon Dec 18 2000 rufus t firefly <rufus.t.firefly@linux-mandrake.com>
-  - v1.5pre3-1mdk
-  - pre-release 3 for sourceforge
-  - moved away from 1.4.99 ... 
-
-* Wed Nov 08 2000 rufus t firefly <rufus.t.firefly@linux-mandrake.com>
-  - v1.4.99-0.20001108mdk
-  - pre-release 2 for sourceforge
-
-* Wed Sep 27 2000 rufus t firefly <rufus.t.firefly@linux-mandrake.com>
-  - v1.4.99-0.20000927mdk
-  - pre-release 1 for sourceforge
-
-%prep
-%setup -q -n %{tardir}/
-
-%build
-export LD_PRELOAD=
-CFLAGS="$RPM_OPT_FLAGS -fomit-frame-pointer -fsigned-char" ./configure \
-       --prefix=%{prefix} \
-    --with-config-dir=/etc/atalk \
-       --with-uams-path=/etc/atalk/uams \
-    --with-message-dir=/etc/atalk/msg \
-       --enable-lastdid \
-       --enable-redhat \
-       --with-cracklib \
-       --with-pam \
-       --with-shadow \
-       --with-tcp-wrappers \
-       --with-ssl \
-       --enable-pgp-uam
-make all
-
-%install
-### INSTALL (USING "make install") ###
-mkdir -p $RPM_BUILD_ROOT{%{prefix},/etc/atalk/{uams,msg}}
-make DESTDIR=$RPM_BUILD_ROOT install-strip
-
-# bzip2 man pages
-for i in 1 3 4 5 8; do
-       bzip2 -v $RPM_BUILD_ROOT/usr/man/man$i/*.$i
-done
-
-%post
-### RUN CHKCONFIG ###
-/sbin/chkconfig --add atalk
-/sbin/ldconfig
-# after the first install only
-if [ "$1" = 1 ]; then
-       # add the ddp lines to /etc/services
-       if (grep '[0-9][0-9]*/ddp' /etc/services >/dev/null); then
-               cat <<'_EOD1_' >&2
-warning: The DDP services appear to be present in /etc/services.
-warning: Please check them against services.atalk in the documentation.
-_EOD1_
-               true
-       else
-               cat <<'_EOD2_' >>/etc/services
-# start of DDP services
-#
-# Everything between the 'start of DDP services' and 'end of DDP services'
-# lines will be automatically deleted when the netatalk package is removed.
-#
-rtmp           1/ddp           # Routing Table Maintenance Protocol
-nbp            2/ddp           # Name Binding Protocol
-echo           4/ddp           # AppleTalk Echo Protocol
-zip            6/ddp           # Zone Information Protocol
-
-afpovertcp     548/tcp         # AFP over TCP
-afpovertcp     548/udp
-# end of DDP services
-_EOD2_
-       fi
-fi
-
-%preun
-### RUN CHKCONFIG ###
-/sbin/chkconfig --del atalk
-
-%postun
-# do only for the last un-install
-if [ "$1" = 0 ]; then
-       # remove the ddp lines from /etc/services
-       if (grep '^# start of DDP services$' /etc/services >/dev/null && \
-           grep '^# end of DDP services$'   /etc/services >/dev/null ); then
-         sed -e '/^# start of DDP services$/,/^# end of DDP services$/d' \
-           </etc/services >/tmp/services.tmp$$
-         cat /tmp/services.tmp$$ >/etc/services
-         rm /tmp/services.tmp$$
-       else
-         cat <<'_EOD3_' >&2
-warning: Unable to find the lines `# start of DDP services` and
-warning: `# end of DDP services` in the file /etc/services.
-warning: You should remove the DDP services from /etc/services manually.
-_EOD3_
-       fi
-fi
-
-%clean
-rm -rf $RPM_BUILD_ROOT
-rm -rf $RPM_BUILD_DIR/%{tardir}/
-
-%files
-%defattr(-,root,root)
-%doc [A-Z][A-Z]* ChangeLog doc/[A-Z][A-Z]*
-%dir /etc/atalk
-%dir /etc/atalk/msg
-%config /etc/atalk/Apple*
-%config /etc/atalk/*.conf
-%config /etc/pam.d/netatalk
-%dir /etc/atalk/nls
-/etc/atalk/nls/*
-%dir /etc/atalk/uams
-/etc/atalk/uams/*.so
-/etc/rc.d/init.d/atalk
-%{prefix}/bin/*
-%{prefix}/sbin/*
-%{prefix}/man/man*/*
-
-%files devel
-%defattr(-,root,root)
-%{prefix}/lib/*.a
-%dir %{prefix}/include/atalk
-%{prefix}/include/atalk/*.h
-%dir %{prefix}/include/netatalk
-%{prefix}/include/netatalk/*.h
-%{prefix}/share/aclocal/netatalk.m4
diff --git a/distrib/rpm/netatalk-redhat.spec b/distrib/rpm/netatalk-redhat.spec
deleted file mode 100644 (file)
index b2c8a3e..0000000
+++ /dev/null
@@ -1,194 +0,0 @@
-#################################################### VERSIONING INFORMATION
-%define name    netatalk
-%define version __VERSION__
-%define release 1
-
-################################################# BASIC PACKAGE INFORMATION
-Summary: Appletalk and Appleshare/IP services for Linux
-Name: %{name}
-Version: %{version}
-Release: %{release}
-Copyright: BSD
-Group: Networking/Daemons
-Source0: %{name}-%{version}.tar.gz
-Patch0: netatalk-rpmbuild.patch
-URL: http://netatalk.sourceforge.net/
-Packager: rufus t firefly <rufus.t.firefly@linux-mandrake.com>
-Obsoletes: netatalk-1.4b2+asun netatalk-1.4.99
-
-############################################################## REQUIREMENTS
-Requires: cracklib, openssl, tcp_wrappers, pam
-BuildRequires: openssl-devel
-
-# Note: RedHat 7.3 build requires autoconf >= 2.53, automake >= 1.5, ac-archive >= 0.5
-
-Prefix:    %{_prefix}
-BuildRoot: /var/tmp/%{name}-buildroot
-
-%description
-netatalk is an implementation of the AppleTalk Protocol Suite for Unix/Linux
-systems. The current release contains support for Ethertalk Phase I and II,
-DDP, RTMP, NBP, ZIP, AEP, ATP, PAP, ASP, and AFP. It provides Appletalk file
-printing and routing services on Solaris 2.5, Linux, FreeBSD, SunOS 4.1 and
-Ultrix 4. It also supports AFP 2.1 and 2.2 (Appleshare IP).
-
-%package devel
-Group: Development/Networking
-Summary: Appletalk and Appleshare/IP services for Linux development files
-%description devel
-netatalk is an implementation of the AppleTalk Protocol Suite for Unix/Linux
-systems. The current release contains support for Ethertalk Phase I and II,
-DDP, RTMP, NBP, ZIP, AEP, ATP, PAP, ASP, and AFP. It provides Appletalk file
-printing and routing services on Solaris 2.5, Linux, FreeBSD, SunOS 4.1 and
-Ultrix 4. It also supports AFP 2.1 and 2.2 (Appleshare IP).
-
-This package is required for developing appletalk-based applications.
-
-%changelog
-
-* Sat Jan 04 2002 Steven N. Hirsch <shirsch@adelphia.net>
-  - Fix RedHat RPM build.
-  - Build Apple2 boot support.
-
-* Thu Apr 12 2001 rufus t firefly <rufus.t.firefly@linux-mandrake.com>
-  - v1.5pre6-1
-  - pre-release 6 for sourceforge
-
-* Wed Mar 07 2001 rufus t firefly <rufus.t.firefly@linux-mandrake.com>
-  - v1.5pre5-1
-  - pre-release 5 for sourceforge
-
-* Fri Feb 23 2001 rufus t firefly <rufus.t.firefly@linux-mandrake.com>
-  - v1.5pre5-0
-  - pre-release 5 for sourceforge (prebuild)
-
-* Tue Feb 20 2001 rufus t firefly <rufus.t.firefly@linux-mandrake.com>
-  - v1.5pre4-1
-  - pre-release 4 for sourceforge
-  - modified/split mandrake spec for redhat 7 build
-
-* Mon Dec 18 2000 rufus t firefly <rufus.t.firefly@linux-mandrake.com>
-  - v1.5pre3-1mdk
-  - pre-release 3 for sourceforge
-  - moved away from 1.4.99 ... 
-
-* Wed Nov 08 2000 rufus t firefly <rufus.t.firefly@linux-mandrake.com>
-  - v1.4.99-0.20001108mdk
-  - pre-release 2 for sourceforge
-
-* Wed Sep 27 2000 rufus t firefly <rufus.t.firefly@linux-mandrake.com>
-  - v1.4.99-0.20000927mdk
-  - pre-release 1 for sourceforge
-
-%prep
-%setup -q -n %{name}-%{version}/
-%patch0 -p1 -b .rpmbuild
-
-%build
-CFLAGS="$RPM_OPT_FLAGS -fomit-frame-pointer -fsigned-char" ./configure \
-       --prefix=%{prefix} \
-       --libexec=%{prefix}/libexec/netatalk \
-       --with-config-dir=/etc/atalk \
-       --with-pkgconfdir=/etc/atalk \
-       --with-uams-path=/etc/atalk/uams \
-       --with-message-dir=/etc/atalk/msg \
-       --enable-lastdid \
-       --enable-redhat \
-       --with-cracklib \
-       --with-pam \
-       --with-shadow \
-       --with-tcp-wrappers \
-       --with-ssl \
-       --enable-pgp-uam \
-       --enable-a2boot
-make all
-
-%install
-### INSTALL (USING "make install") ###
-mkdir -p $RPM_BUILD_ROOT{%{prefix},/etc/atalk/{uams,msg}}
-make DESTDIR=$RPM_BUILD_ROOT install-strip
-
-%post
-### RUN CHKCONFIG ###
-/sbin/chkconfig --add atalk
-/sbin/ldconfig
-# after the first install only
-if [ "$1" = 1 ]; then
-       # add the ddp lines to /etc/services
-       if (grep '[0-9][0-9]*/ddp' /etc/services >/dev/null); then
-               cat <<'_EOD1_' >&2
-warning: The DDP services appear to be present in /etc/services.
-warning: Please check them against services.atalk in the documentation.
-_EOD1_
-               true
-       else
-               cat <<'_EOD2_' >>/etc/services
-# start of DDP services
-#
-# Everything between the 'start of DDP services' and 'end of DDP services'
-# lines will be automatically deleted when the netatalk package is removed.
-#
-rtmp           1/ddp           # Routing Table Maintenance Protocol
-nbp            2/ddp           # Name Binding Protocol
-echo           4/ddp           # AppleTalk Echo Protocol
-zip            6/ddp           # Zone Information Protocol
-
-afpovertcp     548/tcp         # AFP over TCP
-afpovertcp     548/udp
-# end of DDP services
-_EOD2_
-       fi
-fi
-
-%preun
-### RUN CHKCONFIG ###
-/sbin/chkconfig --del atalk
-
-%postun
-# do only for the last un-install
-if [ "$1" = 0 ]; then
-       # remove the ddp lines from /etc/services
-       if (grep '^# start of DDP services$' /etc/services >/dev/null && \
-           grep '^# end of DDP services$'   /etc/services >/dev/null ); then
-         sed -e '/^# start of DDP services$/,/^# end of DDP services$/d' \
-           </etc/services >/tmp/services.tmp$$
-         cat /tmp/services.tmp$$ >/etc/services
-         rm /tmp/services.tmp$$
-       else
-         cat <<'_EOD3_' >&2
-warning: Unable to find the lines `# start of DDP services` and
-warning: `# end of DDP services` in the file /etc/services.
-warning: You should remove the DDP services from /etc/services manually.
-_EOD3_
-       fi
-fi
-
-%clean
-rm -rf $RPM_BUILD_ROOT
-rm -rf $RPM_BUILD_DIR/%{name}/
-
-%files
-%defattr(-,root,root)
-%doc doc/[A-L,N-Z]*
-%config /etc/atalk/Apple*
-%config /etc/atalk/*.conf
-%config /etc/pam.d/netatalk
-/etc/atalk/nls/*
-/etc/atalk/uams/*.so
-/etc/rc.d/init.d/atalk
-%dir /etc/atalk
-%dir /etc/atalk/nls
-%dir /etc/atalk/uams
-%{prefix}/bin/*
-%{prefix}/sbin/*
-%{prefix}/libexec/*
-%{prefix}/man/man*/*.gz
-
-%files devel
-%defattr(-,root,root)
-%{prefix}/lib/*.a
-%dir %{prefix}/include/atalk
-%{prefix}/include/atalk/*.h
-%dir %{prefix}/include/netatalk
-%{prefix}/include/netatalk/*.h
-%{prefix}/share/aclocal/netatalk.m4
diff --git a/distrib/rpm/netatalk-rpmbuild.patch b/distrib/rpm/netatalk-rpmbuild.patch
deleted file mode 100644 (file)
index f965b2f..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
---- netatalk-1.7cvs/bin/afile/Makefile.in.orig 2003-01-07 20:44:23.000000000 -0500
-+++ netatalk-1.7cvs/bin/afile/Makefile.in      2003-01-08 07:09:05.000000000 -0500
-@@ -117,12 +117,12 @@
- install_sh = @install_sh@
- bin_PROGRAMS = afile achfile
--bin_SCRIPTS = acleandir.rc
-+bin_SCRIPTS = # acleandir.rc
- afile_SOURCES = afile.c common.c common.h
- achfile_SOURCES = achfile.c common.c common.h
--EXTRA_DIST = acleandir.rc
-+EXTRA_DIST = # acleandir.rc
- subdir = bin/afile
- mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
- CONFIG_HEADER = $(top_builddir)/config.h
index 39eecd248a42ba5fea316b2ec44eb1b2c1168622..9ba1765bcf4fa9364f8be79be7f9349beb84a89b 100644 (file)
@@ -144,16 +144,82 @@ Author: Andrew Morgan <morgan@linux.kernel.org>
 
 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/
-
 Netatalk also supports other standard PAM implementations such as OpenPAM.
 
-8 Berkeley DB
+8. Berkeley DB
 Berkeley DB is a programmatic toolkit that provides fast, reliable,
 scalable, and mission-critical database support to software
 developers. BDB can downloaded from
 http://www.oracle.com/database/berkeley-db/index.html
 Netatalk's CNID database uses the library and header files from BDB.
 Currently, Netatalk supports BDB 4.6 and later.
+
+Error checking and logging
+==========================
+We wan't rigid error checking and concise log messages. This often leads
+to signifant code bloat where the relevant function call is buried in error
+checking and logging statements.
+In order to alleviate error checking and code readability, we provide a set
+of error checking macros in <atalk/errchk.h>. These macros compare the return
+value of statements againt 0, NULL, -1 (and maybe more, check it out).
+Every macro comes in four flavours: EC_CHECK, EC_CHECK_LOG, EC_CHECK_LOG_ERR
+and EC_CHECK_CUSTOM:
+- EC_CHECK just checks the CHECK
+- EC_CHECK_LOG additionally logs the stringified function call.
+- EC_CHECK_LOG_ERR allows specifying the return value
+- EC_CHECK_CUSTOM allows custom actions
+The macros EC_CHECK* unconditionally jump to a cleanup label where the
+neccessary cleanup can be done alongside controlling the return value.
+EC_CHECK_CUSTOM doesn't do that, so an extra "goto EC_CLEANUP" may be
+performed as appropiate.
+
+Example:
+- stat() without EC macro:
+  static int func(const char *name) {
+    int ret = 0;
+    ...
+    if ((ret = stat(name, &some_struct_stat)) != 0) {
+      LOG(...);
+      ret = -1; /* often needed to explicitly set the error indicating return value */
+      goto cleanup;
+    }
+
+    return ret;
+
+  cleanup:
+    ...
+    return ret;
+  }
+
+- stat() with EC macro:
+  static int func(const char *name) {
+    EC_INIT; /* expands to int ret = 0; */
+
+    char *uppername = NULL
+    EC_NULL(uppername = strdup(name));
+    EC_ZERO(strtoupper(uppername));
+
+    EC_ZERO(stat(uppername, &some_struct_stat)); /* expands to complete if block from above */
+
+    EC_STATUS(0);
+
+EC_CLEANUP:
+    if (uppername) free(uppername);
+    EC_EXIT;
+  }
+
+A boileplate function template is:
+
+int func(void)
+{
+    EC_INIT;
+
+    ...your code here...
+
+    EC_STATUS(0);
+
+EC_CLEANUP:
+    EC_EXIT;
+}
diff --git a/doc/FAQ b/doc/FAQ
deleted file mode 100644 (file)
index 5092ac7..0000000
--- a/doc/FAQ
+++ /dev/null
@@ -1,636 +0,0 @@
-Netatalk Frequently Asked Questions
-($Id: FAQ,v 1.14 2010-04-25 13:59:53 hat001 Exp $)
-
------------------------------------------------------------------------------
-
-Q1: Where can I get more information on Netatalk?
-Q2: What is this I keep seeing about asun?
-Q3: How do I get the most recent version of Netatalk?
-Q4: Can I get an almost current version of Netatalk without having to learn Git?
-Q4a: Is there an RPM, package, or tarball for my platform?
-Q5: I'm having massive file deletion problems!
-Q6: I am having lots of file locking problems!
-Q7: I'm getting this message in my logs:
-     WARNING: DID conflict for ...  Are these the same file?
-Q8: I can't seem to use passwords longer than 8 characters for my netatalk
-    accounts. How can I fix that? 
-Q9: I would like to use encrypted passwords to authenticate to the Netatalk
-    server. How do I do that?
-Q10: How can I set who has access to certain directories?
-Q11: What are the .AppleDouble and .Parent directories which are created in
-     the netatalk locations?
-Q12: Hidden files - what's up with that?
-Q13: I get a "socket: Invalid argument" error when trying to start netatalk
-     under Linux. What is causing this?
-Q14: Netatalk works over Appletalk, but my IP connections are refused, even
-     though I have enabled them in the configuration files.
-Q15: I'm having Quark Express file locking problems, is there information on that?
-Q16: I'm getting this error in Quark Express when trying to save a file to
-     the server: 'Error Type -50'
-Q17: Does netatalk work with Mac OSX?
-Q18: I'm getting an 'Application for this document not found' error on OS X.
-Q19: I'm getting an 'Error Type -43' error on OS X.
-Q20: How do I get the directories that are created by Netatalk to have the
-     correct permissions by default?
-Q21:  What does this error mean:
-     'afpd[#####]: setdirmode: chmod .AppleDouble Operation not permitted'
-Q22: I'm having problems with the Trash folder: either when someone drags
-     files into it, the system want's them todelete them immeidately, or files
-     get stuck in there and won't delete.
-Q23: The daemons aren't starting, things aren't showing up in the Chooser,
-     and I get a message like this in the logs: afpd[####]: Can't register
-     Tests:AFPServer@*
-Q24: I want to be able to allow users to change their passwords?  How do
-     I enable this feature.  Every time I try I get an error that it was
-     unable to save the password.
-Q25: Can a mount a Mac volume on my unix machine?
-Q26: Can I run Samba and Netatalk together to access the same files?
-Q27: Files I create on my Samba shares are invisible on the mac side.
-Q27a: How can I set netatalk to hide some files from the Samba (or
-     unix) sides?
-Q28: Files I create on my netatalk shares are invisible on the PC side.
-Q28a: How can I set Samba to hide the netatalk specific files (e.g.
-     .AppleDouble).
-Q29: I compiled Samba with the --with-netatalk flag. What did that do?
-Q30: What about the differences in naming schemes, and legal/illegal
-     characters between Windows, Macs (and unix?)
-Q31: Where can I get the cnid-db (Berkely DB) software? (needed for
-     --with-did=cnid)
-Q32: What about security in Netatalk?
-
-
-
------------------------------------------------------------------------------
-
-
-Q1: Where can I get more information on Netatalk?
-
-A:  Netatalk's home page can be found at:
-
-      http://netatalk.sourceforge.net/
-
-    Netatalk is maintained at SourceForge. The Netatalk project page on
-    SourceForge is located at:
-
-      http://sourceforge.net/projects/netatalk/
-
-    There are (at least) three very active e-mail lists to which you can
-    subscribe. The first, netatalk-admins, is for usage and setup/compile
-    questions. Subscription information as well as an archive are available at:
-
-      http://lists.sourceforge.net/lists/listinfo/netatalk-admins
-
-    This can be very high volume, but usually a few messages a day.
-
-    Netatalk-devel list is more specific to coding and testing. The archive
-    and more information can found at:
-
-      http://lists.sourceforge.net/lists/listinfo/netatalk-devel
-
-    This list varies in volume, but is usually moderately active.
-
-    Netatalk-docs is specific to documentation. For more information see:
-
-      http://lists.sourceforge.net/mailman/listinfo/netatalk-docs
-    There are other netatalk information sites. Some of these are no
-    longer actively updated, some are site-specific, but still have
-    good information:
-
-      http://www.anders.com/projects/netatalk/
-      http://www.faredge.com.au/netatalk/index.html
-
-
-Q2: What is this I keep seeing about asun?
-
-A:  Before Netatalk moved to SourceForge, Adrian Sun (asun) had written
-    some patches to Netatalk which helped significantly with its usability,
-    especially using AppleShare IP. These patches are still provided by many
-    Unix vendors. All of these patches are included in the current SourceForge
-    versions.
-
-
-Q3: How do I get the most recent version of Netatalk?
-
-A:  Via Git from SourceForge.net. This is the actively maintained version
-    of Netatalk, changes are being made constantly, and therefore it is not
-    suitable for production environments. The netatalk at SourceForge is in
-    Beta, so keep that in mind.
-
-    Downloading the Git repository can be done quickly and easily.
-
-    Make sure you have Git installed. which git should produce a path to git.
-
-     $> which git
-     /usr/bin/git
-
-    If you don't have one make a source directory. cd to this directory.
-
-     $> mkdir /path/to/new/source/dir
-     $> cd /path/to/new/source/dir
-
-    Now get the source:
-
-     $> git clone git://netatalk.git.sourceforge.net/gitroot/netatalk/netatalk
-     Initialized empty Git repository in /path/to/new/source/dir/netatalk/.git/
-     remote: Counting objects: 2503, done.
-     ...
-
-    This will create a local directory called "netatalk" containing a complete
-    and fresh copy of the whole Netatalk source from the Git repository.
-
-    In order to keep your repository copy updated, occasionally run:
-
-     $> git pull
-
-    Now cd to the netatalk directory and run ./bootstrap. This will create the
-    configure script required in the next step.
-
-     $> ./bootstrap
-
-
-Q4: Can I get an almost current version of Netatalk without having to learn Git?
-
-A:  Yes.  Snapshots of the Git tree should be posted for the benefit of
-    those that don't want to / can't use Git. They are available at:
-
-      http://netatalk.git.sourceforge.net/git/gitweb-index.cgi
-    
-    You should be able to treat these images as you would a release.  Just
-    configure as you normally work, then run make (or gmake as the case may
-    be).  There is no need to run ./bootstrap on these images.
-
-
-Q4a: Is there an RPM, package, or tarball for my platform?
-
-A:  Perhaps. These vary in how often they're updated:
-
-    FreeBSD
-      port: /usr/ports/net/netatalk - maintained by Joe Clark
-    SuSE Linux
-      included in the distribution
-    OpenBSD
-      port: /usr/ports/net/netatalk/ - not actively maintained
-    Debian GNU/Linux
-      included in all current distributions
-    RedHat Linux
-      included in the distribution
-
-
-Q5: I'm having massive file deletion problems!
-
-Q6: I am having lots of file locking problems!
-
-Q7: I'm getting this message in my logs:
-    WARNING: DID conflict for ...  Are these the same file?
-
-A:  Compile with the --with-did=last flag set. This activates a different
-    method of calculating inodes in the software, and will hopefully fix some
-    of these problems. This code, along with the CNID code, was still being
-    worked out in Pre7. The cnid/bdb flags also go along with this:
-
-      --with-bdb=PATH         specify path to Berkeley DB installation
-      --with-did=[scheme]     set DID scheme (cnid,last) 
-    
-    (For more information on CNID, see the README.cnid file.)
-    
-    --with-did=last reverted things back to the old 1.4b2 directory ID
-    calculation algorithm.  This also solved the problem of the syslog
-    messages and the users complaining of file deletions.  It's also been
-    found that by disabling *BSD's SOFTUPDATES feature on Netatalk volumes (on
-    FreeBSD), multi-user interaction seemed to work better.  This was back in
-    a late 4.2-BETA, so it's not clear if this still holds true in 4.4-RELEASE
-    or not.
-
-
-Q8: I can't seem to use passwords longer than 8 characters for my Netatalk
-    accounts. How can I fix that? 
-
-Q9: I would like to use encrypted passwords to authenticate to the Netatalk
-    server. How do I do that?
-
-A:  Update to a newer version of AppleShare Client (I think the most
-    recent is 3.8.8). This allows longer passwords, and will allow you to
-    use encrypted passwords. Set which way you would like to authenticate
-    in either afpd.conf or netatalk.conf, depending on your setup.
-
-    For more information on the AppleShare Client from Apple, and which clients
-    are needed for which MacOS, see 
-
-      http://til.info.apple.com/techinfo.nsf/artnum/n60792?OpenDocument&software
-
-    (this site requires cookies, and a registration and sign-in).
-
-
-Q10: How can I set who has access to certain directories?
-    
-A:  You can certainly do this with your Unix permissions, but also explore the 
-    allow/deny/rwlist/rolist options in the AppleVolumes.default file:
-    
-      # 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.
-    
-    Also, some unices, specially FreeBSD, have other options:
-    (By Joe Clark)
-    
-    "What about file and directory permissions?  Since I didn't use the FORCE
-    UID/GID code, I decided to use a feature of FreeBSD called SUIDDIR. From
-    the LINT kernel config file:
-    
-    # If you are running a machine just as a fileserver for PC and MAC
-    # users, using SAMBA or Netatalk, you may consider setting this option
-    # and keeping all those users' directories on a filesystem that is
-    # mounted with the suiddir option. This gives new files the same
-    # ownership as the directory (similar to group). It's a security hole
-    # if you let these users run programs, so confine it to file-servers
-    # (but it'll save you lots of headaches in those cases). Root owned
-    # directories are exempt and X bits are cleared. The suid bit must be
-    # set on the directory as well; see chmod(1) PC owners can't see/set
-    # ownerships so they keep getting their toes trodden on. This saves
-    # you all the support calls as the filesystem it's used on will act as
-    # they expect: "It's my dir so it must be my file".
-    
-     FORCE UID/GID code, I decided to use a feature of FreeBSD called
-     SUIDDIR.  From the LINT kernel config file:
-    
-    # If you are running a machine just as a fileserver for PC and MAC
-    # users, using SAMBA or Netatalk, you may consider setting this option
-    # and keeping all those users' directories on a filesystem that is
-    # mounted with the suiddir option. This gives new files the same
-    # ownership as the directory (similar to group). It's a security hole
-    # if you let these users run programs, so confine it to file-servers
-    # (but it'll save you lots of headaches in those cases). Root owned
-    # directories are exempt and X bits are cleared. The suid bit must be
-    # set on the directory as well; see chmod(1) PC owners can't see/set
-    # ownerships so they keep getting their toes trodden on. This saves
-    # you all the support calls as the filesystem it's used on will act as
-    # they expect: "It's my dir so it must be my file".
-    
-    And the associated mount command:
-    
-    mount -o suiddir /dev/da2s1e /macvol/artfiles
-    
-    This was used on my dedicated Netatalk/Samba filesystems.  On
-    filesystems that were also used for interactive shell access, I chmod'd
-    my Netatalk shares 2770.  The reason for this is that I set up a UNIX
-    group for each department in the ad agency.  I had an art group, a media
-    group, an accounting group, and then, or course, a general staff group.
-    Each share was only allowed access by the group that needed to access
-    the share.  So, the Artfiles share allowed access only to the art group:
-    
-    /macvol/artfiles "Art Files" allow:@art
-    
-    And the others followed in kind.  Therefore, the 2770 mask allowed only
-    owners and people in the associated group access to read and write
-    files.  The leading 2 set the setgid bit so that all child files and
-    directories would retain the same group permissions.  I found this to
-    work well.
-    
-    This was used on my dedicated Netatalk/Samba filesystems.  On
-    filesystems that were also used for interactive shell access, I chmod'd
-    my Netatalk shares 2770.  The reason for this is that I set up a UNIX
-    group for each department in the ad agency.  I had an art group, a media
-    group, an accounting group, and then, or course, a general staff group.
-    Each share was only allowed access by the group that needed to access
-    the share.  So, the Artfiles share allowed access only to the art group:
-    
-    /macvol/artfiles "Art Files" allow:@art
-    
-    And the others followed in kind.  Therefore, the 2770 mask allowed only
-    owners and people in the associated group access to read and write
-    files.  The leading 2 set the setgid bit so that all child files and
-    directories would retain the same group permissions.  I found this to
-    work well."
-
-
-Q11: What are the .AppleDouble and .Parent directories which are created in
-     the Netatalk locations?
-
-A:  See the README.veto file in this directory.
-    
-    The .AppleDouble folders hold the resource fork information for the Mac
-    files, plus other attributes which are not normally stored by Unix. For
-    this reason, when you want to move files around in your Mac volumes, it's
-    a good idea to do it from the Mac side (as opposed to from the Unix side,
-    or Samba), unless you make absolutely sure you get the .AppleDouble
-    directories. These directories are often hidden from the Samba side, via
-    the veto files configuration.
-    
-    You can also set Netatalk to not create an .AppleDouble directory unless
-    it absolutely needs it, by setting the noadouble setting in
-    AppleVolumes.default.
-    
-    
-Q12: Hidden files - what's up with that?
-    
-A:  If you set the noadouble flag in AppleVolumes.default, you won't see
-    the .Apple* or .Parent directories on the Mac side. If you use the veto
-    files option in Samba, they may be hidden from the Windows side as well.
-    (More information in the Samba section, and in the README.veto file in
-    this directory.)
-
-
-Q13: I get a "socket: Invalid argument" error when trying to start Netatalk
-     under Linux. What is causing this?
-
-A:  The "appletalk" and "ipddp" kernel modules have to be installed under
-    linux for Netatalk to function. The appletalk module can be automatically
-    loaded by adding the line "alias net-pf-5 appletalk" to the
-    /etc/modules.conf file. Issuing the command "modprobe (module)" will
-    load the module for the current session.
-
-
-Q14: Netatalk works over AppleTalk, but my IP connections are refused, even
-     though I have enabled them in the configuration files.
-
-A:  If tcp_wrappers support is compiled into Netatalk, access has to be
-    granted in /etc/hosts.allow for Netatalk to successfully accept IP
-    connections. This can be done by the addition of the line:
-
-      afpd:  127. xxx.xxx.xxx. (whatever other subnets)    
-    
-
-Q15: I'm having Quark Express file locking problems, is there information on
-     that?
-
-A:  Yes, see the question regarding DID conflicts and the --enable-did= flag. 
-    Also, try using the --flock-locks flag. Enabling this code disabled the 
-    new byte locking feature. With FLOCK locks, the whole file would be locked. 
-    With byte locks, a byte range could be locked without locking the whole
-    file.
-
-
-Q16: I'm getting this error in Quark Express when trying to save a file to
-     the server: 'Error Type -50'
-
-A:  Turn off the document preview feature off in Quark.
-
-
-Q17: Does netatalk work with MacOS X?
-
-A:  Yes, but only the most recent versions, and it's still being finalized.
-    Versions prior to 1.5Pre7 did NOT work with OS X, although some really
-    early versions did (netatalk 1.4+asun?).
-
-
-Q18: I'm getting an 'Application for this document not found' error on MacOS X.
-
-Q19: I'm getting an 'Error Type -43' error on MacOS X.
-
-A:  Configure with --with-did=last. More info on this flag is given in the 
-    DID conflicts question.
-
-
-Q20: How do I get the directories that are created by Netatalk to have the
-     correct permissions by default?
-
-A:  Investigate the setgid bit on your Unix platform. It's a good idea to
-    set this on your shared directories, and your .AppleDouble directories.
-    From the mail archives: "Usually directories designated for use with
-    AppleShare have the setgid (g+s) bit set.  It forces inheritance of
-    permissions.  Without it, the .AppleDouble subdirectory can't be created
-    since the new folder doesn't necessarily have the same write privileges."
-
-    Information about the setgid bit can be found in Evi Nemeth's 
-    "Unix System Administration Handbook" (3rd. ed, chap 5.5, pg. 69):
-
-    "The bits with octal values 4000 and 2000 are the setuid and setgid bits.
-    These bits allow programs to access files and processes that would
-    otherwise be off-limits to the users that run them. [...] When set on a
-    directory, the setgid bit causes newly created files within the directory
-    to take on the group membership of the directory rather than the defualt
-    group of the user that created the file. This convention makes it easier
-    to share a directory of files among several users, as long as they all
-    belong to a common group. Check your system before relying on this
-    feature, since not all version of UNIX provide it. [...] This interpretation
-    of the setgid bit is unrelated to it's meaning when set on an executable
-    file, but there is never any ambiguity as to which meaning is
-    appropriate."
-    
-    NOTE: The setuid is usually discussed along with the setgid bit. The
-    setuid bit is VERY dangerous. If you set it on an executable, and the
-    executable is owned by root, anyone who runs that executable is root for
-    the duration of that executable's run, so a clever person can leverage
-    that into a full-scale compromise. The setgid bit also has other security
-    implications, so be careful where you set it.
-    
-    You set it by doing a chmod 2xxx, where xxx are the normal file permissions
-    (i.e. owner/group/other permissions).
-    
-
-Q21:  What does this error mean:
-     'afpd[#####]: setdirmode: chmod .AppleDouble Operation not permitted'
-
-A:  This can be due to a few things.
-
-    1) The setgid bit might not be set on either your directory, or on the
-    .AppleDouble directory. It has to be set recursively on the .AppleDouble
-    folder.
-    
-    2) You may not be member of the group set on the directory you're trying
-    to write to.
-    
-    3) This was a persistant bug in 1.5pre6 for awhile, upgrading might help.
-    
-    
-Q22: I'm having problems with the Trash folder: either when someone drags
-     files into it, the system wants them to delete them immediately, or files
-     get stuck in there and won't delete.
-    
-A:  chmod the Network Trash folder to 2775 (/home/public/Network Trash
-    Folder for instance).
-
-    As of 10/16/01, MacOS X trash didn't work properly with afps volumes. 
-    Apple is working on it.
-
-Q23: The daemons aren't starting, things aren't showing up in the Chooser,
-     and I get a message like this in the logs: afpd[####]: Can't register
-     Tests:AFPServer@*
-
-    This is sometimes a result of missing NIC information in the atalkd.conf
-    file. Put your network interface (something like le0, eth0, fxp0, lo0)
-    alone on a line in atalkd.conf, and reboot. When atalkd starts, it will
-    populate the file with a line such as:
-
-      le1 -seed -phase 2 -addr 66.6 -net 66-67 -zone "No Parking"
-
-    To find your network interface, run
-
-      % ifconfig -a | more
-
-    and see which interface has your IP address. Use that one.
-
-
-Q24: I want to be able to allow users to change their passwords.  How do
-     I enable this feature?  Every time I try I get an error that it was
-     unable to save the password.
-
-A:  Use -[no]setpassword in afpd.conf. This enables or disables the ability of
-    clients to change their passwords.
-
-
-Q25: Can a mount a Mac volume on my Unix machine?
-
-A:  Well, maybe. MacOS X obviously might be able to do this with NFS. 
-    Also, there is a program called afpfs which was designed to do this, 
-    but is not actively maintained and has been reportedly highly unstable. 
-    It should be available from:
-
-      http://www.panix.com/~dfoster/afpfs/
-
-Q26: Can I run Samba and Netatalk together to access the same files?
-
-A:  Sure. Lots of us do. But there are some concerns. Quite often it's 
-    useful, for instance, to hide files of one OS from the other. See
-    the AppleVolumes.default file in Netatalk, and investigate the veto
-    files option in Samba. (See the README.veto file.)
-
-    Also, when copying and moving files created on the Mac, it's better
-    to do that from the Mac, rather than from the Unix server or from
-    Samba. This is because the .AppleDouble folders hold the resource fork 
-    information for the Mac files, plus other attributes which are not 
-    normally stored by Unix.
-    
-    You can also set Netatalk to not create an .AppleDouble directory unless
-    it absolutely needs it, by setting the noadouble setting in
-    AppleVolumes.default.
-
-
-Q27: Files I create on my Samba shares are invisible on the Mac side.
-
-A:   Have you checked the AppleVolumes(.default? .sytem? I don't remember
-     which one hides files!) file?
-
-     How long are the file names? Names longer than 31 BYTES (not characters) 
-     are not visible on the Mac side. This is because some old MacOS's don't 
-     accept long names, and some Finders crash when they encounter them. 
-     Therefore Netatalk hides long filenames to prevent crashes. If you
-     prefer Netatalk to truncate the names, use the --with-mangling ./configure
-     option when compiling Netatalk.
-
-     The BYTES distiction is made because there exist doublebyte fonts too, 
-     which limit names to 15 chars.
-
-
-Q27a: How can I set Netatalk to hide some files created on the Samba 
-     (or Unix) sides?
-
-A:   AppleVolumes(.system or .default?) allows you to hide certain files.
-     This might be a good thing to set on, say, .cshrc, ssh keys, and
-     the like.
-
-
-Q28: Files I create on my Netatalk shares are invisible on the PC side.
-
-Q28a: How can I set Samba to hide the Netatalk specific files (e.g.
-     .AppleDouble).
-
-A:   Check your Samba veto files option in smb.conf. It's often useful
-     to hide files like .AppleDouble or the network trash folder here.
-
-     Does the mac file have a \ or / in it? Would this cause Samba to 
-     not see the file?
-
-
-Q29: I compiled Samba with the --with-netatalk flag. What did that do?
-
-A:   Nothing. Some code was written (by a Samba developer?), but as of 
-     Fall 2001, Samba doesn't utilize it.
-
-
-Q30: What about the differences in naming schemes, and legal/illegal
-     characters between Windows, Macs, and Unix?
-
-A:   Check out the documentation about the 'mswindows' flag in
-     AppleVolumes.default. For instance, having / or \ or : in a name is
-     especially bad, as they are path seperators on Unix, Windows, and MacOS, 
-     respectively). Educating the end user is important for this problem.
-
-
-Q31: Where can I get the cnid-db (Berkely DB) software? (needed for
-     --with-did=cnid)
-
-A:   First check to see if your Unix has a port or package. If not,
-     Berkeley DB is available at:
-
-       http://www.sleepycat.com/download.html
-
-Q32: What about security in Netatalk?
-
-A:   Most of the security for Netatalk must be derived from the
-     security of the Unix server on which it runs. Directory permissions,
-     valid users, firewalls, IP filters, file integrity checkers, etc.
-     are all part of the equation. That said, it is possible to configure
-     Netatalk to minimize access, and close potential security holes.
-
-     These two flags are especially important:
-
-       --with-tcp-wrappers: enable TCP wrappers support.
-
-         Enables 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/
-
-         Note, if you use TCP Wrappers, it would be a good idea to set your
-         afpd.conf file to disable DDP, or accept connections only on TCP.
-         You can also configure afpd to only run on a certain port, which
-         you can then let through your IPFilter.
-     
-       --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
-         this 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-libgcrypt-dir=[PATH]: specify path to Libgcrypt installation.
-
-         NOTE: This is dependent on the same directory layout as the
-         source distribution of Libgcrypt. That is: include/ and
-        lib/ to be on the same level.
-         This is required to enable DHX2 login support, which
-         will encrypt all of the passwords being sent across the 
-         connection. (Some old Mac clients don't support this, check
-         this FAQ for the section on AppleShare clients.)
-         Check to see if your Unix has Libgcrypt already, or
-         get everything at:
-
-           http://directory.fsf.org/project/libgcrypt/
-
-    Be aware that on the volumes that are shared, some of the 
-    special folders (.AppleDesktop, "Network Trash Folder") get
-    assigned. A lot of these get created as world-writable (because that's
-    what the Mac clients are expecting them to be) which is often quite
-    undesirable from the Unix system administrator's point of view.
-    Documenting this behavior could be a somewhat daunting task, but
-    highly desirable.
-
-    Shares can be set to be read/write only by certain people and groups.
-
-    The Netatalk code has not been through a major code audit. However,
-    it's Open Source, so if you want to do said audit, contact the 
-    Netatalk maintainers (which can be done through the SourceForge site).
-
-    Has anyone tried to run Netatalk in a chroot jail? If so, please
-    share your experiences with the mailing lists.
index e242667ca577a75134659b2fb8cf95fb95e1a62c..05eaf8415abe36d5a1e997727004daf6c1d15da7 100644 (file)
@@ -1,10 +1,3 @@
 # Makefile.am for INSTALL/
 
-EXTRA_DIST = \
-       DEVELOPER \
-       FAQ \
-       README.documentation \
-       README.hidden-items \
-       README.ids \
-       README.AppleTalk \
-       README.ACLs
+EXTRA_DIST = DEVELOPER README.AppleTalk
diff --git a/doc/README.ACLs b/doc/README.ACLs
deleted file mode 100644 (file)
index 916ddbe..0000000
+++ /dev/null
@@ -1,86 +0,0 @@
-
-                 ACLs - Konfiguration and Infos vor Developpers
-                 ==============================================
-
-ACL support for AFP is implemented with NFSv4 ACLs. Few filesystems and fewer OSes support
-these. At the time of implementation its only provided with ZFS on Solaris, Opensolaris and
-derived distributions.
-
-  Configuration
-  -------------
-
-In order to be able to support ACLs, the following things have to be configured:
-
-1. ZFS Volumes
-2. Authentication Domain
-3. Netatalk Volumes
-
-  1. ZFS Volumes:
-
-     You MUST configure one ACL parameter for any volume you want to use with Netatalk:
-
-        aclinherit = passthrough
-
-     For an explanation of what these parameters mean and how to apply them see, your hosts
-     ZFS documentation (e.g. man zfs).
-
-  2. Authentication Domain
-
-     Your server and the clients must be part of a security association where identity data
-     is coming from a common source. ACLs in Darwin are based on UUIDs and so is the ACL
-     specification in AFP 3.2. Therefor your source of identity data has to provide an
-     attribute for every user and group where a UUID is stored as a ASCII string.
-
-     In other words:
-      - you need an Open Directory Server or an LDAP server where you store UUIDs in some
-       attribute
-      - your clients must be configured to use this server 
-      - your server should be configured to use this server via nsswitch and PAM
-      - configure Netatalk via afp_ldap.conf so that Netatalk is able to retrieve the UUID
-       for users and groups via LDAP search queries
-
-  3. Netatalk Volumes
-
-     Finally you can add "options:acls" to your volume defintions to add ACL support.
-     In case your volume basedir doesn't grant read permissions via mode (like: 0700 root:adm)
-     but only via ACLs, you MUST add the "nostat" option to the volume defintion.
-
-  Implemantation Notes
-  --------------------
-
-Some implementation details that are buried in the code are worthwhile to be documented.
-
-1. Darwin ACEs vs NFSv4 ACEs
-2. .AppleDouble VFS integration
-
-  1. Darwin ACEs vs NFSv4 ACEs
-
-     Basically as far as implementing AFP support is concerned they're equivalent.
-     Subtleties arise at other places:
-
-     FPAccess
-
-       The AFP client frequently checks the (DARWIN_)ACE_DELETE_CHILD right. This is most
-       often not explicitly granted via an ACE. Therefor the client would get an no access
-        error. The client in turn then declares the object in question read only.
-       Thus we have to the check the mode for every directory and add ACE_DELETE_CHILD if
-       the requestor has write permissions.
-
-     FPGetFileDirParms
-
-       10.5 does not only use unix mode and FPAccess for permission check, but also OS 9
-       access bits from FPGetFileDirParms. Thus we have to adjust the Access Rights bitmap
-       user bits by including any ACL rigths.
-
-  2. .AppleDouble VFS integration
-
-     FPSetACL sets ACLs on files and dirs. Our implementation also sets the same ACL on the
-     .AppleDouble file for files and on the .AppleDouble dir itself for dirs.
-
-     Thereafter ACLs for created files is taken care of by ACLs own inheritance rules.
-
-     For dirs on the other hand whe have to make sure that any ACL the dir inherits is
-     copied verbatim to its .AppleDouble dir. 
-
-
-                                                                    January 2009, Frank Lahm
\ No newline at end of file
diff --git a/doc/README.documentation b/doc/README.documentation
deleted file mode 100644 (file)
index db58a07..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-                       ATTENTION
-
-The Netatalk documentation is now maintained in Docbook XML format.
-It is kept in the separate Git module 'netatalk-docs'.
diff --git a/doc/README.hidden-items b/doc/README.hidden-items
deleted file mode 100644 (file)
index f07b125..0000000
+++ /dev/null
@@ -1,130 +0,0 @@
-              Special folders created inside Netatalk shares
-
-(Originally by ali@gwc.org.uk 2001-10-20)
-(Amended by Sebastian Rittau 2001-11-03)
-(Amended by HAT 2010-03-30)
-
-Inside netatalk share points you will find several files and directories
-which are created automatically by the afpd process either for its own
-internal use or for the internal use of the MacOS.
-
-None of them should be directly visible in the Finder on the Mac. 
-
-Many of them have to be writeable in order for netatalk to function
-properly. This can present problems if users have shell access to the
-netatalk server. At the very least, users can "hide" files inside these
-writeable folders. At worst, a malicious user could confuse netatalk in a
-bad way. It is unlikely that a malicious user could cause loss of another
-user's data by exploiting permissions on these items.
-
-Below is what I hope to be a comprehensive list of these files and
-directories, their purpose, and a discussion of what Unix permissions
-should be set on them.
-
-Note that in general on Netatalk shares, all directories should have the
-setgid bit set. This forces any new files or folders created to have the
-same group as the folder they were created in. On some operating systems,
-notably FreeBSD, the group owner is always inherited from the parent
-directory, so the setgid bit is not necessary.
-
-
-.AppleDouble/
-
-This directory exists inside each folder on a Netatalk share. It contains
-meta information like the resource fork, or creator/type of each file in that
-folder. Its permissions should match those of its parent directory, i.e.
-anyone who has write access to the parent directory must have write access to
-the corresponding .AppleDouble directory.
-
-
-.AppleDouble/.Parent
-
-This file specifically contains meta information about the directory.
-
-
-.AppleDesktop/
-
-This directory exists under the top level of each share point. It contains
-the "desktop database" which is the method by which the MacOS associates a
-type/creator code with a particular application. Without it, documents
-will lose their application-specific icons and will have a generic icon
-instead. Double-clicking documents will also fail.
-
-To allow the desktop database to be maintained correctly, any user who is
-likely to copy an application on to the share must have write access to
-this directory and all directories below it. 
-
-
-Icon\r and .AppleDouble\Icon\r
-
-These files will exist in any folder, including the top level of a share,
-if it has a custom icon. Make them writeable to any user who should be
-allowed to change that custom icon; make them read-only if you don't want
-the custom icon to be changeable.
-
-
-.AppleDB/
-.AppleDBcnid.lock
-
-These will exist at the top level of each sharepoint on servers that run
-netatalk compiled with the new CNID DB code. Any user who has write access
-to any part of the share must have full write access to this directory /
-file and all the files within it otherwise the CNID DB code will not work
-properly.
-
-
-Network\ Trash\ Folder/
-
-This exists at the top level of each sharepoint. This is where files that
-are put in the Trash on clients go, until the Trash is emptied.
-
-The permissions of items in this directory are a pretty complicated
-subject, but basically you should make this directory and everything in it
-world-writeable if you want the Trash can to work properly. If you don't
-make it writeable then users will get a message "That item cannot be put
-in the Trash. Do you want to delete it immediately?" if they try to put
-something in the Trash.
-
-Unfortunately networked trash handling is broken in current versions of Mac
-OS X even if this directory is writeable. Apple is aware of this problem
-and is working on a solution.
-
-
-Temporary\ Items/
-.TemporaryItems/ (:2eTemporaryItems/)
-
-These folder may exist at the top level of a sharepoint. These folder is
-used by certain applications (Adobe PhotoShop among others) to store,
-well, temporary items. These programs may not work correctly if this
-folder is missing or not writeable, when a user tries to work on a
-document stored in that Netatalk share.
-
-
-TheFindByContentFolder/
-
-This folder is used by Sherlock 2 to store information use by its Find by
-Content feature. Make it writeable by users if you want to allow them to
-update the Find by Content index on a netatalk share. Otherwise, make it
-read-only.
-
-
-TheVolumeSettingsFolder/
-
-This folder is created at the top level of each share point. It
-always appears to be empty. It would be wise to set its permissions
-the same as the top level of the sharepoint.
-
-
-.DS_Store (:2eDS_Store)
-
-This file may appear in share points which have been accessed by a
-machine running Mac OS X. Its permissions should be set to match
-those of the enclosing directory.
-
-
-.FBCIndex (.FBCIndex)
-.FBCLockFolder/.FBCSemaphoreFile (:2eFBCLockFolder/:2eFBCSemaphoreFile)
-
-These are created to preserve retrieval information by Sherlock
-on Mac OS X 10.1. If these are removed, the next retrieval will slow.
-Mac OS X 10.2 and later do not use these.
diff --git a/doc/README.ids b/doc/README.ids
deleted file mode 100644 (file)
index a8539c3..0000000
+++ /dev/null
@@ -1,102 +0,0 @@
-File and Directory IDs explained.
-
-What are File and Directory ID's?
-
-On a mac the file system stores all files and directory information on each 
-volume in a big file called the catalogue file.  Inside the catalogue, all 
-files and directories are accessed using a key, central to which is a number, 
-called the ID.  In the case of a file its a file ID (FID) or for a directory, 
-a directory ID (DID).
-
-How many IDs can there be?
-
-The ID in a catalogue key is stored using 4 bytes, which means it can only 
-be between 0 and 4,294,967,295 (FF FF FF FF in hex).  However the first 16 
-IDs are reserved so you don't have quite that many.  Each ID is unique for 
-ever, on any given volume.  Once all 4 billion have been used, you cannot 
-create new files, so will need to reformat the volume to continue using it.
-
-Why are IDs so important?
-
-Most system calls relating to files inside a mac (either vi a network or a 
-hard disk) can refer to files or directories by ID.  This makes the ID a 
-powerful piece of information.  
-
-So whats the problem?
-
-The problem lies in file servers that don't use IDs.  The protocol used by
-macs to share files over a network is called the Apple Filing Protocol (AFP)
-and it requires the use of IDs.  So if you want to support AFP fully, any
-AFP server, must adopt its own system for storing and maintaining a link
-between each file or directory and its respective ID.  This is most critical
-when acessing directories.  
-
-So why does this matter on a non mac server like netatalk?
-
-The three big stumbling blocks that crop up with AFP servers that don't 
-fully support IDs are 1) aliases, 2) the trash can and 3) linked documents.
-
-Alias problems.
-
-An alias on a mac is quite special.  Rather than just storing the path to 
-the original file (like a unix symlink), it stores the ID to that file and 
-a special identifier for the volume (and the server it's on).  Ideally this 
-is great.  If the file moves or is renamed, the alias still works.  However 
-if either the file (or directory) ID changes, or the volume identifier 
-(or server identifer), then the alias will break.  The file it claims to 
-point to will claim to have been removed.  
-
-Trash can (accidentally deleted file) problems.
-
-The trash can has similar problems.  Files that have been moved to the trash
-are represented by their ID.  When you empty the trash all ID's listed are 
-deleted.  However if the ID of a file that was in the trash, is reallocated
-to an ordinary file, then when the trash is emptied that file will be deleted.
-
-Linked document problems.
-
-Finally linked documents: Linked documents are documents that contain hidden
-links to other documents.  Print setting and layout application (such as 
-Quark) use this technique.  Sometimes these documents contain IDs linking to
-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.
-
-This uses a running number to allocate IDs.  When an ID is allocated the 
-server remembers this by adding it to a table.  If an ID is referenced, then
-the server looks up on the table.  When the server is restarted, the table is
-lost.  This is the most simple method, but it is unreliable.  If you stick to
-the mac features which don't rely heavily on IDs it works fine.  If you try
-to use IDs much, things break.  
-
-DID = cnid. 
-
-The CNID scheme in Netatalk attempts to assign unique IDs to each file and
-directory, then keep those IDs persistent across mounts of the volume.  This
-way, cross-volume aliases will work, and users are less likely to encounter
-duplicate CNID errors.  Prior to Netatalk 1.6.0, the CNID calculation
-scheme was not persistent, and IDs were assigned based on the UNIX device and
-inode number of a given file or directory (see DID = last above).  This was 
-fine for the most part, but due to limitations, not all available CNIDs could 
-be used.  As well, these IDs could change independently from Netatalk, and 
-thus were not persistent.  As of Netatalk 1.6.0, the CNID scheme is now the 
-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 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
-libatalk/cnid/README file.  It was later picked up and modernized by Uwe Hees
-<uwe.hees@rz-online.de>.  Then, Joe Marcus Clarke <marcus@marcuscom.com>
-started fixing bugs and adding additional features.  The Concurrent
-Datastore support was subsequently added by Dan Wilga <dwilga@mtholyoke.edu>.
-The CNID code is currently maintained by Joe Marcus Clarke.
diff --git a/doc/TODO2.1 b/doc/TODO2.1
deleted file mode 100644 (file)
index 8296a10..0000000
+++ /dev/null
@@ -1,118 +0,0 @@
-NEW
-===
-Protocol level:
-* AFP 3.2
-* IPv6
-* Extended Attributes support
-* ACL support with ZFS
-* AppleTalk support in afpd and AppleTalk daemons (atalkd and papd) are disabled by default
-
-afpd:
-* default CNID backend is "dbd"
-* enable live debugging with SIGINT
-* afpd uses an in memory temporary DB if can't open the volume's database, but currently this only
-  works with the "cbd" or "tdb" backends not with the default "dbd".
-
-atalkd:
-* atalkd: workaround for broken Linux 2.6 AT kernel module:
-  Linux 2.6 sends broadcast queries to the first available socket which is in our case
-  the last configured one. atalkd now tries to find the right one.
-  Note: now a misconfigured or plugged router can broadcast a wrong route !
-
-Tools:
-* dbd: "dbd" CNID database and volume maintanance and intergrity check utility
-* apple_dump: dump AppleDouble files
-
-
-Upgrading from a 2.0 version
-============================
-2.1 and 2.0 filenames encoding and adouble headers are compatible thus
-it's possible to upgrade and downgrade between 2.0 and 2.1, you may have 
-to upgrade/downgrade (or delete) your .AppleDB folders in case the bdb versions differ.
-
-Requirements
-============
-BerkeleyDB 4.6
-
-configure
-=========
-new default:
-* sendfile is enable on linux
-
-new options
---disable-sendfile
---enable-nfsv4acls     NFSv4 ACL Support (only Solaris?)
-
-Webmin:
---with-webmin          path where webmin is installed [$PKGCONFDIR/webmin]
---with-webminuser              name for the webmin admin user
---with-webminversion           Webmin version to fetch from sf.net [1.490]
---with-webminpass      password for the webmin admin user
---with-webminport      TCP port for webmin
-
-removed options
---with-logfile
---with-cnid-dbd-txn     dbd always use transaction
---with-cnid-db3-backend  use dbd for transaction
---with-cnid-hash-backend never really work
-
-afpd.conf
-=========
-new defaults:
-* slp is disable by default
-* ddp is disable by default
-
-new options:
--slp                    advertise with SRVLOC
--hostname 
--volnamelen
--setuplog
--closevol
--ntdomain
--ntseparator
-
-removed options
--noslp
-
-AppleVolume.default
-===================
-new options:
-acl
-caseinsensitive                volume is case insensitive (JFS in OS2 mode)
-nocnidcache
-ea:sys|ad
-
-removed options:
-cachecnid
-
-Todo:
-=====
-- Clean up error messages, many messages should be move to the info/debug level
-  rather than error.
-- Are all options documented in the man pages/configuration files?
-- update dbd logic to others db.
-
-Best Practices:
-===============
-
-- use a separate user group for cnid_dbd daemons
-  cnid_metad -u afpd -g afpd
-
-- All CNID databases in the same directory
-
-  AppleVolumes.default
-
-    :DEFAUT: dbpath:/var/lib/afpd/$v
-
-  with /var/lib/afpd
-
-     drwxr-xr-x  afpd afpd 4096 2009-11-24 15:12 /var/lib/afpd
-
-  afpd or cnid_metad will create the right subdirectory ($v is replaced by the
-  volume name)
-
-MISC
-====
-Bonjour:
-with avahi you can add an afpd.service file in "/etc/avahi/services/".
-Drawback: AFP is advertised even if the server is down.
index 7ed56ed6612fc957a815944cf3eaf610e0727de5..6ad182a5693bd5b7278f9804bf0c0708e52282ca 100644 (file)
@@ -1,3 +1,7 @@
 # Makefile.am for etc/
 
-SUBDIRS = afpd cnid_dbd atalkd papd psf uams
+SUBDIRS = afpd cnid_dbd uams
+
+if USE_APPLETALK
+SUBDIRS += atalkd papd psf
+endif
index 54ae84fee31e9661e5a88c92f5ec8f8e5d151488..7e93dec2b5b42ab59c6de70dcc5bb2a03914ddb1 100644 (file)
@@ -5,33 +5,73 @@ pkgconfdir = @PKGCONFDIR@
 sbin_PROGRAMS = afpd
 noinst_PROGRAMS = hash
 
-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 quota.c uam.c afs.c uid.c afp_util.c \
-       catsearch.c afprun.c hash.c extattrs.c
+afpd_SOURCES = \
+       afp_asp.c \
+       afp_avahi.c \
+       afp_config.c \
+       afp_dsi.c \
+       afp_options.c \
+       afp_util.c \
+       afp_zeroconf.c \
+       afprun.c \
+       afs.c \
+       appl.c \
+       auth.c \
+       catsearch.c \
+       desktop.c \
+       dircache.c \
+       directory.c \
+       enumerate.c \
+       extattrs.c \
+       file.c \
+       filedir.c \
+       fork.c \
+       gettok.c \
+       hash.c \
+       main.c \
+       mangle.c \
+       messages.c  \
+       nfsquota.c \
+       ofork.c \
+       quota.c \
+       status.c \
+       switch.c \
+       uam.c \
+       uid.c \
+       unix.c \
+       volume.c
 
-if USE_NFSv4_ACLS
+afpd_LDADD =  \
+       $(top_builddir)/libatalk/cnid/libcnid.la \
+       $(top_builddir)/libatalk/libatalk.la \
+       @QUOTA_LIBS@ @SLP_LIBS@ @WRAP_LIBS@ @LIBADD_DL@ @ACL_LIBS@ @ZEROCONF_LIBS@ @PTHREAD_LIBS@
+
+afpd_LDFLAGS = -export-dynamic 
+
+afpd_CFLAGS = \
+       -I$(top_srcdir)/include \
+       -I$(top_srcdir)/sys \
+       @SLP_CFLAGS@ @ZEROCONF_CFLAGS@ \
+       -DAPPLCNAME \
+       -DSERVERTEXT=\"$(SERVERTEXT)/\" \
+       -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_AFPDSIGCONF=\"$(pkgconfdir)/afp_signature.conf\" \
+       -D_PATH_AFPDUAMPATH=\"$(UAMS_PATH)/\" \
+       -D_PATH_ACL_LDAPCONF=\"$(pkgconfdir)/afp_ldap.conf\" \
+       -D_PATH_AFPDUUIDCONF=\"$(pkgconfdir)/afp_voluuid.conf\"
+
+if HAVE_ACLS
 afpd_SOURCES += acls.c
 endif
 
-afpd_LDADD =  $(top_builddir)/libatalk/cnid/libcnid.la $(top_builddir)/libatalk/libatalk.la @QUOTA_LIBS@ @SLP_LIBS@ @WRAP_LIBS@ @LIBADD_DL@
-afpd_LDFLAGS = -export-dynamic 
-afpd_CFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/sys \
-        @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_AFPDSIGCONF=\"$(pkgconfdir)/afp_signature.conf\" \
-        -D_PATH_AFPDUAMPATH=\"$(UAMS_PATH)/\" \
-        -D_PATH_ACL_LDAPCONF=\"$(pkgconfdir)/afp_ldap.conf\" \
-        -DAPPLCNAME \
-        -DSERVERTEXT=\"$(SERVERTEXT)/\"
 
 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 hash.h acls.h acl_mappings.h extattrs.h
+        uam_auth.h uid.h unix.h volume.h hash.h acls.h acl_mappings.h extattrs.h \
+        dircache.h afp_zeroconf.h afp_avahi.h
 
 hash_SOURCES = hash.c
 hash_CFLAGS = -DKAZLIB_TEST_MAIN -I$(top_srcdir)/include
index e2d9f3d2d051d3600a8275b05572a4f3c0fc7fe0..b7c4b6d266fdb9863005c61dc889cd66785453e7 100644 (file)
 #ifndef ACL_MAPPINGS
 #define ACL_MAPPINGS
 
+#ifdef HAVE_SOLARIS_ACLS
 #include <sys/acl.h>
+#endif
+
 #include "acls.h"
 
 /* 
@@ -32,6 +35,7 @@ struct ace_rights_map {
     u_int32_t to;
 };
 
+#ifdef HAVE_SOLARIS_ACLS
 struct ace_rights_map nfsv4_to_darwin_rights[] = {
     {ACE_READ_DATA,         DARWIN_ACE_READ_DATA},
     {ACE_WRITE_DATA,        DARWIN_ACE_WRITE_DATA},
@@ -93,5 +97,6 @@ struct darwin_to_nfsv4_flags_map darwin_to_nfsv4_flags[] = {
     {DARWIN_ACE_FLAGS_INHERITED,         ACE_INHERITED_ACE},
     {0,0}
 };
+#endif /* HAVE_SOLARIS_ACLS */
 
 #endif /* ACL_MAPPINGS */
index bca61c491125b91bbfc473784a657b63b0775c35..206f2d9f2f774f58c46b4c90e5067ebfd3da7abb 100644 (file)
@@ -1,5 +1,5 @@
 /*
-  Copyright (c) 2008,2009 Frank Lahm <franklahm@gmail.com>
+  Copyright (c) 2008, 2009, 2010 Frank Lahm <franklahm@gmail.com>
 
   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
 #include <grp.h>
 #include <pwd.h>
 #include <errno.h>
+#ifdef HAVE_SOLARIS_ACLS
 #include <sys/acl.h>
+#endif
+#ifdef HAVE_POSIX_ACLS
+#include <sys/acl.h>
+#include <acl/libacl.h>
+#endif
 
+#include <atalk/errchk.h>
 #include <atalk/adouble.h>
 #include <atalk/vfs.h>
 #include <atalk/afp.h>
 #include <atalk/logger.h>
 #include <atalk/uuid.h>
 #include <atalk/acl.h>
+#include <atalk/bstrlib.h>
+#include <atalk/bstradd.h>
 
 #include "directory.h"
 #include "desktop.h"
 #include "volume.h"
 #include "fork.h"
-
+#include "unix.h"
 #include "acls.h"
 #include "acl_mappings.h"
+#include "auth.h"
 
 /* for map_acl() */
-#define SOLARIS_2_DARWIN 1
-#define DARWIN_2_SOLARIS 2
+#define SOLARIS_2_DARWIN       1
+#define DARWIN_2_SOLARIS       2
+#define POSIX_DEFAULT_2_DARWIN 3
+#define POSIX_ACCESS_2_DARWIN  4
+#define DARWIN_2_POSIX_DEFAULT 5
+#define DARWIN_2_POSIX_ACCESS  6
+
+#define MAP_MASK               31
+#define IS_DIR                 32
 
 /********************************************************
- * Basic and helper funcs
+ * Solaris funcs
  ********************************************************/
 
-/*
-  Takes a users name, uid and primary gid and checks if user is member of any group
-  Returns -1 if no or error, 0 if yes
-*/
-static int check_group(char *name, uid_t uid, gid_t pgid, gid_t path_gid)
+#ifdef HAVE_SOLARIS_ACLS
+
+/*! 
+ * Compile access rights for a user to one file-system object
+ *
+ * This combines combines all access rights for a user to one fs-object and
+ * returns the result as a Darwin allowed rights ACE.
+ * This must honor trivial ACEs which are a mode_t mapping.
+ *
+ * @param path           (r) path to filesystem object
+ * @param sb             (r) struct stat of path
+ * @param result         (w) resulting Darwin allow ACE
+ *
+ * @returns                  0 or -1 on error
+ */
+static int solaris_acl_rights(const char *path,
+                              const struct stat *sb,
+                              uint32_t *result)
 {
-    int i;
-    struct group *grp;
+    EC_INIT;
+    int      i, ace_count, checkgroup;
+    ace_t    *aces = NULL;
+    uid_t    who;
+    uint16_t flags, type;
+    uint32_t rights, allowed_rights = 0, denied_rights = 0, darwin_rights;
 
-    if (pgid == path_gid)
-        return 0;
+    /* Get ACL from file/dir */
+    EC_NEG1_LOG(ace_count = get_nfsv4_acl(path, &aces));
 
-    grp = getgrgid(path_gid);
-    if (!grp)
-        return -1;
+    if (ace_count == 0)
+        goto EC_CLEANUP;
 
+    /* Now check requested rights */
     i = 0;
-    while (grp->gr_mem[i] != NULL) {
-        if ( (strcmp(grp->gr_mem[i], name)) == 0 ) {
-            LOG(log_debug, logtype_afpd, "check_group: requested user:%s is member of: %s", name, grp->gr_name);
-            return 0;
+    do { /* Loop through ACEs */
+        who = aces[i].a_who;
+        flags = aces[i].a_flags;
+        type = aces[i].a_type;
+        rights = aces[i].a_access_mask;
+
+        if (flags & ACE_INHERIT_ONLY_ACE)
+            continue;
+
+        /* Now the tricky part: decide if ACE effects our user. I'll explain:
+           if its a dedicated (non trivial) ACE for the user
+           OR
+           if its a ACE for a group we're member of
+           OR
+           if its a trivial ACE_OWNER ACE and requested UUID is the owner
+           OR
+           if its a trivial ACE_GROUP ACE and requested UUID is group
+           OR
+           if its a trivial ACE_EVERYONE ACE
+           THEN
+           process ACE */
+        if (((who == uuid) && !(flags & (ACE_TRIVIAL|ACE_IDENTIFIER_GROUP)))
+            ||
+            ((flags & ACE_IDENTIFIER_GROUP) && !(flags & ACE_GROUP) && gmem(who))
+            ||
+            ((flags & ACE_OWNER) && (uuid == sb->st_uid))
+            ||
+            ((flags & ACE_GROUP) && gmem(sb->st_gid))
+            ||
+            (flags & ACE_EVERYONE)
+            ) {
+            /* Found an applicable ACE */
+            if (type == ACE_ACCESS_ALLOWED_ACE_TYPE)
+                allowed_rights |= rights;
+            else if (type == ACE_ACCESS_DENIED_ACE_TYPE)
+                /* Only or to denied rights if not previously allowed !! */
+                denied_rights |= ((!allowed_rights) & rights);
         }
-        i++;
+    } while (++i < ace_count);
+
+
+    /* Darwin likes to ask for "delete_child" on dir,
+       "write_data" is actually the same, so we add that for dirs */
+    if (S_ISDIR(sb->st_mode) && (allowed_rights & ACE_WRITE_DATA))
+        allowed_rights |= ACE_DELETE_CHILD;
+
+    /* Remove denied from allowed rights */
+    allowed_rights &= ~denied_rights;
+
+    /* map rights */
+    darwin_rights = 0;
+    for (i=0; nfsv4_to_darwin_rights[i].from != 0; i++) {
+        if (allowed_rights & nfsv4_to_darwin_rights[i].from)
+            darwin_rights |= nfsv4_to_darwin_rights[i].to;
     }
 
-    return -1;
+    *result |= darwin_rights;
+
+EC_CLEANUP:
+    if (aces) free(aces);
+
+    EC_EXIT;
 }
 
 /*
@@ -83,51 +170,42 @@ static int check_group(char *name, uid_t uid, gid_t pgid, gid_t path_gid)
   Return numer of mapped ACEs or -1 on error.
   All errors while mapping (e.g. getting UUIDs from LDAP) are fatal.
 */
-static int map_aces_solaris_to_darwin(ace_t *aces, darwin_ace_t *darwin_aces, int ace_count)
+static int map_aces_solaris_to_darwin(const ace_t *aces,
+                                      darwin_ace_t *darwin_aces,
+                                      int ace_count)
 {
+    EC_INIT;
     int i, count = 0;
     uint32_t flags;
     uint32_t rights;
     struct passwd *pwd = NULL;
     struct group *grp = NULL;
 
-    LOG(log_debug7, logtype_afpd, "map_aces_solaris_to_darwin: parsing %d ACES", ace_count);
+    LOG(log_maxdebug, logtype_afpd, "map_aces_solaris_to_darwin: parsing %d ACES", ace_count);
 
     while(ace_count--) {
-        LOG(log_debug7, logtype_afpd, "map_aces_solaris_to_darwin: parsing ACE No. %d", ace_count + 1);
+        LOG(log_maxdebug, logtype_afpd, "ACE No. %d", ace_count + 1);
         /* if its a ACE resulting from nfsv4 mode mapping, discard it */
         if (aces->a_flags & (ACE_OWNER | ACE_GROUP | ACE_EVERYONE)) {
-            LOG(log_debug, logtype_afpd, "map_aces_solaris_to_darwin: trivial ACE");
+            LOG(log_debug, logtype_afpd, "trivial ACE");
             aces++;
             continue;
         }
 
-        if ( ! (aces->a_flags & ACE_IDENTIFIER_GROUP) ) {
-            /* its a user ace */
-            LOG(log_debug, logtype_afpd, "map_aces_solaris_to_darwin: found user ACE with uid: %d", aces->a_who);
-            pwd = getpwuid(aces->a_who);
-            if (!pwd) {
-                LOG(log_error, logtype_afpd, "map_aces_solaris_to_darwin: getpwuid error: %s", strerror(errno));
-                return -1;
-            }
-            LOG(log_debug, logtype_afpd, "map_aces_solaris_to_darwin: uid: %d -> name: %s", aces->a_who, pwd->pw_name);
-            if ( (getuuidfromname(pwd->pw_name, UUID_USER, darwin_aces->darwin_ace_uuid)) != 0) {
-                LOG(log_error, logtype_afpd, "map_aces_solaris_to_darwin: getuuidfromname error");
-                return -1;
-            }
-        } else {
-            /* its a group ace */
-            LOG(log_debug, logtype_afpd, "map_aces_solaris_to_darwin: found group ACE with gid: %d", aces->a_who);
-            grp = getgrgid(aces->a_who);
-            if (!grp) {
-                LOG(log_error, logtype_afpd, "map_aces_solaris_to_darwin: getgrgid error: %s", strerror(errno));
-                return -1;
-            }
-            LOG(log_debug, logtype_afpd, "map_aces_solaris_to_darwin: gid: %d -> name: %s", aces->a_who, grp->gr_name);
-            if ( (getuuidfromname(grp->gr_name, UUID_GROUP, darwin_aces->darwin_ace_uuid)) != 0) {
-                LOG(log_error, logtype_afpd, "map_aces_solaris_to_darwin: getuuidfromname error");
-                return -1;
-            }
+        if ( ! (aces->a_flags & ACE_IDENTIFIER_GROUP) ) { /* user ace */
+            LOG(log_debug, logtype_afpd, "uid: %d", aces->a_who);
+            EC_NULL_LOG(pwd = getpwuid(aces->a_who));
+            LOG(log_debug, logtype_afpd, "uid: %d -> name: %s", aces->a_who, pwd->pw_name);
+            EC_ZERO_LOG(getuuidfromname(pwd->pw_name,
+                                        UUID_USER,
+                                        darwin_aces->darwin_ace_uuid));
+        } else { /* group ace */
+            LOG(log_debug, logtype_afpd, "gid: %d", aces->a_who);
+            EC_NULL_LOG(grp = getgrgid(aces->a_who));
+            LOG(log_debug, logtype_afpd, "gid: %d -> name: %s", aces->a_who, grp->gr_name);
+            EC_ZERO_LOG(getuuidfromname(grp->gr_name,
+                                        UUID_GROUP,
+                                        darwin_aces->darwin_ace_uuid));
         }
 
         /* map flags */
@@ -159,6 +237,8 @@ static int map_aces_solaris_to_darwin(ace_t *aces, darwin_ace_t *darwin_aces, in
     }
 
     return count;
+EC_CLEANUP:
+    EC_EXIT;
 }
 
 /*
@@ -166,14 +246,17 @@ static int map_aces_solaris_to_darwin(ace_t *aces, darwin_ace_t *darwin_aces, in
   Return numer of mapped ACEs or -1 on error.
   All errors while mapping (e.g. getting UUIDs from LDAP) are fatal.
 */
-int map_aces_darwin_to_solaris(darwin_ace_t *darwin_aces, ace_t *nfsv4_aces, int ace_count)
+static int map_aces_darwin_to_solaris(darwin_ace_t *darwin_aces,
+                                      ace_t *nfsv4_aces,
+                                      int ace_count)
 {
+    EC_INIT;
     int i, mapped_aces = 0;
     uint32_t darwin_ace_flags;
     uint32_t darwin_ace_rights;
     uint16_t nfsv4_ace_flags;
     uint32_t nfsv4_ace_rights;
-    char *name;
+    char *name = NULL;
     uuidtype_t uuidtype;
     struct passwd *pwd;
     struct group *grp;
@@ -183,25 +266,22 @@ int map_aces_darwin_to_solaris(darwin_ace_t *darwin_aces, ace_t *nfsv4_aces, int
         nfsv4_ace_rights = 0;
 
         /* uid/gid first */
-        if ( (getnamefromuuid(darwin_aces->darwin_ace_uuid, &name, &uuidtype)) != 0)
-            return -1;
-        if (uuidtype == UUID_USER) {
-            pwd = getpwnam(name);
-            if (!pwd) {
-                LOG(log_error, logtype_afpd, "map_aces_darwin_to_solaris: getpwnam: %s", strerror(errno));
-                free(name);
-                return -1;
-            }
+        EC_ZERO(getnamefromuuid(darwin_aces->darwin_ace_uuid, &name, &uuidtype));
+        switch (uuidtype) {
+        case UUID_LOCAL:
+            free(name);
+            name = NULL;
+            darwin_aces++;
+            continue;
+        case UUID_USER:
+            EC_NULL_LOG(pwd = getpwnam(name));
             nfsv4_aces->a_who = pwd->pw_uid;
-        } else { /* hopefully UUID_GROUP*/
-            grp = getgrnam(name);
-            if (!grp) {
-                LOG(log_error, logtype_afpd, "map_aces_darwin_to_solaris: getgrnam: %s", strerror(errno));
-                free(name);
-                return -1;
-            }
+            break;
+        case UUID_GROUP:
+            EC_NULL_LOG(grp = getgrnam(name));
             nfsv4_aces->a_who = (uid_t)(grp->gr_gid);
             nfsv4_ace_flags |= ACE_IDENTIFIER_GROUP;
+            break;
         }
         free(name);
         name = NULL;
@@ -241,32 +321,487 @@ int map_aces_darwin_to_solaris(darwin_ace_t *darwin_aces, ace_t *nfsv4_aces, int
     }
 
     return mapped_aces;
+EC_CLEANUP:
+    if (name)
+        free(name);
+    EC_EXIT;
 }
+#endif /* HAVE_SOLARIS_ACLS */
 
 /********************************************************
- * 2nd level funcs
+ * POSIX 1e funcs
  ********************************************************/
 
-/*  Map between ACL styles (SOLARIS_2_DARWIN, DARWIN_2_SOLARIS).
-    Reads from 'aces' buffer, writes to 'rbuf' buffer.
-    Caller must provide buffer.
-    Darwin ACEs are read and written in network byte order.
-    Needs to know how many ACEs are in the ACL (ace_count). Ignores trivial ACEs.
-    Return no of mapped ACEs or -1 on error. */
-static int map_acl(int type, ace_t *nfsv4_aces, darwin_ace_t *buf, int ace_count)
+#ifdef HAVE_POSIX_ACLS
+
+static uint32_t posix_permset_to_darwin_rights(acl_entry_t e, int is_dir)
+{
+    EC_INIT;
+    uint32_t rights = 0;
+    acl_permset_t permset;
+
+    EC_ZERO_LOG(acl_get_permset(e, &permset));
+
+    if (acl_get_perm(permset, ACL_READ))
+        rights = DARWIN_ACE_READ_DATA
+            | DARWIN_ACE_READ_EXTATTRIBUTES
+            | DARWIN_ACE_READ_ATTRIBUTES
+            | DARWIN_ACE_READ_SECURITY;
+    if (acl_get_perm(permset, ACL_WRITE)) {
+        rights |= DARWIN_ACE_WRITE_DATA
+            | DARWIN_ACE_APPEND_DATA
+            | DARWIN_ACE_WRITE_EXTATTRIBUTES
+            | DARWIN_ACE_WRITE_ATTRIBUTES;
+        if (is_dir)
+            rights |= DARWIN_ACE_DELETE_CHILD;
+    }
+    if (acl_get_perm(permset, ACL_EXECUTE))
+        rights |= DARWIN_ACE_EXECUTE;
+
+EC_CLEANUP:
+    LOG(log_maxdebug, logtype_afpd, "mapped rights: 0x%08x", rights);
+    return rights;
+}
+
+/*! 
+ * Compile access rights for a user to one file-system object
+ *
+ * This combines combines all access rights for a user to one fs-object and
+ * returns the result as a Darwin allowed rights ACE.
+ * This must honor trivial ACEs which are a mode_t mapping.
+ *
+ * @param path           (r) path to filesystem object
+ * @param sb             (r) struct stat of path
+ * @param result         (rw) resulting Darwin allow ACE
+ *
+ * @returns                  0 or -1 on error
+ */
+static int posix_acl_rights(const char *path,
+                            const struct stat *sb,
+                            uint32_t *result)
+{
+    EC_INIT;
+    int havemask = 0;
+    int entry_id = ACL_FIRST_ENTRY;
+    uint32_t rights = 0, maskrights = 0;
+    uid_t *uid = NULL;
+    gid_t *gid = NULL;
+    acl_t acl = NULL;
+    acl_entry_t e;
+    acl_tag_t tag;
+
+    EC_NULL_LOG(acl = acl_get_file(path, ACL_TYPE_ACCESS));
+
+    /* itereate through all ACEs to get the mask */
+    while (!havemask && acl_get_entry(acl, entry_id, &e) == 1) {
+        entry_id = ACL_NEXT_ENTRY;
+        EC_ZERO_LOG(acl_get_tag_type(e, &tag));
+        switch (tag) {
+        case ACL_MASK:
+            maskrights = posix_permset_to_darwin_rights(e, S_ISDIR(sb->st_mode));
+            LOG(log_maxdebug, logtype_afpd, "maskrights: 0x%08x", maskrights);
+            havemask = 1;
+            break;
+        default:
+            continue;
+        }
+    }
+
+    /* itereate through all ACEs */
+    entry_id = ACL_FIRST_ENTRY;
+    while (acl_get_entry(acl, entry_id, &e) == 1) {
+        entry_id = ACL_NEXT_ENTRY;
+        EC_ZERO_LOG(acl_get_tag_type(e, &tag));
+        switch (tag) {
+        case ACL_USER:
+            EC_NULL_LOG(uid = (uid_t *)acl_get_qualifier(e));
+            if (*uid == uuid) {
+                LOG(log_maxdebug, logtype_afpd, "ACL_USER: %u", *uid);
+                rights |= posix_permset_to_darwin_rights(e, S_ISDIR(sb->st_mode));
+            }
+            acl_free(uid);
+            uid = NULL;
+            break;
+        case ACL_USER_OBJ:
+            if (sb->st_uid == uuid) {
+                LOG(log_maxdebug, logtype_afpd, "ACL_USER_OBJ: %u", sb->st_uid);
+                rights |= posix_permset_to_darwin_rights(e, S_ISDIR(sb->st_mode));
+            }
+            break;
+        case ACL_GROUP:
+            EC_NULL_LOG(gid = (gid_t *)acl_get_qualifier(e));
+            if (gmem(*gid)) {
+                LOG(log_maxdebug, logtype_afpd, "ACL_GROUP: %u", *gid);
+                rights |= (posix_permset_to_darwin_rights(e, S_ISDIR(sb->st_mode)) & maskrights);
+            }
+            acl_free(gid);
+            gid = NULL;
+            break;
+        case ACL_GROUP_OBJ:
+            if (gmem(sb->st_gid)) {
+                LOG(log_maxdebug, logtype_afpd, "ACL_GROUP_OBJ: %u", sb->st_gid);
+                rights |= posix_permset_to_darwin_rights(e, S_ISDIR(sb->st_mode));            
+            }
+            break;
+        case ACL_OTHER:
+            LOG(log_maxdebug, logtype_afpd, "ACL_OTHER");
+            rights |= posix_permset_to_darwin_rights(e, S_ISDIR(sb->st_mode));
+            break;
+        default:
+            continue;
+        }
+    } /* while */
+
+    *result |= rights;
+
+EC_CLEANUP:
+    if (acl) acl_free(acl);
+    if (uid) acl_free(uid);
+    if (gid) acl_free(gid);
+    EC_EXIT;
+}
+
+/*!
+ * Add entries of one acl to another acl
+ *
+ * @param aclp   (rw) destination acl where new aces will be added
+ * @param acl    (r)  source acl where aces will be copied from
+ *
+ * @returns 0 on success, -1 on error
+ */
+static int acl_add_acl(acl_t *aclp, const acl_t acl)
+{
+    EC_INIT;
+    int id;
+    acl_entry_t se, de;
+
+    for (id = ACL_FIRST_ENTRY; acl_get_entry(acl, id, &se) == 1; id = ACL_NEXT_ENTRY) {
+        EC_ZERO_LOG_ERR(acl_create_entry(aclp, &de), AFPERR_MISC);
+        EC_ZERO_LOG_ERR(acl_copy_entry(de, se), AFPERR_MISC);
+    }
+
+EC_CLEANUP:
+    EC_EXIT;
+}
+
+/*!
+ * Map Darwin ACE rights to POSIX 1e perm
+ *
+ * We can only map few rights:
+ *   DARWIN_ACE_READ_DATA                    -> ACL_READ
+ *   DARWIN_ACE_WRITE_DATA                   -> ACL_WRITE
+ *   DARWIN_ACE_DELETE_CHILD & (is_dir == 1) -> ACL_WRITE
+ *   DARWIN_ACE_EXECUTE                      -> ACL_EXECUTE
+ *
+ * @param entry             (rw) result of the mapping
+ * @param is_dir            (r) 1 for dirs, 0 for files
+ *
+ * @returns mapping result as acl_perm_t, -1 on error
+ */
+static acl_perm_t map_darwin_right_to_posix_permset(uint32_t darwin_ace_rights, int is_dir)
+{
+    acl_perm_t perm = 0;
+
+    if (darwin_ace_rights & DARWIN_ACE_READ_DATA)
+        perm |= ACL_READ;
+
+    if (darwin_ace_rights & (DARWIN_ACE_WRITE_DATA | (DARWIN_ACE_DELETE_CHILD & is_dir)))
+        perm |= ACL_WRITE;
+
+    if (darwin_ace_rights & DARWIN_ACE_EXECUTE)
+        perm |= ACL_EXECUTE;
+
+    return perm;
+}
+
+/*!
+ * Add a ACL_USER or ACL_GROUP permission to an ACL, extending existing ACEs
+ *
+ * Add a permission of "type" for user or group "id" to an ACL. Scan the ACL
+ * for existing permissions for this type/id, if there is one add the perm,
+ * otherwise create a new ACL entry.
+ * perm can be or'ed ACL_READ, ACL_WRITE and ACL_EXECUTE.  
+ *
+ * @param aclp     (rw) pointer to ACL
+ * @param type     (r)  acl_tag_t of ACL_USER or ACL_GROUP
+ * @param id       (r)  uid_t uid for ACL_USER, or gid casted to uid_t for ACL_GROUP
+ * @param perm     (r)  acl_perm_t permissions to add
+ *
+ * @returns 0 on success, -1 on failure
+ */
+static int posix_acl_add_perm(acl_t *aclp, acl_tag_t type, uid_t id, acl_perm_t perm)
+{
+    EC_INIT;
+    uid_t *eid = NULL;
+    acl_entry_t e;
+    acl_tag_t tag;
+    int entry_id = ACL_FIRST_ENTRY;
+    acl_permset_t permset;
+
+    int found = 0;
+    for ( ; (! found) && acl_get_entry(*aclp, entry_id, &e) == 1; entry_id = ACL_NEXT_ENTRY) {
+        EC_ZERO_LOG(acl_get_tag_type(e, &tag));
+        if (tag != ACL_USER && tag != ACL_GROUP)
+            continue;
+        EC_NULL_LOG(eid = (uid_t *)acl_get_qualifier(e));
+        if ((*eid == id) && (type == tag)) {
+            /* found an ACE for this type/id */
+            found = 1;
+            EC_ZERO_LOG(acl_get_permset(e, &permset));
+            EC_ZERO_LOG(acl_add_perm(permset, perm));
+        }
+
+        acl_free(eid);
+        eid = NULL;
+    }
+
+    if ( ! found) {
+        /* there was no existing ACE for this type/id */
+        EC_ZERO_LOG(acl_create_entry(aclp, &e));
+        EC_ZERO_LOG(acl_set_tag_type(e, type));
+        EC_ZERO_LOG(acl_set_qualifier(e, &id));
+        EC_ZERO_LOG(acl_get_permset(e, &permset));
+        EC_ZERO_LOG(acl_clear_perms(permset));
+        EC_ZERO_LOG(acl_add_perm(permset, perm));
+        EC_ZERO_LOG(acl_set_permset(e, permset));
+    }
+    
+EC_CLEANUP:
+    if (eid) acl_free(eid);
+
+    EC_EXIT;
+}
+
+/*!
+ * Map Darwin ACL to POSIX ACL.
+ *
+ * aclp must point to a acl_init'ed acl_t or an acl_t that can eg contain default ACEs.
+ * Mapping pecularities:
+ * - we create a default ace (which inherits to files and dirs) if either
+     DARWIN_ACE_FLAGS_FILE_INHERIT or DARWIN_ACE_FLAGS_DIRECTORY_INHERIT is requested
+ * - we throw away DARWIN_ACE_FLAGS_LIMIT_INHERIT (can't be mapped), thus the ACL will
+ *   not be limited
+ *
+ * @param darwin_aces  (r)  pointer to darwin_aces buffer
+ * @param def_aclp     (rw) directories: pointer to an initialized acl_t with the default acl
+ *                          files: *def_aclp will be NULL
+ * @param acc_aclp     (rw) pointer to an initialized acl_t with the access acl
+ * @param ace_count    (r)  number of ACEs in darwin_aces buffer
+ *
+ * @returns 0 on success storing the result in aclp, -1 on error.
+ */
+static int map_aces_darwin_to_posix(const darwin_ace_t *darwin_aces,
+                                    acl_t *def_aclp,
+                                    acl_t *acc_aclp,
+                                    int ace_count)
+{
+    EC_INIT;
+    char *name = NULL;
+    uuidtype_t uuidtype;
+    struct passwd *pwd;
+    struct group *grp;
+    uid_t id;
+    uint32_t darwin_ace_flags, darwin_ace_rights;
+    acl_tag_t tag;
+    acl_perm_t perm;
+
+    for ( ; ace_count != 0; ace_count--, darwin_aces++) {
+        /* type: allow/deny, posix only has allow */
+        darwin_ace_flags = ntohl(darwin_aces->darwin_ace_flags);
+        if ( ! (darwin_ace_flags & DARWIN_ACE_FLAGS_PERMIT))
+            continue;
+
+        darwin_ace_rights = ntohl(darwin_aces->darwin_ace_rights);
+        perm = map_darwin_right_to_posix_permset(darwin_ace_rights, (*def_aclp != NULL));
+        if (perm == 0)
+            continue;       /* dont add empty perm */
+
+        LOG(log_debug, logtype_afpd, "map_ace: no: %u, flags: %08x, darwin: %08x, posix: %02x",
+            ace_count, darwin_ace_flags, darwin_ace_rights, perm);
+
+         /* uid/gid */
+        EC_ZERO_LOG(getnamefromuuid(darwin_aces->darwin_ace_uuid, &name, &uuidtype));
+        switch (uuidtype) {
+        case UUID_LOCAL:
+            free(name);
+            name = NULL;
+            continue;
+        case UUID_USER:
+            EC_NULL_LOG(pwd = getpwnam(name));
+            tag = ACL_USER;
+            id = pwd->pw_uid;
+            LOG(log_debug, logtype_afpd, "map_ace: name: %s, uid: %u", name, id);
+            break;
+        case UUID_GROUP:
+            EC_NULL_LOG(grp = getgrnam(name));
+            tag = ACL_GROUP;
+            id = (uid_t)(grp->gr_gid);
+            LOG(log_debug, logtype_afpd, "map_ace: name: %s, gid: %u", name, id);
+            break;
+        }
+        free(name);
+        name = NULL;
+
+        if (darwin_ace_flags & DARWIN_ACE_INHERIT_CONTROL_FLAGS) {
+            if (*def_aclp == NULL) {
+                /* ace request inheritane but we haven't got a default acl pointer */
+                LOG(log_warning, logtype_afpd, "map_acl: unexpected ACE, flags: 0x%04x",
+                    darwin_ace_flags);
+                EC_FAIL;
+            }
+            /* add it as default ace */
+            EC_ZERO_LOG(posix_acl_add_perm(def_aclp, tag, id, perm));
+
+
+            if (! (darwin_ace_flags & DARWIN_ACE_FLAGS_ONLY_INHERIT))
+                /* if it not a "inherit only" ace, it must be added as access aces too */
+                EC_ZERO_LOG(posix_acl_add_perm(acc_aclp, tag, id, perm));
+        } else {
+            EC_ZERO_LOG(posix_acl_add_perm(acc_aclp, tag, id, perm));
+        }
+    }
+
+EC_CLEANUP:
+    if (name)
+        free(name);
+
+    EC_EXIT;
+}
+
+/*
+ * Map ACEs from POSIX to Darwin.
+ * type is either POSIX_DEFAULT_2_DARWIN or POSIX_ACCESS_2_DARWIN, cf. acl_get_file.
+ * Return number of mapped ACES, -1 on error.
+ */
+static int map_acl_posix_to_darwin(int type, const acl_t acl, darwin_ace_t *darwin_aces)
+{
+    EC_INIT;
+    int mapped_aces = 0;
+    int entry_id = ACL_FIRST_ENTRY;
+    acl_entry_t e;
+    acl_tag_t tag;
+    uid_t *uid = NULL;
+    gid_t *gid = NULL;
+    struct passwd *pwd = NULL;
+    struct group *grp = NULL;
+    uint32_t flags;
+    uint32_t rights, maskrights = 0;
+    darwin_ace_t *saved_darwin_aces = darwin_aces;
+
+    LOG(log_maxdebug, logtype_afpd, "map_aces_posix_to_darwin(%s)",
+        (type & MAP_MASK) == POSIX_DEFAULT_2_DARWIN ?
+        "POSIX_DEFAULT_2_DARWIN" : "POSIX_ACCESS_2_DARWIN");
+
+    /* itereate through all ACEs */
+    while (acl_get_entry(acl, entry_id, &e) == 1) {
+        entry_id = ACL_NEXT_ENTRY;
+
+        /* get ACE type */
+        EC_ZERO_LOG(acl_get_tag_type(e, &tag));
+
+        /* we return user and group ACE */
+        switch (tag) {
+        case ACL_USER:
+            EC_NULL_LOG(uid = (uid_t *)acl_get_qualifier(e));
+            EC_NULL_LOG(pwd = getpwuid(*uid));
+            LOG(log_debug, logtype_afpd, "map_aces_posix_to_darwin: uid: %d -> name: %s",
+                *uid, pwd->pw_name);
+            EC_ZERO_LOG(getuuidfromname(pwd->pw_name, UUID_USER, darwin_aces->darwin_ace_uuid));
+            acl_free(uid);
+            uid = NULL;
+            break;
+
+        case ACL_GROUP:
+            EC_NULL_LOG(gid = (gid_t *)acl_get_qualifier(e));
+            EC_NULL_LOG(grp = getgrgid(*gid));
+            LOG(log_debug, logtype_afpd, "map_aces_posix_to_darwin: gid: %d -> name: %s",
+                *gid, grp->gr_name);
+            EC_ZERO_LOG(getuuidfromname(grp->gr_name, UUID_GROUP, darwin_aces->darwin_ace_uuid));
+            acl_free(gid);
+            gid = NULL;
+            break;
+
+        case ACL_MASK:
+            maskrights = posix_permset_to_darwin_rights(e, type & IS_DIR);
+            continue;
+
+        default:
+            continue;
+        }
+
+        /* flags */
+        flags = DARWIN_ACE_FLAGS_PERMIT;
+        if ((type & MAP_MASK) == POSIX_DEFAULT_2_DARWIN)
+            flags |= DARWIN_ACE_FLAGS_FILE_INHERIT
+                | DARWIN_ACE_FLAGS_DIRECTORY_INHERIT
+                | DARWIN_ACE_FLAGS_ONLY_INHERIT;
+        darwin_aces->darwin_ace_flags = htonl(flags);
+
+        /* rights */
+        rights = posix_permset_to_darwin_rights(e, type & IS_DIR);
+        darwin_aces->darwin_ace_rights = htonl(rights);
+
+        darwin_aces++;
+        mapped_aces++;
+    } /* while */
+
+    /* Loop through the mapped ACE buffer once again, applying the mask */
+    for (int i = mapped_aces; i > 0; i--) {
+        saved_darwin_aces->darwin_ace_rights &= htonl(maskrights);
+        saved_darwin_aces++;
+    }
+
+    EC_STATUS(mapped_aces);
+
+EC_CLEANUP:
+    if (uid) acl_free(uid);
+    if (gid) acl_free(gid);
+    EC_EXIT;
+}
+#endif
+
+/*
+ * Multiplex ACL mapping (SOLARIS_2_DARWIN, DARWIN_2_SOLARIS, POSIX_2_DARWIN, DARWIN_2_POSIX).
+ * Reads from 'aces' buffer, writes to 'rbuf' buffer.
+ * Caller must provide buffer.
+ * Darwin ACEs are read and written in network byte order.
+ * Needs to know how many ACEs are in the ACL (ace_count) for Solaris ACLs.
+ * Ignores trivial ACEs.
+ * Return no of mapped ACEs or -1 on error.
+ */
+static int map_acl(int type, void *acl, darwin_ace_t *buf, int ace_count)
 {
     int mapped_aces;
 
     LOG(log_debug9, logtype_afpd, "map_acl: BEGIN");
 
-    switch (type) {
+    switch (type & MAP_MASK) {
+
+#ifdef HAVE_SOLARIS_ACLS
     case SOLARIS_2_DARWIN:
-        mapped_aces = map_aces_solaris_to_darwin( nfsv4_aces, buf, ace_count);
+        mapped_aces = map_aces_solaris_to_darwin( acl, buf, ace_count);
         break;
 
     case DARWIN_2_SOLARIS:
-        mapped_aces = map_aces_darwin_to_solaris( buf, nfsv4_aces, ace_count);
+        mapped_aces = map_aces_darwin_to_solaris( buf, acl, ace_count);
         break;
+#endif /* HAVE_SOLARIS_ACLS */
+
+#ifdef HAVE_POSIX_ACLS
+    case POSIX_DEFAULT_2_DARWIN:
+        mapped_aces = map_acl_posix_to_darwin(type, (const acl_t)acl, buf);
+        break;
+
+    case POSIX_ACCESS_2_DARWIN:
+        mapped_aces = map_acl_posix_to_darwin(type, (const acl_t)acl, buf);
+        break;
+
+    case DARWIN_2_POSIX_DEFAULT:
+        break;
+
+    case DARWIN_2_POSIX_ACCESS:
+        break;
+#endif /* HAVE_POSIX_ACLS */
 
     default:
         mapped_aces = -1;
@@ -277,20 +812,22 @@ static int map_acl(int type, ace_t *nfsv4_aces, darwin_ace_t *buf, int ace_count
     return mapped_aces;
 }
 
-/********************************************************
- * 1st level funcs
- ********************************************************/
-
-
 /* Get ACL from object omitting trivial ACEs. Map to Darwin ACL style and
    store Darwin ACL at rbuf. Add length of ACL written to rbuf to *rbuflen.
    Returns 0 on success, -1 on error. */
 static int get_and_map_acl(char *name, char *rbuf, size_t *rbuflen)
 {
-    int ace_count, mapped_aces, err;
-    ace_t *aces;
+    EC_INIT;
+    int mapped_aces = 0;
+    int dirflag;
     uint32_t *darwin_ace_count = (u_int32_t *)rbuf;
-
+#ifdef HAVE_SOLARIS_ACLS
+    int ace_count = 0;
+    ace_t *aces = NULL;
+#endif
+#ifdef HAVE_POSIX_ACLS
+    struct stat st;
+#endif
     LOG(log_debug9, logtype_afpd, "get_and_map_acl: BEGIN");
 
     /* Skip length and flags */
@@ -298,38 +835,72 @@ static int get_and_map_acl(char *name, char *rbuf, size_t *rbuflen)
     *rbuf = 0;
     rbuf += 4;
 
-    if ( (ace_count = get_nfsv4_acl(name, &aces)) == -1) {
-        LOG(log_error, logtype_afpd, "get_and_map_acl: couldnt get ACL");
-        return -1;
+#ifdef HAVE_SOLARIS_ACLS
+    EC_NEG1(ace_count = get_nfsv4_acl(name, &aces));
+    EC_NEG1(mapped_aces = map_acl(SOLARIS_2_DARWIN, aces, (darwin_ace_t *)rbuf, ace_count));
+#endif /* HAVE_SOLARIS_ACLS */
+
+#ifdef HAVE_POSIX_ACLS
+    acl_t defacl = NULL , accacl = NULL;
+
+    /* stat to check if its a dir */
+    EC_ZERO_LOG(lstat(name, &st));
+
+    /* if its a dir, check for default acl too */
+    dirflag = 0;
+    if (S_ISDIR(st.st_mode)) {
+        dirflag = IS_DIR;
+        EC_NULL_LOG(defacl = acl_get_file(name, ACL_TYPE_DEFAULT));
+        EC_NEG1(mapped_aces = map_acl(POSIX_DEFAULT_2_DARWIN | dirflag,
+                                      defacl,
+                                      (darwin_ace_t *)rbuf,
+                                      0));
     }
 
-    if ( (mapped_aces = map_acl(SOLARIS_2_DARWIN, aces, (darwin_ace_t *)rbuf, ace_count)) == -1) {
-        err = -1;
-        goto cleanup;
-    }
+    EC_NULL_LOG(accacl = acl_get_file(name, ACL_TYPE_ACCESS));
+
+    int tmp;
+    EC_NEG1(tmp = map_acl(POSIX_ACCESS_2_DARWIN | dirflag,
+                          accacl,
+                          (darwin_ace_t *)(rbuf + mapped_aces * sizeof(darwin_ace_t)),
+                          0));
+    mapped_aces += tmp;
+#endif /* HAVE_POSIX_ACLS */
+
     LOG(log_debug, logtype_afpd, "get_and_map_acl: mapped %d ACEs", mapped_aces);
 
-    err = 0;
     *darwin_ace_count = htonl(mapped_aces);
     *rbuflen += sizeof(darwin_acl_header_t) + (mapped_aces * sizeof(darwin_ace_t));
 
-cleanup:
-    free(aces);
+    EC_STATUS(0);
+
+EC_CLEANUP:
+#ifdef HAVE_SOLARIS_ACLS
+    if (aces) free(aces);
+#endif
+#ifdef HAVE_POSIX_ACLS
+    if (defacl) acl_free(defacl);
+    if (accacl) acl_free(accacl);
+#endif /* HAVE_POSIX_ACLS */
 
     LOG(log_debug9, logtype_afpd, "get_and_map_acl: END");
-    return err;
+
+    EC_EXIT;
 }
 
 /* Removes all non-trivial ACLs from object. Returns full AFPERR code. */
-static int remove_acl_vfs(const struct vol *vol,const char *path, int dir)
+static int remove_acl(const struct vol *vol,const char *path, int dir)
 {
-    int ret;
+    int ret = AFP_OK;
 
+#if (defined HAVE_SOLARIS_ACLS || defined HAVE_POSIX_ACLS)
     /* Ressource etc. first */
     if ((ret = vol->vfs->vfs_remove_acl(vol, path, dir)) != AFP_OK)
         return ret;
     /* now the data fork or dir */
-    return (remove_acl(path));
+    ret = remove_acl_vfs(path);
+#endif
+    return ret;
 }
 
 /*
@@ -340,19 +911,21 @@ static int remove_acl_vfs(const struct vol *vol,const char *path, int dir)
   We will store inherited ACEs first, which is Darwins canonical order.
   - returns AFPerror code
 */
-static int set_acl_vfs(const struct vol *vol, char *name, int inherit, char *ibuf)
+#ifdef HAVE_SOLARIS_ACLS
+static int set_acl(const struct vol *vol,
+                   char *name,
+                   int inherit,
+                   darwin_ace_t *daces,
+                   uint32_t ace_count)
 {
-    int ret, i, nfsv4_ace_count, tocopy_aces_count = 0, new_aces_count = 0, trivial_ace_count = 0;
+    EC_INIT;
+    int i, nfsv4_ace_count;
+    int tocopy_aces_count = 0, new_aces_count = 0, trivial_ace_count = 0;
     ace_t *old_aces, *new_aces = NULL;
     uint16_t flags;
-    uint32_t ace_count;
 
     LOG(log_debug9, logtype_afpd, "set_acl: BEGIN");
 
-    /*  Get no of ACEs the client put on the wire */
-    ace_count = htonl(*((uint32_t *)ibuf));
-    ibuf += 8;      /* skip ACL flags (see acls.h) */
-
     if (inherit)
         /* inherited + trivial ACEs */
         flags = ACE_INHERITED_ACE | ACE_OWNER | ACE_GROUP | ACE_EVERYONE;
@@ -369,11 +942,10 @@ static int set_acl_vfs(const struct vol *vol, char *name, int inherit, char *ibu
     }
 
     /* Now malloc buffer exactly sized to fit all new ACEs */
-    new_aces = malloc( (ace_count + tocopy_aces_count) * sizeof(ace_t) );
-    if (new_aces == NULL) {
+    if ((new_aces = malloc((ace_count + tocopy_aces_count) * sizeof(ace_t))) == NULL) {
         LOG(log_error, logtype_afpd, "set_acl: malloc %s", strerror(errno));
-        ret = AFPERR_MISC;
-        goto cleanup;
+        EC_STATUS(AFPERR_MISC);
+        goto EC_CLEANUP;
     }
 
     /* Start building new ACL */
@@ -391,13 +963,15 @@ static int set_acl_vfs(const struct vol *vol, char *name, int inherit, char *ibu
     LOG(log_debug7, logtype_afpd, "set_acl: copied %d inherited ACEs", new_aces_count);
 
     /* Now the ACEs from the client */
-    ret = map_acl(DARWIN_2_SOLARIS, &new_aces[new_aces_count], (darwin_ace_t *)ibuf, ace_count);
-    if (ret == -1) {
-        ret = AFPERR_PARAM;
-        goto cleanup;
+    if ((ret = (map_acl(DARWIN_2_SOLARIS,
+                        &new_aces[new_aces_count],
+                        daces,
+                        ace_count))) == -1) {
+        EC_STATUS(AFPERR_PARAM);
+        goto EC_CLEANUP;
     }
-    new_aces_count += ace_count;
-    LOG(log_debug7, logtype_afpd, "set_acl: mapped %d ACEs from client", ace_count);
+    new_aces_count += ret;
+    LOG(log_debug7, logtype_afpd, "set_acl: mapped %d ACEs from client", ret);
 
     /* Now copy the trivial ACEs */
     for (i=0; i < nfsv4_ace_count; i++) {
@@ -412,203 +986,197 @@ static int set_acl_vfs(const struct vol *vol, char *name, int inherit, char *ibu
     /* Ressourcefork first.
        Note: for dirs we set the same ACL on the .AppleDouble/.Parent _file_. This
        might be strange for ACE_DELETE_CHILD and for inheritance flags. */
-    if ( (ret = vol->vfs->vfs_acl(vol, name, ACE_SETACL, new_aces_count, new_aces)) != 0) {
+    if ((ret = (vol->vfs->vfs_acl(vol, name, ACE_SETACL, new_aces_count, new_aces))) != 0) {
         LOG(log_error, logtype_afpd, "set_acl: error setting acl: %s", strerror(errno));
         if (errno == (EACCES | EPERM))
-            ret = AFPERR_ACCESS;
+            EC_STATUS(AFPERR_ACCESS);
         else if (errno == ENOENT)
-            ret = AFPERR_NOITEM;
+            EC_STATUS(AFPERR_NOITEM);
         else
-            ret = AFPERR_MISC;
-        goto cleanup;
+            EC_STATUS(AFPERR_MISC);
+        goto EC_CLEANUP;
     }
-    if ( (ret = acl(name, ACE_SETACL, new_aces_count, new_aces)) != 0) {
+    if ((ret = (acl(name, ACE_SETACL, new_aces_count, new_aces))) != 0) {
         LOG(log_error, logtype_afpd, "set_acl: error setting acl: %s", strerror(errno));
         if (errno == (EACCES | EPERM))
-            ret = AFPERR_ACCESS;
+            EC_STATUS(AFPERR_ACCESS);
         else if (errno == ENOENT)
-            ret = AFPERR_NOITEM;
+            EC_STATUS(AFPERR_NOITEM);
         else
-            ret = AFPERR_MISC;
-        goto cleanup;
+            EC_STATUS(AFPERR_MISC);
+        goto EC_CLEANUP;
     }
 
-    ret = AFP_OK;
+    EC_STATUS(AFP_OK);
 
-cleanup:
-    free(old_aces);
-    free(new_aces);
+EC_CLEANUP:
+    if (old_aces) free(old_aces);
+    if (new_aces) free(new_aces);
 
     LOG(log_debug9, logtype_afpd, "set_acl: END");
-    return ret;
+    EC_EXIT;
 }
-
-/*
-  Checks if a given UUID has requested_rights(type darwin_ace_rights) for path.
-  Note: this gets called frequently and is a good place for optimizations !
-*/
-static int check_acl_access(const char *path, const uuidp_t uuid, uint32_t requested_darwin_rights)
+#endif /* HAVE_SOLARIS_ACLS */
+
+#ifdef HAVE_POSIX_ACLS
+static int set_acl(const struct vol *vol,
+                   const char *name,
+                   int inherit _U_,
+                   darwin_ace_t *daces,
+                   uint32_t ace_count)
 {
-    int                 ret, i, ace_count, dir, checkgroup;
-    char                *username = NULL; /* might be group too */
-    uuidtype_t          uuidtype;
-    uid_t               uid;
-    gid_t               pgid;
-    uint32_t            requested_rights = 0, allowed_rights = 0, denied_rights = 0;
-    ace_t               *aces;
-    struct passwd       *pwd;
-    struct stat         st;
-    int                 check_user_trivace = 0, check_group_trivace = 0;
-    uid_t               who;
-    uint16_t            flags;
-    uint16_t            type;
-    uint32_t            rights;
-
-#ifdef DEBUG
-    LOG(log_debug9, logtype_afpd, "check_access: BEGIN. Request: %08x", requested_darwin_rights);
-#endif
-    /* Get uid or gid from UUID */
-    if ( (getnamefromuuid(uuid, &username, &uuidtype)) != 0) {
-        LOG(log_error, logtype_afpd, "check_access: error getting name from UUID");
-        return AFPERR_PARAM;
-    }
+    EC_INIT;
+    acl_t def_acl = NULL;
+    acl_t acc_acl = NULL;
 
-    /* File or dir */
-    if ((lstat(path, &st)) != 0) {
-        LOG(log_error, logtype_afpd, "check_access: stat: %s", strerror(errno));
-        ret = AFPERR_PARAM;
-        goto exit;
-    }
-    dir = S_ISDIR(st.st_mode);
+    LOG(log_maxdebug, logtype_afpd, "set_acl: BEGIN");
 
-    if (uuidtype == UUID_USER) {
-        pwd = getpwnam(username);
-        if (!pwd) {
-            LOG(log_error, logtype_afpd, "check_access: getpwnam: %s", strerror(errno));
-            ret = AFPERR_MISC;
-            goto exit;
-        }
-        uid = pwd->pw_uid;
-        pgid = pwd->pw_gid;
+    struct stat st;
+    EC_ZERO_LOG_ERR(lstat(name, &st), AFPERR_NOOBJ);
 
-        /* If user is file/dir owner we must check the user trivial ACE */
-        if (uid == st.st_uid) {
-            LOG(log_debug, logtype_afpd, "check_access: user: %s is files owner. Must check trivial user ACE", username);
-            check_user_trivace = 1;
-        }
+    /* seed default ACL with access ACL */
+    if (S_ISDIR(st.st_mode))
+        EC_NULL_LOG_ERR(def_acl = acl_get_file(name, ACL_TYPE_ACCESS), AFPERR_MISC);
 
-        /* Now check if requested user is files owning group. If yes we must check the group trivial ACE */
-        if ( (check_group(username, uid, pgid, st.st_gid)) == 0) {
-            LOG(log_debug, logtype_afpd, "check_access: user: %s is in group: %d. Must check trivial group ACE", username, st.st_gid);
-            check_group_trivace = 1;
-        }
-    } else { /* hopefully UUID_GROUP*/
-        LOG(log_error, logtype_afpd, "check_access: afp_access for UUID of groups not supported!");
-#if 0
-        grp = getgrnam(username);
-        if (!grp) {
-            LOG(log_error, logtype_afpd, "check_access: getgrnam: %s", strerror(errno));
-            return -1;
-        }
-        if (st.st_gid == grp->gr_gid )
-            check_group_trivace = 1;
-#endif
-    }
+    /* for files def_acl will be NULL */
 
-    /* Map requested rights to Solaris style. */
-    for (i=0; darwin_to_nfsv4_rights[i].from != 0; i++) {
-        if (requested_darwin_rights & darwin_to_nfsv4_rights[i].from)
-            requested_rights |= darwin_to_nfsv4_rights[i].to;
-    }
+    /* create access acl from mode */
+    EC_NULL_LOG_ERR(acc_acl = acl_from_mode(st.st_mode), AFPERR_MISC);
 
-    /* Get ACL from file/dir */
-    if ( (ace_count = get_nfsv4_acl(path, &aces)) == -1) {
-        LOG(log_error, logtype_afpd, "check_access: error getting ACEs");
-        ret = AFPERR_MISC;
-        goto exit;
-    }
-    if (ace_count == 0) {
-        LOG(log_debug, logtype_afpd, "check_access: 0 ACEs from get_nfsv4_acl");
-        ret = AFPERR_MISC;
-        goto exit;
+    /* adds the clients aces */
+    EC_ZERO_ERR(map_aces_darwin_to_posix(daces, &def_acl, &acc_acl, ace_count), AFPERR_MISC);
+
+    /* calcuate ACL mask */
+    EC_ZERO_LOG_ERR(acl_calc_mask(&acc_acl), AFPERR_MISC);
+
+    /* is it ok? */
+    EC_ZERO_LOG_ERR(acl_valid(acc_acl), AFPERR_MISC);
+
+    /* set it */
+    EC_ZERO_LOG_ERR(acl_set_file(name, ACL_TYPE_ACCESS, acc_acl), AFPERR_MISC);
+    EC_ZERO_LOG_ERR(vol->vfs->vfs_acl(vol, name, ACL_TYPE_ACCESS, 0, acc_acl), AFPERR_MISC);
+
+    if (def_acl) {
+        EC_ZERO_LOG_ERR(acl_set_file(name, ACL_TYPE_DEFAULT, def_acl), AFPERR_MISC);
+        EC_ZERO_LOG_ERR(vol->vfs->vfs_acl(vol, name, ACL_TYPE_DEFAULT, 0, def_acl), AFPERR_MISC);
     }
 
-    /* Now check requested rights */
-    ret = AFPERR_ACCESS;
-    i = 0;
-    do { /* Loop through ACEs */
-        who = aces[i].a_who;
-        flags = aces[i].a_flags;
-        type = aces[i].a_type;
-        rights = aces[i].a_access_mask;
+EC_CLEANUP:
+    acl_free(acc_acl);
+    acl_free(def_acl);
 
-        if (flags & ACE_INHERIT_ONLY_ACE)
-            continue;
+    LOG(log_maxdebug, logtype_afpd, "set_acl: END");
+    EC_EXIT;
+}
+#endif /* HAVE_POSIX_ACLS */
+
+/*!
+ * Checks if a given UUID has requested_rights(type darwin_ace_rights) for path.
+ *
+ * Note: this gets called frequently and is a good place for optimizations !
+ *
+ * @param vol              (r) volume
+ * @param dir              (r) directory
+ * @param path             (r) path to filesystem object
+ * @param uuid             (r) UUID of user
+ * @param requested_rights (r) requested Darwin ACE
+ *
+ * @returns                    AFP result code
+*/
+static int check_acl_access(const struct vol *vol,
+                            const struct dir *dir,
+                            const char *path,
+                            const uuidp_t uuid,
+                            uint32_t requested_rights)
+{
+    int            ret;
+    uint32_t       allowed_rights = 0;
+    char           *username = NULL;
+    uuidtype_t     uuidtype;
+    struct stat    st;
+    bstring        parent = NULL;
 
-        /* Check if its a group ACE and set checkgroup to 1 if yes */
-        checkgroup = 0;
-        if ( (flags & ACE_IDENTIFIER_GROUP) && !(flags & ACE_GROUP) ) {
-            if ( (check_group(username, uid, pgid, who)) == 0)
-                checkgroup = 1;
-            else
-                continue;
-        }
+    LOG(log_maxdebug, logtype_afpd, "check_access: Request: 0x%08x", requested_rights);
 
-        /* Now the tricky part: decide if ACE effects our user. I'll explain:
-           if its a dedicated (non trivial) ACE for the user
-           OR
-           if its a ACE for a group we're member of
-           OR
-           if its a trivial ACE_OWNER ACE and requested UUID is the owner
-           OR
-           if its a trivial ACE_GROUP ACE and requested UUID is group
-           OR
-           if its a trivial ACE_EVERYONE ACE
-           THEN
-           process ACE */
-        if (
-            ( (who == uid) && !(flags & (ACE_TRIVIAL|ACE_IDENTIFIER_GROUP)) ) ||
-            (checkgroup) ||
-            ( (flags & ACE_OWNER) && check_user_trivace ) ||
-            ( (flags & ACE_GROUP) && check_group_trivace ) ||
-            ( flags & ACE_EVERYONE )
-            ) {
-            /* Found an applicable ACE */
-            if (type == ACE_ACCESS_ALLOWED_ACE_TYPE)
-                allowed_rights |= rights;
-            else if (type == ACE_ACCESS_DENIED_ACE_TYPE)
-                /* Only or to denied rights if not previously allowed !! */
-                denied_rights |= ((!allowed_rights) & rights);
+    /* Get uid or gid from UUID */
+    EC_ZERO_LOG_ERR(getnamefromuuid(uuid, &username, &uuidtype), AFPERR_PARAM);
+    EC_ZERO_LOG_ERR(lstat(path, &st), AFPERR_PARAM);
+
+    switch (uuidtype) {
+    case UUID_USER:
+        break;
+    case UUID_GROUP:
+        LOG(log_warning, logtype_afpd, "check_access: afp_access not supported for groups");
+        EC_STATUS(AFPERR_MISC);
+        goto EC_CLEANUP;
+
+    case UUID_LOCAL:
+        LOG(log_warning, logtype_afpd, "check_access: local UUID");
+        EC_STATUS(AFPERR_MISC);
+        goto EC_CLEANUP;
+    }
+
+#ifdef HAVE_SOLARIS_ACLS
+    EC_ZERO_LOG(solaris_acl_rights(path, &st, &allowed_rights));
+#endif
+#ifdef HAVE_POSIX_ACLS
+    EC_ZERO_LOG(posix_acl_rights(path, &st, &allowed_rights));
+#endif
+
+    LOG(log_debug, logtype_afpd, "allowed rights: 0x%08x", allowed_rights);
+
+    /*
+     * The DARWIN_ACE_DELETE right might implicitly result from write acces to the parent
+     * directory. As it seems the 10.6 AFP client is puzzled when this right is not
+     * allowed where a delete would succeed because the parent dir gives write perms.
+     * So we check the parent dir for write access and set the right accordingly.
+     * Currentyl acl2ownermode calls us with dir = NULL, because it doesn't make sense
+     * there to do this extra check -- afaict.
+     */
+    if (vol && dir && (requested_rights & DARWIN_ACE_DELETE)) {
+        int i;
+        uint32_t parent_rights = 0;
+
+        if (dir->d_did == DIRDID_ROOT_PARENT) {
+            /* use volume path */
+            EC_NULL_LOG_ERR(parent = bfromcstr(vol->v_path), AFPERR_MISC);
+        } else {
+            /* build path for parent */
+            EC_NULL_LOG_ERR(parent = bstrcpy(dir->d_fullpath), AFPERR_MISC);
+            EC_ZERO_LOG_ERR(bconchar(parent, '/'), AFPERR_MISC);
+            EC_ZERO_LOG_ERR(bcatcstr(parent, path), AFPERR_MISC);
+            EC_NEG1_LOG_ERR(i = bstrrchr(parent, '/'), AFPERR_MISC);
+            EC_ZERO_LOG_ERR(binsertch(parent, i, 1, 0), AFPERR_MISC);
         }
-    } while (++i < ace_count);
 
+        LOG(log_debug, logtype_afpd,"parent: %s", cfrombstr(parent));
+        EC_ZERO_LOG_ERR(lstat(cfrombstr(parent), &st), AFPERR_MISC);
 
-    /* Darwin likes to ask for "delete_child" on dir,
-       "write_data" is actually the same, so we add that for dirs */
-    if (dir && (allowed_rights & ACE_WRITE_DATA))
-        allowed_rights |= ACE_DELETE_CHILD;
+#ifdef HAVE_SOLARIS_ACLS
+        EC_ZERO_LOG(solaris_acl_rights(cfrombstr(parent), &st, &parent_rights));
+#endif
+#ifdef HAVE_POSIX_ACLS
+    EC_ZERO_LOG(posix_acl_rights(path, &st, &allowed_rights));
+#endif
+        if (parent_rights & (DARWIN_ACE_WRITE_DATA | DARWIN_ACE_DELETE_CHILD))
+            allowed_rights |= DARWIN_ACE_DELETE; /* man, that was a lot of work! */
+    }
 
-    if (requested_rights & denied_rights) {
-        LOG(log_debug, logtype_afpd, "check_access: some requested right was denied:");
-        ret = AFPERR_ACCESS;
-    } else if ((requested_rights & allowed_rights) != requested_rights) {
-        LOG(log_debug, logtype_afpd, "check_access: some requested right wasn't allowed:");
-        ret = AFPERR_ACCESS;
+    if ((requested_rights & allowed_rights) != requested_rights) {
+        LOG(log_debug, logtype_afpd, "some requested right wasn't allowed: 0x%08x / 0x%08x",
+            requested_rights, allowed_rights);
+        EC_STATUS(AFPERR_ACCESS);
     } else {
-        LOG(log_debug, logtype_afpd, "check_access: all requested rights are allowed:");
-        ret = AFP_OK;
+        LOG(log_debug, logtype_afpd, "all requested rights are allowed: 0x%08x",
+            requested_rights);
+        EC_STATUS(AFP_OK);
     }
 
-    LOG(log_debug, logtype_afpd, "check_access: Requested rights: %08x, allowed_rights: %08x, denied_rights: %08x, Result: %d",
-        requested_rights, allowed_rights, denied_rights, ret);
+EC_CLEANUP:
+    if (username) free(username);
+    if (parent) bdestroy(parent);
 
-exit:
-    free(aces);
-    free(username);
-#ifdef DEBUG
-    LOG(log_debug9, logtype_afpd, "check_access: END");
-#endif
-    return ret;
+    EC_EXIT;
 }
 
 /********************************************************
@@ -625,8 +1193,6 @@ int afp_access(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size
     struct path         *s_path;
     uuidp_t             uuid;
 
-    LOG(log_debug9, logtype_afpd, "afp_access: BEGIN");
-
     *rbuflen = 0;
     ibuf += 2;
 
@@ -668,9 +1234,8 @@ int afp_access(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size
         return AFPERR_NOOBJ;
     }
 
-    ret = check_acl_access(s_path->u_name, uuid, darwin_ace_rights);
+    ret = check_acl_access(vol, dir, s_path->u_name, uuid, darwin_ace_rights);
 
-    LOG(log_debug9, logtype_afpd, "afp_access: END");
     return ret;
 }
 
@@ -758,7 +1323,11 @@ int afp_getacl(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size
     /* Shall we return ACL ? */
     if (bitmap & kFileSec_ACL) {
         LOG(log_debug, logtype_afpd, "afp_getacl: client requested files ACL");
-        get_and_map_acl(s_path->u_name, rbuf, rbuflen);
+        if (get_and_map_acl(s_path->u_name, rbuf, rbuflen) != 0) {
+            LOG(log_error, logtype_afpd, "afp_getacl(\"%s/%s\"): mapping error",
+                getcwdpath(), s_path->u_name);
+            return AFPERR_MISC;
+        }
     }
 
     LOG(log_debug9, logtype_afpd, "afp_getacl: END");
@@ -817,14 +1386,14 @@ int afp_setacl(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size
 
     /* Change owner: dont even try */
     if (bitmap & kFileSec_UUID) {
-        LOG(log_debug, logtype_afpd, "afp_setacl: change owner request. discarded.");
+        LOG(log_note, logtype_afpd, "afp_setacl: change owner request, discarded");
         ret = AFPERR_ACCESS;
         ibuf += UUID_BINSIZE;
     }
 
     /* Change group: certain changes might be allowed, so try it. FIXME: not implemented yet. */
     if (bitmap & kFileSec_UUID) {
-        LOG(log_debug, logtype_afpd, "afp_setacl: change group request. not supported this time.");
+        LOG(log_note, logtype_afpd, "afp_setacl: change group request, not supported");
         ret = AFPERR_PARAM;
         ibuf += UUID_BINSIZE;
     }
@@ -832,19 +1401,24 @@ int afp_setacl(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size
     /* Remove ACL ? */
     if (bitmap & kFileSec_REMOVEACL) {
         LOG(log_debug, logtype_afpd, "afp_setacl: Remove ACL request.");
-        if ((ret = remove_acl_vfs(vol, s_path->u_name, S_ISDIR(s_path->st.st_mode))) != AFP_OK)
+        if ((ret = remove_acl(vol, s_path->u_name, S_ISDIR(s_path->st.st_mode))) != AFP_OK)
             LOG(log_error, logtype_afpd, "afp_setacl: error from remove_acl");
     }
 
     /* Change ACL ? */
     if (bitmap & kFileSec_ACL) {
         LOG(log_debug, logtype_afpd, "afp_setacl: Change ACL request.");
-
-        /* Check if its our job to preserve inherited ACEs */
-        if (bitmap & kFileSec_Inherit)
-            ret = set_acl_vfs(vol, s_path->u_name, 1, ibuf);
-        else
-            ret = set_acl_vfs(vol, s_path->u_name, 0, ibuf);
+        /*  Get no of ACEs the client put on the wire */
+        uint32_t ace_count;
+        memcpy(&ace_count, ibuf, sizeof(uint32_t));
+        ace_count = htonl(ace_count);
+        ibuf += 8;      /* skip ACL flags (see acls.h) */
+
+        ret = set_acl(vol,
+                      s_path->u_name,
+                      (bitmap & kFileSec_Inherit),
+                      (darwin_ace_t *)ibuf,
+                      ace_count);
         if (ret == 0)
             ret = AFP_OK;
         else {
@@ -858,115 +1432,81 @@ int afp_setacl(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size
     return ret;
 }
 
-/*
-  unix.c/accessmode calls this: map ACL to OS 9 mode
-*/
-void acltoownermode(char *path, struct stat *st, uid_t uid, struct maccess *ma)
+/********************************************************************
+ * ACL funcs interfacing with other parts
+ ********************************************************************/
+
+/*!
+ * map ACL to user maccess
+ *
+ * This is the magic function that makes ACLs usable by calculating
+ * the access granted by ACEs to the logged in user.
+ */
+int acltoownermode(char *path, struct stat *st, struct maccess *ma)
 {
-    struct passwd *pw;
-    uuid_t uuid;
-    int dir, r_ok, w_ok, x_ok;
-
-    if ( ! (AFPobj->options.flags & OPTION_UUID))
-        return;
+    EC_INIT;
+    uint32_t rights = 0;
 
-    LOG(log_maxdebug, logtype_afpd, "acltoownermode('%s')", path);
+    if ( ! (AFPobj->options.flags & OPTION_ACL2MACCESS)
+         || (current_vol == NULL)
+         || ! (current_vol->v_flags & AFPVOL_ACLS))
+         return 0;
 
-    if ((pw = getpwuid(uid)) == NULL) {
-        LOG(log_error, logtype_afpd, "acltoownermode: %s", strerror(errno));
-        return;
-    }
+    LOG(log_maxdebug, logtype_afpd, "acltoownermode(\"%s/%s\", 0x%02x)",
+        getcwdpath(), path, ma->ma_user);
 
-    /* We need the UUID for check_acl_access */
-    if ((getuuidfromname(pw->pw_name, UUID_USER, uuid)) != 0)
-        return;
+#ifdef HAVE_SOLARIS_ACLS
+    EC_ZERO_LOG(solaris_acl_rights(path, st, &rights));
+#endif
+#ifdef HAVE_POSIX_ACLS
+    EC_ZERO_LOG(posix_acl_rights(path, st, &rights));
+#endif
 
-    /* These work for files and dirs */
-    r_ok = check_acl_access(path, uuid, DARWIN_ACE_READ_DATA);
-    w_ok = check_acl_access(path, uuid, (DARWIN_ACE_WRITE_DATA|DARWIN_ACE_APPEND_DATA));
-    x_ok = check_acl_access(path, uuid, DARWIN_ACE_EXECUTE);
+    LOG(log_maxdebug, logtype_afpd, "rights: 0x%08x", rights);
 
-    LOG(log_debug7, logtype_afpd, "acltoownermode: ma_user before: %04o",ma->ma_user);
-    if (r_ok == 0)
+    if (rights & DARWIN_ACE_READ_DATA)
         ma->ma_user |= AR_UREAD;
-    if (w_ok == 0)
+    if (rights & DARWIN_ACE_WRITE_DATA)
         ma->ma_user |= AR_UWRITE;
-    if (x_ok == 0)
+    if (rights & (DARWIN_ACE_EXECUTE | DARWIN_ACE_SEARCH))
         ma->ma_user |= AR_USEARCH;
-    LOG(log_debug7, logtype_afpd, "acltoownermode: ma_user after: %04o", ma->ma_user);
 
-    return;
+    LOG(log_maxdebug, logtype_afpd, "resulting user maccess: 0x%02x", ma->ma_user);
+
+EC_CLEANUP:
+    EC_EXIT;
 }
 
-/*
-  We're being called at the end of afp_createdir. We're (hopefully) inside dir
-  and ".AppleDouble" and ".AppleDouble/.Parent" should have already been created.
-  We then inherit any explicit ACE from "." to ".AppleDouble" and ".AppleDouble/.Parent".
-  FIXME: add to VFS layer ?
-*/
-void addir_inherit_acl(const struct vol *vol)
+/*!
+ * Check whether a volume supports ACLs
+ *
+ * @param vol  (r) volume
+ *
+ * @returns        0 if not, 1 if yes
+ */
+int check_vol_acl_support(const struct vol *vol)
 {
-    ace_t *diraces = NULL, *adaces = NULL, *combinedaces = NULL;
-    int diracecount, adacecount;
-
-    LOG(log_debug9, logtype_afpd, "addir_inherit_acl: BEGIN");
+    int ret = 1;
 
-    /* Check if ACLs are enabled for the volume */
-    if (vol->v_flags & AFPVOL_ACLS) {
-
-        if ((diracecount = get_nfsv4_acl(".", &diraces)) <= 0)
-            goto cleanup;
-        /* Remove any trivial ACE from "." */
-        if ((diracecount = strip_trivial_aces(&diraces, diracecount)) <= 0)
-            goto cleanup;
-
-        /*
-          Inherit to ".AppleDouble"
-        */
-
-        if ((adacecount = get_nfsv4_acl(".AppleDouble", &adaces)) <= 0)
-            goto cleanup;
-        /* Remove any non-trivial ACE from ".AppleDouble" */
-        if ((adacecount = strip_nontrivial_aces(&adaces, adacecount)) <= 0)
-            goto cleanup;
-
-        /* Combine ACEs */
-        if ((combinedaces = concat_aces(diraces, diracecount, adaces, adacecount)) == NULL)
-            goto cleanup;
-
-        /* Now set new acl */
-        if ((acl(".AppleDouble", ACE_SETACL, diracecount + adacecount, combinedaces)) != 0)
-            LOG(log_error, logtype_afpd, "addir_inherit_acl: acl: %s", strerror(errno));
-
-        free(adaces);
-        adaces = NULL;
-        free(combinedaces);
-        combinedaces = NULL;
-
-        /*
-          Inherit to ".AppleDouble/.Parent"
-        */
-
-        if ((adacecount = get_nfsv4_acl(".AppleDouble/.Parent", &adaces)) <= 0)
-            goto cleanup;
-        if ((adacecount = strip_nontrivial_aces(&adaces, adacecount)) <= 0)
-            goto cleanup;
-
-        /* Combine ACEs */
-        if ((combinedaces = concat_aces(diraces, diracecount, adaces, adacecount)) == NULL)
-            goto cleanup;
-
-        /* Now set new acl */
-        if ((acl(".AppleDouble/.Parent", ACE_SETACL, diracecount + adacecount, combinedaces)) != 0)
-            LOG(log_error, logtype_afpd, "addir_inherit_acl: acl: %s", strerror(errno));
-
-
-    }
+#ifdef HAVE_SOLARIS_ACLS
+    ace_t *aces = NULL;
+    if (get_nfsv4_acl(vol->v_path, &aces) == -1)
+        ret = 0;
+#endif
+#ifdef HAVE_POSIX_ACLS
+    acl_t acl = NULL;
+    if ((acl = acl_get_file(vol->v_path, ACL_TYPE_ACCESS)) == NULL)
+        ret = 0;
+#endif
 
-cleanup:
-    LOG(log_debug9, logtype_afpd, "addir_inherit_acl: END");
+#ifdef HAVE_SOLARIS_ACLS
+    if (aces) free(aces);
+#endif
+#ifdef HAVE_POSIX_ACLS
+    if (acl) acl_free(acl);
+#endif /* HAVE_POSIX_ACLS */
 
-    free(diraces);
-    free(adaces);
-    free(combinedaces);
+    LOG(log_debug, logtype_afpd, "Volume \"%s\" ACL support: %s",
+        vol->v_path, ret ? "yes" : "no");
+    return ret;
 }
index a1b1e52d4da85a4fcbb08c34f5537905a911c7b6..c89fe9c8f3c5fe0ee8df275a5e9d8c8b3dd9d9f6 100644 (file)
@@ -1,5 +1,4 @@
 /*
-   $Id: acls.h,v 1.3 2009-11-20 17:45:47 franklahm Exp $
    Copyright (c) 2008,2009 Frank Lahm <franklahm@gmail.com>
 
    This program is free software; you can redistribute it and/or modify
 #ifndef AFPD_ACLS_H 
 #define AFPD_ACLS_H
 
+#ifdef HAVE_SOLARIS_ACLS
 #include <sys/acl.h>
-#include <atalk/uuid.h>                /* for uuid_t */
+#endif
+
+#include <atalk/uuid.h>                /* for atalk_uuid_t */
 
 /*
  * This is what Apple says about ACL flags in sys/kauth.h:
  * the wire! We will ignore and spoil em.
  */
 
+#ifdef HAVE_SOLARIS_ACLS
 /* Some stuff for the handling of NFSv4 ACLs */
 #define ACE_TRIVIAL (ACE_OWNER | ACE_GROUP | ACE_EVERYONE)
+#endif /* HAVE_SOLARIS_ACLS */
 
 /* FPGet|Set Bitmap */
 enum {
@@ -53,13 +57,13 @@ enum {
 
 /* ACE Flags */
 #define DARWIN_ACE_FLAGS_KINDMASK           0xf
-#define DARWIN_ACE_FLAGS_PERMIT             (1<<0)
-#define DARWIN_ACE_FLAGS_DENY               (1<<1)
-#define DARWIN_ACE_FLAGS_INHERITED          (1<<4)
-#define DARWIN_ACE_FLAGS_FILE_INHERIT       (1<<5)
-#define DARWIN_ACE_FLAGS_DIRECTORY_INHERIT  (1<<6)
-#define DARWIN_ACE_FLAGS_LIMIT_INHERIT      (1<<7)
-#define DARWIN_ACE_FLAGS_ONLY_INHERIT       (1<<8)
+#define DARWIN_ACE_FLAGS_PERMIT             (1<<0) /* 0x00000001 */
+#define DARWIN_ACE_FLAGS_DENY               (1<<1) /* 0x00000002 */
+#define DARWIN_ACE_FLAGS_INHERITED          (1<<4) /* 0x00000010 */
+#define DARWIN_ACE_FLAGS_FILE_INHERIT       (1<<5) /* 0x00000020 */
+#define DARWIN_ACE_FLAGS_DIRECTORY_INHERIT  (1<<6) /* 0x00000040 */
+#define DARWIN_ACE_FLAGS_LIMIT_INHERIT      (1<<7) /* 0x00000080 */
+#define DARWIN_ACE_FLAGS_ONLY_INHERIT       (1<<8) /* 0x00000100 */
 
 /* All flag bits controlling ACE inheritance */
 #define DARWIN_ACE_INHERIT_CONTROL_FLAGS \
@@ -89,7 +93,7 @@ enum {
 
 /* Access Control List Entry (ACE) */
 typedef struct {
-    uuid_t      darwin_ace_uuid;
+    atalk_uuid_t      darwin_ace_uuid;
     uint32_t    darwin_ace_flags;
     uint32_t    darwin_ace_rights;
 } darwin_ace_t;
@@ -108,4 +112,7 @@ int afp_setacl (AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf,  size_t *rb
 /* Parse afp_ldap.conf */
 extern int acl_ldap_readconfig(char *name);
 
+/* Misc funcs */
+extern int acltoownermode(char *path, struct stat *st, struct maccess *ma);
+extern int check_vol_acl_support(const struct vol *vol);
 #endif
diff --git a/etc/afpd/afp_avahi.c b/etc/afpd/afp_avahi.c
new file mode 100644 (file)
index 0000000..28c72e2
--- /dev/null
@@ -0,0 +1,356 @@
+/*
+ * Author:  Daniel S. Haischt <me@daniel.stefan.haischt.name>
+ * Purpose: Avahi based Zeroconf support
+ * Docs:    http://avahi.org/download/doxygen/
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef HAVE_AVAHI
+
+#include <unistd.h>
+
+#include <avahi-common/strlst.h>
+
+#include <atalk/logger.h>
+#include <atalk/util.h>
+#include <atalk/dsi.h>
+#include <atalk/unicode.h>
+
+#include "afp_avahi.h"
+#include "afp_config.h"
+#include "volume.h"
+
+/*****************************************************************
+ * Global variables
+ *****************************************************************/
+struct context *ctx = NULL;
+
+/*****************************************************************
+ * Private functions
+ *****************************************************************/
+
+static void publish_reply(AvahiEntryGroup *g,
+                          AvahiEntryGroupState state,
+                          void *userdata);
+
+/*
+ * This function tries to register the AFP DNS
+ * SRV service type.
+ */
+static void register_stuff(void) {
+    uint port;
+    const AFPConfig *config;
+    const struct vol *volume;
+    DSI *dsi;
+    char name[MAXINSTANCENAMELEN+1];
+    AvahiStringList *strlist = NULL;
+    char tmpname[256];
+
+    assert(ctx->client);
+
+    if (!ctx->group) {
+        if (!(ctx->group = avahi_entry_group_new(ctx->client, publish_reply, ctx))) {
+            LOG(log_error, logtype_afpd, "Failed to create entry group: %s",
+                avahi_strerror(avahi_client_errno(ctx->client)));
+            goto fail;
+        }
+    }
+
+    if (avahi_entry_group_is_empty(ctx->group)) {
+        /* Register our service */
+
+        /* Build AFP volumes list */
+        int i = 0;
+        strlist = avahi_string_list_add_printf(strlist, "sys=waMa=0,adVF=0x100");
+               
+        for (volume = getvolumes(); volume; volume = volume->v_next) {
+
+            if (convert_string(CH_UCS2, CH_UTF8_MAC, volume->v_name, -1, tmpname, 255) <= 0) {
+                LOG ( log_error, logtype_afpd, "Could not set Zeroconf volume name for TimeMachine");
+                goto fail;
+            }
+
+            if (volume->v_flags & AFPVOL_TM) {
+                if (volume->v_uuid) {
+                    LOG(log_info, logtype_afpd, "Registering volume '%s' with UUID: '%s' for TimeMachine",
+                        volume->v_localname, volume->v_uuid);
+                    strlist = avahi_string_list_add_printf(strlist, "dk%u=adVN=%s,adVF=0xa1,adVU=%s",
+                                                           i++, tmpname, volume->v_uuid);
+                } else {
+                    LOG(log_warning, logtype_afpd, "Registering volume '%s' for TimeMachine. But UUID is invalid.",
+                        volume->v_localname);
+                    strlist = avahi_string_list_add_printf(strlist, "dk%u=adVN=%s,adVF=0xa1",
+                                                           i++, tmpname);
+                }      
+            }
+        }
+
+        /* AFP server */
+        for (config = ctx->configs; config; config = config->next) {
+
+            dsi = (DSI *)config->obj.handle;
+            port = getip_port((struct sockaddr *)&dsi->server);
+            
+            if (convert_string(config->obj.options.unixcharset, CH_UTF8,
+                               config->obj.options.server ? config->obj.options.server : config->obj.options.hostname, -1,
+                               name, MAXINSTANCENAMELEN) <= 0) {
+                LOG ( log_error, logtype_afpd, "Could not set Zeroconf instance name");
+                goto fail;
+            }
+
+            if (avahi_entry_group_add_service(ctx->group,
+                                              AVAHI_IF_UNSPEC,
+                                              AVAHI_PROTO_UNSPEC,
+                                              0,
+                                              name,
+                                              AFP_DNS_SERVICE_TYPE,
+                                              NULL,
+                                              NULL,
+                                              port,
+                                              NULL) < 0) {
+                LOG(log_error, logtype_afpd, "Failed to add service: %s",
+                    avahi_strerror(avahi_client_errno(ctx->client)));
+                goto fail;
+            }
+
+            if (i && avahi_entry_group_add_service_strlst(ctx->group,
+                                                          AVAHI_IF_UNSPEC,
+                                                          AVAHI_PROTO_UNSPEC,
+                                                          0,
+                                                          name,
+                                                          ADISK_SERVICE_TYPE,
+                                                          NULL,
+                                                          NULL,
+                                                          9, /* discard */
+                                                          strlist) < 0) {
+                LOG(log_error, logtype_afpd, "Failed to add service: %s",
+                    avahi_strerror(avahi_client_errno(ctx->client)));
+                goto fail;
+            }  /* if */
+        }      /* for config*/
+
+        if (avahi_entry_group_commit(ctx->group) < 0) {
+            LOG(log_error, logtype_afpd, "Failed to commit entry group: %s",
+                avahi_strerror(avahi_client_errno(ctx->client)));
+            goto fail;
+        }
+
+    }  /* if avahi_entry_group_is_empty*/
+
+    return;
+
+fail:
+    avahi_client_free (ctx->client);
+    avahi_threaded_poll_quit(ctx->threaded_poll);
+}
+
+/* Called when publishing of service data completes */
+static void publish_reply(AvahiEntryGroup *g,
+                          AvahiEntryGroupState state,
+                          AVAHI_GCC_UNUSED void *userdata)
+{
+    assert(ctx->group == NULL || g == ctx->group);
+
+    switch (state) {
+
+    case AVAHI_ENTRY_GROUP_ESTABLISHED :
+        /* The entry group has been established successfully */
+        LOG(log_debug, logtype_afpd, "publish_reply: AVAHI_ENTRY_GROUP_ESTABLISHED");
+        break;
+
+    case AVAHI_ENTRY_GROUP_COLLISION:
+        /* With multiple names there's no way to know which one collided */
+        LOG(log_error, logtype_afpd, "publish_reply: AVAHI_ENTRY_GROUP_COLLISION",
+            avahi_strerror(avahi_client_errno(ctx->client)));
+        avahi_client_free(avahi_entry_group_get_client(g));
+        avahi_threaded_poll_quit(ctx->threaded_poll);
+        break;
+               
+    case AVAHI_ENTRY_GROUP_FAILURE:
+        LOG(log_error, logtype_afpd, "Failed to register service: %s",
+            avahi_strerror(avahi_client_errno(ctx->client)));
+        avahi_client_free(avahi_entry_group_get_client(g));
+        avahi_threaded_poll_quit(ctx->threaded_poll);
+        break;
+
+    case AVAHI_ENTRY_GROUP_UNCOMMITED:
+        break;
+    case AVAHI_ENTRY_GROUP_REGISTERING:
+        break;
+    }
+}
+
+static void client_callback(AvahiClient *client,
+                            AvahiClientState state,
+                            void *userdata)
+{
+    ctx->client = client;
+
+    switch (state) {
+    case AVAHI_CLIENT_S_RUNNING:
+        /* The server has startup successfully and registered its host
+         * name on the network, so it's time to create our services */
+        if (!ctx->group)
+            register_stuff();
+        break;
+
+    case AVAHI_CLIENT_S_COLLISION:
+        if (ctx->group)
+            avahi_entry_group_reset(ctx->group);
+        break;
+
+    case AVAHI_CLIENT_FAILURE: {
+        if (avahi_client_errno(client) == AVAHI_ERR_DISCONNECTED) {
+            int error;
+
+            avahi_client_free(ctx->client);
+            ctx->client = NULL;
+            ctx->group = NULL;
+
+            /* Reconnect to the server */
+            if (!(ctx->client = avahi_client_new(avahi_threaded_poll_get(ctx->threaded_poll),
+                                                 AVAHI_CLIENT_NO_FAIL,
+                                                 client_callback,
+                                                 ctx,
+                                                 &error))) {
+
+                LOG(log_error, logtype_afpd, "Failed to contact server: %s",
+                    avahi_strerror(error));
+
+                avahi_client_free (ctx->client);
+                avahi_threaded_poll_quit(ctx->threaded_poll);
+            }
+
+        } else {
+            LOG(log_error, logtype_afpd, "Client failure: %s",
+                avahi_strerror(avahi_client_errno(client)));
+            avahi_client_free (ctx->client);
+            avahi_threaded_poll_quit(ctx->threaded_poll);
+        }
+        break;
+    }
+
+    case AVAHI_CLIENT_S_REGISTERING:
+        break;
+    case AVAHI_CLIENT_CONNECTING:
+        break;
+    }
+}
+
+/************************************************************************
+ * Public funcions
+ ************************************************************************/
+
+/*
+ * Tries to setup the Zeroconf thread and any
+ * neccessary config setting.
+ */
+void av_zeroconf_setup(const AFPConfig *configs) {
+    int error;
+
+    /* initialize the struct that holds our config settings. */
+    if (ctx) {
+        LOG(log_debug, logtype_afpd, "Resetting zeroconf records");
+        avahi_entry_group_reset(ctx->group);
+    } else {
+        ctx = calloc(1, sizeof(struct context));
+        ctx->configs = configs;
+        assert(ctx);
+    }
+
+/* first of all we need to initialize our threading env */
+    if (!(ctx->threaded_poll = avahi_threaded_poll_new())) {
+        goto fail;
+    }
+
+/* now we need to acquire a client */
+    if (!(ctx->client = avahi_client_new(avahi_threaded_poll_get(ctx->threaded_poll),
+                                         AVAHI_CLIENT_NO_FAIL,
+                                         client_callback,
+                                         NULL,
+                                         &error))) {
+        LOG(log_error, logtype_afpd, "Failed to create client object: %s",
+            avahi_strerror(avahi_client_errno(ctx->client)));
+        goto fail;
+    }
+
+    return;
+
+fail:
+    if (ctx)
+        av_zeroconf_unregister();
+
+    return;
+}
+
+/*
+ * This function finally runs the loop impl.
+ */
+int av_zeroconf_run(void) {
+    /* Finally, start the event loop thread */
+    if (avahi_threaded_poll_start(ctx->threaded_poll) < 0) {
+        LOG(log_error, logtype_afpd, "Failed to create thread: %s",
+            avahi_strerror(avahi_client_errno(ctx->client)));
+        goto fail;
+    } else {
+        LOG(log_info, logtype_afpd, "Successfully started avahi loop.");
+    }
+
+    ctx->thread_running = 1;
+    return 0;
+
+fail:
+    if (ctx)
+        av_zeroconf_unregister();
+
+    return -1;
+}
+
+/*
+ * Tries to shutdown this loop impl.
+ * Call this function from outside this thread.
+ */
+void av_zeroconf_shutdown() {
+    /* Call this when the app shuts down */
+    avahi_threaded_poll_stop(ctx->threaded_poll);
+    avahi_client_free(ctx->client);
+    avahi_threaded_poll_free(ctx->threaded_poll);
+    free(ctx);
+    ctx = NULL;
+}
+
+/*
+ * Tries to shutdown this loop impl.
+ * Call this function from inside this thread.
+ */
+int av_zeroconf_unregister() {
+    if (ctx->thread_running) {
+        /* First, block the event loop */
+        avahi_threaded_poll_lock(ctx->threaded_poll);
+
+        /* Than, do your stuff */
+        avahi_threaded_poll_quit(ctx->threaded_poll);
+
+        /* Finally, unblock the event loop */
+        avahi_threaded_poll_unlock(ctx->threaded_poll);
+        ctx->thread_running = 0;
+    }
+
+    if (ctx->client)
+        avahi_client_free(ctx->client);
+
+    if (ctx->threaded_poll)
+        avahi_threaded_poll_free(ctx->threaded_poll);
+
+    free(ctx);
+    ctx = NULL;
+
+    return 0;
+}
+
+#endif /* USE_AVAHI */
+
diff --git a/etc/afpd/afp_avahi.h b/etc/afpd/afp_avahi.h
new file mode 100644 (file)
index 0000000..2c6ca70
--- /dev/null
@@ -0,0 +1,48 @@
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: t; c-basic-offset: 2 -*- */
+/*
+ * Author:  Daniel S. Haischt <me@daniel.stefan.haischt.name>
+ * Purpose: Avahi based Zeroconf support
+ * Docs:    http://avahi.org/download/doxygen/
+ *
+ */
+
+#ifndef AFPD_AVAHI_H
+#define AFPD_AVAHI_H
+
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+
+#include <avahi-client/client.h>
+#include <avahi-client/publish.h>
+#include <avahi-common/alternative.h>
+#include <avahi-common/thread-watch.h>
+#include <avahi-common/malloc.h>
+#include <avahi-common/error.h>
+
+#include <atalk/logger.h>
+
+#include "afp_config.h"
+
+#define AFP_DNS_SERVICE_TYPE "_afpovertcp._tcp"
+#define ADISK_SERVICE_TYPE "_adisk._tcp"
+
+#define MAXINSTANCENAMELEN 63
+
+struct context {
+       /* Avahi stuff */
+  int               thread_running;
+  AvahiThreadedPoll *threaded_poll;
+  AvahiClient       *client;
+  AvahiEntryGroup   *group;
+       /* Netatalk stuff */
+       const AFPConfig   *configs;
+};
+
+/* prototype definitions */
+void av_zeroconf_setup(const AFPConfig *configs);
+int av_zeroconf_run(void);
+int av_zeroconf_unregister(void);
+void av_zeroconf_shutdown(void);
+
+#endif   /* AFPD_AVAHI_H */
index 86ee093a0da93a660f751cbfc157aa300982bce6..52592564cb84b1d9769f68696a5f015a32a581c8 100644 (file)
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
-
-/* STDC check */
-#if 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_UNISTD_H
 #include <unistd.h>
-#endif /* HAVE_UNISTD_H */
 #include <ctype.h>
-#include <atalk/logger.h>
-#include <atalk/util.h>
-
 #include <sys/socket.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
 
+#ifdef USE_SRVLOC
+#include <slp.h>
+#endif /* USE_SRVLOC */
+
+#include <atalk/logger.h>
+#include <atalk/util.h>
 #include <atalk/dsi.h>
 #include <atalk/atp.h>
 #include <atalk/asp.h>
@@ -45,10 +31,8 @@ char *strchr (), *strrchr ();
 #include <atalk/afp.h>
 #include <atalk/compat.h>
 #include <atalk/server_child.h>
-#ifdef USE_SRVLOC
-#include <slp.h>
-#endif /* USE_SRVLOC */
-#ifdef HAVE_NFSv4_ACLS
+
+#ifdef HAVE_LDAP
 #include <atalk/ldapconfig.h>
 #endif
 
@@ -56,6 +40,8 @@ char *strchr (), *strrchr ();
 #include "afp_config.h"
 #include "uam_auth.h"
 #include "status.h"
+#include "volume.h"
+#include "afp_zeroconf.h"
 
 #define LINESIZE 1024  
 
@@ -94,6 +80,9 @@ void configfree(AFPConfig *configs, const AFPConfig *config)
         }
         free(p);
     }
+
+    /* the master loaded the volumes for zeroconf, get rid of that */
+    unload_volumes_and_extmap();
 }
 
 #ifdef USE_SRVLOC
@@ -155,9 +144,9 @@ static char * srvloc_encode(const struct afp_options *options, const char *name)
 }
 #endif /* USE_SRVLOC */
 
-#ifdef USE_SRVLOC
 static void dsi_cleanup(const AFPConfig *config)
 {
+#ifdef USE_SRVLOC
     SLPError err;
     SLPError callbackerr;
     SLPHandle hslp;
@@ -190,8 +179,8 @@ static void dsi_cleanup(const AFPConfig *config)
 srvloc_dereg_err:
     dsi->srvloc_url[0] = '\0';
     SLPClose(hslp);
-}
 #endif /* USE_SRVLOC */
+}
 
 #ifndef NO_DDP
 static void asp_cleanup(const AFPConfig *config)
@@ -225,25 +214,30 @@ static int asp_start(AFPConfig *config, AFPConfig *configs,
 }
 #endif /* no afp/asp */
 
-static int dsi_start(AFPConfig *config, AFPConfig *configs,
-                     server_child *server_children)
+static afp_child_t *dsi_start(AFPConfig *config, AFPConfig *configs,
+                              server_child *server_children)
 {
-    DSI *dsi;
+    DSI *dsi = config->obj.handle;
+    afp_child_t *child = NULL;
 
-    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( EXITERR_CLNT );
+    if (!(child = dsi_getsession(dsi,
+                                 server_children,
+                                 config->obj.options.tickleval))) {
+        LOG(log_error, logtype_afpd, "dsi_start: session error: %s", strerror(errno));
+        return NULL;
     }
 
     /* we've forked. */
-    if (dsi->child) {
+    if (parent_or_child == 1) {
         configfree(configs, config);
+        config->obj.ipc_fd = child->ipc_fds[1];
+        close(child->ipc_fds[0]); /* Close parent IPC fd */
+        free(child);
         afp_over_dsi(&config->obj); /* start a session */
         exit (0);
     }
 
-    return 0;
+    return child;
 }
 
 #ifndef NO_DDP
@@ -453,7 +447,6 @@ srvloc_reg_err:
     }
 #endif /* USE_SRVLOC */
 
-
     config->fd = dsi->serversock;
     config->obj.handle = dsi;
     config->obj.config = config;
@@ -476,7 +469,7 @@ srvloc_reg_err:
 /* allocate server configurations. this should really store the last
  * entry in config->last or something like that. that would make
  * supporting multiple dsi transports easier. */
-static AFPConfig *AFPConfigInit(const struct afp_options *options,
+static AFPConfig *AFPConfigInit(struct afp_options *options,
                                 const struct afp_options *defoptions)
 {
     AFPConfig *config = NULL, *next = NULL;
@@ -543,13 +536,6 @@ AFPConfig *configinit(struct afp_options *cmdline)
     struct afp_options options;
     AFPConfig *config=NULL, *first = NULL; 
 
-#ifdef HAVE_NFSv4_ACLS
-    /* Parse afp_ldap.conf first so we can set the uuid option */
-    LOG(log_debug, logtype_afpd, "Start parsing afp_ldap.conf");
-    acl_ldap_readconfig(_PATH_ACL_LDAPCONF);
-    LOG(log_debug, logtype_afpd, "Finished parsing afp_ldap.conf");
-#endif
-
     /* if config file doesn't exist, load defaults */
     if ((fp = fopen(cmdline->configfile, "r")) == NULL)
     {
@@ -558,8 +544,6 @@ AFPConfig *configinit(struct afp_options *cmdline)
         return AFPConfigInit(cmdline, cmdline);
     }
 
-    LOG(log_debug, logtype_afpd, "Loading ConfigFile"); 
-
     /* scan in the configuration file */
     len = 0;
     while (!feof(fp)) {
@@ -585,13 +569,7 @@ AFPConfig *configinit(struct afp_options *cmdline)
         if (!afp_options_parseline(p, &options))
             continue;
 
-#ifdef HAVE_NFSv4_ACLS
-       /* Enable UUID support if LDAP config is complete */
-       if (ldap_config_valid)
-           options.flags |= OPTION_UUID;
-#endif
-
-        /* this should really get a head and a tail to simplify things. */
+        /* AFPConfigInit can return two linked configs due to DSI and ASP */
         if (!first) {
             if ((first = AFPConfigInit(&options, cmdline)))
                 config = first->next ? first->next : first;
@@ -600,11 +578,20 @@ AFPConfig *configinit(struct afp_options *cmdline)
         }
     }
 
+#ifdef HAVE_LDAP
+    /* Parse afp_ldap.conf */
+    acl_ldap_readconfig(_PATH_ACL_LDAPCONF);
+#endif /* HAVE_LDAP */
+
     LOG(log_debug, logtype_afpd, "Finished parsing Config File");
     fclose(fp);
 
     if (!have_option)
         first = AFPConfigInit(cmdline, cmdline);
 
+    /* Now register with zeroconf, we also need the volumes for that */
+    load_volumes(&first->obj);
+    zeroconf_register(first);
+
     return first;
 }
index 1a0d08ef8859426a5e7fa8d113046d95308ff2c3..ba800ce3aa45c5b547b296ea0e650ebf9a48d6f7 100644 (file)
@@ -19,7 +19,7 @@ typedef struct AFPConfig {
     unsigned char *optcount;
     char status[1400];
     const void *defoptions, *signature;
-    int (*server_start) (struct AFPConfig *, struct AFPConfig *,
+    afp_child_t *(*server_start) (struct AFPConfig *, struct AFPConfig *,
                              server_child *);
     void (*server_cleanup) (const struct AFPConfig *);
     struct AFPConfig *next;
index 8bcfb9c6399ee9aeeeb7aeb0eeca131b229f3073..aaf3d8d64cd94dc3d8433ac2c76898259a193c2e 100644 (file)
@@ -1,6 +1,4 @@
 /*
- * $Id: afp_dsi.c,v 1.53 2010-03-30 12:55:26 franklahm Exp $
- *
  * Copyright (c) 1999 Adrian Sun (asun@zoology.washington.edu)
  * Copyright (c) 1990,1993 Regents of The University of Michigan.
  * All Rights Reserved.  See COPYRIGHT.
@@ -28,6 +26,7 @@
 #include <netinet/in.h>
 #include <arpa/inet.h>
 #include <atalk/logger.h>
+#include <setjmp.h>
 
 #include <atalk/dsi.h>
 #include <atalk/compat.h>
 #include "switch.h"
 #include "auth.h"
 #include "fork.h"
+#include "dircache.h"
 
 #ifdef FORCE_UIDGID
 #warning UIDGID
 #include "uid.h"
 #endif /* FORCE_UIDGID */
 
-#define CHILD_DIE         (1 << 0)
-#define CHILD_RUNNING     (1 << 1)
-#define CHILD_SLEEPING    (1 << 2)
-#define CHILD_DATA        (1 << 3)
-
 /* 
  * We generally pass this from afp_over_dsi to all afp_* funcs, so it should already be
  * available everywhere. Unfortunately some funcs (eg acltoownermode) need acces to it
  */
 AFPObj *AFPobj = NULL;
 
-static struct {
-    AFPObj *obj;
-    unsigned char flags;
-    int tickle;
-} child;
+typedef struct {
+    uint16_t DSIreqID;
+    uint8_t  AFPcommand;
+    uint32_t result;
+} rc_elem_t;
 
+/*
+ * AFP replay cache:
+ * - fix sized array
+ * - indexed just by taking DSIreqID mod REPLAYCACHE_SIZE
+ */
+static rc_elem_t replaycache[REPLAYCACHE_SIZE];
 
+static sigjmp_buf recon_jmp;
 static void afp_dsi_close(AFPObj *obj)
 {
     DSI *dsi = obj->handle;
 
+    close(obj->ipc_fd);
+    obj->ipc_fd = -1;
+
     /* we may have been called from a signal handler caught when afpd was running
      * as uid 0, that's the wrong user for volume's prexec_close scripts if any,
      * restore our login user
@@ -85,8 +90,9 @@ static void afp_dsi_close(AFPObj *obj)
     if (obj->logout)
         (*obj->logout)();
 
-    LOG(log_info, logtype_afpd, "%.2fKB read, %.2fKB written",
+    LOG(log_note, logtype_afpd, "AFP statistics: %.2f KB read, %.2f KB written",
         dsi->read_count/1024.0, dsi->write_count/1024.0);
+    log_dircache_stat();
 
     dsi_close(dsi);
 }
@@ -97,19 +103,21 @@ static void afp_dsi_close(AFPObj *obj)
  */
 static void afp_dsi_die(int sig)
 {
-static volatile int in_handler;
-    
-    if (in_handler) {
-       return;
+    DSI *dsi = (DSI *)AFPobj->handle;
+
+    if (dsi->flags & DSI_RECONINPROG) {
+        /* Primary reconnect succeeded, got SIGTERM from afpd parent */
+        dsi->flags &= ~DSI_RECONINPROG;
+        return; /* this returns to afp_disconnect */
+    }
+
+    if (dsi->flags & DSI_DISCONNECTED) {
+        LOG(log_note, logtype_afpd, "Disconnected session terminating");
+        exit(0);
     }
-    /* 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);
+
+    dsi_attention(AFPobj->handle, AFPATTN_SHUTDOWN);
+    afp_dsi_close(AFPobj);
     if (sig) /* if no signal, assume dieing because logins are disabled &
                 don't log it (maintenance mode)*/
         LOG(log_info, logtype_afpd, "Connection terminated");
@@ -121,11 +129,55 @@ static volatile int in_handler;
     }
 }
 
-/* */
-static void afp_dsi_sleep(void)
+/* SIGURG handler (primary reconnect) */
+static void afp_dsi_transfer_session(int sig _U_)
 {
-    child.flags |= CHILD_SLEEPING;
-    dsi_sleep(child.obj->handle, 1);
+    uint16_t dsiID;
+    int socket;
+    DSI *dsi = (DSI *)AFPobj->handle;
+
+    LOG(log_debug, logtype_afpd, "afp_dsi_transfer_session: got SIGURG, trying to receive session");
+
+    if (readt(AFPobj->ipc_fd, &dsiID, 2, 0, 2) != 2) {
+        LOG(log_error, logtype_afpd, "afp_dsi_transfer_session: couldn't receive DSI id, goodbye");
+        afp_dsi_close(AFPobj);
+        exit(EXITERR_SYS);
+    }
+
+    if ((socket = recv_fd(AFPobj->ipc_fd, 1)) == -1) {
+        LOG(log_error, logtype_afpd, "afp_dsi_transfer_session: couldn't receive session fd, goodbye");
+        afp_dsi_close(AFPobj);
+        exit(EXITERR_SYS);
+    }
+
+    LOG(log_debug, logtype_afpd, "afp_dsi_transfer_session: received socket fd: %i", socket);
+
+    dsi->proto_close(dsi);
+    dsi->socket = socket;
+    dsi->flags = DSI_RECONSOCKET;
+    dsi->datalen = 0;
+    dsi->eof = dsi->start = dsi->buffer;
+    dsi->in_write = 0;
+    dsi->header.dsi_requestID = dsiID;
+    dsi->header.dsi_command = DSIFUNC_CMD;
+
+    /*
+     * The session transfer happens in the middle of FPDisconnect old session, thus we
+     * have to send the reply now.
+     */
+    if (!dsi_cmdreply(dsi, AFP_OK)) {
+        LOG(log_error, logtype_afpd, "dsi_cmdreply: %s", strerror(errno) );
+        afp_dsi_close(AFPobj);
+        exit(EXITERR_CLNT);
+    }
+
+    LOG(log_note, logtype_afpd, "afp_dsi_transfer_session: succesfull primary reconnect");
+    /* 
+     * Now returning from this signal handler return to dsi_receive which should start
+     * reading/continuing from the connected socket that was passed via the parent from
+     * another session. The parent will terminate that session.
+     */
+    siglongjmp(recon_jmp, 1);
 }
 
 /* ------------------- */
@@ -133,13 +185,13 @@ static void afp_dsi_timedown(int sig _U_)
 {
     struct sigaction   sv;
     struct itimerval   it;
-
-    child.flags |= CHILD_DIE;
+    DSI                 *dsi = (DSI *)AFPobj->handle;
+    dsi->flags |= DSI_DIE;
     /* shutdown and don't reconnect. server going down in 5 minutes. */
     setmessage("The server is going down for maintenance.");
-    if (dsi_attention(child.obj->handle, AFPATTN_SHUTDOWN | AFPATTN_NORECONNECT |
+    if (dsi_attention(AFPobj->handle, AFPATTN_SHUTDOWN | AFPATTN_NORECONNECT |
                   AFPATTN_MESG | AFPATTN_TIME(5)) < 0) {
-        DSI *dsi = (DSI *) child.obj->handle;
+        DSI *dsi = (DSI *)AFPobj->handle;
         dsi->down_request = 1;
     }                  
 
@@ -175,8 +227,7 @@ static void afp_dsi_timedown(int sig _U_)
 
 /* ---------------------------------
  * SIGHUP reload configuration file
- * FIXME here or we wait ?
-*/
+ */
 volatile int reload_request = 0;
 
 static void afp_dsi_reload(int sig _U_)
@@ -195,48 +246,71 @@ static void afp_dsi_debug(int sig _U_)
 }
 
 /* ---------------------- */
-#ifdef SERVERTEXT
 static void afp_dsi_getmesg (int sig _U_)
 {
-    DSI *dsi = (DSI *) child.obj->handle;
+    DSI *dsi = (DSI *)AFPobj->handle;
 
     dsi->msg_request = 1;
-    if (dsi_attention(child.obj->handle, AFPATTN_MESG | AFPATTN_TIME(5)) < 0)
+    if (dsi_attention(AFPobj->handle, AFPATTN_MESG | AFPATTN_TIME(5)) < 0)
         dsi->msg_request = 2;
 }
-#endif /* SERVERTEXT */
 
 static void alarm_handler(int sig _U_)
 {
     int err;
-    DSI *dsi = (DSI *) child.obj->handle;
+    DSI *dsi = (DSI *)AFPobj->handle;
 
-    /* we have to restart the timer because some libraries 
-     * may use alarm() */
+    /* we have to restart the timer because some libraries may use alarm() */
     setitimer(ITIMER_REAL, &dsi->timer, NULL);
 
-    /* we got some traffic from the client since the previous timer 
-     * tick. */
-    if ((child.flags & CHILD_DATA)) {
-        child.flags &= ~CHILD_DATA;
+    /* we got some traffic from the client since the previous timer tick. */
+    if ((dsi->flags & DSI_DATA)) {
+        dsi->flags &= ~DSI_DATA;
         return;
     }
 
-    /* if we're in the midst of processing something,
-       don't die. */
-    if ((child.flags & CHILD_SLEEPING) && child.tickle++ < child.obj->options.sleep) {
+    dsi->tickle++;
+    LOG(log_maxdebug, logtype_afpd, "alarm: tickles: %u, flags: %s|%s|%s|%s|%s|%s|%s|%s|%s",
+        dsi->tickle,
+        (dsi->flags & DSI_DATA) ?         "DSI_DATA" : "-",
+        (dsi->flags & DSI_RUNNING) ?      "DSI_RUNNING" : "-",
+        (dsi->flags & DSI_SLEEPING) ?     "DSI_SLEEPING" : "-",
+        (dsi->flags & DSI_EXTSLEEP) ?     "DSI_EXTSLEEP" : "-",
+        (dsi->flags & DSI_DISCONNECTED) ? "DSI_DISCONNECTED" : "-",
+        (dsi->flags & DSI_DIE) ?          "DSI_DIE" : "-",
+        (dsi->flags & DSI_NOREPLY) ?      "DSI_NOREPLY" : "-",
+        (dsi->flags & DSI_RECONSOCKET) ?  "DSI_RECONSOCKET" : "-",
+        (dsi->flags & DSI_RECONINPROG) ?  "DSI_RECONINPROG" : "-");
+
+    if (dsi->flags & DSI_SLEEPING) {
+        if (dsi->tickle > AFPobj->options.sleep) {
+            LOG(log_error, logtype_afpd, "afp_alarm: sleep time ended");
+            afp_dsi_die(EXITERR_CLNT);
+        }
         return;
     } 
-        
-    if ((child.flags & CHILD_RUNNING) || (child.tickle++ < child.obj->options.timeout)) {
-        if (!(err = pollvoltime(child.obj)))
-            err = dsi_tickle(child.obj->handle);
-        if (err <= 0) 
+
+    if (dsi->flags & DSI_DISCONNECTED) {
+        if (dsi->tickle > AFPobj->options.disconnected) {
+             LOG(log_error, logtype_afpd, "afp_alarm: no reconnect within 10 minutes, goodbye");
             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(EXITERR_CLNT);
+        }
+        return;
+    }
+
+    /* if we're in the midst of processing something, don't die. */        
+    if ( !(dsi->flags & DSI_RUNNING) && (dsi->tickle >= AFPobj->options.timeout)) {
+        LOG(log_error, logtype_afpd, "afp_alarm: child timed out, entering disconnected state");
+        dsi->proto_close(dsi);
+        dsi->flags |= DSI_DISCONNECTED;
+        return;
+    }
+
+    if ((err = pollvoltime(AFPobj)) == 0)
+        err = dsi_tickle(AFPobj->handle);
+    if (err <= 0) {
+        LOG(log_error, logtype_afpd, "afp_alarm: connection problem, entering disconnected state");
+        dsi->flags |= DSI_DISCONNECTED;
     }
 }
 
@@ -252,14 +326,14 @@ static void pending_request(DSI *dsi)
     if (dsi->msg_request) {
         if (dsi->msg_request == 2) {
             /* didn't send it in signal handler */
-            dsi_attention(child.obj->handle, AFPATTN_MESG | AFPATTN_TIME(5));
+            dsi_attention(AFPobj->handle, AFPATTN_MESG | AFPATTN_TIME(5));
         }
         dsi->msg_request = 0;
-        readmessage(child.obj);
+        readmessage(AFPobj);
     }
     if (dsi->down_request) {
         dsi->down_request = 0;
-        dsi_attention(child.obj->handle, AFPATTN_SHUTDOWN | AFPATTN_NORECONNECT |
+        dsi_attention(AFPobj->handle, AFPATTN_SHUTDOWN | AFPATTN_NORECONNECT |
                   AFPATTN_MESG | AFPATTN_TIME(5));
     }
 }
@@ -270,6 +344,7 @@ static void pending_request(DSI *dsi)
 void afp_over_dsi(AFPObj *obj)
 {
     DSI *dsi = (DSI *) obj->handle;
+    int rc_idx;
     u_int32_t err, cmd;
     u_int8_t function;
     struct sigaction action;
@@ -278,10 +353,7 @@ 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;
+    dsi->tickle = 0;
 
     memset(&action, 0, sizeof(action));
 
@@ -292,15 +364,27 @@ void afp_over_dsi(AFPObj *obj)
     sigaddset(&action.sa_mask, SIGTERM);
     sigaddset(&action.sa_mask, SIGUSR1);
     sigaddset(&action.sa_mask, SIGINT);
-#ifdef SERVERTEXT
     sigaddset(&action.sa_mask, SIGUSR2);
-#endif    
     action.sa_flags = SA_RESTART;
     if ( sigaction( SIGHUP, &action, NULL ) < 0 ) {
         LOG(log_error, logtype_afpd, "afp_over_dsi: sigaction: %s", strerror(errno) );
         afp_dsi_die(EXITERR_SYS);
     }
 
+    /* install SIGURG */
+    action.sa_handler = afp_dsi_transfer_session;
+    sigemptyset( &action.sa_mask );
+    sigaddset(&action.sa_mask, SIGALRM);
+    sigaddset(&action.sa_mask, SIGTERM);
+    sigaddset(&action.sa_mask, SIGUSR1);
+    sigaddset(&action.sa_mask, SIGINT);
+    sigaddset(&action.sa_mask, SIGUSR2);
+    action.sa_flags = SA_RESTART;
+    if ( sigaction( SIGURG, &action, NULL ) < 0 ) {
+        LOG(log_error, logtype_afpd, "afp_over_dsi: sigaction: %s", strerror(errno) );
+        afp_dsi_die(EXITERR_SYS);
+    }
+
     /* install SIGTERM */
     action.sa_handler = afp_dsi_die;
     sigemptyset( &action.sa_mask );
@@ -308,16 +392,13 @@ void afp_over_dsi(AFPObj *obj)
     sigaddset(&action.sa_mask, SIGHUP);
     sigaddset(&action.sa_mask, SIGUSR1);
     sigaddset(&action.sa_mask, SIGINT);
-#ifdef SERVERTEXT
     sigaddset(&action.sa_mask, SIGUSR2);
-#endif    
     action.sa_flags = SA_RESTART;
     if ( sigaction( SIGTERM, &action, NULL ) < 0 ) {
         LOG(log_error, logtype_afpd, "afp_over_dsi: sigaction: %s", strerror(errno) );
         afp_dsi_die(EXITERR_SYS);
     }
 
-#ifdef SERVERTEXT
     /* Added for server message support */
     action.sa_handler = afp_dsi_getmesg;
     sigemptyset( &action.sa_mask );
@@ -331,7 +412,6 @@ void afp_over_dsi(AFPObj *obj)
         LOG(log_error, logtype_afpd, "afp_over_dsi: sigaction: %s", strerror(errno) );
         afp_dsi_die(EXITERR_SYS);
     }
-#endif /* SERVERTEXT */
 
     /*  SIGUSR1 - set down in 5 minutes  */
     action.sa_handler = afp_dsi_timedown;
@@ -340,9 +420,7 @@ void afp_over_dsi(AFPObj *obj)
     sigaddset(&action.sa_mask, SIGHUP);
     sigaddset(&action.sa_mask, SIGTERM);
     sigaddset(&action.sa_mask, SIGINT);
-#ifdef SERVERTEXT
     sigaddset(&action.sa_mask, SIGUSR2);
-#endif    
     action.sa_flags = SA_RESTART;
     if ( sigaction( SIGUSR1, &action, NULL) < 0 ) {
         LOG(log_error, logtype_afpd, "afp_over_dsi: sigaction: %s", strerror(errno) );
@@ -366,9 +444,7 @@ void afp_over_dsi(AFPObj *obj)
     sigaddset(&action.sa_mask, SIGTERM);
     sigaddset(&action.sa_mask, SIGUSR1);
     sigaddset(&action.sa_mask, SIGINT);
-#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)) {
@@ -376,47 +452,77 @@ void afp_over_dsi(AFPObj *obj)
     }
 #endif /* DEBUGGING */
 
+    if (dircache_init(obj->options.dircachesize) != 0)
+        afp_dsi_die(EXITERR_SYS);
+
     /* get stuck here until the end */
-    while ((cmd = dsi_receive(dsi))) {
-        child.tickle = 0;
-        child.flags &= ~CHILD_SLEEPING;
-        dsi_sleep(dsi, 0); /* wake up */
+    while (1) {
+        if (sigsetjmp(recon_jmp, 1) != 0)
+            /* returning from SIGALARM handler for a primary reconnect */
+            continue;
+
+        /* Blocking read on the network socket */
+        cmd = dsi_receive(dsi);
+
+        if (cmd == 0) {
+            /* cmd == 0 is the error condition */
+            if (dsi->flags & DSI_RECONSOCKET) {
+                /* we just got a reconnect so we immediately try again to receive on the new fd */
+                dsi->flags &= ~DSI_RECONSOCKET;
+                continue;
+            }
+            /* Some error on the client connection, enter disconnected state */
+            dsi->flags |= DSI_DISCONNECTED;
+            pause(); /* gets interrupted by SIGALARM or SIGURG tickle */
+            continue; /* continue receiving until disconnect timer expires
+                       * or a primary reconnect succeeds  */
+        }
+
+        if (!(dsi->flags & DSI_EXTSLEEP) && (dsi->flags & DSI_SLEEPING)) {
+            LOG(log_debug, logtype_afpd, "afp_over_dsi: got data, ending normal sleep");
+            dsi->flags &= ~DSI_SLEEPING;
+            dsi->tickle = 0;
+        }
 
         if (reload_request) {
             reload_request = 0;
-            load_volumes(child.obj);
+            load_volumes(AFPobj);
+            dircache_dump();
+            log_dircache_stat();
         }
 
+        /* The first SIGINT enables debugging, the next restores the config */
         if (debug_request) {
-            char logstr[50];
+            static int debugging = 0;
             debug_request = 0;
 
-            /* The first SIGINT enables debugging, the second one kills us */
-            action.sa_handler = afp_dsi_die;
-            sigfillset( &action.sa_mask );
-            action.sa_flags = SA_RESTART;
-            if ( sigaction( SIGINT, &action, NULL ) < 0 ) {
-                LOG(log_error, logtype_afpd, "afp_over_dsi: sigaction: %s", strerror(errno) );
-                afp_dsi_die(EXITERR_SYS);
+            if (debugging) {
+                if (obj->options.logconfig)
+                    setuplog(obj->options.logconfig);
+                else
+                    setuplog("default log_note");
+                debugging = 0;
+            } else {
+                char logstr[50];
+                debugging = 1;
+                sprintf(logstr, "default log_maxdebug /tmp/afpd.%u.XXXXXX", getpid());
+                setuplog(logstr);
             }
-
-            sprintf(logstr, "default log_maxdebug /tmp/afpd.%u.XXXXXX", getpid());
-            setuplog(logstr);
         }
 
         if (cmd == DSIFUNC_TICKLE) {
             /* timer is not every 30 seconds anymore, so we don't get killed on the client side. */
-            if ((child.flags & CHILD_DIE))
+            if ((dsi->flags & DSI_DIE))
                 dsi_tickle(dsi);
             pending_request(dsi);
             continue;
         } 
 
-        child.flags |= CHILD_DATA;
+        dsi->flags |= DSI_DATA;
         switch(cmd) {
         case DSIFUNC_CLOSE:
             afp_dsi_close(obj);
-            LOG(log_info, logtype_afpd, "done");
+            LOG(log_note, logtype_afpd, "done");
             return;
             break;
 
@@ -432,41 +538,61 @@ void afp_over_dsi(AFPObj *obj)
 
             function = (u_char) dsi->commands[0];
 
-            /* send off an afp command. in a couple cases, we take advantage
-             * of the fact that we're a stream-based protocol. */
-            if (afp_switch[function]) {
-                dsi->datalen = DSI_DATASIZ;
-                child.flags |= CHILD_RUNNING;
+            /* AFP replay cache */
+            rc_idx = REPLAYCACHE_SIZE % dsi->clientID;
+            LOG(log_debug, logtype_afpd, "DSI request ID: %u", dsi->clientID);
 
-                LOG(log_debug, logtype_afpd, "<== Start AFP command: %s", AfpNum2name(function));
+            if (replaycache[rc_idx].DSIreqID == dsi->clientID
+                && replaycache[rc_idx].AFPcommand == function) {
+                LOG(log_debug, logtype_afpd, "AFP Replay Cache match: id: %u / cmd: %s",
+                    dsi->clientID, AfpNum2name(function));
+                err = replaycache[rc_idx].result;
+            /* AFP replay cache end */
+            } else {
+                /* send off an afp command. in a couple cases, we take advantage
+                 * of the fact that we're a stream-based protocol. */
+                if (afp_switch[function]) {
+                    dsi->datalen = DSI_DATASIZ;
+                    dsi->flags |= DSI_RUNNING;
 
-                err = (*afp_switch[function])(obj,
-                                              (char *)&dsi->commands, dsi->cmdlen,
-                                              (char *)&dsi->data, &dsi->datalen);
+                    LOG(log_debug, logtype_afpd, "<== Start AFP command: %s", AfpNum2name(function));
+
+                    err = (*afp_switch[function])(obj,
+                                                  (char *)&dsi->commands, dsi->cmdlen,
+                                                  (char *)&dsi->data, &dsi->datalen);
+
+                    LOG(log_debug, logtype_afpd, "==> Finished AFP command: %s -> %s",
+                        AfpNum2name(function), AfpErr2name(err));
+
+                    dir_free_invalid_q();
 
-                LOG(log_debug, logtype_afpd, "==> Finished AFP command: %s -> %s",
-                    AfpNum2name(function), AfpErr2name(err));
 #ifdef FORCE_UIDGID
-               /* bring everything back to old euid, egid */
-                if (obj->force_uid)
-                   restore_uidgid ( &obj->uidgid );
+                    /* bring everything back to old euid, egid */
+                    if (obj->force_uid)
+                        restore_uidgid ( &obj->uidgid );
 #endif /* FORCE_UIDGID */
-                child.flags &= ~CHILD_RUNNING;
-            } else {
-                LOG(log_error, logtype_afpd, "bad function %X", function);
-                dsi->datalen = 0;
-                err = AFPERR_NOOP;
+                    dsi->flags &= ~DSI_RUNNING;
+
+                    /* Add result to the AFP replay cache */
+                    replaycache[rc_idx].DSIreqID = dsi->clientID;
+                    replaycache[rc_idx].AFPcommand = function;
+                    replaycache[rc_idx].result = err;
+                } else {
+                    LOG(log_error, logtype_afpd, "bad function %X", function);
+                    dsi->datalen = 0;
+                    err = AFPERR_NOOP;
+                }
             }
 
             /* single shot toggle that gets set by dsi_readinit. */
-            if (dsi->noreply) {
-                dsi->noreply = 0;
+            if (dsi->flags & DSI_NOREPLY) {
+                dsi->flags &= ~DSI_NOREPLY;
                 break;
             }
 
             if (!dsi_cmdreply(dsi, err)) {
                 LOG(log_error, logtype_afpd, "dsi_cmdreply(%d): %s", dsi->socket, strerror(errno) );
-                afp_dsi_die(EXITERR_CLNT);
+                dsi->flags |= DSI_DISCONNECTED;
             }
             break;
 
@@ -474,7 +600,7 @@ void afp_over_dsi(AFPObj *obj)
             function = (u_char) dsi->commands[0];
             if ( afp_switch[ function ] != NULL ) {
                 dsi->datalen = DSI_DATASIZ;
-                child.flags |= CHILD_RUNNING;
+                dsi->flags |= DSI_RUNNING;
 
                 LOG(log_debug, logtype_afpd, "<== Start AFP command: %s", AfpNum2name(function));
 
@@ -485,7 +611,7 @@ void afp_over_dsi(AFPObj *obj)
                 LOG(log_debug, logtype_afpd, "==> Finished AFP command: %s -> %s",
                     AfpNum2name(function), AfpErr2name(err));
 
-                child.flags &= ~CHILD_RUNNING;
+                dsi->flags &= ~DSI_RUNNING;
 #ifdef FORCE_UIDGID
                /* bring everything back to old euid, egid */
                if (obj->force_uid)
@@ -499,7 +625,7 @@ void afp_over_dsi(AFPObj *obj)
 
             if (!dsi_wrtreply(dsi, err)) {
                 LOG(log_error, logtype_afpd, "dsi_wrtreply: %s", strerror(errno) );
-                afp_dsi_die(EXITERR_CLNT);
+                dsi->flags |= DSI_DISCONNECTED;
             }
             break;
 
index 418e044d2803851fee4f597bcb11199a22c97782..e513821789bac0dba5e197a8336be5182baf4464 100644 (file)
 
 #include <stdio.h>
 #include <stdlib.h>
-
-/* STDC check */
-#if 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 */
-
 #include <ctype.h>
-#ifdef HAVE_UNISTD_H
 #include <unistd.h>
-#endif /* HAVE_UNISTD_H */
 #include <sys/param.h>
 #include <sys/socket.h>
 #include <atalk/logger.h>
 
 #include <netinet/in.h>
 #include <arpa/inet.h>
+
 #ifdef HAVE_NETDB_H
 #include <netdb.h>
 #endif /* HAVE_NETDB_H */
 
+#ifdef ADMIN_GRP
+#include <grp.h>
+#include <sys/types.h>
+#endif /* ADMIN_GRP */
+
 #include <atalk/paths.h>
 #include <atalk/util.h>
+#include <atalk/compat.h>
+
 #include "globals.h"
 #include "status.h"
 #include "auth.h"
-
-#include <atalk/compat.h>
-
-#ifdef ADMIN_GRP
-#include <grp.h>
-#include <sys/types.h>
-#endif /* ADMIN_GRP */
+#include "dircache.h"
 
 #ifndef MIN
 #define MIN(a, b)  ((a) < (b) ? (a) : (b))
@@ -152,6 +137,8 @@ void afp_options_free(struct afp_options *opt,
        free(opt->ntdomain);
     if (opt->ntseparator && (opt->ntseparator != save->ntseparator))
        free(opt->ntseparator);
+    if (opt->logconfig && (opt->logconfig != save->logconfig))
+       free(opt->logconfig);
 }
 
 /* initialize options */
@@ -164,6 +151,7 @@ void afp_options_init(struct afp_options *options)
     options->systemvol.name = _PATH_AFPDSYSVOL;
     options->configfile = _PATH_AFPDCONF;
     options->sigconffile = _PATH_AFPDSIGCONF;
+    options->uuidconf = _PATH_AFPDUUIDCONF;
     options->uampath = _PATH_AFPDUAMPATH;
     options->uamlist = "uams_dhx.so,uams_dhx2.so";
     options->guest = "nobody";
@@ -171,8 +159,9 @@ void afp_options_init(struct afp_options *options)
     options->transports = AFPTRANS_TCP; /*  TCP only */
     options->passwdfile = _PATH_AFPDPWFILE;
     options->tickleval = 30;
-    options->timeout = 4;
-    options->sleep = 10* 120; /* 10 h in 30 seconds tick */
+    options->timeout = 4;       /* 4 tickles = 2 minutes */
+    options->sleep = 10 * 60 * 2; /* 10 h in 30 seconds tick */
+    options->disconnected = 10 * 60 * 2; /* 10 h in 30 seconds tick */
     options->server_notif = 1;
     options->authprintdir = NULL;
     options->signatureopt = "auto";
@@ -194,6 +183,9 @@ void afp_options_init(struct afp_options *options)
     /* don't advertize slp by default */
     options->flags |= OPTION_NOSLP;
 #endif
+    options->dircachesize = DEFAULT_MAX_DIRCACHE_SIZE;
+    options->flags |= OPTION_ACL2MACCESS;
+    options->flags |= OPTION_UUID;
 }
 
 /* parse an afpd.conf line. i'm doing it this way because it's
@@ -219,7 +211,10 @@ int afp_options_parseline(char *buf, struct afp_options *options)
     if (strstr(buf, " -slp"))
         options->flags &= ~OPTION_NOSLP;
 #endif
-
+#ifdef USE_ZEROCONF
+    if (strstr(buf, " -nozeroconf"))
+        options->flags |= OPTION_NOZEROCONF;
+#endif
     if (strstr(buf, " -nouservolfirst"))
         options->flags &= ~OPTION_USERVOLFIRST;
     if (strstr(buf, " -uservolfirst"))
@@ -236,6 +231,8 @@ int afp_options_parseline(char *buf, struct afp_options *options)
         options->flags |= OPTION_CUSTOMICON;
     if (strstr(buf, " -advertise_ssh"))
         options->flags |= OPTION_ANNOUNCESSH;
+    if (strstr(buf, " -noacl2maccess"))
+        options->flags &= ~OPTION_ACL2MACCESS;
 
     /* passwd bits */
     if (strstr(buf, " -nosavepassword"))
@@ -345,6 +342,7 @@ int afp_options_parseline(char *buf, struct afp_options *options)
         char *optstr;
         if ((optstr = getoption(c, "-setuplog"))) {
             setuplog(optstr);
+            options->logconfig = optstr; /* at least store the last (possibly only) one */
             c += sizeof("-setuplog");
         }
     }
@@ -462,6 +460,9 @@ int afp_options_parseline(char *buf, struct afp_options *options)
     if ((c = getoption(buf, "-ntseparator")) && (opt = strdup(c)))
        options->ntseparator = opt;
 
+    if ((c = getoption(buf, "-dircachesize")))
+        options->dircachesize = atoi(c);
+     
     return 1;
 }
 
@@ -480,18 +481,15 @@ static void show_version( void )
 
        puts( "afpd has been compiled with support for these features:\n" );
 
-       printf( "        AFP3.x support:\t" );
-#ifdef AFP3x
-       puts( "Yes" );
-#else
-       puts( "No" );
-#endif
+       printf( "        AFP3.x support:\tYes\n" );
+        printf( "        TCP/IP Support:\t" );
+        puts( "Yes" );
 
-       printf( "      Transport layers:\t" );
+       printf( "DDP(AppleTalk) Support:\t" );
 #ifdef NO_DDP
-       puts( "TCP/IP" );
+       puts( "No" );
 #else
-       puts( "TCP/IP DDP" );
+       puts( "Yes" );
 #endif
 
        printf( "         CNID backends:\t" );
@@ -538,6 +536,13 @@ static void show_version_extended(void )
        puts( "No" );
 #endif
 
+       printf( "      Zeroconf support:\t" );
+#ifdef USE_ZEROCONF
+       puts( "Yes" );
+#else
+       puts( "No" );
+#endif
+
        printf( "  TCP wrappers support:\t" );
 #ifdef TCPWRAP
        puts( "Yes" );
@@ -586,6 +591,23 @@ static void show_version_extended(void )
 #else
        puts( "No" );
 #endif
+
+       printf( "           ACL support:\t" );
+#ifdef HAVE_ACLS
+       puts( "Yes" );
+#else
+       puts( "No" );
+#endif
+
+       printf( "            EA support:\t" );
+       puts( EA_MODULES );
+
+       printf( "          LDAP support:\t" );
+#ifdef HAVE_LDAP
+       puts( "Yes" );
+#else
+       puts( "No" );
+#endif
 }
 
 /*
@@ -594,11 +616,18 @@ static void show_version_extended(void )
 static void show_paths( void )
 {
        printf( "             afpd.conf:\t%s\n", _PATH_AFPDCONF );
-       printf( "    afp_signature.conf:\t%s\n", _PATH_AFPDSIGCONF );
        printf( "   AppleVolumes.system:\t%s\n", _PATH_AFPDSYSVOL );
        printf( "  AppleVolumes.default:\t%s\n", _PATH_AFPDDEFVOL );
+       printf( "    afp_signature.conf:\t%s\n", _PATH_AFPDSIGCONF );
+       printf( "      afp_voluuid.conf:\t%s\n", _PATH_AFPDUUIDCONF );
+#ifdef HAVE_LDAP
+       printf( "         afp_ldap.conf:\t%s\n", _PATH_ACL_LDAPCONF );
+#else
+       printf( "         afp_ldap.conf:\tnot supported\n");
+#endif
        printf( "       UAM search path:\t%s\n", _PATH_AFPDUAMPATH );
-    printf( "  Server messages path:\t%s\n", SERVERTEXT);
+       printf( "  Server messages path:\t%s\n", SERVERTEXT);
+       printf( "              lockfile:\t%s\n", _PATH_AFPDLOCK);
 }
 
 /*
diff --git a/etc/afpd/afp_zeroconf.c b/etc/afpd/afp_zeroconf.c
new file mode 100644 (file)
index 0000000..84f1871
--- /dev/null
@@ -0,0 +1,41 @@
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: t; c-basic-offset: 2 -*- */
+/*
+ * Author:  Daniel S. Haischt <me@daniel.stefan.haischt.name>
+ * Purpose: Zeroconf facade, that abstracts access to a
+ *          particular Zeroconf implementation
+ * Doc:     http://www.dns-sd.org/
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "afp_zeroconf.h"
+#include "afp_config.h"
+
+#ifdef HAVE_AVAHI
+#include "afp_avahi.h"
+#endif
+
+
+/*
+ * Functions (actually they are just facades)
+ */
+void zeroconf_register(const AFPConfig *configs)
+{
+#if defined (HAVE_AVAHI)
+  LOG(log_debug, logtype_afpd, "Attempting to register with mDNS using Avahi");
+
+       av_zeroconf_setup(configs);
+  av_zeroconf_run();
+#endif
+}
+
+void zeroconf_deregister(void)
+{
+#if defined (HAVE_AVAHI)
+  LOG(log_debug, logtype_afpd, "Attempting to de-register mDNS using Avahi");
+       av_zeroconf_shutdown();
+#endif
+}
diff --git a/etc/afpd/afp_zeroconf.h b/etc/afpd/afp_zeroconf.h
new file mode 100644 (file)
index 0000000..e2711af
--- /dev/null
@@ -0,0 +1,29 @@
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: t; c-basic-offset: 2 -*- */
+/*
+ * Author:  Daniel S. Haischt <me@daniel.stefan.haischt.name>
+ * Purpose: Zeroconf facade, that abstracts access to a
+ *          particular Zeroconf implementation
+ * Doc:     http://www.dns-sd.org/
+ *
+ */
+
+#ifndef AFPD_ZEROCONF_H
+#define AFPD_ZEROCONF_H
+
+#include "afp_config.h"
+
+/*
+ * Prototype Definitions
+ */
+
+/*
+ * registers service with a particular Zerconf implemenation.
+ */
+void zeroconf_register(const AFPConfig *configs);
+
+/*
+ * de-registers the ntpd service with a particular Zerconf implemenation.
+ */
+void zeroconf_deregister(void);
+
+#endif /* AFPD_ZEROCONF_H */
index 37850f62c471be718dd60f5046e3ce2325de32eb..fe9ff250336214d410a32bee946578865d490fd2 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: appl.c,v 1.18 2009-10-15 10:43:13 didg Exp $
+ * $Id: appl.c,v 1.18.4.1 2010-02-01 10:56:08 franklahm Exp $
  *
  * Copyright (c) 1990,1993 Regents of The University of Michigan.
  * All Rights Reserved.  See COPYRIGHT.
@@ -20,6 +20,8 @@
 
 #include <atalk/adouble.h>
 #include <atalk/afp.h>
+#include <atalk/bstrlib.h>
+#include <atalk/bstradd.h>
 
 #include "volume.h"
 #include "globals.h"
@@ -122,7 +124,7 @@ static int copyapplfile(int sfd, int dfd, char *mpath, u_short mplen)
  * See afp_getappl() for the backward compatiblity code.
  */
 static char *
-makemacpath(char *mpath, int mpathlen, struct dir *dir, char *path)
+makemacpath(const struct vol *vol, char *mpath, int mpathlen, struct dir *dir, char *path)
 {
     char       *p;
 
@@ -130,16 +132,65 @@ makemacpath(char *mpath, int mpathlen, struct dir *dir, char *path)
     p -= strlen( path );
     memcpy( p, path, strlen( path )); 
 
-    while ( dir->d_parent != NULL ) {
-        p -= strlen( dir->d_m_name ) + 1;
+    while ( dir->d_did != DIRDID_ROOT ) {
+        p -= blength(dir->d_m_name) + 1;
         if (p < mpath) {
             /* FIXME: pathname too long */
             return NULL;
         }
-        strcpy( p, dir->d_m_name );
-        dir = dir->d_parent;
+        memcpy(p, cfrombstr(dir->d_m_name), blength(dir->d_m_name) + 1);
+        if ((dir = dirlookup(vol, dir->d_pdid)) == NULL)
+            return NULL;
     }
     return( p );
+
+
+#if 0
+    char buffer[12 + MAXPATHLEN + 1];
+    int buflen = 12 + MAXPATHLEN + 1;
+    char *ret = mpath;
+    char *path = name;
+    char *uname = NULL;
+    struct bstrList *pathlist = NULL;
+    cnid_t cnid = dir->d_pdid;
+
+    /* Create list for path elements, request 16 list elements for now*/
+    if ((pathlist = bstListCreateMin(16)) == NULL) {
+        LOG(log_error, logtype_afpd, "makemacpath: OOM: %s", strerror(errno));
+        return NULL;
+    }
+
+    while ( cnid != DIRDID_ROOT ) {
+
+        /* construct path, copy already found uname to path element list*/
+        if ((bstrListPush(pathlist, bfromcstr(path))) != BSTR_OK) {
+            afp_errno = AFPERR_MISC;
+            ret = NULL;
+            goto exit;
+        }
+
+        /* next part */
+        if ((uname = cnid_resolve(vol->v_cdb, &cnid, buffer, buflen)) == NULL ) {
+            afp_errno = AFPERR_NOOBJ;
+            ret = NULL;
+            goto exit;
+        }
+
+        if ((path = utompath(vol, uname, cnid, utf8_encoding())) == NULL) {
+            afp_errno = AFPERR_MISC;
+            ret = NULL;
+            goto exit;
+        }
+    }
+
+
+
+exit:
+    if (pathlist)
+        bstrListDestroy(pathlist);
+
+    return(ret);
+#endif
 }
 
 
@@ -197,7 +248,7 @@ int afp_addappl(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, siz
         return( AFPERR_PARAM );
     }
     mpath = obj->newtmp;
-    mp = makemacpath( mpath, AFPOBJ_TMPSIZ, curdir, path->m_name );
+    mp = makemacpath( vol, mpath, AFPOBJ_TMPSIZ, curdir, path->m_name );
     if (!mp) {
         return AFPERR_PARAM;
     }
@@ -280,7 +331,7 @@ int afp_rmvappl(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, siz
         return( AFPERR_PARAM );
     }
     mpath = obj->newtmp;
-    mp = makemacpath( mpath, AFPOBJ_TMPSIZ, curdir, path->m_name );
+    mp = makemacpath( vol, mpath, AFPOBJ_TMPSIZ, curdir, path->m_name );
     if (!mp) {
         return AFPERR_PARAM ;
     }
@@ -418,7 +469,7 @@ int afp_getappl(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t
     memcpy( q, p, len );
     q = cbuf;
 
-    if (( path = cname( vol, vol->v_dir, &q )) == NULL ) {
+    if (( path = cname( vol, vol->v_root, &q )) == NULL ) {
         *rbuflen = 0;
         return( AFPERR_NOITEM );
     }
index 77e946ce3f02ff165f847e0c86d0c11f83107df3..cd2f73f3cfb7a384df8e7dc9f0ca8154eabba3af 100644 (file)
@@ -26,9 +26,6 @@
 #include <time.h>
 #include <pwd.h>
 #include <grp.h>
-#include <atalk/logger.h>
-#include <atalk/server_ipc.h>
-#include <atalk/uuid.h>
 
 #ifdef TRU64
 #include <netdb.h>
 extern void afp_get_cmdline( int *ac, char ***av );
 #endif /* TRU64 */
 
+#include <atalk/logger.h>
+#include <atalk/server_ipc.h>
+#include <atalk/uuid.h>
+
 #include "globals.h"
 #include "auth.h"
 #include "uam_auth.h"
@@ -46,7 +47,7 @@ extern void afp_get_cmdline( int *ac, char ***av );
 #include "status.h"
 #include "fork.h"
 #include "extattrs.h"
-#ifdef HAVE_NFSv4_ACLS
+#ifdef HAVE_ACLS
 #include "acls.h"
 #endif
 
@@ -78,11 +79,10 @@ static struct afp_versions  afp_versions[] = {
     { "AFPVersion 2.1", 21 },
 #endif /* ! NO_DDP */
     { "AFP2.2", 22 },
-#ifdef AFP3x
     { "AFPX03", 30 },
     { "AFP3.1", 31 },
-    { "AFP3.2", 32 }
-#endif /* AFP3x */
+    { "AFP3.2", 32 },
+    { "AFP3.3", 33 }
 };
 
 static struct uam_mod uam_modules = {NULL, NULL, &uam_modules, &uam_modules};
@@ -207,21 +207,25 @@ static int set_auth_switch(int expired)
     else {
         afp_switch = postauth_switch;
         switch (afp_version) {
+
+        case 33:
         case 32:
-#ifdef HAVE_NFSv4_ACLS
+#ifdef HAVE_ACLS
             uam_afpserver_action(AFP_GETACL, UAM_AFPSERVER_POSTAUTH, afp_getacl, NULL);
             uam_afpserver_action(AFP_SETACL, UAM_AFPSERVER_POSTAUTH, afp_setacl, NULL);
             uam_afpserver_action(AFP_ACCESS, UAM_AFPSERVER_POSTAUTH, afp_access, NULL);
-#endif
+#endif /* HAVE_ACLS */
             uam_afpserver_action(AFP_GETEXTATTR, UAM_AFPSERVER_POSTAUTH, afp_getextattr, NULL);
             uam_afpserver_action(AFP_SETEXTATTR, UAM_AFPSERVER_POSTAUTH, afp_setextattr, NULL);
             uam_afpserver_action(AFP_REMOVEATTR, UAM_AFPSERVER_POSTAUTH, afp_remextattr, NULL);
             uam_afpserver_action(AFP_LISTEXTATTR, UAM_AFPSERVER_POSTAUTH, afp_listextattr, NULL);
+
         case 31:
             uam_afpserver_action(AFP_SYNCDIR, UAM_AFPSERVER_POSTAUTH, afp_syncdir, NULL);
             uam_afpserver_action(AFP_SYNCFORK, UAM_AFPSERVER_POSTAUTH, afp_syncfork, NULL);
             uam_afpserver_action(AFP_SPOTLIGHT_PRIVATE, UAM_AFPSERVER_POSTAUTH, afp_null_nolog, NULL);
             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);
@@ -432,25 +436,54 @@ static int login(AFPObj *obj, struct passwd *pwd, void (*logout)(void), int expi
 }
 
 /* ---------------------- */
-int afp_zzz ( /* Function 122 */
-    AFPObj       *obj,
-    char         *ibuf _U_, size_t ibuflen _U_, 
-    char *rbuf, size_t *rbuflen)
+int afp_zzz(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
 {
-    u_int32_t   retdata;
+    uint32_t data;
+    DSI *dsi = (DSI *)AFPobj->handle;
 
     *rbuflen = 0;
 
-    retdata = obj->options.sleep /120;
-    if (!retdata) {
-        retdata = 1;
+    if (ibuflen < 4)
+        return AFPERR_MISC;
+    memcpy(&data, ibuf, 4); /* flag */
+    data = ntohl(data);
+
+    /*
+     * Possible sleeping states:
+     * 1) normal sleep: DSI_SLEEPING (up to 10.3)
+     * 2) extended sleep: DSI_SLEEPING | DSI_EXTSLEEP (starting with 10.4)
+     */
+
+    if (data & AFPZZZ_EXT_WAKEUP) {
+        /* wakeup request from exetended sleep */
+        if (dsi->flags & DSI_EXTSLEEP) {
+            LOG(log_debug, logtype_afpd, "afp_zzz: waking up from extended sleep");
+            dsi->flags &= ~(DSI_SLEEPING | DSI_EXTSLEEP);
+        }
+    } else {
+        /* sleep request */
+        dsi->flags |= DSI_SLEEPING;
+        if (data & AFPZZZ_EXT_SLEEP) {
+            LOG(log_debug, logtype_afpd, "afp_zzz: entering extended sleep");
+            dsi->flags |= DSI_EXTSLEEP;
+        } else {
+            LOG(log_debug, logtype_afpd, "afp_zzz: entering normal sleep");
+        }
+    }
+    /*
+     * According to AFP 3.3 spec we should not return anything,
+     * but eg 10.5.8 server still returns the numbers of hours
+     * the server is keeping the sessino (ie max sleeptime).
+     */
+    data = obj->options.sleep / 120; /* hours */
+    if (!data) {
+        data = 1;
     }
-    *rbuflen = sizeof(retdata);
-    retdata = htonl(retdata);
-    memcpy(rbuf, &retdata, sizeof(retdata));
-    if (obj->sleep)
-        obj->sleep();
-    rbuf += sizeof(retdata);
+    *rbuflen = sizeof(data);
+    data = htonl(data);
+    memcpy(rbuf, &data, sizeof(data));
+    rbuf += sizeof(data);
+
     return AFP_OK;
 }
 
@@ -545,7 +578,7 @@ int afp_getsession(
             token = obj->sinfo.sessiontoken;
         }
         break;
-    case 3: /* Jaguar */
+    case 3:
     case 4:
         if (ibuflen >= 8 ) {
             p = ibuf;
@@ -558,7 +591,7 @@ int afp_getsession(
             if (ibuflen < idlen || idlen > (90-10)) {
                 return AFPERR_PARAM;
             }
-            server_ipc_write(IPC_GETSESSION, idlen+8, p );
+            ipc_child_write(obj->ipc_fd, IPC_GETSESSION, idlen+8, p);
             tklen = obj->sinfo.sessiontoken_len;
             token = obj->sinfo.sessiontoken;
         }
@@ -588,10 +621,10 @@ int afp_getsession(
 }
 
 /* ---------------------- */
-int afp_disconnect(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
+int afp_disconnect(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
 {
+    DSI                 *dsi = (DSI *)obj->handle;
     u_int16_t           type;
-
     u_int32_t           tklen;
     pid_t               token;
     int                 i;
@@ -632,11 +665,41 @@ int afp_disconnect(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _
         }
     }
 
-    /* killed old session, not easy */
-    server_ipc_write(IPC_KILLTOKEN, tklen, &token);
-    sleep(1);
+    LOG(log_note, logtype_afpd, "afp_disconnect: trying primary reconnect");
+    dsi->flags |= DSI_RECONINPROG;
+
+    /* Deactivate tickle timer */
+    const struct itimerval none = {{0, 0}, {0, 0}};
+    setitimer(ITIMER_REAL, &none, NULL);
+
+    /* check for old session, possibly transfering session from here to there */
+    if (ipc_child_write(obj->ipc_fd, IPC_DISCOLDSESSION, tklen, &token) == -1)
+        goto exit;
+    /* write uint16_t DSI request ID */
+    if (writet(obj->ipc_fd, &dsi->header.dsi_requestID, 2, 0, 2) != 2) {
+        LOG(log_error, logtype_afpd, "afp_disconnect: couldn't send DSI request ID");
+        goto exit;
+    }
+    /* now send our connected AFP client socket */
+    if (send_fd(obj->ipc_fd, dsi->socket) != 0)
+        goto exit;
+    /* Now see what happens: either afpd master sends us SIGTERM because our session */
+    /* has been transfered to a old disconnected session, or we continue    */
+    sleep(5);
+
+    if (!(dsi->flags & DSI_RECONINPROG)) { /* deleted in SIGTERM handler */
+        /* Reconnect succeeded, we exit now after sleeping some more */
+        sleep(2); /* sleep some more to give the recon. session time */
+        LOG(log_note, logtype_afpd, "afp_disconnect: primary reconnect succeeded");
+        exit(0);
+    }
+
+exit:
+    /* Reinstall tickle timer */
+    setitimer(ITIMER_REAL, &dsi->timer, NULL);
 
-    return AFPERR_SESSCLOS;   /* was AFP_OK */
+    LOG(log_error, logtype_afpd, "afp_disconnect: primary reconnect failed");
+    return AFPERR_MISC;
 }
 
 /* ---------------------- */
@@ -959,6 +1022,7 @@ int afp_getuserinfo(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf,
     u_int8_t  thisuser;
     u_int32_t id;
     u_int16_t bitmap;
+    char *bitmapp;
 
     LOG(log_debug, logtype_afpd, "begin afp_getuserinfo:");
 
@@ -977,8 +1041,9 @@ int afp_getuserinfo(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf,
     if ((bitmap & USERIBIT_ALL) != bitmap)
         return AFPERR_BITMAP;
 
-    /* copy the bitmap back to reply buffer */
+    /* remember place where we store the possibly modified bitmap later */
     memcpy(rbuf, ibuf, sizeof(bitmap));
+    bitmapp = rbuf;
     rbuf += sizeof(bitmap);
     *rbuflen = sizeof(bitmap);
 
@@ -997,29 +1062,27 @@ int afp_getuserinfo(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf,
         *rbuflen += sizeof(id);
     }
 
-#ifdef HAVE_NFSv4_ACLS
     if (bitmap & USERIBIT_UUID) {
-        int ret;
-        uuid_t uuid;
-        char *uuidstring;
-
-        if ( ! (obj->options.flags & OPTION_UUID))
-            return AFPERR_BITMAP;
-        LOG(log_debug, logtype_afpd, "afp_getuserinfo: get UUID for \'%s\'", obj->username);
-        ret = getuuidfromname( obj->username, UUID_USER, uuid);
-        if (ret != 0) {
-            LOG(log_info, logtype_afpd, "afp_getuserinfo: error getting UUID !");
-            return AFPERR_NOITEM;
-        }
-        if (0 == (uuid_bin2string( uuid, &uuidstring))) {
-            LOG(log_debug, logtype_afpd, "afp_getuserinfo: got UUID: %s", uuidstring);
-            free(uuidstring);
+        if ( ! (obj->options.flags & OPTION_UUID)) {
+            bitmap &= ~USERIBIT_UUID;
+            bitmap = htons(bitmap);
+            memcpy(bitmapp, &bitmap, sizeof(bitmap));
+        } else {
+            LOG(log_debug, logtype_afpd, "afp_getuserinfo: get UUID for \'%s\'", obj->username);
+            int ret;
+            atalk_uuid_t uuid;
+            ret = getuuidfromname( obj->username, UUID_USER, uuid);
+            if (ret != 0) {
+                LOG(log_info, logtype_afpd, "afp_getuserinfo: error getting UUID !");
+                return AFPERR_NOITEM;
+            }
+            LOG(log_debug, logtype_afpd, "afp_getuserinfo: got UUID: %s", uuid_bin2string(uuid));
+
+            memcpy(rbuf, uuid, UUID_BINSIZE);
+            rbuf += UUID_BINSIZE;
+            *rbuflen += UUID_BINSIZE;
         }
-        memcpy(rbuf, uuid, UUID_BINSIZE);
-        rbuf += UUID_BINSIZE;
-        *rbuflen += UUID_BINSIZE;
     }
-#endif
 
     LOG(log_debug, logtype_afpd, "END afp_getuserinfo:");
     return AFP_OK;
index a1e96dfc50ab74649f67c09569f6ea8c99818e37..0faeef9494b92619dd6cbcf2f905d6ce88a12dd8 100644 (file)
@@ -1,6 +1,7 @@
 /* 
  * Netatalk 2002 (c)
  * Copyright (C) 1990, 1993 Regents of The University of Michigan
+ * Copyright (C) 2010 Frank Lahm
  * All Rights Reserved. See COPYRIGHT
  */
 
  *
  * Initial version written by Rafal Lewczuk <rlewczuk@pronet.pl>
  *
+ * Starting with Netatalk 2.2 searching by name criteria utilizes the
+ * CNID database in conjunction with an enhanced cnid_dbd. This requires
+ * the use of cnidscheme:dbd for the searched volume, the new functionality
+ * is not built into cnidscheme:cdb.
  */
 
 #ifdef HAVE_CONFIG_H
 #include <ctype.h>
 #include <string.h>
 #include <time.h>
-
-#if STDC_HEADERS
 #include <string.h>
-#else
-#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
-
 #include <sys/file.h>
 #include <netinet/in.h>
 
 #include <atalk/afp.h>
 #include <atalk/adouble.h>
 #include <atalk/logger.h>
-#ifdef CNID_DB
 #include <atalk/cnid.h>
-#endif /* CNID_DB */
+#include <atalk/cnid_dbd_private.h>
 #include <atalk/util.h>
+#include <atalk/bstradd.h>
+#include <atalk/unicode.h>
 
 #include "desktop.h"
 #include "directory.h"
+#include "dircache.h"
 #include "file.h"
 #include "volume.h"
 #include "globals.h"
@@ -144,6 +142,7 @@ static int addstack(char *uname, struct dir *dir, int pidx)
        /* Put new element. Allocate and copy lname and path. */
        ds = dstack + dsidx++;
        ds->dir = dir;
+    dir->d_flags |= DIRF_CACHELOCK;
        ds->pidx = pidx;
        ds->checked = 0;
        if (pidx >= 0) {
@@ -176,6 +175,7 @@ static int reducestack(void)
        while (dsidx > 0) {
                if (dstack[dsidx-1].checked) {
                        dsidx--;
+            dstack[dsidx].dir->d_flags &= ~DIRF_CACHELOCK;
                        free(dstack[dsidx].path);
                } else
                        return dsidx - 1;
@@ -189,6 +189,7 @@ static void clearstack(void)
        save_cidx = -1;
        while (dsidx > 0) {
                dsidx--;
+        dstack[dsidx].dir->d_flags &= ~DIRF_CACHELOCK;
                free(dstack[dsidx].path);
        }
 } 
@@ -479,18 +480,29 @@ static int rslt_add ( struct vol *vol, struct path *path, char **buf, int ext)
 #define VETO_STR \
         "./../.AppleDouble/.AppleDB/Network Trash Folder/TheVolumeSettingsFolder/TheFindByContentFolder/.AppleDesktop/.Parent/"
 
-/* This function performs search. It is called directly from afp_catsearch 
- * vol - volume we are searching on ...
- * dir - directory we are starting from ...
- * c1, c2 - search criteria
- * rmatches - maximum number of matches we can return
- * pos - position we've stopped recently
- * rbuf - output buffer
- * rbuflen - output buffer length
+/*!
+ * This function performs a filesystem search
+ *
+ * Uses globals c1, c2, the search criteria
+ *
+ * @param vol       (r)  volume we are searching on ...
+ * @param dir       (rw) directory we are starting from ...
+ * @param rmatches  (r)  maximum number of matches we can return
+ * @param pos       (r)  position we've stopped recently
+ * @param rbuf      (w)  output buffer
+ * @param nrecs     (w)  number of matches
+ * @param rsize     (w)  length of data written to output buffer
+ * @param ext       (r)  extended search flag
  */
 #define NUM_ROUNDS 200
-static int catsearch(struct vol *vol, struct dir *dir,  
-                    int rmatches, u_int32_t *pos, char *rbuf, u_int32_t *nrecs, int *rsize, int ext)
+static int catsearch(struct vol *vol,
+                     struct dir *dir,  
+                     int rmatches,
+                     uint32_t *pos,
+                     char *rbuf,
+                     uint32_t *nrecs,
+                     int *rsize,
+                     int ext)
 {
     static u_int32_t cur_pos;    /* Saved position index (ID) - used to remember "position" across FPCatSearch calls */
     static DIR *dirpos;                 /* UNIX structure describing currently opened directory. */
@@ -503,7 +515,6 @@ static int catsearch(struct vol *vol, struct dir *dir,
        char *rrbuf = rbuf;
     time_t start_time;
     int num_rounds = NUM_ROUNDS;
-    int cached;
     int cwd = -1;
     int error;
         
@@ -540,14 +551,14 @@ static int catsearch(struct vol *vol, struct dir *dir,
     start_time = time(NULL);
 
        while ((cidx = reducestack()) != -1) {
-               cached = 1;
-
                error = lchdir(dstack[cidx].path);
 
-               if (!error && dirpos == NULL) {
+               if (!error && dirpos == NULL)
                        dirpos = opendir(".");
-                       cached = (dstack[cidx].dir->d_child != NULL);
-               }
+
+               if (dirpos == NULL)
+                       dirpos = opendir(dstack[cidx].path);
+
                if (error || dirpos == NULL) {
                        switch (errno) {
                        case EACCES:
@@ -594,18 +605,16 @@ static int catsearch(struct vol *vol, struct dir *dir,
                                   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(vol, dstack[cidx].dir, path.u_name);
-               else
-                       path.d_dir = NULL;
-               if (!path.d_dir) {
+                int unlen = strlen(path.u_name);
+                path.d_dir = dircache_search_by_name(vol, dstack[cidx].dir, path.u_name, unlen, path.st.st_ctime);
+               if (path.d_dir == NULL) {
                        /* path.m_name is set by adddir */
-                   if (NULL == (path.d_dir = adddir( vol, dstack[cidx].dir, &path) ) ) {
+                   if (NULL == (path.d_dir = dir_add( vol, dstack[cidx].dir, &path, unlen) ) ) {
                                                result = AFPERR_MISC;
                                                goto catsearch_end;
                                        }
                 }
-                path.m_name = path.d_dir->d_m_name; 
+                path.m_name = cfrombstr(path.d_dir->d_m_name);
                        
                                if (addstack(path.u_name, path.d_dir, cidx) == -1) {
                                        result = AFPERR_MISC;
@@ -667,6 +676,156 @@ catsearch_end: /* Exiting catsearch: error condition */
        return result;
 } /* catsearch() */
 
+/*!
+ * This function performs a CNID db search
+ *
+ * Uses globals c1, c2, the search criteria
+ *
+ * @param vol       (r)  volume we are searching on ...
+ * @param dir       (rw) directory we are starting from ...
+ * @param uname     (r)  UNIX name of object to search
+ * @param rmatches  (r)  maximum number of matches we can return
+ * @param pos       (r)  position we've stopped recently
+ * @param rbuf      (w)  output buffer
+ * @param nrecs     (w)  number of matches
+ * @param rsize     (w)  length of data written to output buffer
+ * @param ext       (r)  extended search flag
+ */
+static int catsearch_db(struct vol *vol,
+                        struct dir *dir,  
+                        const char *uname,
+                        int rmatches,
+                        uint32_t *pos,
+                        char *rbuf,
+                        uint32_t *nrecs,
+                        int *rsize,
+                        int ext)
+{
+    static char resbuf[DBD_MAX_SRCH_RSLTS * sizeof(cnid_t)];
+    static uint32_t cur_pos;
+    static int num_matches;
+    int ccr ,r;
+       int result = AFP_OK;
+    struct path path;
+       char *rrbuf = rbuf;
+    char buffer[MAXPATHLEN +2];
+    uint16_t flags = CONV_TOLOWER;
+
+    LOG(log_debug, logtype_afpd, "catsearch_db(req pos: %u): {pos: %u, name: %s}",
+        *pos, cur_pos, uname);
+        
+       if (*pos != 0 && *pos != cur_pos) {
+               result = AFPERR_CATCHNG;
+               goto catsearch_end;
+       }
+
+    if (cur_pos == 0 || *pos == 0) {
+        if (convert_charset(vol->v_volcharset,
+                            vol->v_volcharset,
+                            vol->v_maccharset,
+                            uname,
+                            strlen(uname),
+                            buffer,
+                            MAXPATHLEN,
+                            &flags) == (size_t)-1) {
+            LOG(log_error, logtype_cnid, "catsearch_db: conversion error");
+            result = AFPERR_MISC;
+            goto catsearch_end;
+        }
+
+        LOG(log_debug, logtype_afpd, "catsearch_db: %s", buffer);
+
+        if ((num_matches = cnid_find(vol->v_cdb,
+                                     buffer,
+                                     strlen(uname),
+                                     resbuf,
+                                     sizeof(resbuf))) == -1) {
+            result = AFPERR_MISC;
+            goto catsearch_end;
+        }
+    }
+       
+       while (cur_pos < num_matches) {
+        char *name;
+        cnid_t cnid, did;
+        char resolvebuf[12 + MAXPATHLEN + 1];
+        struct dir *dir;
+
+        /* Next CNID to process from buffer */
+        memcpy(&cnid, resbuf + cur_pos * sizeof(cnid_t), sizeof(cnid_t));
+        did = cnid;
+
+        if ((name = cnid_resolve(vol->v_cdb, &did, resolvebuf, 12 + MAXPATHLEN + 1)) == NULL)
+            goto next;
+        LOG(log_debug, logtype_afpd, "catsearch_db: {pos: %u, name:%s, cnid: %u}",
+            cur_pos, name, ntohl(cnid));
+        if ((dir = dirlookup(vol, did)) == NULL)
+            goto next;
+        if (movecwd(vol, dir) < 0 )
+            goto next;
+
+        memset(&path, 0, sizeof(path));
+        path.u_name = name;
+        path.m_name = utompath(vol, name, cnid, utf8_encoding());
+
+        if (of_stat(&path) != 0) {
+            switch (errno) {
+            case EACCES:
+            case ELOOP:
+                goto next;
+            case ENOENT:
+                
+            default:
+                result = AFPERR_MISC;
+                goto catsearch_end;
+            } 
+        }
+        /* For files path.d_dir is the parent dir, for dirs its the dir itself */
+        if (S_ISDIR(path.st.st_mode))
+            if ((dir = dirlookup(vol, cnid)) == NULL)
+                goto next;
+        path.d_dir = dir;
+
+        LOG(log_maxdebug, logtype_afpd,"catsearch_db: dir: %s, cwd: %s, name: %s", 
+            cfrombstr(dir->d_fullpath), getcwdpath(), path.u_name);
+
+        /* At last we can check the search criteria */
+        ccr = crit_check(vol, &path);
+        if ((ccr & 1)) {
+            LOG(log_debug, logtype_afpd,"catsearch_db: match: %s/%s",
+                getcwdpath(), path.u_name);
+            /* bit 1 means that criteria has been met */
+            r = rslt_add(vol, &path, &rrbuf, ext);
+            if (r == 0) {
+                result = AFPERR_MISC;
+                goto catsearch_end;
+            } 
+            *nrecs += r;
+            /* Number of matches limit */
+            if (--rmatches == 0) 
+                goto catsearch_pause;
+            /* Block size limit */
+            if (rrbuf - rbuf >= 448)
+                goto catsearch_pause;
+        }
+    next:
+        cur_pos++;
+    } /* while */
+
+       /* finished */
+       result = AFPERR_EOF;
+    cur_pos = 0;
+       goto catsearch_end;
+
+catsearch_pause:
+    *pos = cur_pos;
+
+catsearch_end: /* Exiting catsearch: error condition */
+       *rsize = rrbuf - rbuf;
+    LOG(log_debug, logtype_afpd, "catsearch_db(req pos: %u): {pos: %u}", *pos, cur_pos);
+       return result;
+}
+
 /* -------------------------- */
 static int catsearch_afp(AFPObj *obj _U_, char *ibuf, size_t ibuflen,
                   char *rbuf, size_t *rbuflen, int ext)
@@ -683,7 +842,8 @@ static int catsearch_afp(AFPObj *obj _U_, char *ibuf, size_t ibuflen,
     size_t     len;
     u_int16_t  namelen;
     u_int16_t  flags;
-    char       tmppath[256];
+    char           tmppath[256];
+    char        *uname;
 
     *rbuflen = 0;
 
@@ -858,7 +1018,9 @@ static int catsearch_afp(AFPObj *obj _U_, char *ibuf, size_t ibuflen,
                        namelen = 255;
 
                memcpy (c1.utf8name, spec1+2, namelen);
-               c1.utf8name[(namelen+1)] =0;
+               c1.utf8name[namelen] = 0;
+        if ((uname = mtoupath(vol, c1.utf8name, 0, utf8_encoding())) == NULL)
+            return AFPERR_PARAM;
 
                /* convert charset */
                flags = CONV_PRECOMPOSE;
@@ -869,7 +1031,15 @@ static int catsearch_afp(AFPObj *obj _U_, char *ibuf, size_t ibuflen,
     
     /* Call search */
     *rbuflen = 24;
-    ret = catsearch(vol, vol->v_dir, rmatches, &catpos[0], rbuf+24, &nrecs, &rsize, ext);
+    if ((c1.rbitmap & (1 << FILPBIT_PDINFO))
+        && (strcmp(vol->v_cnidscheme, "dbd") == 0)
+        && (vol->v_flags & AFPVOL_SEARCHDB))
+        /* we've got a name and it's a dbd volume, so search CNID database */
+        ret = catsearch_db(vol, vol->v_root, uname, rmatches, &catpos[0], rbuf+24, &nrecs, &rsize, ext);
+    else
+        /* perform a slow filesystem tree search */
+        ret = catsearch(vol, vol->v_root, rmatches, &catpos[0], rbuf+24, &nrecs, &rsize, ext);
+
     memcpy(rbuf, catpos, sizeof(catpos));
     rbuf += sizeof(catpos);
 
index 5db36f71925a0cf0dd06f04fab94bca8f14acae0..9f105e13e13c612757386f70c342626e28fe5e77 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: desktop.c,v 1.50 2010-01-22 04:40:38 didg Exp $
+ * $Id: desktop.c,v 1.50.2.1 2010-02-01 10:56:08 franklahm Exp $
  *
  * See COPYRIGHT.
  *
@@ -600,7 +600,8 @@ char *mtoupath(const struct vol *vol, char *mpath, cnid_t did, int utf8)
     u_int16_t   flags;
         
     if ( *mpath == '\0' ) {
-        return( "." );
+        strcpy(upath, ".");
+        return upath;
     }
 
     /* set conversion flags */
@@ -700,7 +701,7 @@ static int ad_addcomment(struct vol *vol, struct path *path, char *ibuf)
     if (ad_getentryoff(adp, ADEID_COMMENT)) {
         if ( (ad_get_MD_flags( adp ) & O_CREAT) ) {
             if ( *path->m_name == '\0' ) {
-                name = curdir->d_m_name;
+                name = (char *)curdir->d_m_name->data;
             } else {
                 name = path->m_name;
             }
diff --git a/etc/afpd/dircache.c b/etc/afpd/dircache.c
new file mode 100644 (file)
index 0000000..52ef747
--- /dev/null
@@ -0,0 +1,665 @@
+/*
+  Copyright (c) 2010 Frank Lahm <franklahm@gmail.com>
+
+  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.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <assert.h>
+#include <time.h>
+
+#include <atalk/util.h>
+#include <atalk/cnid.h>
+#include <atalk/logger.h>
+#include <atalk/volume.h>
+#include <atalk/directory.h>
+#include <atalk/queue.h>
+#include <atalk/bstrlib.h>
+#include <atalk/bstradd.h>
+
+#include "dircache.h"
+#include "directory.h"
+#include "hash.h"
+#include "globals.h"
+
+/*
+ * Directory Cache
+ * ===============
+ *
+ * Cache files and directories in a LRU cache.
+ *
+ * The directory cache caches directories and files(!). The main reason for having the cache
+ * is avoiding recursive walks up the path, querying the CNID database each time, when
+ * we have to calculate the location of eg directory with CNID 30, which is located in a dir with
+ * CNID 25, next CNID 20 and then CNID 2 (the volume root as per AFP spec).
+ * If all these dirs where in the cache, each database look up can be avoided. Additionally there's
+ * the element "fullpath" in struct dir, which is used to avoid the recursion in any case. Wheneveer
+ * a struct dir is initialized, the fullpath to the directory is stored there.
+ *
+ * In order to speed up the CNID query for files too, which eg happens when a directory is enumerated,
+ * files are stored too in the dircache. In order to differentiate between files and dirs, we re-use
+ * the element fullpath, which for files is always NULL.
+ *
+ * The most frequent codepatch that leads to caching is directory enumeration (cf enumerate.c):
+ * - if a element is a directory:
+ *   (1) the cache is searched by dircache_search_by_name()
+ *   (2) if it wasn't found a new struct dir is created and cached both from within dir_add()
+ * - for files the caching happens a little bit down the call chain:
+ *   (3) first getfilparams() is called, which calls
+ *   (4) getmetadata() where the cache is searched with dircache_search_by_name()
+ *   (5) if the element is not found
+ *   (6) get_id() queries the CNID from the database
+ *   (7) then a struct dir is initialized via dir_new() (note the fullpath arg is NULL)
+ *   (8) finally added to the cache with dircache_add()
+ * (2) of course does contain the steps 6,7 and 8.
+ *
+ * The dircache is a LRU cache, whenever it fills up we call dircache_evict internally which removes
+ * DIRCACHE_FREE_QUANTUM elements from the cache.
+ *
+ * There is only one cache for all volumes, so of course we use the volume id in hashing calculations.
+ *
+ * In order to avoid cache poisoning, we store the cached entries st_ctime from stat in
+ * struct dir.ctime_dircache. Later when we search the cache we compare the stored
+ * value with the result of a fresh stat. If the times differ, we remove the cached
+ * entry and return "no entry found in cache".
+ * A elements ctime changes when
+ *   1) the element is renamed
+ *      (we loose the cached entry here, but it will expire when the cache fills)
+ *   2) its a directory and an object has been created therein
+ *   3) the element is deleted and recreated under the same name
+ * Using ctime leads to cache eviction in case 2) where it wouldn't be necessary, because
+ * the dir itself (name, CNID, ...) hasn't changed, but there's no other way.
+ *
+ * Indexes
+ * =======
+ *
+ * The maximum dircache size is:
+ * max(DEFAULT_MAX_DIRCACHE_SIZE, min(size, MAX_POSSIBLE_DIRCACHE_SIZE)).
+ * It is a hashtable which we use to store "struct dir"s in. If the cache get full, oldest
+ * entries are evicted in chunks of DIRCACHE_FREE.
+ *
+ * We have/need two indexes:
+ * - a DID/name index on the main dircache, another hashtable
+ * - a queue index on the dircache, for evicting the oldest entries
+ * The cache supports locking of struct dir elements through the DIRF_CACHELOCK flag. A dir
+ * locked this way wont ever be removed from the cache, so be careful.
+ *
+ * Debugging
+ * =========
+ *
+ * Sending SIGHUP to a afpd child causes it to dump the dircache to a file "/tmp/dircache.PID".
+ */
+
+/********************************************************
+ * Local funcs and variables
+ ********************************************************/
+
+/*****************************
+ *       the dircache        */
+
+static hash_t       *dircache;        /* The actual cache */
+static unsigned int dircache_maxsize; /* cache maximum size */
+
+static struct dircache_stat {
+    unsigned long long lookups;
+    unsigned long long hits;
+    unsigned long long misses;
+    unsigned long long added;
+    unsigned long long removed;
+    unsigned long long expunged;
+    unsigned long long evicted;
+} dircache_stat;
+
+/* FNV 1a */
+static hash_val_t hash_vid_did(const void *key)
+{
+    const struct dir *k = (const struct dir *)key;
+    hash_val_t hash = 2166136261;
+
+    hash ^= k->d_vid >> 8;
+    hash *= 16777619;
+    hash ^= k->d_vid;
+    hash *= 16777619;
+
+    hash ^= k->d_did >> 24;
+    hash *= 16777619;
+    hash ^= (k->d_did >> 16) & 0xff;
+    hash *= 16777619;
+    hash ^= (k->d_did >> 8) & 0xff;
+    hash *= 16777619;
+    hash ^= (k->d_did >> 0) & 0xff;
+    hash *= 16777619;
+
+    return hash;
+}
+
+static int hash_comp_vid_did(const void *key1, const void *key2)
+{
+    const struct dir *k1 = key1;
+    const struct dir *k2 = key2;
+
+    return !(k1->d_did == k2->d_did && k1->d_vid == k2->d_vid);
+}
+
+/**************************************************
+ * DID/name index on dircache (another hashtable) */
+
+static hash_t *index_didname;
+
+#undef get16bits
+#if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__)    \
+    || defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__)
+#define get16bits(d) (*((const uint16_t *) (d)))
+#endif
+
+#if !defined (get16bits)
+#define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8)    \
+                      +(uint32_t)(((const uint8_t *)(d))[0]) )
+#endif
+
+static hash_val_t hash_didname(const void *p)
+{
+    const struct dir *key = (const struct dir *)p;
+    const unsigned char *data = key->d_u_name->data;
+    int len = key->d_u_name->slen;
+    hash_val_t hash = key->d_pdid + key->d_vid;
+    hash_val_t tmp;
+
+    int rem = len & 3;
+    len >>= 2;
+
+    /* Main loop */
+    for (;len > 0; len--) {
+        hash  += get16bits (data);
+        tmp    = (get16bits (data+2) << 11) ^ hash;
+        hash   = (hash << 16) ^ tmp;
+        data  += 2*sizeof (uint16_t);
+        hash  += hash >> 11;
+    }
+
+    /* Handle end cases */
+    switch (rem) {
+    case 3: hash += get16bits (data);
+        hash ^= hash << 16;
+        hash ^= data[sizeof (uint16_t)] << 18;
+        hash += hash >> 11;
+        break;
+    case 2: hash += get16bits (data);
+        hash ^= hash << 11;
+        hash += hash >> 17;
+        break;
+    case 1: hash += *data;
+        hash ^= hash << 10;
+        hash += hash >> 1;
+    }
+
+    /* Force "avalanching" of final 127 bits */
+    hash ^= hash << 3;
+    hash += hash >> 5;
+    hash ^= hash << 4;
+    hash += hash >> 17;
+    hash ^= hash << 25;
+    hash += hash >> 6;
+
+    return hash;
+}
+
+static int hash_comp_didname(const void *k1, const void *k2)
+{
+    const struct dir *key1 = (const struct dir *)k1;
+    const struct dir *key2 = (const struct dir *)k2;
+
+    return ! (key1->d_vid == key2->d_vid
+              && key1->d_pdid == key2->d_pdid
+              && (bstrcmp(key1->d_u_name, key2->d_u_name) == 0) );
+}
+
+/***************************
+ * queue index on dircache */
+
+static q_t *index_queue;    /* the index itself */
+static unsigned long queue_count;
+
+/*!
+ * @brief Remove a fixed number of (oldest) entries from the cache and indexes
+ *
+ * The default is to remove the 256 oldest entries from the cache.
+ * 1. Get the oldest entry
+ * 2. If it's in use ie open forks reference it or it's curdir requeue it,
+ *    or it's locked (from catsearch) dont remove it
+ * 3. Remove the dir from the main cache and the didname index
+ * 4. Free the struct dir structure and all its members
+ */
+static void dircache_evict(void)
+{
+    int i = DIRCACHE_FREE_QUANTUM;
+    struct dir *dir;
+
+    LOG(log_debug, logtype_afpd, "dircache: {starting cache eviction}");
+
+    while (i--) {
+        if ((dir = (struct dir *)dequeue(index_queue)) == NULL) { /* 1 */
+            dircache_dump();
+            AFP_PANIC("dircache_evict");
+        }
+        queue_count--;
+
+        if (curdir == dir
+            || (dir->d_flags & DIRF_CACHELOCK)) {     /* 2 */
+            if ((dir->qidx_node = enqueue(index_queue, dir)) == NULL) {
+                dircache_dump();
+                AFP_PANIC("dircache_evict");
+            }
+            queue_count++;
+            continue;
+        }
+
+        dircache_remove(NULL, dir, DIRCACHE | DIDNAME_INDEX); /* 3 */
+        dir_free(dir);                                        /* 4 */
+    }
+
+    AFP_ASSERT(queue_count == dircache->hash_nodecount);
+    dircache_stat.evicted += DIRCACHE_FREE_QUANTUM;
+    LOG(log_debug, logtype_afpd, "dircache: {finished cache eviction}");
+}
+
+
+/********************************************************
+ * Interface
+ ********************************************************/
+
+/*!
+ * @brief Search the dircache via a CNID for a directory
+ *
+ * Found cache entries are expunged if both the parent directory st_ctime and the objects
+ * st_ctime are modified.
+ * This func builds on the fact, that all our code only ever needs to and does search
+ * the dircache by CNID expecting directories to be returned, but not files.
+ * Thus
+ * (1) if we find a file (d_fullpath == NULL) for a given CNID we
+ *     (1a) remove it from the cache
+ *     (1b) return NULL indicating nothing found
+ * (2) we can then use d_fullpath to stat the directory
+ *
+ * @param vol      (r) pointer to struct vol
+ * @param cnid     (r) CNID of the directory to search
+ *
+ * @returns            Pointer to struct dir if found, else NULL
+ */
+struct dir *dircache_search_by_did(const struct vol *vol, cnid_t cnid)
+{
+    struct dir *cdir = NULL;
+    struct dir key;
+    struct stat st;
+    hnode_t *hn;
+
+    AFP_ASSERT(vol);
+    AFP_ASSERT(ntohl(cnid) >= CNID_START);
+
+    dircache_stat.lookups++;
+    key.d_vid = vol->v_vid;
+    key.d_did = cnid;
+    if ((hn = hash_lookup(dircache, &key)))
+        cdir = hnode_get(hn);
+
+    if (cdir) {
+        if (cdir->d_fullpath == NULL) { /* (1) */
+            LOG(log_debug, logtype_afpd, "dircache(cnid:%u): {not a directory:\"%s\"}",
+                ntohl(cnid), cfrombstr(cdir->d_u_name));
+            (void)dir_remove(vol, cdir); /* (1a) */
+            dircache_stat.expunged++;
+            return NULL;        /* (1b) */
+
+        }
+        if (lstat(cfrombstr(cdir->d_fullpath), &st) != 0) {
+            LOG(log_debug, logtype_afpd, "dircache(cnid:%u): {missing:\"%s\"}",
+                ntohl(cnid), cfrombstr(cdir->d_fullpath));
+            (void)dir_remove(vol, cdir);
+            dircache_stat.expunged++;
+            return NULL;
+        }
+        if (cdir->ctime_dircache != st.st_ctime) {
+            LOG(log_debug, logtype_afpd, "dircache(cnid:%u): {modified:\"%s\"}",
+                ntohl(cnid), cfrombstr(cdir->d_u_name));
+            (void)dir_remove(vol, cdir);
+            dircache_stat.expunged++;
+            return NULL;
+        }
+        LOG(log_debug, logtype_afpd, "dircache(cnid:%u): {cached: path:\"%s\"}",
+            ntohl(cnid), cfrombstr(cdir->d_fullpath));
+        dircache_stat.hits++;
+    } else {
+        LOG(log_debug, logtype_afpd, "dircache(cnid:%u): {not in cache}", ntohl(cnid));
+        dircache_stat.misses++;
+    }
+    
+    return cdir;
+}
+
+/*!
+ * @brief Search the cache via did/name hashtable
+ *
+ * Found cache entries are expunged if both the parent directory st_ctime and the objects
+ * st_ctime are modified.
+ *
+ * @param vol      (r) volume
+ * @param dir      (r) directory
+ * @param name     (r) name (server side encoding)
+ * @parma len      (r) strlen of name
+ * @param ctime    (r) current st_ctime from stat
+ *
+ * @returns pointer to struct dir if found in cache, else NULL
+ */
+struct dir *dircache_search_by_name(const struct vol *vol, const struct dir *dir, char *name, int len, time_t ctime)
+{
+    struct dir *cdir = NULL;
+    struct dir key;
+
+    hnode_t *hn;
+    static_bstring uname = {-1, len, (unsigned char *)name};
+
+    AFP_ASSERT(vol);
+    AFP_ASSERT(dir);
+    AFP_ASSERT(name);
+    AFP_ASSERT(len == strlen(name));
+    AFP_ASSERT(len < 256);
+
+    dircache_stat.lookups++;
+    LOG(log_debug, logtype_afpd, "dircache_search_by_name(did:%u, \"%s\")",
+        ntohl(dir->d_did), name);
+
+    if (dir->d_did != DIRDID_ROOT_PARENT) {
+        key.d_vid = vol->v_vid;
+        key.d_pdid = dir->d_did;
+        key.d_u_name = &uname;
+
+        if ((hn = hash_lookup(index_didname, &key)))
+            cdir = hnode_get(hn);
+    }
+
+    if (cdir) {
+        if (cdir->ctime_dircache != ctime) {
+            LOG(log_debug, logtype_afpd, "dircache(did:%u,\"%s\"): {modified}",
+                ntohl(dir->d_did), name);
+            (void)dir_remove(vol, cdir);
+            dircache_stat.expunged++;
+            return NULL;
+        }
+        LOG(log_debug, logtype_afpd, "dircache(did:%u,\"%s\"): {found in cache}",
+            ntohl(dir->d_did), name);
+        dircache_stat.hits++;
+    } else {
+        LOG(log_debug, logtype_afpd, "dircache(did:%u,\"%s\"): {not in cache}",
+            ntohl(dir->d_did), name);
+        dircache_stat.misses++;
+    }
+
+    return cdir;
+}
+
+/*!
+ * @brief create struct dir from struct path
+ *
+ * Add a struct dir to the cache and its indexes.
+ *
+ * @param dir   (r) pointer to parrent directory
+ *
+ * @returns 0 on success, -1 on error which should result in an abort
+ */
+int dircache_add(struct dir *dir)
+{
+   AFP_ASSERT(dir);
+   AFP_ASSERT(ntohl(dir->d_pdid) >= 2);
+   AFP_ASSERT(ntohl(dir->d_did) >= CNID_START);
+   AFP_ASSERT(dir->d_u_name);
+   AFP_ASSERT(dir->d_vid);
+   AFP_ASSERT(dircache->hash_nodecount <= dircache_maxsize);
+
+    /* Check if cache is full */
+    if (dircache->hash_nodecount == dircache_maxsize)
+        dircache_evict();
+
+    /* Add it to the main dircache */
+    if (hash_alloc_insert(dircache, dir, dir) == 0) {
+        dircache_dump();
+        exit(EXITERR_SYS);
+    }
+
+    /* Add it to the did/name index */
+    if (hash_alloc_insert(index_didname, dir, dir) == 0) {
+        dircache_dump();
+        exit(EXITERR_SYS);
+    }
+
+    /* Add it to the fifo queue index */
+    if ((dir->qidx_node = enqueue(index_queue, dir)) == NULL) {
+        dircache_dump();
+        exit(EXITERR_SYS);
+    } else {
+        queue_count++;
+    }
+
+    dircache_stat.added++;
+    LOG(log_debug, logtype_afpd, "dircache(did:%u,'%s'): {added}",
+        ntohl(dir->d_did), cfrombstr(dir->d_u_name));
+
+   AFP_ASSERT(queue_count == index_didname->hash_nodecount 
+           && queue_count == dircache->hash_nodecount);
+
+    return 0;
+}
+
+/*!
+  * @brief Remove an entry from the dircache
+  *
+  * Callers outside of dircache.c should call this with
+  * flags = QUEUE_INDEX | DIDNAME_INDEX | DIRCACHE.
+  */
+void dircache_remove(const struct vol *vol _U_, struct dir *dir, int flags)
+{
+    hnode_t *hn;
+
+   AFP_ASSERT(dir);
+   AFP_ASSERT((flags & ~(QUEUE_INDEX | DIDNAME_INDEX | DIRCACHE)) == 0);
+
+    if (dir->d_flags & DIRF_CACHELOCK)
+        return;
+
+    if (flags & QUEUE_INDEX) {
+        /* remove it from the queue index */
+        dequeue(dir->qidx_node->prev); /* this effectively deletes the dequeued node */
+        queue_count--;
+    }
+
+    if (flags & DIDNAME_INDEX) {
+        if ((hn = hash_lookup(index_didname, dir)) == NULL) {
+            LOG(log_error, logtype_default, "dircache_remove(%u,\"%s\"): not in didname index", 
+                ntohl(dir->d_did), cfrombstr(dir->d_u_name));
+            dircache_dump();
+            AFP_PANIC("dircache_remove");
+        }
+        hash_delete_free(index_didname, hn);
+    }
+
+    if (flags & DIRCACHE) {
+        if ((hn = hash_lookup(dircache, dir)) == NULL) {
+            LOG(log_error, logtype_default, "dircache_remove(%u,\"%s\"): not in dircache", 
+                ntohl(dir->d_did), cfrombstr(dir->d_u_name));
+            dircache_dump();
+            AFP_PANIC("dircache_remove");
+        }
+        hash_delete_free(dircache, hn);
+    }
+
+    LOG(log_debug, logtype_afpd, "dircache(did:%u,\"%s\"): {removed}",
+        ntohl(dir->d_did), cfrombstr(dir->d_u_name));
+
+    dircache_stat.removed++;
+    AFP_ASSERT(queue_count == index_didname->hash_nodecount 
+               && queue_count == dircache->hash_nodecount);
+}
+
+/*!
+ * @brief Initialize the dircache and indexes
+ *
+ * This is called in child afpd initialisation. The maximum cache size will be
+ * max(DEFAULT_MAX_DIRCACHE_SIZE, min(size, MAX_POSSIBLE_DIRCACHE_SIZE)).
+ * It initializes a hashtable which we use to store a directory cache in.
+ * It also initializes two indexes:
+ * - a DID/name index on the main dircache
+ * - a queue index on the dircache
+ *
+ * @param size   (r) requested maximum size from afpd.conf
+ *
+ * @return 0 on success, -1 on error
+ */
+int dircache_init(int reqsize)
+{
+    dircache_maxsize = DEFAULT_MAX_DIRCACHE_SIZE;
+
+    /* Initialize the main dircache */
+    if (reqsize > DEFAULT_MAX_DIRCACHE_SIZE && reqsize < MAX_POSSIBLE_DIRCACHE_SIZE) {
+        while ((dircache_maxsize < MAX_POSSIBLE_DIRCACHE_SIZE) && (dircache_maxsize < reqsize))
+               dircache_maxsize *= 2;
+    }
+    if ((dircache = hash_create(dircache_maxsize, hash_comp_vid_did, hash_vid_did)) == NULL)
+        return -1;
+    
+    LOG(log_debug, logtype_afpd, "dircache_init: done. max dircache size: %u", dircache_maxsize);
+
+    /* Initialize did/name index hashtable */
+    if ((index_didname = hash_create(dircache_maxsize, hash_comp_didname, hash_didname)) == NULL)
+        return -1;
+
+    /* Initialize index queue */
+    if ((index_queue = queue_init()) == NULL)
+        return -1;
+    else
+        queue_count = 0;
+
+    /* Initialize index queue */
+    if ((invalid_dircache_entries = queue_init()) == NULL)
+        return -1;
+
+    /* As long as directory.c hasn't got its own initializer call, we do it for it */
+    rootParent.d_did = DIRDID_ROOT_PARENT;
+    rootParent.d_fullpath = bfromcstr("ROOT_PARENT");
+    rootParent.d_m_name = bfromcstr("ROOT_PARENT");
+    rootParent.d_u_name = rootParent.d_m_name;
+
+    return 0;
+}
+
+/*!
+ * Log dircache statistics
+ */
+void log_dircache_stat(void)
+{
+    LOG(log_info, logtype_afpd, "dircache statistics: "
+        "entries: %lu, lookups: %llu, hits: %llu, misses: %llu, added: %llu, removed: %llu, expunged: %llu, evicted: %llu",
+        queue_count,
+        dircache_stat.lookups,
+        dircache_stat.hits,
+        dircache_stat.misses,
+        dircache_stat.added,
+        dircache_stat.removed,
+        dircache_stat.expunged,
+        dircache_stat.evicted);
+}
+
+/*!
+ * @brief Dump dircache to /tmp/dircache.PID
+ */
+void dircache_dump(void)
+{
+    char tmpnam[64];
+    FILE *dump;
+    qnode_t *n = index_queue->next;
+    hnode_t *hn;
+    hscan_t hs;
+    const struct dir *dir;
+    int i;
+
+    LOG(log_warning, logtype_afpd, "Dumping directory cache...");
+
+    sprintf(tmpnam, "/tmp/dircache.%u", getpid());
+    if ((dump = fopen(tmpnam, "w+")) == NULL) {
+        LOG(log_error, logtype_afpd, "dircache_dump: %s", strerror(errno));
+        return;
+    }
+    setbuf(dump, NULL);
+
+    fprintf(dump, "Number of cache entries in LRU queue: %lu\n", queue_count);
+    fprintf(dump, "Configured maximum cache size: %u\n\n", dircache_maxsize);
+
+    fprintf(dump, "Primary CNID index:\n");
+    fprintf(dump, "       VID     DID    CNID STAT PATH\n");
+    fprintf(dump, "====================================================================\n");
+    hash_scan_begin(&hs, dircache);
+    i = 1;
+    while ((hn = hash_scan_next(&hs))) {
+        dir = hnode_get(hn);
+        fprintf(dump, "%05u: %3u  %6u  %6u  %s%s  %s\n",
+                i++,
+                ntohs(dir->d_vid),
+                ntohl(dir->d_pdid),
+                ntohl(dir->d_did),
+                dir->d_fullpath ? "d" : "f",
+                (dir->d_flags & DIRF_CACHELOCK) ? "l" : "-",
+                cfrombstr(dir->d_u_name));
+    }
+
+    fprintf(dump, "\nSecondary DID/name index:\n");
+    fprintf(dump, "       VID     DID    CNID STAT PATH\n");
+    fprintf(dump, "====================================================================\n");
+    hash_scan_begin(&hs, index_didname);
+    i = 1;
+    while ((hn = hash_scan_next(&hs))) {
+        dir = hnode_get(hn);
+        fprintf(dump, "%05u: %3u  %6u  %6u  %s%s  %s\n",
+                i++,
+                ntohs(dir->d_vid),
+                ntohl(dir->d_pdid),
+                ntohl(dir->d_did),
+                dir->d_fullpath ? "d" : "f",
+                (dir->d_flags & DIRF_CACHELOCK) ? "l" : "-",
+                cfrombstr(dir->d_u_name));
+    }
+
+    fprintf(dump, "\nLRU Queue:\n");
+    fprintf(dump, "       VID     DID    CNID STAT PATH\n");
+    fprintf(dump, "====================================================================\n");
+
+    for (i = 1; i <= queue_count; i++) {
+        if (n == index_queue)
+            break;
+        dir = (struct dir *)n->data;
+        fprintf(dump, "%05u: %3u  %6u  %6u  %s%s  %s\n",
+                i,
+                ntohs(dir->d_vid),
+                ntohl(dir->d_pdid),
+                ntohl(dir->d_did),
+                dir->d_fullpath ? "d" : "f",
+                (dir->d_flags & DIRF_CACHELOCK) ? "l" : "-",
+                cfrombstr(dir->d_u_name));
+        n = n->next;
+    }
+
+    fprintf(dump, "\n");
+    return;
+}
diff --git a/etc/afpd/dircache.h b/etc/afpd/dircache.h
new file mode 100644 (file)
index 0000000..69c5f9a
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+   Copyright (c) 2010 Frank Lahm <franklahm@gmail.com>
+
+   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.
+ */
+
+#ifndef DIRCACHE_H 
+#define DIRCACHE_H
+
+#include <sys/types.h>
+
+#include <atalk/volume.h>
+#include <atalk/directory.h>
+
+/* Maximum size of the dircache hashtable */
+#define DEFAULT_MAX_DIRCACHE_SIZE 8192
+#define MAX_POSSIBLE_DIRCACHE_SIZE 131072
+#define DIRCACHE_FREE_QUANTUM 256
+
+/* flags for dircache_remove */
+#define DIRCACHE      (1 << 0)
+#define DIDNAME_INDEX (1 << 1)
+#define QUEUE_INDEX   (1 << 2)
+#define DIRCACHE_ALL  (DIRCACHE|DIDNAME_INDEX|QUEUE_INDEX)
+
+extern int        dircache_init(int reqsize);
+extern int        dircache_add(struct dir *);
+extern void       dircache_remove(const struct vol *, struct dir *, int flag);
+extern struct dir *dircache_search_by_did(const struct vol *vol, cnid_t did);
+extern struct dir *dircache_search_by_name(const struct vol *, const struct dir *dir, char *name, int len, time_t ctime);
+extern void       dircache_dump(void);
+extern void       log_dircache_stat(void);
+#endif /* DIRCACHE_H */
index fd17618ab64223ddb317458e6fa5c1732b5e6221..55918eaeb8ed2ef6b8fa8dd0e064d01bc6c0ebbb 100644 (file)
@@ -1,40 +1,22 @@
 /*
  * Copyright (c) 1990,1993 Regents of The University of Michigan.
  * All Rights Reserved.  See COPYRIGHT.
- *
- * 19 jan 2000 implemented red-black trees for directory lookups
- * (asun@cobalt.com).
  */
 
 #ifdef HAVE_CONFIG_H
 #include "config.h"
 #endif /* HAVE_CONFIG_H */
 
-/* STDC check */
-#if 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_STRINGS_H
-#include <strings.h>
-#endif
 #include <stdio.h>
 #include <stdlib.h>
-
 #include <grp.h>
 #include <pwd.h>
 #include <sys/param.h>
+#include <sys/stat.h>
 #include <errno.h>
 #include <utime.h>
+#include <assert.h>
 
 #include <atalk/adouble.h>
 #include <atalk/vfs.h>
@@ -44,8 +26,11 @@ char *strchr (), *strrchr ();
 #include <atalk/logger.h>
 #include <atalk/uuid.h>
 #include <atalk/unix.h>
+#include <atalk/bstrlib.h>
+#include <atalk/bstradd.h>
 
 #include "directory.h"
+#include "dircache.h"
 #include "desktop.h"
 #include "volume.h"
 #include "fork.h"
@@ -56,583 +41,564 @@ char *strchr (), *strrchr ();
 #include "mangle.h"
 #include "hash.h"
 
-#ifdef HAVE_NFSv4_ACLS
-extern void addir_inherit_acl(const struct vol *vol);
-#endif
-
-/* 
- * Directory caches
- * ================
- *
- * There are currently two cache structures where afpd caches directory information
- * a) a DID/dirname cache in a hashtable 
- * b) a (red-black) tree with CNIDs as key
- *
- * a) is for searching by DID/dirname
- * b) is for searching by CNID
- *
- * Through additional parent, child, previous and next pointers, b) is also used to
- * represent the on-disk layout of the filesystem. parent and child point to parent
- * and child directory respectively, linking 2 or more subdirectories in one
- * directory with previous and next pointers.
- *
- * Usage examples, highlighting the main functions:
- * 
- * a) is eg used in enumerate():
- * if IS_DIR
- *     dir = dirsearch_byname() // search in cache
- *     if (dir == NULL)         // not found
- *         dir = adddir()       // add to cache
- *      getdirparams()
- *
- * b) is eg used in afp_getfildirparams()
- * dirlookup()             // wrapper for cache and db search
- *   => dir = dirsearch()  // search in cache
- *      if (dir)           // found
- *          return
- *      else               // not found,
- *          cnid_resolve() // resolve with CNID database
- *      cname()            // add to cache
+/*
+ * FIXMEs, loose ends after the dircache rewrite:
+ * o merge dircache_search_by_name and dir_add ??
+ * o case-insensitivity is gone from cname
  */
 
-struct dir  *curdir;
+
+/*******************************************************************************************
+ * Globals
+ ******************************************************************************************/
+
 int         afp_errno;
+/* As long as directory.c hasn't got its own init call, this get initialized in dircache_init */
+struct dir rootParent  = {
+    NULL, NULL, NULL, NULL,          /* path, d_m_name, d_u_name, d_m_name_ucs2 */
+    NULL, 0, 0,                      /* qidx_node, ctime, d_flags */
+    0, 0, 0, 0                       /* pdid, did, offcnt, d_vid */
+};
+struct dir  *curdir = &rootParent;
+struct path Cur_Path = {
+    0,
+    "",  /* mac name */
+    ".", /* unix name */
+    0,   /* id */
+    NULL,/* struct dir * */
+    0,   /* stat is not set */
+    0,   /* errno */
+    {0} /* struct stat */
+};
 
-#define SENTINEL (&sentinel)
-static struct dir sentinel = { SENTINEL, SENTINEL, NULL, /* left, right, back */
-                               DIRTREE_COLOR_BLACK,      /* color */
-                               NULL, NULL,               /* parent, child */
-                               NULL, NULL,               /* previous, next */
-                               NULL, 0, 0,               /* oforks, did, flags */
-                               0, 0,                     /* ctime, offcnt */
-                               NULL, NULL, NULL};        /* mname, uname, ucs2-name */
-static struct dir rootpar  = { SENTINEL, SENTINEL, NULL,
-                               0,
-                               NULL, NULL,
-                               NULL, NULL,
-                               NULL, 0, 0,
-                               0, 0,
-                               NULL, NULL, NULL};
-
-/* (from IM: Toolbox Essentials)
- * dirFinderInfo (DInfo) fields:
- * field        bytes
- * frRect       8    folder's window rectangle
- * frFlags      2    flags
- * frLocation   4    folder's location in window
- * frView       2    folder's view (default == closedView (256))
- *
- * extended dirFinderInfo (DXInfo) fields:
- * frScroll     4    scroll position
- * frOpenChain: 4    directory ID chain of open folders
- * frScript:    1    script flag and code
- * frXFlags:    1    reserved
- * frComment:   2    comment ID
- * frPutAway:   4    home directory ID
+/*
+ * dir_remove queues struct dirs to be freed here. We can't just delete them immeidately
+ * eg in dircache_search_by_id, because a caller somewhere up the stack might be
+ * referencing it.
+ * So instead:
+ * - we mark it as invalid by setting d_did to CNID_INVALID (ie 0)
+ * - queue it in "invalid_dircache_entries" queue
+ * - which is finally freed at the end of every AFP func in afp_dsi.c.
  */
+q_t *invalid_dircache_entries;
 
-static struct dir *
-vol_tree_root(const struct vol *vol, u_int32_t did)
-{
-    struct dir *dir;
 
-    if (vol->v_curdir && vol->v_curdir->d_did == did) {
-        dir = vol->v_curdir;
-    }
-    else {
-        dir = vol->v_root;
-    }
-    return dir;
-}
+/*******************************************************************************************
+ * Locals
+ ******************************************************************************************/
 
-/*
- * redid did assignment for directories. now we use red-black trees.
- * how exciting.
- */
-struct dir *
-dirsearch(const struct vol *vol, u_int32_t did)
+
+/* -------------------------
+   appledouble mkdir afp error code.
+*/
+static int netatalk_mkdir(const struct vol *vol, const char *name)
 {
-    struct dir  *dir;
+    int ret;
+    struct stat st;
 
+    if (vol->v_flags & AFPVOL_UNIX_PRIV) {
+        if (lstat(".", &st) < 0)
+            return AFPERR_MISC;
+        int mode = (DIRBITS & (~S_ISGID & st.st_mode)) | (0777 & ~vol->v_umask);
+        LOG(log_maxdebug, logtype_afpd, "netatalk_mkdir(\"%s\") {parent mode: %04o, vol umask: %04o}",
+            name, st.st_mode, vol->v_umask);
 
-    /* check for 0 did */
-    if (!did) {
-        afp_errno = AFPERR_PARAM;
-        return NULL;
-    }
-    if ( did == DIRDID_ROOT_PARENT ) {
-        if (!rootpar.d_did)
-            rootpar.d_did = DIRDID_ROOT_PARENT;
-        rootpar.d_child = vol->v_dir;
-        return( &rootpar );
+        ret = mkdir(name, mode);
+    } else {
+        ret = ad_mkdir(name, DIRBITS | 0777);
     }
 
-    dir = vol_tree_root(vol, did);
-
-    afp_errno = AFPERR_NOOBJ;
-    while ( dir != SENTINEL ) {
-        if (dir->d_did == did)
-            return dir->d_m_name ? dir : NULL;
-        dir = (dir->d_did > did) ? dir->d_left : dir->d_right;
+    if (ret < 0) {
+        switch ( errno ) {
+        case ENOENT :
+            return( AFPERR_NOOBJ );
+        case EROFS :
+            return( AFPERR_VLOCK );
+        case EPERM:
+        case EACCES :
+            return( AFPERR_ACCESS );
+        case EEXIST :
+            return( AFPERR_EXIST );
+        case ENOSPC :
+        case EDQUOT :
+            return( AFPERR_DFULL );
+        default :
+            return( AFPERR_PARAM );
+        }
     }
-    return NULL;
+    return AFP_OK;
 }
 
 /* ------------------- */
-int get_afp_errno(const int param)
+static int deletedir(int dirfd, char *dir)
 {
-    if (afp_errno != AFPERR_DID1)
-        return afp_errno;
-    return param;
-}
+    char path[MAXPATHLEN + 1];
+    DIR *dp;
+    struct dirent   *de;
+    struct stat st;
+    size_t len;
+    int err = AFP_OK;
+    size_t remain;
 
-/* ------------------- */
-struct dir *
-dirsearch_byname( const struct vol *vol, struct dir *cdir, char *name)
-{
-    struct dir *dir = NULL;
+    if ((len = strlen(dir)) +2 > sizeof(path))
+        return AFPERR_PARAM;
 
-    if ((cdir->d_did != DIRDID_ROOT_PARENT) && (cdir->d_child)) {
-        struct dir key;
-        hnode_t *hn;
+    /* already gone */
+    if ((dp = opendirat(dirfd, dir)) == NULL)
+        return AFP_OK;
 
-        key.d_parent = cdir;
-        key.d_u_name = name;
-        hn = hash_lookup(vol->v_hash, &key);
-        if (hn) {
-            dir = hnode_get(hn);
+    strcpy(path, dir);
+    strcat(path, "/");
+    len++;
+    remain = sizeof(path) -len -1;
+    while ((de = readdir(dp)) && err == AFP_OK) {
+        /* skip this and previous directory */
+        if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
+            continue;
+
+        if (strlen(de->d_name) > remain) {
+            err = AFPERR_PARAM;
+            break;
+        }
+        strcpy(path + len, de->d_name);
+        if (lstatat(dirfd, path, &st)) {
+            continue;
+        }
+        if (S_ISDIR(st.st_mode)) {
+            err = deletedir(dirfd, path);
+        } else {
+            err = netatalk_unlinkat(dirfd, path);
         }
     }
-    return dir;
+    closedir(dp);
+
+    /* okay. the directory is empty. delete it. note: we already got rid
+       of .AppleDouble.  */
+    if (err == AFP_OK) {
+        err = netatalk_rmdir(dirfd, dir);
+    }
+    return err;
 }
 
-/* -----------------------------------------
- * if did is not in the cache resolve it with cnid
- *
- * FIXME
- * OSX call it with bogus id, ie file ID not folder ID,
- * and we are really bad in this case.
- */
-struct dir *
-dirlookup( struct vol *vol, u_int32_t did)
+/* do a recursive copy. */
+static int copydir(const struct vol *vol, int dirfd, char *src, char *dst)
 {
-    struct dir   *ret;
-    char     *upath;
-    cnid_t       id, cnid;
-    static char  path[MAXPATHLEN + 1];
-    size_t len,  pathlen;
-    char         *ptr;
-    static char  buffer[12 + MAXPATHLEN + 1];
-    int          buflen = 12 + MAXPATHLEN + 1;
-    char         *mpath;
-    int          utf8;
-    size_t       maxpath;
+    char spath[MAXPATHLEN + 1], dpath[MAXPATHLEN + 1];
+    DIR *dp;
+    struct dirent   *de;
+    struct stat st;
+    struct utimbuf      ut;
+    size_t slen, dlen;
+    size_t srem, drem;
+    int err;
 
-    ret = dirsearch(vol, did);
-    if (ret != NULL || afp_errno == AFPERR_PARAM)
-        return ret;
+    /* doesn't exist or the path is too long. */
+    if (((slen = strlen(src)) > sizeof(spath) - 2) ||
+        ((dlen = strlen(dst)) > sizeof(dpath) - 2) ||
+        ((dp = opendirat(dirfd, src)) == NULL))
+        return AFPERR_PARAM;
 
-    utf8 = utf8_encoding();
-    maxpath = (utf8)?MAXPATHLEN -7:255;
-    id = did;
-    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, did, utf8) ) ) {
-        afp_errno = AFPERR_NOOBJ;
-        return NULL;
+    /* try to create the destination directory */
+    if (AFP_OK != (err = netatalk_mkdir(vol, dst)) ) {
+        closedir(dp);
+        return err;
     }
-    len = strlen(mpath);
-    pathlen = len;          /* no 0 in the last part */
-    len++;
-    strcpy(ptr - len, mpath);
-    ptr -= len;
-    while (1) {
-        ret = dirsearch(vol,id);
-        if (ret != NULL) {
-            break;
-        }
-        cnid = id;
-        if ( NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, buflen))
-             ||
-             NULL == (mpath = utompath(vol, upath, cnid, utf8))
-            ) {
-            afp_errno = AFPERR_NOOBJ;
-            return NULL;
-        }
 
-        len = strlen(mpath) + 1;
-        pathlen += len;
-        if (pathlen > maxpath) {
-            afp_errno = AFPERR_PARAM;
-            return NULL;
+    /* set things up to copy */
+    strcpy(spath, src);
+    strcat(spath, "/");
+    slen++;
+    srem = sizeof(spath) - slen -1;
+
+    strcpy(dpath, dst);
+    strcat(dpath, "/");
+    dlen++;
+    drem = sizeof(dpath) - dlen -1;
+
+    err = AFP_OK;
+    while ((de = readdir(dp))) {
+        /* skip this and previous directory */
+        if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
+            continue;
+
+        if (strlen(de->d_name) > srem) {
+            err = AFPERR_PARAM;
+            break;
         }
-        strcpy(ptr - len, mpath);
-        ptr -= len;
-    }
+        strcpy(spath + slen, de->d_name);
 
-    /* fill the cache, another place where we know about the path type */
-    if (utf8) {
-        u_int16_t temp16;
-        u_int32_t temp;
+        if (lstatat(dirfd, spath, &st) == 0) {
+            if (strlen(de->d_name) > drem) {
+                err = AFPERR_PARAM;
+                break;
+            }
+            strcpy(dpath + dlen, de->d_name);
 
-        ptr -= 2;
-        temp16 = htons(pathlen);
-        memcpy(ptr, &temp16, sizeof(temp16));
+            if (S_ISDIR(st.st_mode)) {
+                if (AFP_OK != (err = copydir(vol, dirfd, spath, dpath)))
+                    goto copydir_done;
+            } else if (AFP_OK != (err = copyfile(vol, vol, dirfd, spath, dpath, NULL, NULL))) {
+                goto copydir_done;
 
-        temp = htonl(kTextEncodingUTF8);
-        ptr -= 4;
-        memcpy(ptr, &temp, sizeof(temp));
-        ptr--;
-        *ptr = 3;
+            } else {
+                /* keep the same time stamp. */
+                ut.actime = ut.modtime = st.st_mtime;
+                utime(dpath, &ut);
+            }
+        }
     }
-    else {
-        ptr--;
-        *ptr = (unsigned char)pathlen;
-        ptr--;
-        *ptr = 2;
+
+    /* keep the same time stamp. */
+    if (lstatat(dirfd, src, &st) == 0) {
+        ut.actime = ut.modtime = st.st_mtime;
+        utime(dst, &ut);
     }
-    /* cname is not efficient */
-    if (cname( vol, ret, &ptr ) == NULL )
-        return NULL;
 
-    return dirsearch(vol, did);
+copydir_done:
+    closedir(dp);
+    return err;
 }
 
-/* child addition/removal */
-static void dirchildadd(const struct vol *vol, struct dir *a, struct dir *b)
+/* ---------------------
+ * is our cached offspring count valid?
+ */
+static int diroffcnt(struct dir *dir, struct stat *st)
 {
-    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;
-    }
-    if (!hash_alloc_insert(vol->v_hash, b, b)) {
-        LOG(log_error, logtype_afpd, "dirchildadd: can't hash %s", b->d_u_name);
-    }
+    return st->st_ctime == dir->ctime;
 }
 
-static void dirchildremove(struct dir *a,struct dir *b)
+/* --------------------- */
+static int invisible_dots(const struct vol *vol, const char *name)
 {
-    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;
+    return vol_inv_dots(vol) && *name  == '.' && strcmp(name, ".") && strcmp(name, "..");
 }
 
-/* --------------------------- */
-/* rotate the tree to the left */
-static void dir_leftrotate(struct vol *vol, struct dir *dir)
+/* ------------------ */
+static int set_dir_errors(struct path *path, const char *where, int err)
 {
-    struct dir *right = dir->d_right;
-
-    /* whee. move the right's left tree into dir's right tree */
-    dir->d_right = right->d_left;
-    if (right->d_left != SENTINEL)
-        right->d_left->d_back = dir;
-
-    if (right != SENTINEL) {
-        right->d_back = dir->d_back;
-        right->d_left = dir;
+    switch ( err ) {
+    case EPERM :
+    case EACCES :
+        return AFPERR_ACCESS;
+    case EROFS :
+        return AFPERR_VLOCK;
     }
-
-    if (!dir->d_back) /* no parent. move the right tree to the top. */
-        vol->v_root = right;
-    else if (dir == dir->d_back->d_left) /* we were on the left */
-        dir->d_back->d_left = right;
-    else
-        dir->d_back->d_right = right; /* we were on the right */
-
-    /* re-insert dir on the left tree */
-    if (dir != SENTINEL)
-        dir->d_back = right;
+    LOG(log_error, logtype_afpd, "setdirparam(%s): %s: %s", fullpathname(path->u_name), where, strerror(err) );
+    return AFPERR_PARAM;
 }
 
-
-
-/* rotate the tree to the right */
-static void dir_rightrotate(struct vol *vol, struct dir *dir)
+/*!
+ * @brief Convert name in client encoding to server encoding
+ *
+ * Convert ret->m_name to ret->u_name from client encoding to server encoding.
+ * This only gets called from cname().
+ *
+ * @returns 0 on success, -1 on error
+ *
+ * @note If the passed ret->m_name is mangled, we'll demangle it
+ */
+static int cname_mtouname(const struct vol *vol, const struct dir *dir, struct path *ret, int toUTF8)
 {
-    struct dir *left = dir->d_left;
+    static char temp[ MAXPATHLEN + 1];
+    char *t;
+    cnid_t fileid;
+
+    if (afp_version >= 30) {
+        if (toUTF8) {
+            if (dir->d_did == DIRDID_ROOT_PARENT) {
+                /*
+                 * With uft8 volume name is utf8-mac, but requested path may be a mangled longname. See #2611981.
+                 * So we compare it with the longname from the current volume and if they match
+                 * we overwrite the requested path with the utf8 volume name so that the following
+                 * strcmp can match.
+                 */
+                ucs2_to_charset(vol->v_maccharset, vol->v_macname, temp, AFPVOL_MACNAMELEN + 1);
+                if (strcasecmp(ret->m_name, temp) == 0)
+                    ucs2_to_charset(CH_UTF8_MAC, vol->v_u8mname, ret->m_name, AFPVOL_U8MNAMELEN);
+            } else {
+                /* toUTF8 */
+                if (mtoUTF8(vol, ret->m_name, strlen(ret->m_name), temp, MAXPATHLEN) == (size_t)-1) {
+                    afp_errno = AFPERR_PARAM;
+                    return -1;
+                }
+                strcpy(ret->m_name, temp);
+            }
+        }
 
-    /* whee. move the left's right tree into dir's left tree */
-    dir->d_left = left->d_right;
-    if (left->d_right != SENTINEL)
-        left->d_right->d_back = dir;
+        /* check for OS X mangled filename :( */
+        t = demangle_osx(vol, ret->m_name, dir->d_did, &fileid);
+        LOG(log_maxdebug, logtype_afpd, "cname_mtouname('%s',did:%u) {demangled:'%s', fileid:%u}",
+            ret->m_name, ntohl(dir->d_did), t, ntohl(fileid));
+
+        if (t != ret->m_name) {
+            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(ret->m_name, t);
+            }
+        }
+    } /* afp_version >= 30 */
 
-    if (left != SENTINEL) {
-        left->d_back = dir->d_back;
-        left->d_right = dir;
+    /* If we haven't got it by now, get it */
+    if (ret->u_name == NULL) {
+        if ((ret->u_name = mtoupath(vol, ret->m_name, dir->d_did, utf8_encoding())) == NULL) {
+            afp_errno = AFPERR_PARAM;
+            return -1;
+        }
     }
 
-    if (!dir->d_back) /* no parent. move the left tree to the top. */
-        vol->v_root = left;
-    else if (dir == dir->d_back->d_right) /* we were on the right */
-        dir->d_back->d_right = left;
-    else
-        dir->d_back->d_left = left; /* we were on the left */
-
-    /* re-insert dir on the right tree */
-    if (dir != SENTINEL)
-        dir->d_back = left;
+    return 0;
 }
 
-#if 0
-/* recolor after a removal */
-static struct dir *dir_rmrecolor(struct vol *vol, struct dir *dir)
+/*!
+ * @brief Build struct path from struct dir
+ *
+ * The final movecwd in cname failed, possibly with EPERM or ENOENT. We:
+ * 1. move cwd into parent dir (we're often already there, but not always)
+ * 2. set struct path to the dirname
+ * 3. in case of
+ *    AFPERR_ACCESS: the dir is there, we just cant chdir into it
+ *    AFPERR_NOOBJ: the dir was there when we stated it in cname, so we have a race
+ *                  4. indicate there's no dir for this path
+ *                  5. remove the dir
+ */
+static struct path *path_from_dir(struct vol *vol, struct dir *dir, struct path *ret)
 {
-    struct dir *leaf;
-
-    while ((dir != vol->v_root) && (dir->d_color == DIRTREE_COLOR_BLACK)) {
-        /* are we on the left tree? */
-        if (dir == dir->d_back->d_left) {
-            leaf = dir->d_back->d_right; /* get right side */
-            if (leaf->d_color == DIRTREE_COLOR_RED) {
-                /* we're red. we need to change to black. */
-                leaf->d_color = DIRTREE_COLOR_BLACK;
-                dir->d_back->d_color = DIRTREE_COLOR_RED;
-                dir_leftrotate(vol, dir->d_back);
-                leaf = dir->d_back->d_right;
-            }
+    if (dir->d_did == DIRDID_ROOT_PARENT || dir->d_did == DIRDID_ROOT)
+        return NULL;
 
-            /* right leaf has black end nodes */
-            if ((leaf->d_left->d_color == DIRTREE_COLOR_BLACK) &&
-                (leaf->d_right->d_color = DIRTREE_COLOR_BLACK)) {
-                leaf->d_color = DIRTREE_COLOR_RED; /* recolor leaf as red */
-                dir = dir->d_back; /* ascend */
-            } else {
-                if (leaf->d_right->d_color == DIRTREE_COLOR_BLACK) {
-                    leaf->d_left->d_color = DIRTREE_COLOR_BLACK;
-                    leaf->d_color = DIRTREE_COLOR_RED;
-                    dir_rightrotate(vol, leaf);
-                    leaf = dir->d_back->d_right;
-                }
-                leaf->d_color = dir->d_back->d_color;
-                dir->d_back->d_color = DIRTREE_COLOR_BLACK;
-                leaf->d_right->d_color = DIRTREE_COLOR_BLACK;
-                dir_leftrotate(vol, dir->d_back);
-                dir = vol->v_root;
-            }
-        } else { /* right tree */
-            leaf = dir->d_back->d_left; /* left tree */
-            if (leaf->d_color == DIRTREE_COLOR_RED) {
-                leaf->d_color = DIRTREE_COLOR_BLACK;
-                dir->d_back->d_color = DIRTREE_COLOR_RED;
-                dir_rightrotate(vol, dir->d_back);
-                leaf = dir->d_back->d_left;
-            }
+    switch (afp_errno) {
 
-            /* left leaf has black end nodes */
-            if ((leaf->d_right->d_color == DIRTREE_COLOR_BLACK) &&
-                (leaf->d_left->d_color = DIRTREE_COLOR_BLACK)) {
-                leaf->d_color = DIRTREE_COLOR_RED; /* recolor leaf as red */
-                dir = dir->d_back; /* ascend */
-            } else {
-                if (leaf->d_left->d_color == DIRTREE_COLOR_BLACK) {
-                    leaf->d_right->d_color = DIRTREE_COLOR_BLACK;
-                    leaf->d_color = DIRTREE_COLOR_RED;
-                    dir_leftrotate(vol, leaf);
-                    leaf = dir->d_back->d_left;
-                }
-                leaf->d_color = dir->d_back->d_color;
-                dir->d_back->d_color = DIRTREE_COLOR_BLACK;
-                leaf->d_left->d_color = DIRTREE_COLOR_BLACK;
-                dir_rightrotate(vol, dir->d_back);
-                dir = vol->v_root;
-            }
+    case AFPERR_ACCESS:
+        if (movecwd( vol, dirlookup(vol, dir->d_pdid)) < 0 ) /* 1 */
+            return NULL;
+
+        memcpy(ret->m_name, cfrombstr(dir->d_m_name), blength(dir->d_m_name) + 1); /* 3 */
+        if (dir->d_m_name == dir->d_u_name) {
+            ret->u_name = ret->m_name;
+        } else {
+            ret->u_name =  ret->m_name + blength(dir->d_m_name) + 1;
+            memcpy(ret->u_name, cfrombstr(dir->d_u_name), blength(dir->d_u_name) + 1);
         }
-    }
-    dir->d_color = DIRTREE_COLOR_BLACK;
 
-    return dir;
-}
-#endif /* 0 */
+        ret->d_dir = dir;
 
-/* --------------------- */
-static void dir_hash_del(const struct vol *vol, struct dir *dir)
-{
-    hnode_t *hn;
+        LOG(log_debug, logtype_afpd, "cname('%s') {path-from-dir: AFPERR_ACCESS. curdir:'%s', path:'%s'}",
+            cfrombstr(dir->d_fullpath),
+            cfrombstr(curdir->d_fullpath),
+            ret->u_name);
 
-    hn = hash_lookup(vol->v_hash, dir);
-    if (!hn) {
-        LOG(log_error, logtype_afpd, "dir_hash_del: %s not hashed", dir->d_u_name);
-    }
-    else {
-        hash_delete(vol->v_hash, hn);
-    }
-}
+        return ret;
 
-/* remove the node from the tree. this is just like insertion, but
- * different. actually, it has to worry about a bunch of things that
- * insertion doesn't care about. */
+    case AFPERR_NOOBJ:
+        if (movecwd(vol, dirlookup(vol, dir->d_pdid)) < 0 ) /* 1 */
+            return NULL;
 
-static void dir_remove( struct vol *vol, struct dir *dir)
-{
-#ifdef REMOVE_NODES
-    struct ofork *of, *last;
-    struct dir *node, *leaf;
-#endif /* REMOVE_NODES */
-
-    if (!dir || (dir == SENTINEL))
-        return;
-
-    /* i'm not sure if it really helps to delete stuff. */
-    dir_hash_del(vol, dir);
-    vol->v_curdir = NULL;
-#ifndef REMOVE_NODES
-    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 */
-    if ((dir->d_left == SENTINEL) || (dir->d_right == SENTINEL)) {
-        node = dir;
-    } else {
-        node = dir->d_right;
-        while (node->d_left != SENTINEL)
-            node = node->d_left;
-    }
+        memcpy(ret->m_name, cfrombstr(dir->d_m_name), blength(dir->d_m_name) + 1);
+        if (dir->d_m_name == dir->d_u_name) {
+            ret->u_name = ret->m_name;
+        } else {
+            ret->u_name =  ret->m_name + blength(dir->d_m_name) + 1;
+            memcpy(ret->u_name, cfrombstr(dir->d_u_name), blength(dir->d_u_name) + 1);
+        }
 
-    /* get that child */
-    leaf = (node->d_left != SENTINEL) ? node->d_left : node->d_right;
+        ret->d_dir = NULL;      /* 4 */
+        dir_remove(vol, dir);   /* 5 */
+        return ret;
 
-    /* detach node */
-    leaf->d_back = node->d_back;
-    if (!node->d_back) {
-        vol->v_root = leaf;
-    } else if (node == node->d_back->d_left) { /* left tree */
-        node->d_back->d_left = leaf;
-    } else {
-        node->d_back->d_right = leaf;
+    default:
+        return NULL;
     }
 
-    /* we want to free node, but we also want to free the data in dir.
-     * currently, that's d_name and the directory traversal bits.
-     * we just copy the necessary bits and then fix up all the
-     * various pointers to the directory. needless to say, there are
-     * a bunch of places that store the directory struct. */
-    if (node != dir) {
-        struct dir save, *tmp;
+    /* DEADC0DE: never get here */
+    return NULL;
+}
 
-        memcpy(&save, dir, sizeof(save));
-        memcpy(dir, node, sizeof(struct dir));
 
-        /* restore the red-black bits */
-        dir->d_left = save.d_left;
-        dir->d_right = save.d_right;
-        dir->d_back = save.d_back;
-        dir->d_color = save.d_color;
+/*********************************************************************************************
+ * Interface
+ ********************************************************************************************/
 
-        if (node == vol->v_dir) {/* we may need to fix up this pointer */
-            vol->v_dir = dir;
-            rootpar.d_child = vol->v_dir;
-        } else {
-            /* if we aren't the root directory, we have parents and
-             * siblings to worry about */
-            if (dir->d_parent->d_child == node)
-                dir->d_parent->d_child = dir;
-            dir->d_next->d_prev = dir;
-            dir->d_prev->d_next = dir;
-        }
+int get_afp_errno(const int param)
+{
+    if (afp_errno != AFPERR_DID1)
+        return afp_errno;
+    return param;
+}
 
-        /* fix up children. */
-        tmp = dir->d_child;
-        while (tmp) {
-            tmp->d_parent = dir;
-            tmp = (tmp == dir->d_child->d_prev) ? NULL : tmp->d_next;
-        }
+/*!
+ * @brief Resolve a DID
+ *
+ * Resolve a DID, allocate a struct dir for it
+ * 1. Check for special CNIDs 0 (invalid), 1 and 2.
+ * 2a. Check if the DID is in the cache.
+ * 2b. Check if it's really a dir (d_fullpath != NULL) because we cache files too.
+ * 3. If it's not in the cache resolve it via the database.
+ * 4. Build complete server-side path to the dir.
+ * 5. Check if it exists and is a directory.
+ * 6. Create the struct dir and populate it.
+ * 7. Add it to the cache.
+ *
+ * @param vol   (r) pointer to struct vol
+ * @param did   (r) DID to resolve
+ *
+ * @returns pointer to struct dir
+ *
+ * @note FIXME: OSX calls it with bogus id, ie file ID not folder ID,
+ *       and we are really bad in this case.
+ */
+struct dir *dirlookup(const struct vol *vol, cnid_t did)
+{
+    static char  buffer[12 + MAXPATHLEN + 1];
+    struct stat  st;
+    struct dir   *ret = NULL, *pdir;
+    bstring      fullpath = NULL;
+    char         *upath = NULL, *mpath;
+    cnid_t       cnid, pdid;
+    size_t       maxpath;
+    int          buflen = 12 + MAXPATHLEN + 1;
+    int          utf8;
+    int          err = 0;
+
+    LOG(log_debug, logtype_afpd, "dirlookup(did: %u) {start}", ntohl(did));
 
-        if (node == curdir) /* another pointer to fixup */
-            curdir = dir;
+    /* check for did 0, 1 and 2 */
+    if (did == 0 || vol == NULL) { /* 1 */
+        afp_errno = AFPERR_PARAM;
+        return NULL;
+    } else if (did == DIRDID_ROOT_PARENT) {
+        rootParent.d_vid = vol->v_vid;
+        return (&rootParent);
+    } else if (did == DIRDID_ROOT) {
+        return vol->v_root;
+    }
 
-        /* we also need to fix up oforks. bleah */
-        if ((of = dir->d_ofork)) {
-            last = of->of_d_prev;
-            while (of) {
-                of->of_dir = dir;
-                of = (last == of) ? NULL : of->of_d_next;
+    /* Search the cache */
+    if ((ret = dircache_search_by_did(vol, did)) != NULL) { /* 2a */
+        if (ret->d_fullpath == NULL) {                      /* 2b */
+            afp_errno = AFPERR_BADTYPE;
+            return NULL;
+        }
+        if (lstat(cfrombstr(ret->d_fullpath), &st) != 0) {
+            LOG(log_debug, logtype_afpd, "dirlookup(did: %u) {lstat: %s}", ntohl(did), strerror(errno));
+            switch (errno) {
+            case ENOENT:
+            case ENOTDIR:
+                /* It's not there anymore, so remove it */
+                LOG(log_debug, logtype_afpd, "dirlookup(did: %u) {calling dir_remove()}", ntohl(did));
+                dir_remove(vol, ret);
+                afp_errno = AFPERR_NOOBJ;
+                return NULL;
+            default:
+                return ret;
             }
+            /* DEADC0DE */
+            return NULL;
         }
+        return ret;
+    }
+
+    utf8 = utf8_encoding();
+    maxpath = (utf8) ? MAXPATHLEN - 7 : 255;
 
-        /* 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;
+    /* Get it from the database */
+    cnid = did;
+    if ( (upath = cnid_resolve(vol->v_cdb, &cnid, buffer, buflen)) == NULL 
+         || (upath = strdup(upath)) == NULL) { /* 3 */
+        afp_errno = AFPERR_NOOBJ;
+        err = 1;
+        goto exit;
     }
+    pdid = cnid;
 
-    if (node->d_color == DIRTREE_COLOR_BLACK)
-        dir_rmrecolor(vol, leaf);
+    /*
+     * Recurse up the tree, terminates in dirlookup when either
+     * - DIRDID_ROOT is hit
+     * - a cached entry is found
+     */
+    if ((pdir = dirlookup(vol, pdid)) == NULL) {
+        err = 1;
+        goto exit;
+    }
 
-    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);
+    /* build the fullpath */
+    if ((fullpath = bstrcpy(pdir->d_fullpath)) == NULL
+        || bconchar(fullpath, '/') != BSTR_OK
+        || bcatcstr(fullpath, upath) != BSTR_OK) {
+        err = 1;
+        goto exit;
     }
-    free(node->d_m_name);
-    free(node);
-#endif /* ! REMOVE_NODES */
-}
 
-/* ---------------------------------------
- * remove the node and its childs from the tree
- *
- * FIXME what about opened forks with refs to it?
- * it's an afp specs violation because you can't delete
- * an opened forks. Now afpd doesn't care about forks opened by other
- * process. It's fixable within afpd if fnctl_lock, doable with smb and
- * next to impossible for nfs and local filesystem access.
- */
-static void dir_invalidate( struct vol *vol, struct dir *dir)
-{
-    if (curdir == dir) {
-        /* v_root can't be deleted */
-        if (movecwd(vol, vol->v_root) < 0) {
-            LOG(log_error, logtype_afpd, "cname can't chdir to : %s", vol->v_root);
+    /* stat it and check if it's a dir */
+    LOG(log_debug, logtype_afpd, "dirlookup: {stating %s}", cfrombstr(fullpath));
+
+    if (stat(cfrombstr(fullpath), &st) != 0) { /* 5a */
+        switch (errno) {
+        case ENOENT:
+            afp_errno = AFPERR_NOOBJ;
+            err = 1;
+            goto exit;
+        case EPERM:
+            afp_errno = AFPERR_ACCESS;
+            err = 1;
+            goto exit;
+        default:
+            afp_errno = AFPERR_MISC;
+            err = 1;
+            goto exit;
         }
+    } else {
+        if ( ! S_ISDIR(st.st_mode)) { /* 5b */
+            afp_errno = AFPERR_BADTYPE;
+            err = 1;
+            goto exit;
+        }
+    }
+
+    /* Get macname from unix name */
+    if ( (mpath = utompath(vol, upath, did, utf8)) == NULL ) {
+        afp_errno = AFPERR_NOOBJ;
+        err = 1;
+        goto exit;
+    }
+
+    /* Create struct dir */
+    if ((ret = dir_new(mpath, upath, vol, pdid, did, fullpath, st.st_ctime)) == NULL) { /* 6 */
+        LOG(log_error, logtype_afpd, "dirlookup(did: %u) {%s, %s}: %s", ntohl(did), mpath, upath, strerror(errno));
+        err = 1;
+        goto exit;
+    }
+    
+    /* Add it to the cache only if it's a dir */
+    if (dircache_add(ret) != 0) { /* 7 */
+        err = 1;
+        goto exit;
     }
-    /* FIXME */
-    dirchildremove(dir->d_parent, dir);
-    dir_remove( vol, dir );
-}
 
-/* ------------------------------------ */
-static struct dir *dir_insert(const struct vol *vol, struct dir *dir)
-{
-    struct dir  *pdir;
-
-    pdir = vol_tree_root(vol, dir->d_did);
-    while (pdir->d_did != dir->d_did ) {
-        if ( pdir->d_did > dir->d_did ) {
-            if ( pdir->d_left == SENTINEL ) {
-                pdir->d_left = dir;
-                dir->d_back = pdir;
-                return NULL;
-            }
-            pdir = pdir->d_left;
-        } else {
-            if ( pdir->d_right == SENTINEL ) {
-                pdir->d_right = dir;
-                dir->d_back = pdir;
-                return NULL;
-            }
-            pdir = pdir->d_right;
+    LOG(log_debug, logtype_afpd, "dirlookup(did: %u) {end: did:%u, path:'%s'}",
+        ntohl(did), ntohl(pdid), cfrombstr(ret->d_fullpath));
+
+exit:
+    if (upath) free(upath);
+    if (err) {
+        LOG(log_debug, logtype_afpd, "dirlookup(did: %u) {exit_error: %s}",
+            ntohl(did), AfpErr2name(afp_errno));
+        if (fullpath)
+            bdestroy(fullpath);
+        if (ret) {
+            dir_free(ret);
+            ret = NULL;
         }
     }
-    return pdir;
+    return ret;
 }
 
 #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)
+int caseenumerate(const struct vol *vol, struct path *path, struct dir *dir)
 {
     DIR               *dp;
     struct dirent     *de;
@@ -712,635 +678,374 @@ caseenumerate(const struct vol *vol, struct path *path, struct dir *dir)
 }
 
 
-/*
- * attempt to extend the current dir. tree to include path
- * as a side-effect, movecwd to that point and return the new dir
+/*!
+ * @brief Construct struct dir
+ *
+ * Construct struct dir from parameters.
+ *
+ * @param m_name   (r) directory name in UTF8-dec
+ * @param u_name   (r) directory name in server side encoding
+ * @param vol      (r) pointer to struct vol
+ * @param pdid     (r) Parent CNID
+ * @param did      (r) CNID
+ * @param path     (r) Full unix path to dir or NULL for files
+ * @param ctime    (r) st_ctime from stat
+ *
+ * @returns pointer to new struct dir or NULL on error
+ *
+ * @note Most of the time mac name and unix name are the same.
  */
-static struct dir *
-extenddir(struct vol *vol, struct dir *dir, struct path *path)
+struct dir *dir_new(const char *m_name,
+                    const char *u_name,
+                    const struct vol *vol,
+                    cnid_t pdid,
+                    cnid_t did,
+                    bstring path,
+                    time_t ctime)
 {
-    path->d_dir = NULL;
+    struct dir *dir;
 
-    if ( path->u_name == NULL) {
-        afp_errno = AFPERR_PARAM;
+    dir = (struct dir *) calloc(1, sizeof( struct dir ));
+    if (!dir)
         return NULL;
-    }
 
-    if (check_name(vol, path->u_name)) {
-        /* the name is illegal */
-        LOG(log_info, logtype_afpd, "extenddir: illegal path: '%s'", path->u_name);
-        path->u_name = NULL;
-        afp_errno = AFPERR_PARAM;
+    if ((dir->d_m_name = bfromcstr(m_name)) == NULL) {
+        free(dir);
         return NULL;
     }
 
-    if (of_stat( path ) != 0 ) {
-        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->d_dir = dir;
-    if ( movecwd( vol, dir ) < 0 ) {
-        return( NULL );
-    }
-
-    return( dir );
-}
-
-/* -------------------------
-   appledouble mkdir afp error code.
-*/
-static int netatalk_mkdir(const struct vol *vol, const char *name)
-{
-    int ret;
-    struct stat st;
-
-    if (vol->v_flags & AFPVOL_UNIX_PRIV) {
-        if (lstat(".", &st) < 0)
-            return AFPERR_MISC;
-        int mode = (DIRBITS & (~S_ISGID & st.st_mode)) | (0777 & ~vol->v_umask);
-        LOG(log_maxdebug, logtype_afpd, "netatalk_mkdir(\"%s\") {parent mode: %04o, vol umask: %04o}",
-            name, st.st_mode, vol->v_umask);
-
-        ret = mkdir(name, mode);
-    } else {
-        ret = ad_mkdir(name, DIRBITS | 0777);
-    }
-
-    if (ret < 0) {
-        switch ( errno ) {
-        case ENOENT :
-            return( AFPERR_NOOBJ );
-        case EROFS :
-            return( AFPERR_VLOCK );
-        case EPERM:
-        case EACCES :
-            return( AFPERR_ACCESS );
-        case EEXIST :
-            return( AFPERR_EXIST );
-        case ENOSPC :
-        case EDQUOT :
-            return( AFPERR_DFULL );
-        default :
-            return( AFPERR_PARAM );
-        }
-    }
-    return AFP_OK;
-}
-
-/* ------------------- */
-static int deletedir(int dirfd, char *dir)
-{
-    char path[MAXPATHLEN + 1];
-    DIR *dp;
-    struct dirent   *de;
-    struct stat st;
-    size_t len;
-    int err = AFP_OK;
-    size_t remain;
-
-    if ((len = strlen(dir)) +2 > sizeof(path))
-        return AFPERR_PARAM;
-
-    /* already gone */
-    if ((dp = opendirat(dirfd, dir)) == NULL)
-        return AFP_OK;
-
-    strcpy(path, dir);
-    strcat(path, "/");
-    len++;
-    remain = sizeof(path) -len -1;
-    while ((de = readdir(dp)) && err == AFP_OK) {
-        /* skip this and previous directory */
-        if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
-            continue;
-
-        if (strlen(de->d_name) > remain) {
-            err = AFPERR_PARAM;
-            break;
-        }
-        strcpy(path + len, de->d_name);
-        if (lstatat(dirfd, path, &st)) {
-            continue;
-        }
-        if (S_ISDIR(st.st_mode)) {
-            err = deletedir(dirfd, path);
-        } else {
-            err = netatalk_unlinkat(dirfd, path);
-        }
-    }
-    closedir(dp);
-
-    /* okay. the directory is empty. delete it. note: we already got rid
-       of .AppleDouble.  */
-    if (err == AFP_OK) {
-        err = netatalk_rmdir(dirfd, dir);
-    }
-    return err;
-}
-
-/* do a recursive copy. */
-static int copydir(const struct vol *vol, int dirfd, char *src, char *dst)
-{
-    char spath[MAXPATHLEN + 1], dpath[MAXPATHLEN + 1];
-    DIR *dp;
-    struct dirent   *de;
-    struct stat st;
-    struct utimbuf      ut;
-    size_t slen, dlen;
-    size_t srem, drem;
-    int err;
-
-    /* doesn't exist or the path is too long. */
-    if (((slen = strlen(src)) > sizeof(spath) - 2) ||
-        ((dlen = strlen(dst)) > sizeof(dpath) - 2) ||
-        ((dp = opendirat(dirfd, src)) == NULL))
-        return AFPERR_PARAM;
-
-    /* try to create the destination directory */
-    if (AFP_OK != (err = netatalk_mkdir(vol, dst)) ) {
-        closedir(dp);
-        return err;
+    if (convert_string_allocate( (utf8_encoding()) ? CH_UTF8_MAC : vol->v_maccharset,
+                                 CH_UCS2,
+                                 m_name,
+                                 -1, (char **)&dir->d_m_name_ucs2) == (size_t)-1 ) {
+        LOG(log_error, logtype_afpd, "dir_new(did: %u) {%s, %s}: couldn't set UCS2 name", ntohl(did), m_name, u_name);
+        dir->d_m_name_ucs2 = NULL;
     }
 
-    /* set things up to copy */
-    strcpy(spath, src);
-    strcat(spath, "/");
-    slen++;
-    srem = sizeof(spath) - slen -1;
-
-    strcpy(dpath, dst);
-    strcat(dpath, "/");
-    dlen++;
-    drem = sizeof(dpath) - dlen -1;
-
-    err = AFP_OK;
-    while ((de = readdir(dp))) {
-        /* skip this and previous directory */
-        if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
-            continue;
-
-        if (strlen(de->d_name) > srem) {
-            err = AFPERR_PARAM;
-            break;
-        }
-        strcpy(spath + slen, de->d_name);
-
-        if (lstatat(dirfd, spath, &st) == 0) {
-            if (strlen(de->d_name) > drem) {
-                err = AFPERR_PARAM;
-                break;
-            }
-            strcpy(dpath + dlen, de->d_name);
-
-            if (S_ISDIR(st.st_mode)) {
-                if (AFP_OK != (err = copydir(vol, dirfd, spath, dpath)))
-                    goto copydir_done;
-            } else if (AFP_OK != (err = copyfile(vol, vol, dirfd, spath, dpath, NULL, NULL))) {
-                goto copydir_done;
-
-            } else {
-                /* keep the same time stamp. */
-                ut.actime = ut.modtime = st.st_mtime;
-                utime(dpath, &ut);
-            }
-        }
+    if (m_name == u_name || !strcmp(m_name, u_name)) {
+        dir->d_u_name = dir->d_m_name;
     }
-
-    /* keep the same time stamp. */
-    if (lstatat(dirfd, src, &st) == 0) {
-        ut.actime = ut.modtime = st.st_mtime;
-        utime(dst, &ut);
+    else if ((dir->d_u_name = bfromcstr(u_name)) == NULL) {
+        bdestroy(dir->d_m_name);
+        free(dir);
+        return NULL;
     }
 
-copydir_done:
-    closedir(dp);
-    return err;
+    dir->d_did = did;
+    dir->d_pdid = pdid;
+    dir->d_vid = vol->v_vid;
+    dir->d_fullpath = path;
+    dir->ctime_dircache = ctime;
+    return dir;
 }
 
-
-/* --- public functions follow --- */
-
-/* NOTE: we start off with at least one node (the root directory). */
-static struct dir *dirinsert(struct vol *vol, struct dir *dir)
+/*!
+ * @brief Free a struct dir and all its members
+ *
+ * @param (rw) pointer to struct dir
+ */
+void dir_free(struct dir *dir)
 {
-    struct dir *node;
-
-    if ((node = dir_insert(vol, dir)))
-        return node;
-
-    /* recolor the tree. the current node is red. */
-    dir->d_color = DIRTREE_COLOR_RED;
-
-    /* parent of this node has to be black. if the parent node
-     * is red, then we have a grandparent. */
-    while ((dir != vol->v_root) &&
-           (dir->d_back->d_color == DIRTREE_COLOR_RED)) {
-        /* are we on the left tree? */
-        if (dir->d_back == dir->d_back->d_back->d_left) {
-            node = dir->d_back->d_back->d_right;  /* get the right node */
-            if (node->d_color == DIRTREE_COLOR_RED) {
-                /* we're red. we need to change to black. */
-                dir->d_back->d_color = DIRTREE_COLOR_BLACK;
-                node->d_color = DIRTREE_COLOR_BLACK;
-                dir->d_back->d_back->d_color = DIRTREE_COLOR_RED;
-                dir = dir->d_back->d_back; /* finished. go up. */
-            } else {
-                if (dir == dir->d_back->d_right) {
-                    dir = dir->d_back;
-                    dir_leftrotate(vol, dir);
-                }
-                dir->d_back->d_color = DIRTREE_COLOR_BLACK;
-                dir->d_back->d_back->d_color = DIRTREE_COLOR_RED;
-                dir_rightrotate(vol, dir->d_back->d_back);
-            }
-        } else {
-            node = dir->d_back->d_back->d_left;
-            if (node->d_color == DIRTREE_COLOR_RED) {
-                /* we're red. we need to change to black. */
-                dir->d_back->d_color = DIRTREE_COLOR_BLACK;
-                node->d_color = DIRTREE_COLOR_BLACK;
-                dir->d_back->d_back->d_color = DIRTREE_COLOR_RED;
-                dir = dir->d_back->d_back; /* finished. ascend */
-            } else {
-                if (dir == dir->d_back->d_left) {
-                    dir = dir->d_back;
-                    dir_rightrotate(vol, dir);
-                }
-                dir->d_back->d_color = DIRTREE_COLOR_BLACK;
-                dir->d_back->d_back->d_color = DIRTREE_COLOR_RED;
-                dir_leftrotate(vol, dir->d_back->d_back);
-            }
-        }
+    if (dir->d_u_name != dir->d_m_name) {
+        bdestroy(dir->d_u_name);
     }
-
-    vol->v_root->d_color = DIRTREE_COLOR_BLACK;
-    return NULL;
+    if (dir->d_m_name_ucs2)
+        free(dir->d_m_name_ucs2);
+    bdestroy(dir->d_m_name);
+    bdestroy(dir->d_fullpath);
+    free(dir);
 }
 
-/* ---------------------------- */
-struct dir *
-adddir(struct vol *vol, struct dir *dir, struct path *path)
+/*!
+ * @brief Create struct dir from struct path
+ *
+ * Create a new struct dir from struct path. Then add it to the cache.
+ *
+ * 1. Open adouble file, get CNID from it.
+ * 2. Search the database, hinting with the CNID from (1).
+ * 3. Build fullpath and create struct dir.
+ * 4. Add it to the cache.
+ *
+ * @param vol   (r) pointer to struct vol, possibly modified in callee
+ * @param dir   (r) pointer to parrent directory
+ * @param path  (rw) pointer to struct path with valid path->u_name
+ * @param len   (r) strlen of path->u_name
+ *
+ * @returns Pointer to new struct dir or NULL on error.
+ *
+ * @note Function also assigns path->m_name from path->u_name.
+ */
+struct dir *dir_add(struct vol *vol, const struct dir *dir, struct path *path, int len)
 {
-    struct dir  *cdir, *edir;
-    int     upathlen;
-    char        *name;
-    char        *upath;
-    struct stat *st;
-    int         deleted;
+    int err = 0;
+    struct dir  *cdir = NULL;
+    cnid_t      id;
     struct adouble  ad;
     struct adouble *adp = NULL;
-    cnid_t      id;
-
-    upath = path->u_name;
-    st    = &path->st;
-    upathlen = strlen(upath);
+    bstring fullpath;
+
+    AFP_ASSERT(vol);
+    AFP_ASSERT(dir);
+    AFP_ASSERT(path);
+    AFP_ASSERT(len > 0);
+
+    if ((cdir = dircache_search_by_name(vol, dir, path->u_name, strlen(path->u_name), path->st.st_ctime)) != NULL) {
+        /* there's a stray entry in the dircache */
+        LOG(log_debug, logtype_afpd, "dir_add(did:%u,'%s/%s'): {stray cache entry: did:%u,'%s', removing}",
+            ntohl(dir->d_did), cfrombstr(dir->d_fullpath), path->u_name,
+            ntohl(cdir->d_did), cfrombstr(dir->d_fullpath));
+        if (dir_remove(vol, cdir) != 0) {
+            dircache_dump();
+            AFP_PANIC("dir_add");
+        }
+    }
 
     /* get_id needs adp for reading CNID from adouble file */
     ad_init(&ad, vol->v_adouble, vol->v_ad_options);
-    if ((ad_open_metadata(upath, ADFLAGS_DIR, 0, &ad)) == 0)
+    if ((ad_open_metadata(path->u_name, ADFLAGS_DIR, 0, &ad)) == 0) /* 1 */
         adp = &ad;
 
-    id = get_id(vol, adp, st, dir->d_did, upath, upathlen);
+    /* Get CNID */
+    if ((id = get_id(vol, adp, &path->st, dir->d_did, path->u_name, len)) == 0) { /* 2 */
+        err = 1;
+        goto exit;
+    }
 
     if (adp)
         ad_close_metadata(adp);
 
-    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, -1, (char **)&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);
-        if (!deleted)
-            dir_hash_del(vol, edir);
-        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;
-        LOG(log_error, logtype_afpd, "adddir: insert %s", edir->d_m_name);
-        if (!cdir->d_parent || (cdir->d_parent == dir && !deleted)) {
-            hash_alloc_insert(vol->v_hash, cdir, cdir);
-            return cdir;
+    /* Get macname from unixname */
+    if (path->m_name == NULL) {
+        if ((path->m_name = utompath(vol, path->u_name, id, utf8_encoding())) == NULL) {
+            err = 2;
+            goto exit;
         }
-        /* the old was not in the same folder */
-        if (!deleted)
-            dirchildremove(cdir->d_parent, cdir);
     }
 
-    /* parent/child directories */
-    cdir->d_parent = dir;
-    dirchildadd(vol, dir, cdir);
-    return( cdir );
-}
-
-/* --- public functions follow --- */
-/* free everything down. we don't bother to recolor as this is only
- * called to free the entire tree */
-void dirfreename(struct dir *dir)
-{
-    if (dir->d_u_name != dir->d_m_name) {
-        free(dir->d_u_name);
+    /* Build fullpath */
+    if ( ((fullpath = bstrcpy(dir->d_fullpath)) == NULL) /* 3 */
+         || (bconchar(fullpath, '/') != BSTR_OK)
+         || (bcatcstr(fullpath, path->u_name)) != BSTR_OK) {
+        LOG(log_error, logtype_afpd, "dir_add: fullpath: %s", strerror(errno) );
+        err = 3;
+        goto exit;
     }
-    if (dir->d_m_name_ucs2)
-        free(dir->d_m_name_ucs2);
-    free(dir->d_m_name);
-}
-
-void dirfree(struct dir *dir)
-{
-    if (!dir || (dir == SENTINEL))
-        return;
 
-    if ( dir->d_left != SENTINEL ) {
-        dirfree( dir->d_left );
+    /* Allocate and initialize struct dir */
+    if ((cdir = dir_new( path->m_name, path->u_name, vol, dir->d_did, id, fullpath, path->st.st_ctime)) == NULL) { /* 3 */
+        err = 4;
+        goto exit;
     }
-    if ( dir->d_right != SENTINEL ) {
-        dirfree( dir->d_right );
+
+    if ((dircache_add(cdir)) != 0) { /* 4 */
+        LOG(log_error, logtype_afpd, "dir_add: fatal dircache error: %s", cfrombstr(fullpath));
+        exit(EXITERR_SYS);
     }
 
-    if (dir != SENTINEL) {
-        dirfreename(dir);
-        free( dir );
+exit:
+    if (err != 0) {
+        LOG(log_debug, logtype_afpd, "dir_add('%s/%s'): error: %u",
+            cfrombstr(dir->d_u_name), path->u_name, err);
+
+        if (adp)
+            ad_close_metadata(adp);
+        if (!cdir && fullpath)
+            bdestroy(fullpath);
+        if (cdir)
+            dir_free(cdir);
+        cdir = NULL;
+    } else {
+        /* no error */
+        LOG(log_debug, logtype_afpd, "dir_add(did:%u,'%s/%s'): {cached: %u,'%s'}",
+            ntohl(dir->d_did), cfrombstr(dir->d_fullpath), path->u_name,
+            ntohl(cdir->d_did), cfrombstr(cdir->d_fullpath));
     }
+
+    return(cdir);
 }
 
-/* --------------------------------------------
- * most of the time mac name and unix name are the same
+/*!
+ * Free the queue with invalid struct dirs
+ *
+ * This gets called at the end of every AFP func.
  */
-struct dir *dirnew(const char *m_name, const char *u_name)
+void dir_free_invalid_q(void)
 {
     struct dir *dir;
-
-    dir = (struct dir *) calloc(1, sizeof( struct dir ));
-    if (!dir)
-        return NULL;
-
-    if ((dir->d_m_name = strdup(m_name)) == NULL) {
-        free(dir);
-        return NULL;
-    }
-
-    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) {
-        free(dir->d_m_name);
-        free(dir);
-        return NULL;
-    }
-
-    dir->d_m_name_ucs2 = NULL;
-    dir->d_left = dir->d_right = SENTINEL;
-    dir->d_next = dir->d_prev = dir;
-    return dir;
+    while (dir = (struct dir *)dequeue(invalid_dircache_entries))
+        dir_free(dir);
 }
 
-#if 0
-/* ------------------ */
-static hash_val_t hash_fun_dir(const void *key)
+/*!
+ * @brief Remove a dir from a cache and queue it for freeing
+ *
+ * 1. Check if the dir is locked or has opened forks
+ * 2. If it's a request to remove curdir, just chdir to volume root
+ * 3. Remove it from the cache
+ * 4. Queue it for removal
+ * 5. Mark it as invalid
+ *
+ * @param (r) pointer to struct vol
+ * @param (rw) pointer to struct dir
+ */
+int dir_remove(const struct vol *vol, struct dir *dir)
 {
-    const struct dir *k = key;
-
-    static unsigned long randbox[] = {
-        0x49848f1bU, 0xe6255dbaU, 0x36da5bdcU, 0x47bf94e9U,
-        0x8cbcce22U, 0x559fc06aU, 0xd268f536U, 0xe10af79aU,
-        0xc1af4d69U, 0x1d2917b5U, 0xec4c304dU, 0x9ee5016cU,
-        0x69232f74U, 0xfead7bb3U, 0xe9089ab6U, 0xf012f6aeU,
-    };
-
-    const unsigned char *str = (unsigned char *)(k->d_u_name);
-    hash_val_t acc = k->d_parent->d_did;
-
-    while (*str) {
-        acc ^= randbox[(*str + acc) & 0xf];
-        acc = (acc << 1) | (acc >> 31);
-        acc &= 0xffffffffU;
-        acc ^= randbox[((*str++ >> 4) + acc) & 0xf];
-        acc = (acc << 2) | (acc >> 30);
-        acc &= 0xffffffffU;
-    }
-    return acc;
-}
-#endif
+    AFP_ASSERT(vol);
+    AFP_ASSERT(dir);
 
-#undef get16bits
-#if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__)    \
-    || defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__)
-#define get16bits(d) (*((const uint16_t *) (d)))
-#endif
+    if (dir->d_did == DIRDID_ROOT_PARENT || dir->d_did == DIRDID_ROOT)
+        return 0;
 
-#if !defined (get16bits)
-#define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8)    \
-                      +(uint32_t)(((const uint8_t *)(d))[0]) )
-#endif
+    if (dir->d_flags & DIRF_CACHELOCK) { /* 1 */
+        LOG(log_warning, logtype_afpd, "dir_remove(did:%u,'%s'): dir is locked",
+            ntohl(dir->d_did), cfrombstr(dir->d_u_name));
+        return 0;
+    }
 
-static hash_val_t hash_fun2_dir(const void *key)
-{
-    const struct dir *k = key;
-    const char *data = k->d_u_name;
-    int len = strlen(k->d_u_name);
-    hash_val_t hash = k->d_parent->d_did, tmp;
-
-    int rem = len & 3;
-    len >>= 2;
-
-    /* Main loop */
-    for (;len > 0; len--) {
-        hash  += get16bits (data);
-        tmp    = (get16bits (data+2) << 11) ^ hash;
-        hash   = (hash << 16) ^ tmp;
-        data  += 2*sizeof (uint16_t);
-        hash  += hash >> 11;
-    }
-
-    /* Handle end cases */
-    switch (rem) {
-    case 3: hash += get16bits (data);
-        hash ^= hash << 16;
-        hash ^= data[sizeof (uint16_t)] << 18;
-        hash += hash >> 11;
-        break;
-    case 2: hash += get16bits (data);
-        hash ^= hash << 11;
-        hash += hash >> 17;
-        break;
-    case 1: hash += *data;
-        hash ^= hash << 10;
-        hash += hash >> 1;
+    if (curdir == dir) {        /* 2 */
+        if (movecwd(vol, vol->v_root) < 0) {
+            LOG(log_error, logtype_afpd, "dir_remove: can't chdir to : %s", vol->v_root);
+        }
     }
 
-    /* Force "avalanching" of final 127 bits */
-    hash ^= hash << 3;
-    hash += hash >> 5;
-    hash ^= hash << 4;
-    hash += hash >> 17;
-    hash ^= hash << 25;
-    hash += hash >> 6;
+    LOG(log_debug, logtype_afpd, "dir_remove(did:%u,'%s'): {removing}",
+        ntohl(dir->d_did), cfrombstr(dir->d_u_name));
 
-    return hash;
+    dircache_remove(vol, dir, DIRCACHE | DIDNAME_INDEX | QUEUE_INDEX); /* 3 */
+    enqueue(invalid_dircache_entries, dir); /* 4 */
+    dir->d_did = CNID_INVALID;              /* 5 */
+    return 0;
 }
 
-/* ---------------- */
-static int hash_comp_dir(const void *key1, const void *key2)
+/*!
+ * @brief Modify a struct dir, adjust cache
+ *
+ * Any value that is 0 or NULL is not changed. If new_uname is NULL it is set to new_mname.
+ * If given new_uname == new_mname, new_uname will point to new_mname.
+ *
+ * @param vol       (r) pointer to struct vol
+ * @param dir       (rw) pointer to struct dir
+ * @param pdid      (r) new parent DID
+ * @param did       (r) new DID
+ * @param new_mname (r) new mac-name
+ * @param new_uname (r) new unix-name
+ * @param pdir_fullpath (r) new fullpath of parent dir
+ */
+int dir_modify(const struct vol *vol,
+               struct dir *dir,
+               cnid_t pdid,
+               cnid_t did,
+               const char *new_mname,
+               const char *new_uname,
+               bstring pdir_fullpath)
 {
-    const struct dir *k1 = key1;
-    const struct dir *k2 = key2;
+    int ret = 0;
 
-    return !(k1->d_parent->d_did == k2->d_parent->d_did && !strcmp(k1->d_u_name, k2->d_u_name));
-}
+    /* Remove it from the cache */
+    dircache_remove(vol, dir, DIRCACHE | DIDNAME_INDEX | QUEUE_INDEX);
 
-/* ---------------- */
-hash_t *
-dirhash(void)
-{
-    return hash_create(HASHCOUNT_T_MAX, hash_comp_dir, hash_fun2_dir);
-}
+    if (pdid)
+        dir->d_pdid = pdid;
+    if (did)
+        dir->d_did = did;
 
-/* ------------------ */
-static struct path *invalidate (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;
+    if (new_mname) {
+        /* free uname if it's not the same as mname */
+        if (dir->d_m_name != dir->d_u_name)
+            bdestroy(dir->d_u_name);
+
+        if (new_uname == NULL)
+            new_uname = new_mname;
+
+        /* assign new name */
+        if ((bassigncstr(dir->d_m_name, new_mname)) != BSTR_OK) {
+            LOG(log_error, logtype_afpd, "dir_modify: bassigncstr: %s", strerror(errno) );
+            return -1;
         }
-        else {
-            size_t tp = strlen(ret->m_name)+1;
 
-            ret->u_name =  ret->m_name +tp;
-            strcpy(ret->u_name, dir->d_u_name);
+        if (new_mname == new_uname || (strcmp(new_mname, new_uname) == 0)) {
+            dir->d_u_name = dir->d_m_name;
+        } else {
+            if ((dir->d_u_name = bfromcstr(new_uname)) == NULL) {
+                LOG(log_error, logtype_afpd, "dir_modify: bassigncstr: %s", strerror(errno) );
+                return -1;
+            }
         }
-        /* 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
-   if it's a filename:
-   in extenddir:
-   compute unix name
-   stat the file or errno
-   return
-   filename
-   curdir: filename parent directory
-
-   if it's a dirname:
-   not in the cache
-   in extenddir
-   compute unix name
-   stat the dir or errno
-   return
-   if chdir error
-   dirname
-   curdir: dir parent directory
-   sinon
-   dirname: ""
-   curdir: dir
-   in the cache
-   return
-   if chdir error
-   dirname
-   curdir: dir parent directory
-   else
-   dirname: ""
-   curdir: dir
+    if (pdir_fullpath) {
+        if (bassign(dir->d_fullpath, pdir_fullpath) != BSTR_OK)
+            return -1;
+        if (bcatcstr(dir->d_fullpath, "/") != BSTR_OK)
+            return -1;
+        if (bcatcstr(dir->d_fullpath, new_uname) != BSTR_OK)
+            return -1;
+    }
+
+    if (dir->d_m_name_ucs2)
+        free(dir->d_m_name_ucs2);
+    if ((size_t)-1 == convert_string_allocate((utf8_encoding())?CH_UTF8_MAC:vol->v_maccharset, CH_UCS2, dir->d_m_name, -1, (char**)&dir->d_m_name_ucs2))
+        dir->d_m_name_ucs2 = NULL;
+
+    /* Re-add it to the cache */
+    if ((dircache_add(dir)) != 0) {
+        dircache_dump();
+        AFP_PANIC("dir_modify");
+    }
 
-*/
-struct path *
-cname(struct vol *vol, struct dir *dir, char **cpath)
+    return ret;
+}
+
+/*!
+ * @brief Resolve a catalog node name path
+ *
+ * 1. Evaluate path type
+ * 2. Move to start dir, if we cant, it might eg because of EACCES, build
+ *    path from dirname, so eg getdirparams has sth it can chew on. curdir
+ *    is dir parent then. All this is done in path_from_dir().
+ * 3. Parse next cnode name in path, cases:
+ * 4.   single "\0" -> do nothing
+ * 5.   two or more consecutive "\0" -> chdir("..") one or more times
+ * 6.   cnode name -> copy it to path.m_name
+ * 7. Get unix name from mac name
+ * 8. Special handling of request with did 1
+ * 9. stat the cnode name
+ * 10. If it's not there, it's probably an afp_createfile|dir,
+ *     return with curdir = dir parent, struct path = dirname
+ * 11. If it's there and it's a file, it must should be the last element of the requested
+ *     path. Return with curdir = cnode name parent dir, struct path = filename
+ * 12. Treat symlinks like files, dont follow them
+ * 13. If it's a dir:
+ * 14. Search the dircache for it
+ * 15. If it's not in the cache, create a struct dir for it and add it to the cache
+ * 16. chdir into the dir and
+ * 17. set m_name to the mac equivalent of "."
+ * 18. goto 3
+ */
+struct path *cname(struct vol *vol, struct dir *dir, char **cpath)
 {
-    struct dir         *cdir, *scdir=NULL;
     static char        path[ MAXPATHLEN + 1];
     static struct path ret;
 
+    struct dir  *cdir;
     char        *data, *p;
-    int         extend = 0;
     int         len;
     u_int32_t   hint;
     u_int16_t   len16;
     int         size = 0;
-    char        sep;
     int         toUTF8 = 0;
 
+    LOG(log_maxdebug, logtype_afpd, "came('%s'): {start}", cfrombstr(dir->d_fullpath));
+
     data = *cpath;
     afp_errno = AFPERR_NOOBJ;
     memset(&ret, 0, sizeof(ret));
-    switch (ret.m_type = *data) { /* path type */
+
+    switch (ret.m_type = *data) { /* 1 */
     case 2:
         data++;
         len = (unsigned char) *data++;
         size = 2;
-        sep = 0;
         if (afp_version >= 30) {
             ret.m_type = 3;
             toUTF8 = 1;
@@ -1357,7 +1062,6 @@ cname(struct vol *vol, struct dir *dir, char **cpath)
             len = ntohs(len16);
             data += 2;
             size = 7;
-            sep = 0; /* '/';*/
             break;
         }
         /* else it's an error */
@@ -1366,254 +1070,217 @@ cname(struct vol *vol, struct dir *dir, char **cpath)
         return( NULL );
     }
     *cpath += len + size;
-    *path = '\0';
+
+    path[0] = 0;
     ret.m_name = path;
-    for ( ;; ) {
-        if ( len == 0 ) {
-            if (movecwd( vol, dir ) < 0 ) {
-                return invalidate(vol, dir, &ret );
-            }
-            if (*path == '\0') {
-                ret.u_name = ".";
-                ret.d_dir = dir;
-            }
-            return &ret;
-        }
 
-        if (*data == sep ) {
+    if (movecwd(vol, dir) < 0 ) {
+        LOG(log_debug, logtype_afpd, "cname(did:%u): failed to chdir to '%s'",
+            ntohl(dir->d_did), cfrombstr(dir->d_fullpath));
+        if (len == 0)
+            return path_from_dir(vol, dir, &ret);
+        else
+            return NULL;
+    }
+
+    while (len) {         /* 3 */
+        if (*data == 0) { /* 4 or 5 */
             data++;
             len--;
-        }
-        while (*data == sep && len > 0 ) {
-            if ( dir->d_parent == NULL ) {
-                return NULL;
+            while (len > 0 && *data == 0) { /* 5 */
+                /* chdir to parrent dir */
+                if ((dir = dirlookup(vol, dir->d_pdid)) == NULL)
+                    return NULL;
+                if (movecwd( vol, dir ) < 0 ) {
+                    dir_remove(vol, dir);
+                    return NULL;
+                }
+                data++;
+                len--;
             }
-            dir = dir->d_parent;
-            data++;
-            len--;
+            continue;
         }
 
-        /* would this be faster with strlen + strncpy? */
-        p = path;
-        while ( *data != sep && len > 0 ) {
+        /* 6*/
+        for ( p = path; *data != 0 && len > 0; len-- ) {
             *p++ = *data++;
             if (p > &path[ MAXPATHLEN]) {
                 afp_errno = AFPERR_PARAM;
-                return( NULL );
+                return NULL;
             }
-            len--;
-        }
-
-        /* short cut bits by chopping off a trailing \0. this also
-           makes the traversal happy w/ filenames at the end of the
-           cname. */
-        if (len == 1)
-            len--;
-
-        *p = '\0';
-
-        if ( p == path ) { /* end of the name parameter */
-            continue;
         }
+        *p = 0;            /* Terminate string */
         ret.u_name = NULL;
-        if (afp_version >= 30) {
-            char *t;
-            cnid_t fileid;
 
-            if (toUTF8) {
-                static char temp[ MAXPATHLEN + 1];
-
-                if (dir->d_did == DIRDID_ROOT_PARENT) {
-                    /*
-                      With uft8 volume name is utf8-mac, but requested path may be a mangled longname. See #2611981.
-                      So we compare it with the longname from the current volume and if they match
-                      we overwrite the requested path with the utf8 volume name so that the following
-                      strcmp can match.
-                    */
-                    ucs2_to_charset(vol->v_maccharset, vol->v_macname, temp, AFPVOL_MACNAMELEN + 1);
-                    if (strcasecmp( path, temp) == 0)
-                        ucs2_to_charset(CH_UTF8_MAC, vol->v_u8mname, path, AFPVOL_U8MNAMELEN);
-                } else {
-                    /* toUTF8 */
-                    if (mtoUTF8(vol, path, strlen(path), temp, MAXPATHLEN) == (size_t)-1) {
-                        afp_errno = AFPERR_PARAM;
-                        return( NULL );
-                    }
-                    strcpy(path, temp);
-                }
-            }
+        if (cname_mtouname(vol, dir, &ret, toUTF8) != 0) { /* 7 */
+            LOG(log_error, logtype_afpd, "cname('%s'): error from cname_mtouname", path);
+            return NULL;
+        }
 
-            if (strlen(ret.m_name) > 255) {   /* Safeguard */
-                afp_errno = AFPERR_PARAM;
-                return( NULL );
-            }
+        LOG(log_maxdebug, logtype_afpd, "came('%s'): {node: '%s}", cfrombstr(dir->d_fullpath), ret.u_name);
 
-            /* check for OS X mangled filename :( */
+        /* Prevent access to our special folders like .AppleDouble */
+        if (check_name(vol, ret.u_name)) {
+            /* the name is illegal */
+            LOG(log_info, logtype_afpd, "cname: illegal path: '%s'", ret.u_name);
+            afp_errno = AFPERR_PARAM;
+            return NULL;
+        }
 
-            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 (dir->d_did == DIRDID_ROOT_PARENT) { /* 8 */
+            /*
+             * Special case: CNID 1
+             * root parent (did 1) has one child: the volume. Requests for did=1 with
+             * some <name> must check against the volume name.
+             */
+            if ((strcmp(cfrombstr(vol->v_root->d_m_name), ret.m_name)) == 0)
+                cdir = vol->v_root;
+            else
+                return NULL;
+        } else {
+            /*
+             * CNID != 1, eg. most of the times we take this way.
+             * Now check if current path-part is a file or dir:
+             * o if it's dir we have to step into it
+             * o if it's a file we expect it to be the last part of the requested path
+             *   and thus call continue which should terminate the while loop because
+             *   len = 0. Ok?
+             */
+            if (of_stat(&ret) != 0) { /* 9 */
+                /*
+                 * ret.u_name doesn't exist, might be afp_createfile|dir
+                 * that means it should have been the last part
                  */
-                if ( (t = utompath(vol, ret.u_name, fileid, utf8_encoding())) ) {
-                    /* at last got our view of mac name */
-                    strcpy(path,t);
+                if (len > 0) {
+                    /* it wasn't the last part, so we have a bogus path request */
+                    afp_errno = AFPERR_NOOBJ;
+                    return NULL;
                 }
+                /*
+                 * this will terminate clean in while (1) because len == 0,
+                 * probably afp_createfile|dir
+                 */
+                LOG(log_maxdebug, logtype_afpd, "came('%s'): {leave-cnode ENOENT (possile create request): '%s'}",
+                    cfrombstr(dir->d_fullpath), ret.u_name);
+                continue; /* 10 */
             }
-        }
-        if (ret.u_name == NULL) {
-            if (!(ret.u_name = mtoupath(vol, ret.m_name, dir->d_did, utf8_encoding()))) {
-                afp_errno = AFPERR_PARAM;
-                return NULL;
-            }
-        }
-        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, -1, (char **)&tmpname) )
-            {
-                while (cdir) {
-                    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;
-                    }
 
-                    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;
-                }
-                free(tmpname);
-            }
-            else {
-            noucsfallback:
-                if (dir->d_did == DIRDID_ROOT_PARENT) {
-                    /*
-                      root parent (did 1) has one child: the volume. Requests for did=1 with some <name>
-                      must check against the volume name.
-                    */
-                    if (!strcmp(vol->v_dir->d_m_name, ret.m_name))
-                        cdir = vol->v_dir;
-                    else
-                        cdir = NULL;
+            switch (ret.st.st_mode & S_IFMT) {
+            case S_IFREG: /* 11 */
+                LOG(log_debug, logtype_afpd, "came('%s'): {file: '%s'}",
+                    cfrombstr(dir->d_fullpath), ret.u_name);
+                if (len > 0) {
+                    /* it wasn't the last part, so we have a bogus path request */
+                    afp_errno = AFPERR_PARAM;
+                    return NULL;
                 }
-                else {
-                    cdir = dirsearch_byname(vol, dir, ret.u_name);
+                continue; /* continues while loop */
+            case S_IFLNK: /* 12 */
+                LOG(log_debug, logtype_afpd, "came('%s'): {link: '%s'}",
+                    cfrombstr(dir->d_fullpath), ret.u_name);
+                if (len > 0) {
+                    LOG(log_warning, logtype_afpd, "came('%s'): {symlinked dir: '%s'}",
+                        cfrombstr(dir->d_fullpath), ret.u_name);
+                    afp_errno = AFPERR_PARAM;
+                    return NULL;
                 }
+                continue; /* continues while loop */
+            case S_IFDIR: /* 13 */
+                break;
+            default:
+                LOG(log_info, logtype_afpd, "cname: special file: '%s'", ret.u_name);
+                afp_errno = AFPERR_NODIR;
+                return NULL;
             }
 
-            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 ) {
-                ++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);
+            /* Search the cache */
+            int unamelen = strlen(ret.u_name);
+            cdir = dircache_search_by_name(vol, dir, ret.u_name, unamelen, ret.st.st_ctime); /* 14 */
+            if (cdir == NULL) {
+                /* Not in cache, create one */
+                if ((cdir = dir_add(vol, dir, &ret, unamelen)) == NULL) { /* 15 */
+                    LOG(log_error, logtype_afpd, "cname(did:%u, name:'%s', cwd:'%s'): failed to add dir",
+                        ntohl(dir->d_did), ret.u_name, getcwdpath());
                     return NULL;
                 }
-                cdir = extenddir( vol, dir, &ret );
             }
+        } /* if/else cnid==1 */
+
+        /* Now chdir to the evaluated dir */
+        if (movecwd( vol, cdir ) < 0 ) { /* 16 */
+            LOG(log_debug, logtype_afpd, "cname(cwd:'%s'): failed to chdir to new subdir '%s': %s",
+                cfrombstr(curdir->d_fullpath), cfrombstr(cdir->d_fullpath), strerror(errno));
+            if (len == 0)
+                return path_from_dir(vol, cdir, &ret);
+            else
+                return NULL;
+        }
+        dir = cdir;
+        ret.m_name[0] = 0;      /* 17, so we later know last token was a dir */
+    } /* while (len) */
 
-        } else {
-            cdir = extenddir( vol, dir, &ret );
-        } /* if (!extend) */
+    if (curdir->d_did == DIRDID_ROOT_PARENT) {
+        afp_errno = AFPERR_DID1;
+        return NULL;
+    }
 
-        if ( cdir == NULL ) {
+    if (ret.m_name[0] == 0) {
+        /* Last part was a dir */
+        ret.u_name = mtoupath(vol, ret.m_name, 0, 1); /* Force "." into a useable static buffer */
+        ret.d_dir = dir;
+    }
 
-            if ( len > 0 || !ret.u_name ) {
-                return NULL;
-            }
+    LOG(log_debug, logtype_afpd, "came('%s') {end: curdir:'%s', path:'%s'}",
+        cfrombstr(dir->d_fullpath),
+        cfrombstr(curdir->d_fullpath),
+        ret.u_name);
 
-        } else {
-            dir = cdir;
-            *path = '\0';
-        }
-    } /* for (;;) */
+    return &ret;
 }
 
 /*
- * Move curdir to dir, with a possible chdir()
+ * @brief chdir() to dir
+ *
+ * @param vol   (r) pointer to struct vol
+ * @param dir   (r) pointer to struct dir
+ *
+ * @returns 0 on success, -1 on error with afp_errno set appropiately
  */
-int movecwd(struct vol *vol, struct dir *dir)
+int movecwd(const struct vol *vol, struct dir *dir)
 {
-    char path[MAXPATHLEN + 1];
-    struct dir  *d;
-    char    *p, *u;
-    int     n;
-    int     ret;
+    int ret;
 
-    if ( dir == curdir ) {
+    AFP_ASSERT(vol);
+    AFP_ASSERT(dir);
+
+    LOG(log_maxdebug, logtype_afpd, "movecwd(curdir:'%s', cwd:'%s')",
+        cfrombstr(curdir->d_fullpath), getcwdpath());
+
+    if ( dir == curdir)
         return( 0 );
-    }
-    if ( dir->d_did == DIRDID_ROOT_PARENT) {
-        afp_errno = AFPERR_DID1; /* AFPERR_PARAM;*/
-        return( -1 );
+    if (dir->d_did == DIRDID_ROOT_PARENT) {
+        curdir = &rootParent;
+        return 0;
     }
 
-    p = path + sizeof(path) - 1;
-    *p = '\0';
-    for ( d = dir; d->d_parent != NULL && d != curdir; d = d->d_parent ) {
-        u = d->d_u_name;
-        if (!u) {
-            /* parent directory is deleted */
-            afp_errno = AFPERR_NOOBJ;
-            return -1;
-        }
-        n = strlen( u );
-        if (p -n -1 < path) {
-            afp_errno = AFPERR_PARAM;
-            return -1;
-        }
-        *--p = '/';
-        p -= n;
-        memcpy( p, u, n );
-    }
-    if ( d != curdir ) {
-        n = strlen( vol->v_path );
-        if (p -n -1 < path) {
-            afp_errno = AFPERR_PARAM;
-            return -1;
-        }
-        *--p = '/';
-        p -= n;
-        memcpy( p, vol->v_path, n );
-    }
-    if ( (ret = lchdir(p )) != 0 ) {
-        LOG(log_debug, logtype_afpd, "movecwd('%s'): ret:%d, %u/%s", p, ret, errno, strerror(errno));
+    LOG(log_debug, logtype_afpd, "movecwd(did:%u, '%s')",
+        ntohl(dir->d_did), cfrombstr(dir->d_fullpath));
 
+    if ((ret = lchdir(cfrombstr(dir->d_fullpath))) != 0 ) {
+        LOG(log_debug, logtype_afpd, "movecwd('%s'): ret: %u, %s",
+            cfrombstr(dir->d_fullpath), ret, strerror(errno));
         if (ret == 1) {
             /* p is a symlink or getcwd failed */
             afp_errno = AFPERR_BADTYPE;
-            vol->v_curdir = curdir = vol->v_dir;
+
             if (chdir(vol->v_path ) < 0) {
-                LOG(log_debug, logtype_afpd, "can't chdir back'%s': %s", vol->v_path, strerror(errno));
+                LOG(log_error, logtype_afpd, "can't chdir back'%s': %s", vol->v_path, strerror(errno));
                 /* XXX what do we do here? */
             }
+            curdir = vol->v_root;
             return -1;
         }
+
         switch (errno) {
         case EACCES:
         case EPERM:
@@ -1621,11 +1288,11 @@ int movecwd(struct vol *vol, struct dir *dir)
             break;
         default:
             afp_errno = AFPERR_NOOBJ;
-
         }
         return( -1 );
     }
-    vol->v_curdir = curdir = dir;
+
+    curdir = dir;
     return( 0 );
 }
 
@@ -1677,30 +1344,15 @@ void setdiroffcnt(struct dir *dir, struct stat *st,  u_int32_t count)
     dir->d_flags &= ~DIRF_CNID;
 }
 
-/* ---------------------
- * is our cached offspring count valid?
- */
-
-static 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);
 }
 
-/* --------------------- */
-static int invisible_dots(const struct vol *vol, const char *name)
-{
-    return vol_inv_dots(vol) && *name  == '.' && strcmp(name, ".") && strcmp(name, "..");
-}
-
 /* ------------------------------
    (".", curdir)
    (name, dir) with curdir:name == dir, from afp_enumerate
@@ -1739,20 +1391,14 @@ int getdirparams(const struct vol *vol,
                           s_path->st.st_dev,
                           s_path->st.st_ino,
                           dir->d_did,
-                          dir->d_parent->d_did,
+                          dir->d_pdid,
                           vol->v_stamp);
                 ad_flush( &ad);
             }
         }
     }
 
-    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;
-    }
+    pdid = dir->d_pdid;
 
     data = buf;
     while ( bitmap != 0 ) {
@@ -1765,7 +1411,7 @@ int getdirparams(const struct vol *vol,
         case DIRPBIT_ATTR :
             if ( isad ) {
                 ad_getattr(&ad, &ashort);
-            } else if (invisible_dots(vol, dir->d_u_name)) {
+            } else if (invisible_dots(vol, cfrombstr(dir->d_u_name))) {
                 ashort = htons(ATTRBIT_INVISIBLE);
             } else
                 ashort = 0;
@@ -1777,6 +1423,8 @@ int getdirparams(const struct vol *vol,
         case DIRPBIT_PDID :
             memcpy( data, &pdid, sizeof( pdid ));
             data += sizeof( pdid );
+            LOG(log_debug, logtype_afpd, "metadata('%s'):     Parent DID: %u",
+                s_path->u_name, ntohl(pdid));
             break;
 
         case DIRPBIT_CDATE :
@@ -1809,7 +1457,7 @@ int getdirparams(const struct vol *vol,
                 memcpy(data + FINDERINFO_FRVIEWOFF, &ashort, sizeof(ashort));
 
                 /* dot files are by default visible */
-                if (invisible_dots(vol, dir->d_u_name)) {
+                if (invisible_dots(vol, cfrombstr(dir->d_u_name))) {
                     ashort = htons(FINDERINFO_INVISIBLE);
                     memcpy(data + FINDERINFO_FRFLAGOFF, &ashort, sizeof(ashort));
                 }
@@ -1833,6 +1481,8 @@ int getdirparams(const struct vol *vol,
         case DIRPBIT_DID :
             memcpy( data, &dir->d_did, sizeof( aint ));
             data += sizeof( aint );
+            LOG(log_debug, logtype_afpd, "metadata('%s'):            DID: %u",
+                s_path->u_name, ntohl(dir->d_did));
             break;
 
         case DIRPBIT_OFFCNT :
@@ -1930,12 +1580,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, pdid, dir->d_m_name, dir->d_did, 0);
+        data = set_name(vol, data, pdid, cfrombstr(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, pdid, dir->d_m_name, dir->d_did, utf8);
+        data = set_name(vol, data, pdid, cfrombstr(dir->d_m_name), dir->d_did, utf8);
     }
     if ( isad ) {
         ad_close_metadata( &ad );
@@ -2020,33 +1670,7 @@ int afp_setdirparams(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_
  *
  * assume path == '\0' eg. it's a directory in canonical form
  */
-
-struct path Cur_Path = {
-    0,
-    "",  /* mac name */
-    ".", /* unix name */
-    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(struct vol *vol,
-                 struct path *path, u_int16_t d_bitmap, char *buf )
+int setdirparams(struct vol *vol, struct path *path, u_int16_t d_bitmap, char *buf )
 {
     struct maccess  ma;
     struct adouble  ad;
@@ -2198,7 +1822,7 @@ int setdirparams(struct vol *vol,
          * to set our name, etc.
          */
         if ( (ad_get_HF_flags( &ad ) & O_CREAT)) {
-            ad_setname(&ad, curdir->d_m_name);
+            ad_setname(&ad, cfrombstr(curdir->d_m_name));
         }
     }
 
@@ -2355,8 +1979,8 @@ setdirparam_done:
         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);
+            if (dir && dir->d_pdid) {
+                ad_setid(&ad, st->st_dev, st->st_ino,  dir->d_did, dir->d_pdid, vol->v_stamp);
             }
         }
         ad_flush( &ad);
@@ -2365,7 +1989,7 @@ setdirparam_done:
 
     if (change_parent_mdate && dir->d_did != DIRDID_ROOT
         && gettimeofday(&tv, NULL) == 0) {
-        if (!movecwd(vol, dir->d_parent)) {
+        if (movecwd(vol, dirlookup(vol, dir->d_pdid)) == 0) {
             newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
             /* be careful with bitmap because now dir is null */
             bitmap = 1<<DIRPBIT_MDATE;
@@ -2460,7 +2084,7 @@ int afp_syncdir(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_,
 
         if ( fsync(dfd) < 0 )
             LOG(log_error, logtype_afpd, "afp_syncdir(%s): %s",
-                vol->ad_path(dir->d_u_name, ADFLAGS_DIR), strerror(errno) );
+                vol->ad_path(cfrombstr(dir->d_u_name), ADFLAGS_DIR), strerror(errno) );
         close(dfd);
     }
 
@@ -2516,8 +2140,10 @@ int afp_createdir(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_
     if (of_stat(s_path) < 0) {
         return AFPERR_MISC;
     }
+
     curdir->offcnt++;
-    if ((dir = adddir( vol, curdir, s_path)) == NULL) {
+
+    if ((dir = dir_add(vol, curdir, s_path, strlen(s_path->u_name))) == NULL) {
         return AFPERR_MISC;
     }
 
@@ -2538,11 +2164,6 @@ int afp_createdir(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_
     ad_close_metadata( &ad);
 
 createdir_done:
-#ifdef HAVE_NFSv4_ACLS
-    /* FIXME: are we really inside the created dir? */
-    addir_inherit_acl(vol);
-#endif
-
     memcpy( rbuf, &dir->d_did, sizeof( u_int32_t ));
     *rbuflen = sizeof( u_int32_t );
     setvoltime(obj, vol );
@@ -2564,9 +2185,7 @@ int renamedir(const struct vol *vol,
               char *newname)
 {
     struct adouble  ad;
-    struct dir      *parent;
-    char                *buf;
-    int         len, err;
+    int             err;
 
     /* existence check moved to afp_moveandrename */
     if ( unix_rename(dirfd, src, -1, dst ) < 0 ) {
@@ -2597,11 +2216,6 @@ int renamedir(const struct vol *vol,
 
     vol->vfs->vfs_renamedir(vol, dirfd, src, dst);
 
-    len = strlen( newname );
-    /* rename() succeeded so we need to update our tree even if we can't open
-     * metadata
-     */
-
     ad_init(&ad, vol->v_adouble, vol->v_ad_options);
 
     if (!ad_open_metadata( dst, ADFLAGS_DIR, 0, &ad)) {
@@ -2610,50 +2224,6 @@ int renamedir(const struct vol *vol,
         ad_close_metadata( &ad);
     }
 
-    dir_hash_del(vol, dir);
-    if (dir->d_m_name == dir->d_u_name)
-        dir->d_u_name = NULL;
-
-    if ((buf = (char *) realloc( dir->d_m_name, len + 1 )) == NULL ) {
-        LOG(log_error, logtype_afpd, "renamedir: realloc mac name: %s", strerror(errno) );
-        /* FIXME : fatal ? */
-        return AFPERR_MISC;
-    }
-    dir->d_m_name = buf;
-    strcpy( dir->d_m_name, newname );
-
-    if (newname == dst) {
-        free(dir->d_u_name);
-        dir->d_u_name = dir->d_m_name;
-    }
-    else {
-        if ((buf = (char *) realloc( dir->d_u_name, strlen(dst) + 1 )) == NULL ) {
-            LOG(log_error, logtype_afpd, "renamedir: realloc unix name: %s", strerror(errno) );
-            return AFPERR_MISC;
-        }
-        dir->d_u_name = buf;
-        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, -1, (char**)&dir->d_m_name_ucs2))
-        dir->d_m_name_ucs2 = NULL;
-
-    if (( parent = dir->d_parent ) == NULL ) {
-        return( AFP_OK );
-    }
-    if ( parent == newparent ) {
-        hash_alloc_insert(vol->v_hash, dir, dir);
-        return( AFP_OK );
-    }
-
-    /* detach from old parent and add to new one. */
-    dirchildremove(parent, dir);
-    dir->d_parent = newparent;
-    dirchildadd(vol, newparent, dir);
     return( AFP_OK );
 }
 
@@ -2668,7 +2238,7 @@ int deletecurdir(struct vol *vol)
     u_int16_t       ashort;
     int err;
 
-    if ( curdir->d_parent == NULL ) {
+    if ( dirlookup(vol, curdir->d_pdid) == NULL ) {
         return( AFPERR_ACCESS );
     }
 
@@ -2709,14 +2279,13 @@ int deletecurdir(struct vol *vol)
         }
     }
 
-    if ( movecwd( vol, curdir->d_parent ) < 0 ) {
+    if ( movecwd(vol, dirlookup(vol, curdir->d_pdid)) < 0 ) {
         err = afp_errno;
         goto delete_done;
     }
 
-    err = netatalk_rmdir_all_errors(-1, fdir->d_u_name);
+    err = netatalk_rmdir_all_errors(-1, cfrombstr(fdir->d_u_name));
     if ( err ==  AFP_OK || err == AFPERR_NOOBJ) {
-        dirchildremove(curdir, fdir);
         cnid_delete(vol->v_cdb, fdir->d_did);
         dir_remove( vol, fdir );
     }
@@ -2744,7 +2313,6 @@ int afp_mapid(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *r
     sfunc = (unsigned char) *ibuf++;
     *rbuflen = 0;
 
-
     if (sfunc >= 3 && sfunc <= 6) {
         if (afp_version < 30) {
             return( AFPERR_PARAM );
@@ -2783,17 +2351,18 @@ int afp_mapid(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *r
             name = NULL;
         }
         break;
-#ifdef HAVE_NFSv4_ACLS
+
     case 5 : /* UUID -> username */
     case 6 : /* UUID -> groupname */
         if ((afp_version < 32) || !(obj->options.flags & OPTION_UUID ))
             return AFPERR_PARAM;
         LOG(log_debug, logtype_afpd, "afp_mapid: valid UUID request");
         uuidtype_t type;
-        len = getnamefromuuid( ibuf, &name, &type);
+        len = getnamefromuuid((unsigned char*) ibuf, &name, &type);
         if (len != 0)       /* its a error code, not len */
             return AFPERR_NOITEM;
-        if (type == UUID_USER) {
+        switch (type) {
+        case UUID_USER:
             if (( pw = getpwnam( name )) == NULL )
                 return( AFPERR_NOITEM );
             LOG(log_debug, logtype_afpd, "afp_mapid: name:%s -> uid:%d", name, pw->pw_uid);
@@ -2804,7 +2373,8 @@ int afp_mapid(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *r
             memcpy( rbuf, &id, sizeof( id ));
             rbuf += sizeof( id );
             *rbuflen = 2 * sizeof( id );
-        } else {        /* type == UUID_GROUP */
+            break;
+        case UUID_GROUP:
             if (( gr = getgrnam( name )) == NULL )
                 return( AFPERR_NOITEM );
             LOG(log_debug, logtype_afpd, "afp_mapid: group:%s -> gid:%d", name, gr->gr_gid);
@@ -2815,9 +2385,15 @@ int afp_mapid(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *r
             memcpy( rbuf, &id, sizeof( id ));
             rbuf += sizeof( id );
             *rbuflen = 2 * sizeof( id );
+            break;
+        case UUID_LOCAL:
+            free(name);
+            return (AFPERR_NOITEM);
+        default:
+            return AFPERR_MISC;
         }
         break;
-#endif
+
     default :
         return( AFPERR_PARAM );
     }
@@ -2871,7 +2447,6 @@ int afp_mapname(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, siz
     case 4 :
         len = (unsigned char) *ibuf++;
         break;
-#ifdef HAVE_NFSv4_ACLS
     case 5 : /* username -> UUID  */
     case 6 : /* groupname -> UUID */
         if ((afp_version < 32) || !(obj->options.flags & OPTION_UUID ))
@@ -2880,7 +2455,6 @@ int afp_mapname(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, siz
         len = ntohs(ulen);
         ibuf += 2;
         break;
-#endif
     default :
         return( AFPERR_PARAM );
     }
@@ -2914,20 +2488,18 @@ int afp_mapname(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, siz
             memcpy( rbuf, &id, sizeof( id ));
             *rbuflen = sizeof( id );
             break;
-#ifdef HAVE_NFSv4_ACLS
         case 5 :        /* username -> UUID */
             LOG(log_debug, logtype_afpd, "afp_mapname: name: %s",ibuf);
-            if (0 != getuuidfromname(ibuf, UUID_USER, rbuf))
+            if (0 != getuuidfromname(ibuf, UUID_USER, (unsigned char *)rbuf))
                 return AFPERR_NOITEM;
             *rbuflen = UUID_BINSIZE;
             break;
         case 6 :        /* groupname -> UUID */
             LOG(log_debug, logtype_afpd, "afp_mapname: name: %s",ibuf);
-            if (0 != getuuidfromname(ibuf, UUID_GROUP, rbuf))
+            if (0 != getuuidfromname(ibuf, UUID_GROUP, (unsigned char *)rbuf))
                 return AFPERR_NOITEM;
             *rbuflen = UUID_BINSIZE;
             break;
-#endif
         }
     }
     return( AFP_OK );
index 5334be5d5610817c7e117f2efd3390c4420f2aff..76267e73b9dac151a088c175af46d8348468dae3 100644 (file)
@@ -1,6 +1,4 @@
 /*
- * $Id: directory.h,v 1.34 2010-03-12 15:16:49 franklahm Exp $
- *
  * Copyright (c) 1990,1991 Regents of The University of Michigan.
  * All Rights Reserved.
  *
 #include "globals.h"
 #include "volume.h"
 
-#define DIRTREE_COLOR_RED    0
-#define DIRTREE_COLOR_BLACK  1
-
 #define DIRF_FSMASK    (3<<0)
 #define DIRF_NOFS      (0<<0)
 #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 DIRF_OFFCNT    (1<<4) /* offsprings count is valid */
+#define DIRF_CNID         (1<<5) /* renumerate id */
+#define DIRF_CACHELOCK (1<<6) /* lock in cache, don't remove in dircache_eviction, for catsearch */
 
 #define AFPDIR_READ    (1<<0)
 
 #define FILDIRBIT_ISDIR        (1 << 7) /* is a directory */
 #define FILDIRBIT_ISFILE       (0)      /* is a file */
 
-/* reserved directory id's */
-#define DIRDID_ROOT_PARENT    htonl(1)  /* parent directory of root */
-#define DIRDID_ROOT           htonl(2)  /* root directory */
-
 /* file/directory ids. what a mess. we scramble things in a vain attempt
  * to get something meaningful */
 #ifndef AFS
 #define CNID(a,b)     (((a)->st_ino & 0x7fffffff) | CNID_FILE(b))
 #endif /* AFS */
 
-
 struct maccess {
     u_char     ma_user;
     u_char     ma_world;
@@ -113,46 +104,42 @@ struct maccess {
 #define        AR_UWRITE       (1<<2)
 #define        AR_UOWN         (1<<7)
 
-extern struct dir       *dirnew (const char *, const char *);
-extern void             dirfreename (struct dir *);
-extern void             dirfree (struct dir *);
-extern struct dir      *dirsearch (const struct vol *, u_int32_t);
-extern struct dir      *dirlookup (struct vol *, u_int32_t);
-extern struct dir       *dirsearch_byname (const struct vol *, struct dir *,char *);
-
-extern struct dir      *adddir (struct vol *, struct dir *, 
-                                               struct path *);
-
-extern int              movecwd (struct vol *, struct dir *);
-extern int              deletecurdir (struct vol *);
-extern struct path      *cname (struct vol *, struct dir *,
-                             char **);
-extern mode_t           mtoumode (struct maccess *);
-extern void             utommode (struct stat *, struct maccess *);
-extern int getdirparams (const struct vol *, u_int16_t, struct path *,
-                                 struct dir *, char *, size_t *);
-extern int setdirparams (struct vol *, struct path *, u_int16_t, char *);
-extern int renamedir(const struct vol *, int, char *, char *, struct dir *,
-                     struct dir *, char *);
-extern int path_error (struct path *, int error);
-
-extern void setdiroffcnt (struct dir *dir, struct stat *st,  u_int32_t count);
-extern int dirreenumerate (struct dir *dir, struct stat *st);
+q_t *invalid_dircache_entries;
 
 typedef int (*dir_loop)(struct dirent *, char *, void *);
 
-extern int  for_each_dirent (const struct vol *, char *, dir_loop , void *);
-
-extern int  check_access (char *name , int mode);
-extern int file_access   (struct path *path, int mode);
-
-extern int netatalk_unlink (const char *name);
+extern void        dir_free_invalid_q(void);
+extern struct dir  *dir_new(const char *mname, const char *uname, const struct vol *,
+                            cnid_t pdid, cnid_t did, bstring fullpath, time_t ctime);
+extern void        dir_free (struct dir *);
+extern struct dir  *dir_add(struct vol *, const struct dir *, struct path *, int);
+extern int         dir_modify(const struct vol *vol, struct dir *dir, cnid_t pdid, cnid_t did,
+                              const char *new_mname, const char *new_uname, bstring pdir_fullpath);
+extern int         dir_remove(const struct vol *vol, struct dir *dir);
+extern struct dir  *dirlookup (const struct vol *, cnid_t);
+extern int         movecwd (const struct vol *, struct dir *);
+extern struct path *cname (struct vol *, struct dir *, char **);
+
+extern int         deletecurdir (struct vol *);
+extern mode_t      mtoumode (struct maccess *);
+extern void        utommode (struct stat *, struct maccess *);
+extern int         getdirparams (const struct vol *, u_int16_t, struct path *,
+                                 struct dir *, char *, size_t *);
 
-extern int caseenumerate (const struct vol *, struct path *, struct dir *);
+extern int         setdirparams(struct vol *, struct path *, u_int16_t, char *);
+extern int         renamedir(const struct vol *, int, char *, char *, struct dir *,
+                             struct dir *, char *);
+extern int         path_error(struct path *, int error);
+extern void        setdiroffcnt(struct dir *dir, struct stat *st,  u_int32_t count);
+extern int         dirreenumerate(struct dir *dir, struct stat *st);
+extern int         for_each_dirent(const struct vol *, char *, dir_loop , void *);
+extern int         check_access(char *name , int mode);
+extern int         file_access(struct path *path, int mode);
+extern int         netatalk_unlink (const char *name);
+extern int         caseenumerate (const struct vol *, struct path *, struct dir *);
 
-extern hash_t *dirhash (void);
 /* from enumerate.c */
-extern char *check_dirent (const struct vol *, char *);
+extern char        *check_dirent (const struct vol *, char *);
 
 /* FP functions */
 int afp_createdir (AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf,  size_t *rbuflen);
index c06ef20300f3f296e4e2b0d41b2b40404a4538b0..79869dbd0d84fc3256ca7ec8999b02a323f1950f 100644 (file)
@@ -1,6 +1,4 @@
 /*
- * $Id: enumerate.c,v 1.49 2010-02-10 14:05:37 franklahm Exp $
- *
  * Copyright (c) 1990,1993 Regents of The University of Michigan.
  * All Rights Reserved.  See COPYRIGHT.
  */
 #include <atalk/adouble.h>
 #include <atalk/vfs.h>
 #include <atalk/cnid.h>
+#include <atalk/util.h>
+#include <atalk/bstrlib.h>
+#include <atalk/bstradd.h>
+
 #include "desktop.h"
 #include "directory.h"
+#include "dircache.h"
 #include "volume.h"
 #include "globals.h"
 #include "file.h"
@@ -266,8 +269,8 @@ static int enumerate(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_,
         return path_error(o_path, AFPERR_NODIR );
     }
 
-    LOG(log_debug, logtype_afpd, "enumerate(vid:%u, did:%u, name:'%s', f/d:%04x/%04x, rc:%u, i:%u, max:%u)",
-        ntohs(vid), ntohl(did), o_path->u_name, fbitmap, dbitmap, reqcnt, sindex, maxsz);
+    LOG(log_debug, logtype_afpd, "enumerate(\"%s/%s\", f/d:%04x/%04x, rc:%u, i:%u, max:%u)",
+        getcwdpath(), o_path->u_name, fbitmap, dbitmap, reqcnt, sindex, maxsz);
 
     data = rbuf + 3 * sizeof( u_int16_t );
     sz = 3 * sizeof( u_int16_t );      /* fbitmap, dbitmap, reqcount */
@@ -370,19 +373,22 @@ static int enumerate(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_,
             if ( dbitmap == 0 ) {
                 continue;
             }
-            dir = dirsearch_byname(vol, curdir, s_path.u_name);
-            if (!dir && NULL == (dir = adddir( vol, curdir, &s_path) ) ) {
+            int len = strlen(s_path.u_name);
+            if ((dir = dircache_search_by_name(vol, curdir, s_path.u_name, len, s_path.st.st_ctime)) == NULL) {
+                if ((dir = dir_add(vol, curdir, &s_path, len)) == NULL) {
+                    LOG(log_error, logtype_afpd, "enumerate(vid:%u, did:%u, name:'%s'): error adding dir: '%s'",
+                        ntohs(vid), ntohl(did), o_path->u_name, s_path.u_name);
                     return AFPERR_MISC;
                 }
-            if (AFP_OK != ( ret = getdirparams(vol, dbitmap, &s_path, dir,
-                                     data + header , &esz ))) {
-                return( ret );
             }
+            if ((ret = getdirparams(vol, dbitmap, &s_path, dir, data + header , &esz)) != AFP_OK)
+                return( ret );
 
         } else {
             if ( fbitmap == 0 ) {
                 continue;
             }
+            /* files are added to the dircache in getfilparams() -> getmetadata() */
             if (AFP_OK != ( ret = getfilparams(vol, fbitmap, &s_path, curdir, 
                                      data + header , &esz )) ) {
                 return( ret );
index b10330c8aebaeef678a449f46e432988c43b841a..d3bf5600b36e1f68c91a15d3b1fadfe2eaa73f71 100644 (file)
@@ -1,6 +1,4 @@
 /*
- * $Id: file.c,v 1.141 2010-03-12 15:16:49 franklahm Exp $
- *
  * Copyright (c) 1990,1993 Regents of The University of Michigan.
  * All Rights Reserved.  See COPYRIGHT.
  */
@@ -41,6 +39,7 @@ char *strchr (), *strrchr ();
 #include <atalk/unix.h>
 
 #include "directory.h"
+#include "dircache.h"
 #include "desktop.h"
 #include "volume.h"
 #include "fork.h"
@@ -201,9 +200,27 @@ char *set_name(const struct vol *vol, char *data, cnid_t pid, char *name, cnid_t
                                  (1 << FILPBIT_FNUM) |\
                                  (1 << FILPBIT_UNIXPR)))
 
-/* -------------------------- */
-u_int32_t get_id(struct vol *vol, struct adouble *adp,  const struct stat *st,
-                 const cnid_t did, char *upath, const int len) 
+/*!
+ * @brief Get CNID for did/upath args both from database and adouble file
+ *
+ * 1. Get the objects CNID as stored in its adouble file
+ * 2. Get the objects CNID from the database
+ * 3. If there's a problem with a "dbd" database, fallback to "tdb" in memory
+ * 4. In case 2 and 3 differ, store 3 in the adouble file
+ *
+ * @param vol    (rw) volume
+ * @param adp    (rw) adouble struct of object upath, might be NULL
+ * @param st     (r) stat of upath, must NOT be NULL
+ * @param did    (r) parent CNID of upath
+ * @param upath  (r) name of object
+ * @param len    (r) strlen of upath
+ */
+uint32_t get_id(struct vol *vol,
+                struct adouble *adp, 
+                const struct stat *st,
+                const cnid_t did,
+                const char *upath,
+                const int len) 
 {
     static int first = 1;       /* mark if this func is called the first time */
     u_int32_t adcnid;
@@ -213,9 +230,9 @@ restart:
     if (vol->v_cdb != NULL) {
         /* prime aint with what we think is the cnid, set did to zero for
            catching moved files */
-        adcnid = ad_getid(adp, st->st_dev, st->st_ino, 0, vol->v_stamp);
+        adcnid = ad_getid(adp, st->st_dev, st->st_ino, 0, vol->v_stamp); /* (1) */
 
-           dbcnid = cnid_add(vol->v_cdb, st, did, upath, len, adcnid);
+           dbcnid = cnid_add(vol->v_cdb, st, did, upath, len, adcnid); /* (2) */
            /* Throw errors if cnid_add fails. */
            if (dbcnid == CNID_INVALID) {
             switch (errno) {
@@ -233,7 +250,7 @@ restart:
                 /* we have to do it here for "dbd" because it uses "lazy opening" */
                 /* In order to not end in a loop somehow with goto restart below  */
                 /*  */
-                if (first && (strcmp(vol->v_cnidscheme, "dbd") == 0)) {
+                if (first && (strcmp(vol->v_cnidscheme, "dbd") == 0)) { /* (3) */
                     cnid_close(vol->v_cdb);
                     free(vol->v_cnidscheme);
                     vol->v_cnidscheme = strdup("tdb");
@@ -267,9 +284,10 @@ restart:
                 goto exit;
             }
         }
-        else if (adp && (adcnid != dbcnid)) {
+        else if (adp && (adcnid != dbcnid)) { /* 4 */
             /* Update the ressource fork. For a folder adp is always null */
-            LOG(log_debug, logtype_afpd, "get_id: calling ad_setid. adcnid: %u, dbcnid: %u", htonl(adcnid), htonl(dbcnid));
+            LOG(log_debug, logtype_afpd, "get_id(%s/%s): calling ad_setid(old: %u, new: %u)",
+                getcwdpath(), upath, htonl(adcnid), htonl(dbcnid));
             if (ad_setid(adp, st->st_dev, st->st_ino, dbcnid, did, vol->v_stamp)) {
                 ad_flush(adp);
             }
@@ -298,24 +316,50 @@ int getmetadata(struct vol *vol,
     struct stat         *st;
     struct maccess     ma;
 
-#ifdef DEBUG
-    LOG(log_debug9, logtype_afpd, "begin getmetadata:");
-#endif /* DEBUG */
-
     upath = path->u_name;
     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 
+        if (!path->id) {
+            struct dir *cachedfile;
+            int len = strlen(upath);
+            if ((cachedfile = dircache_search_by_name(vol, dir, upath, len, st->st_ctime)) != NULL)
+                id = cachedfile->d_did;
+            else {
+                id = get_id(vol, adp, st, dir->d_did, upath, len);
+
+                /* Add it to the cache */
+                LOG(log_debug, logtype_afpd, "getmetadata: caching: did:%u, \"%s\", cnid:%u",
+                    ntohl(dir->d_did), upath, ntohl(id));
+
+                /* Get macname from unixname first */
+                if (path->m_name == NULL) {
+                    if ((path->m_name = utompath(vol, upath, id, utf8_encoding())) == NULL) {
+                        LOG(log_error, logtype_afpd, "getmetadata: utompath error");
+                        exit(EXITERR_SYS);
+                    }
+                }
+                
+                if ((cachedfile = dir_new(path->m_name, upath, vol, dir->d_did, id, NULL, st->st_ctime)) == NULL) {
+                    LOG(log_error, logtype_afpd, "getmetadata: error from dir_new");
+                    exit(EXITERR_SYS);
+                }
+
+                if ((dircache_add(cachedfile)) != 0) {
+                    LOG(log_error, logtype_afpd, "getmetadata: fatal dircache error");
+                    exit(EXITERR_SYS);
+                }
+            }
+        } else {
             id = path->id;
+        }
+
         if (id == CNID_INVALID)
             return afp_errno;
+
         if (!path->m_name) {
             path->m_name = utompath(vol, upath, id, utf8_encoding());
         }
@@ -348,11 +392,15 @@ int getmetadata(struct vol *vol,
 #endif
             memcpy(data, &ashort, sizeof( ashort ));
             data += sizeof( ashort );
+            LOG(log_debug, logtype_afpd, "metadata('%s'): AFP Attributes: %04x",
+                path->u_name, ntohs(ashort));
             break;
 
         case FILPBIT_PDID :
             memcpy(data, &dir->d_did, sizeof( u_int32_t ));
             data += sizeof( u_int32_t );
+            LOG(log_debug, logtype_afpd, "metadata('%s'):     Parent DID: %u",
+                path->u_name, ntohl(dir->d_did));
             break;
 
         case FILPBIT_CDATE :
@@ -399,6 +447,8 @@ int getmetadata(struct vol *vol,
         case FILPBIT_FNUM :
             memcpy(data, &id, sizeof( id ));
             data += sizeof( id );
+            LOG(log_debug, logtype_afpd, "metadata('%s'):           CNID: %u",
+                path->u_name, ntohl(id));
             break;
 
         case FILPBIT_DFLEN :
@@ -563,10 +613,6 @@ int getfilparams(struct vol *vol,
     int                 opened = 0;
     int rc;    
 
-#ifdef DEBUG
-    LOG(log_debug9, logtype_default, "begin getfilparams:");
-#endif /* DEBUG */
-
     opened = PARAM_NEED_ADP(bitmap);
     adp = NULL;
 
@@ -597,9 +643,6 @@ int getfilparams(struct vol *vol,
     if ( adp ) {
         ad_close_metadata( adp);
     }
-#ifdef DEBUG
-    LOG(log_debug9, logtype_afpd, "end getfilparams:");
-#endif /* DEBUG */
 
     return( rc );
 }
@@ -1945,6 +1988,10 @@ int afp_deleteid(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_
     }
 
     if (NULL == ( dir = dirlookup( vol, id )) ) {
+        if (afp_errno == AFPERR_NOOBJ) {
+            err = AFPERR_NOOBJ;
+            goto delete;
+        }
         return( AFPERR_PARAM );
     }
 
@@ -1968,6 +2015,7 @@ int afp_deleteid(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_
     else if (S_ISDIR(st.st_mode)) /* directories are bad */
         return AFPERR_BADTYPE;
 
+delete:
     if (cnid_delete(vol->v_cdb, fileid)) {
         switch (errno) {
         case EROFS:
@@ -2188,12 +2236,11 @@ int afp_exchangefiles(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U
     /* 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_cdb, sid);
-    }
-    if (did) {
-       cnid_delete(vol->v_cdb, did);
-    }
+    if (sid)
+        cnid_delete(vol->v_cdb, sid);
+    if (did)
+        cnid_delete(vol->v_cdb, did);
+
     if ((did && ( (crossdev && lstat( upath, &srcst) < 0) || 
                 cnid_update(vol->v_cdb, did, &srcst, curdir->d_did,upath, dlen) < 0))
        ||
@@ -2287,5 +2334,11 @@ err_exchangefile:
        ad_close(addp, ADFLAGS_HF);
     }
 
+    struct dir *cached;
+    if ((cached = dircache_search_by_did(vol, sid)) != NULL)
+        (void)dir_remove(vol, cached);
+    if ((cached = dircache_search_by_did(vol, did)) != NULL)
+        (void)dir_remove(vol, cached);
+
     return err;
 }
index 6cf4ae22f8184d15319dddb26d6d25b75bf5c832..483f6be61a4d264fe74910a6f8c66a22a3b29f35 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: file.h,v 1.26 2010-03-12 15:16:49 franklahm Exp $
+ * $Id: file.h,v 1.26 2010/03/12 15:16:49 franklahm Exp $
  *
  * Copyright (c) 1990,1991 Regents of The University of Michigan.
  * All Rights Reserved.
@@ -127,8 +127,12 @@ extern void *get_finderinfo (const struct vol *, const char *, struct adouble *,
 extern size_t mtoUTF8   (const struct vol *, const char *, size_t , char *, size_t );
 extern int  copy_path_name (const struct vol *, char *, char *i);
 
-extern u_int32_t get_id  (struct vol *, struct adouble *, const struct stat *,
-                                const cnid_t , char *, const int );
+extern uint32_t get_id  (struct vol *,
+                         struct adouble *,
+                         const struct stat *,
+                         cnid_t ,
+                         const char *,
+                         int );
 
 /* FP functions */
 int afp_exchangefiles (AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf,  size_t *rbuflen);
index 2a862abeea7ecd2a6556fe267da5f41f9e29a70b..be7056a796ab9c0729d1b8d4307c54ca5f3818d8 100644 (file)
@@ -37,9 +37,12 @@ char *strchr (), *strrchr ();
 #include <atalk/cnid.h>
 #include <atalk/logger.h>
 #include <atalk/unix.h>
+#include <atalk/bstrlib.h>
+#include <atalk/bstradd.h>
 #include <atalk/acl.h>
 
 #include "directory.h"
+#include "dircache.h"
 #include "desktop.h"
 #include "volume.h"
 #include "fork.h"
@@ -51,22 +54,22 @@ char *strchr (), *strrchr ();
 #ifdef DROPKLUDGE
 int matchfile2dirperms(
 /* Since it's kinda' big; I decided against an
-inline function */
-    char       *upath,
+   inline function */
+    char    *upath,
     struct vol  *vol,
-    int                did)
+    int     did)
 /* The below code changes the way file ownership is determined in the name of
-fixing dropboxes.  It has known security problem.  See the netatalk FAQ for
-more information */
+   fixing dropboxes.  It has known security problem.  See the netatalk FAQ for
+   more information */
 {
-    struct stat        st, sb;
-    struct dir *dir;
-    char       *adpath;
+    struct stat st, sb;
+    struct dir  *dir;
+    char    *adpath;
     uid_t       uid;
     int         ret = AFP_OK;
 #ifdef DEBUG
     LOG(log_debug9, logtype_afpd, "begin matchfile2dirperms:");
-#endif 
+#endif
 
     if (stat(upath, &st ) < 0) {
         LOG(log_error, logtype_afpd, "Could not stat %s: %s", upath, strerror(errno));
@@ -118,7 +121,7 @@ more information */
                     adpath, strerror(errno));
                 ret = AFPERR_ACCESS;
             }
-            seteuid(uid); 
+            seteuid(uid);
         }
     } /* end else if stat success */
 
@@ -131,13 +134,13 @@ more information */
 
 int afp_getfildirparams(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
 {
-    struct stat                *st;
-    struct vol         *vol;
-    struct dir         *dir;
+    struct stat     *st;
+    struct vol      *vol;
+    struct dir      *dir;
     u_int32_t           did;
-    int                        ret;
-    size_t             buflen;
-    u_int16_t          fbitmap, dbitmap, vid;
+    int         ret;
+    size_t      buflen;
+    u_int16_t       fbitmap, dbitmap, vid;
     struct path         *s_path;
 
     *rbuflen = 0;
@@ -148,7 +151,7 @@ int afp_getfildirparams(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *r
     if (NULL == ( vol = getvolbyvid( vid )) ) {
         /* was AFPERR_PARAM but it helps OS 10.3 when a volume has been removed
          * from the list.
-         */ 
+         */
         return( AFPERR_ACCESS );
     }
 
@@ -167,11 +170,12 @@ int afp_getfildirparams(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *r
     ibuf += sizeof( dbitmap );
 
     if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
-        return get_afp_errno(AFPERR_NOOBJ); 
+        return get_afp_errno(AFPERR_NOOBJ);
     }
 
-    LOG(log_debug, logtype_afpd, "getfildirparams(vid:%u, did:%u, name:'%s', f/d:%04x/%04x) {cwd: %s}",
-        ntohs(vid), ntohl(dir->d_did), s_path->u_name, fbitmap, dbitmap, getcwdpath());
+    LOG(log_debug, logtype_afpd, "getfildirparams(vid:%u, did:%u, f/d:%04x/%04x) {cwdid:%u, cwd: %s, name:'%s'}",
+        ntohs(vid), ntohl(dir->d_did), fbitmap, dbitmap,
+        ntohl(curdir->d_did), cfrombstr(curdir->d_fullpath), s_path->u_name);
 
     st   = &s_path->st;
     if (!s_path->st_valid) {
@@ -183,7 +187,9 @@ int afp_getfildirparams(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *r
         of_statdir(vol, s_path);
     }
     if ( s_path->st_errno != 0 ) {
-        return( AFPERR_NOOBJ );
+        if (afp_errno != AFPERR_ACCESS) {
+            return( AFPERR_NOOBJ );
+        }
     }
 
 
@@ -191,19 +197,19 @@ int afp_getfildirparams(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *r
     if (S_ISDIR(st->st_mode)) {
         if (dbitmap) {
             dir = s_path->d_dir;
-            if (!dir) 
+            if (!dir)
                 return AFPERR_NOOBJ;
 
             ret = getdirparams(vol, dbitmap, s_path, dir,
-                                 rbuf + 3 * sizeof( u_int16_t ), &buflen );
+                               rbuf + 3 * sizeof( u_int16_t ), &buflen );
             if (ret != AFP_OK )
                 return( ret );
         }
         /* this is a directory */
         *(rbuf + 2 * sizeof( u_int16_t )) = (char) FILDIRBIT_ISDIR;
     } else {
-        if (fbitmap && AFP_OK != (ret = getfilparams(vol, fbitmap, s_path, curdir, 
-                                            rbuf + 3 * sizeof( u_int16_t ), &buflen )) ) {
+        if (fbitmap && AFP_OK != (ret = getfilparams(vol, fbitmap, s_path, curdir,
+                                                     rbuf + 3 * sizeof( u_int16_t ), &buflen )) ) {
             return( ret );
         }
         /* this is a file */
@@ -223,12 +229,12 @@ int afp_getfildirparams(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *r
 
 int afp_setfildirparams(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
 {
-    struct stat        *st;
-    struct vol *vol;
-    struct dir *dir;
+    struct stat *st;
+    struct vol  *vol;
+    struct dir  *dir;
     struct path *path;
-    u_int16_t  vid, bitmap;
-    int                did, rc;
+    u_int16_t   vid, bitmap;
+    int     did, rc;
 
     *rbuflen = 0;
     ibuf += 2;
@@ -246,7 +252,7 @@ int afp_setfildirparams(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf
     ibuf += sizeof( did);
 
     if (NULL == ( dir = dirlookup( vol, did )) ) {
-       return afp_errno;    
+        return afp_errno;
     }
 
     memcpy( &bitmap, ibuf, sizeof( bitmap ));
@@ -254,7 +260,7 @@ int afp_setfildirparams(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf
     ibuf += sizeof( bitmap );
 
     if (NULL == ( path = cname( vol, dir, &ibuf ))) {
-        return get_afp_errno(AFPERR_NOOBJ); 
+        return get_afp_errno(AFPERR_NOOBJ);
     }
 
     st   = &path->st;
@@ -266,7 +272,8 @@ int afp_setfildirparams(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf
     }
 
     if ( path->st_errno != 0 ) {
-        return( AFPERR_NOOBJ );
+        if (afp_errno != AFPERR_ACCESS)
+            return( AFPERR_NOOBJ );
     }
     /*
      * If ibuf is odd, make it even.
@@ -287,7 +294,7 @@ int afp_setfildirparams(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf
     return( rc );
 }
 
-/* -------------------------------------------- 
+/* --------------------------------------------
    Factorise some checks on a pathname
 */
 int check_name(const struct vol *vol, char *name)
@@ -362,14 +369,13 @@ static int moveandrename(const struct vol *vol,
         }
     } else {
         id = sdir->d_did; /* we already have the CNID */
-        p = ctoupath( vol, sdir->d_parent, oldname );
+        p = ctoupath( vol, dirlookup(vol, sdir->d_pdid), oldname );
         if (!p) {
             return AFPERR_PARAM;
         }
         adflags = ADFLAGS_DIR;
     }
 
-
     /*
      * p now points to either
      *   a) full pathname of the source fs object (if renameat is not available)
@@ -410,13 +416,13 @@ static int moveandrename(const struct vol *vol,
         goto exit;
     }
     path.u_name = upath;
-    st = &path.st;    
+    st = &path.st;
     if (0 != (rc = check_name(vol, upath))) {
         goto exit;
     }
 
     /* source == destination. we just silently accept this. */
-    if ((!isdir && curdir == sdir) || (isdir && curdir == sdir->d_parent)) {
+    if ((!isdir && curdir == sdir) || (isdir && curdir->d_did == sdir->d_pdid)) {
         if (strcmp(oldname, newname) == 0) {
             rc = AFP_OK;
             goto exit;
@@ -454,6 +460,14 @@ static int moveandrename(const struct vol *vol,
             rc = AFPERR_MISC;
             goto exit;
         }
+
+        /* Remove it from the cache */
+        struct dir *cacheddir = dircache_search_by_did(vol, id);
+        if (cacheddir) {
+            LOG(log_warning, logtype_afpd,"Still cached: \"%s/%s\"", getcwdpath(), upath);
+            (void)dir_remove(vol, cacheddir);
+        }
+
         /* fix up the catalog entry */
         cnid_update(vol->v_cdb, id, st, curdir->d_did, upath, strlen(upath));
     }
@@ -467,13 +481,13 @@ exit:
 /* -------------------------------------------- */
 int afp_rename(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
 {
-    struct vol *vol;
-    struct dir *sdir;
+    struct vol  *vol;
+    struct dir  *sdir;
     char        *oldname, *newname;
     struct path *path;
-    u_int32_t  did;
+    u_int32_t   did;
     int         plen;
-    u_int16_t  vid;
+    u_int16_t   vid;
     int         isdir = 0;
     int         rc;
 
@@ -492,12 +506,12 @@ int afp_rename(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size
     memcpy( &did, ibuf, sizeof( did ));
     ibuf += sizeof( did );
     if (NULL == ( sdir = dirlookup( vol, did )) ) {
-       return afp_errno;    
+        return afp_errno;
     }
 
     /* source pathname */
     if (NULL == ( path = cname( vol, sdir, &ibuf )) ) {
-        return get_afp_errno(AFPERR_NOOBJ); 
+        return get_afp_errno(AFPERR_NOOBJ);
     }
 
     sdir = curdir;
@@ -512,14 +526,14 @@ int afp_rename(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size
         }
     }
     else {
-        if ( sdir->d_parent == NULL ) { /* root directory */
+        if ( sdir->d_did == DIRDID_ROOT ) { /* root directory */
             return( AFPERR_NORENAME );
         }
         /* move to destination dir */
-        if ( movecwd( vol, sdir->d_parent ) < 0 ) {
+        if ( movecwd( vol, dirlookup(vol, sdir->d_pdid) ) < 0 ) {
             return afp_errno;
         }
-        strcpy(oldname, sdir->d_m_name);
+        memcpy(oldname, cfrombstr(sdir->d_m_name), blength(sdir->d_m_name) +1);
     }
 
     /* another place where we know about the path type */
@@ -542,12 +556,12 @@ int afp_rename(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size
 /* ------------------------------- */
 int afp_delete(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
 {
-    struct vol         *vol;
-    struct dir         *dir;
+    struct vol      *vol;
+    struct dir      *dir;
     struct path         *s_path;
-    char               *upath;
-    int                        did, rc;
-    u_int16_t          vid;
+    char        *upath;
+    int         did, rc;
+    u_int16_t       vid;
 
     *rbuflen = 0;
     ibuf += 2;
@@ -563,22 +577,21 @@ int afp_delete(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size
 
     memcpy( &did, ibuf, sizeof( did ));
     ibuf += sizeof( int );
+
     if (NULL == ( dir = dirlookup( vol, did )) ) {
-       return afp_errno;    
+        return afp_errno;
     }
 
     if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
-        return get_afp_errno(AFPERR_NOOBJ); 
+        return get_afp_errno(AFPERR_NOOBJ);
     }
 
     upath = s_path->u_name;
     if ( path_isadir( s_path) ) {
-       if (*s_path->m_name != '\0') {
-           rc = AFPERR_ACCESS;
-       }
-       else {
+        if (*s_path->m_name != '\0' || curdir->d_did == DIRDID_ROOT)
+            rc = AFPERR_ACCESS;
+        else
             rc = deletecurdir( vol);
-        }
     } else if (of_findname(s_path)) {
         rc = AFPERR_BUSY;
     } else {
@@ -591,10 +604,16 @@ int afp_delete(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size
         }
         else {
             rc = deletefile(vol, -1, upath, 1);
+
+            struct dir *cachedfile;
+            if ((cachedfile = dircache_search_by_name(vol, dir, upath, strlen(upath), s_path->st.st_ctime))) {
+                dircache_remove(vol, cachedfile, DIRCACHE | DIDNAME_INDEX | QUEUE_INDEX);
+                dir_free(cachedfile);
+            }
         }
     }
     if ( rc == AFP_OK ) {
-       curdir->offcnt--;
+        curdir->offcnt--;
         setvoltime(obj, vol );
     }
 
@@ -603,66 +622,51 @@ int afp_delete(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size
 /* ------------------------ */
 char *absupath(const struct vol *vol, struct dir *dir, char *u)
 {
-    struct dir *d;
-    static char        path[ MAXPATHLEN + 1];
-    char       *p;
-    int                len;
+    static char pathbuf[MAXPATHLEN + 1];
+    bstring path;
 
-    if (u == NULL)
+    if (u == NULL || dir == NULL || vol == NULL)
         return NULL;
-        
-    p = path + sizeof( path ) - 1;
-    *p = '\0';
-    len = strlen( u );
-    p -= 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 );
-        if (p -len -1 < path) {
-            /* FIXME 
-               rather rare so LOG error and/or client message ?
-            */
-            return NULL;
-        }
-        *--p = '/';
-        p -= len;
-        memcpy( p, u, len );
-    }
-    len = strlen( vol->v_path );
-    if (p -len -1 < path) {
+
+    if ((path = bstrcpy(dir->d_fullpath)) == NULL)
+        return NULL;
+    if (bcatcstr(path, "/") != BSTR_OK)
+        return NULL;
+    if (bcatcstr(path, u) != BSTR_OK)
+        return NULL;
+    if (path->slen > MAXPATHLEN)
         return NULL;
-    }
-    *--p = '/';
-    p -= len;
-    memcpy( p, vol->v_path, len );
 
-    return( p );
+    LOG(log_debug, logtype_afpd, "absupath: %s", cfrombstr(path));
+
+    strncpy(pathbuf, cfrombstr(path), blength(path) + 1);
+    bdestroy(path);
+
+    return(pathbuf);
 }
 
-/* ------------------------
- * FIXME dir could be NULL
-*/
 char *ctoupath(const struct vol *vol, struct dir *dir, char *name)
 {
+    if (vol == NULL || dir == NULL || name == NULL)
+        return NULL;
     return absupath(vol, dir, mtoupath(vol, name, dir->d_did, utf8_encoding()));
 }
 
 /* ------------------------- */
 int afp_moveandrename(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
 {
-    struct vol *vol;
-    struct dir *sdir, *ddir;
+    struct vol  *vol;
+    struct dir  *sdir, *ddir;
     int         isdir;
-    char       *oldname, *newname;
+    char    *oldname, *newname;
     struct path *path;
-    int                did;
-    int                pdid;
+    int     did;
+    int     pdid;
     int         plen;
-    u_int16_t  vid;
+    u_int16_t   vid;
     int         rc;
 #ifdef DROPKLUDGE
-    int                retvalue;
+    int     retvalue;
 #endif /* DROPKLUDGE */
     int     sdir_fd = -1;
 
@@ -691,13 +695,13 @@ int afp_moveandrename(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U
 
     /* source pathname */
     if (NULL == ( path = cname( vol, sdir, &ibuf )) ) {
-        return get_afp_errno(AFPERR_NOOBJ); 
+        return get_afp_errno(AFPERR_NOOBJ);
     }
 
     sdir = curdir;
     newname = obj->newtmp;
     oldname = obj->oldtmp;
-    
+
     isdir = path_isadir(path);
     if ( *path->m_name != '\0' ) {
         if (isdir) {
@@ -705,7 +709,7 @@ int afp_moveandrename(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U
         }
         strcpy(oldname, path->m_name); /* an extra copy for of_rename */
     } else {
-        strcpy(oldname, sdir->d_m_name);
+        memcpy(oldname, cfrombstr(sdir->d_m_name), blength(sdir->d_m_name) + 1);
     }
 
 #ifdef HAVE_RENAMEAT
@@ -739,11 +743,13 @@ int afp_moveandrename(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U
     }
 
     /* This does the work */
+    LOG(log_debug, logtype_afpd, "afp_move(oldname:'%s', newname:'%s', isdir:%u)",
+        oldname, newname, isdir);
     rc = moveandrename(vol, sdir, sdir_fd, oldname, newname, isdir);
 
     if ( rc == AFP_OK ) {
         char *upath = mtoupath(vol, newname, pdid, utf8_encoding());
-        
+
         if (NULL == upath) {
             rc = AFPERR_PARAM;
             goto exit;
@@ -786,8 +792,8 @@ int veto_file(const char*veto_str, const char*path)
  * otherwise, 0 is returned.
  */
 {
-    int i;     /* index to veto_str */
-    int j;     /* index to path */
+    int i;  /* index to veto_str */
+    int j;  /* index to path */
 
     if ((veto_str == NULL) || (path == NULL))
         return 0;
@@ -802,7 +808,7 @@ int veto_file(const char*veto_str, const char*path)
         } else {
             if (veto_str[i] != path[j]) {
                 while ((veto_str[i] != '/')
-                        && (veto_str[i] != '\0'))
+                       && (veto_str[i] != '\0'))
                     i++;
                 j = 0;
                 continue;
index e8c019e1093cf8723e839daa62fc8a8b9fa493be..f4d0d04cbee4c9f4ee93952c35469010e8f0b688 100644 (file)
@@ -73,7 +73,7 @@ static int getforkparams(struct ofork *ofork, u_int16_t bitmap, char *buf, size_
     }
 
     vol = ofork->of_vol;
-    dir = ofork->of_dir;
+    dir = dirlookup(vol, ofork->of_did);
 
     if (NULL == (path.u_name = mtoupath(vol, of_name(ofork), dir->d_did, utf8_encoding()))) {
         return( AFPERR_MISC );
index 5a42afc71dc202492c3ca875876b913a5f944a86..ab75f1f7930856b8e03a206299d880ce97b6e62c 100644 (file)
@@ -1,6 +1,4 @@
 /*
- * $Id: fork.h,v 1.18 2010-03-12 15:16:49 franklahm Exp $
- *
  * Copyright (c) 1990,1993 Regents of The University of Michigan.
  * All Rights Reserved.  See COPYRIGHT.
  */
 #include "directory.h"
 
 struct file_key {
-    dev_t              dev;
-    ino_t              inode;
+    dev_t       dev;
+    ino_t       inode;
 };
 
 struct ofork {
     struct file_key     key;
-    struct adouble     *of_ad;
+    struct adouble      *of_ad;
     struct vol          *of_vol;
-    struct dir         *of_dir;
-
-    u_int16_t           of_refnum;
+    cnid_t              of_did;
+    uint16_t            of_refnum;
     int                 of_flags;
-
     struct ofork        **prevp, *next;
-    struct ofork        *of_d_prev, *of_d_next;
+//    struct ofork        *of_d_prev, *of_d_next;
 };
 
-#define OPENFORK_DATA  (0)
-#define OPENFORK_RSCS  (1<<7)
+#define OPENFORK_DATA   (0)
+#define OPENFORK_RSCS   (1<<7)
 
-#define OPENACC_RD     (1<<0)
-#define OPENACC_WR     (1<<1)
-#define OPENACC_DRD    (1<<4)
-#define OPENACC_DWR    (1<<5)
+#define OPENACC_RD  (1<<0)
+#define OPENACC_WR  (1<<1)
+#define OPENACC_DRD (1<<4)
+#define OPENACC_DWR (1<<5)
 
 /* ofork.of_flags bits */
-#define AFPFORK_OPEN   (1<<0)
-#define AFPFORK_RSRC   (1<<1)
-#define AFPFORK_DATA   (1<<2)
+#define AFPFORK_OPEN    (1<<0)
+#define AFPFORK_RSRC    (1<<1)
+#define AFPFORK_DATA    (1<<2)
 #define AFPFORK_DIRTY   (1<<3)
 #define AFPFORK_ACCRD   (1<<4)
 #define AFPFORK_ACCWR   (1<<5)
index 40af2fe1d756b9ea92bb620462ef8d80b4f679fb..4b6cea4ae0ca80cfa41a69935531a68af66c9cce 100644 (file)
@@ -35,6 +35,8 @@
 #define OPTION_NOSLP         (1 << 5)
 #define OPTION_ANNOUNCESSH   (1 << 6)
 #define OPTION_UUID          (1 << 7)
+#define OPTION_ACL2MACCESS   (1 << 8)
+#define OPTION_NOZEROCONF    (1 << 9)
 
 #ifdef FORCE_UIDGID
 /* set up a structure for this */
@@ -54,7 +56,9 @@ struct afp_volume_name {
 };
 
 struct afp_options {
-    int connections, transports, tickleval, timeout, server_notif, flags;
+    int connections, transports, tickleval, timeout, server_notif, flags, dircachesize;
+    int sleep;                  /* Maximum time allowed to sleep (in tickles) */
+    int disconnected;           /* Maximum time in disconnected state (in tickles) */
     unsigned char passwdbits, passwdminlen, loginmaxfail;
     u_int32_t server_quantum;
     char hostname[MAXHOSTNAMELEN + 1], *server, *ipaddr, *port, *configfile;
@@ -62,6 +66,7 @@ struct afp_options {
     char *uampath, *fqdn;
     char *pidfile;
     char *sigconffile;
+    char *uuidconf;
     struct afp_volume_name defaultvol, systemvol, uservol;
     int  closevol;
 
@@ -75,7 +80,6 @@ struct afp_options {
     charset_t maccharset, unixcharset; 
     mode_t umask;
     mode_t save_mask;
-    int    sleep;
 #ifdef ADMIN_GRP
     gid_t admingid;
 #endif /* ADMIN_GRP */
@@ -83,26 +87,27 @@ struct afp_options {
 
     /* default value for winbind authentication */
     char *ntdomain, *ntseparator;
+    char *logconfig;
 };
 
 #define AFPOBJ_TMPSIZ (MAXPATHLEN)
 typedef struct _AFPObj {
     int proto;
     unsigned long servernum;
-    void *handle, *config;
+    void *handle;               /* either (DSI *) or (ASP *) */
+    void *config; 
     struct afp_options options;
     char *Obj, *Type, *Zone;
     char username[MAXUSERLEN];
     void (*logout)(void), (*exit)(int);
     int (*reply)(void *, int);
     int (*attention)(void *, AFPUserBytes);
-    void (*sleep)(void);
     /* 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;
     uid_t uid;         /* client running user id */
-
+    int ipc_fd; /* anonymous PF_UNIX socket for IPC with afpd parent */
 #ifdef FORCE_UIDGID
     int                 force_uid;
     uidgidset          uidgid;
@@ -142,6 +147,9 @@ extern int  parseline  (int, char *);
 extern const char *AfpNum2name (int );
 extern const char *AfpErr2name(int err);
 
+/* directory.c */
+extern struct dir rootParent;
+
 #ifndef NO_DDP
 extern void afp_over_asp (AFPObj *);
 #endif /* NO_DDP */
index 8f63fc6e4013ed994d0ad9e89f4916e16db1c3d5..0d552d6f73c77faa3478f4a37702fb630aa6e7a3 100644 (file)
@@ -17,8 +17,9 @@
 #include <atalk/logger.h>
 #include <sys/time.h>
 #include <sys/socket.h>
-
+#include <sys/poll.h>
 #include <errno.h>
+#include <sys/wait.h>
 
 #include <atalk/adouble.h>
 
@@ -38,6 +39,7 @@
 #include "status.h"
 #include "fork.h"
 #include "uam_auth.h"
+#include "afp_zeroconf.h"
 
 #ifdef TRU64
 #include <sys/security.h>
@@ -53,8 +55,14 @@ unsigned char        nologin = 0;
 struct afp_options default_options;
 static AFPConfig *configs;
 static server_child *server_children;
-static fd_set save_rfds;
-static int    Ipc_fd = -1;
+static sig_atomic_t reloadconfig = 0;
+
+/* Two pointers to dynamic allocated arrays which store pollfds and associated data */
+static struct pollfd *fdset;
+static struct polldata *polldata;
+static int fdset_size;          /* current allocated size */
+static int fdset_used;          /* number of used elements */
+
 
 #ifdef TRU64
 void afp_get_cmdline( int *ac, char ***av)
@@ -64,30 +72,41 @@ void afp_get_cmdline( int *ac, char ***av)
 }
 #endif /* TRU64 */
 
-static void afp_exit(const int i)
+/* This is registered with atexit() */
+static void afp_exit(void)
 {
-    server_unlock(default_options.pidfile);
-    exit(i);
+    if (parent_or_child == 0)
+        /* Only do this in the parent */
+        server_unlock(default_options.pidfile);
 }
 
+
 /* ------------------
    initialize fd set we are waiting for.
 */
-static void set_fd(int ipc_fd)
+static void fd_set_listening_sockets(void)
 {
     AFPConfig   *config;
 
-    FD_ZERO(&save_rfds);
     for (config = configs; config; config = config->next) {
         if (config->fd < 0) /* for proxies */
             continue;
-        FD_SET(config->fd, &save_rfds);
-    }
-    if (ipc_fd >= 0) {
-        FD_SET(ipc_fd, &save_rfds);
+        fdset_add_fd(&fdset, &polldata, &fdset_used, &fdset_size, config->fd, LISTEN_FD, config);
     }
 }
  
+static void fd_reset_listening_sockets(void)
+{
+    AFPConfig   *config;
+
+    for (config = configs; config; config = config->next) {
+        if (config->fd < 0) /* for proxies */
+            continue;
+        fdset_del_fd(&fdset, &polldata, &fdset_used, &fdset_size, config->fd);
+    }
+    fd_set_listening_sockets();
+}
+
 /* ------------------ */
 static void afp_goaway(int sig)
 {
@@ -96,58 +115,68 @@ static void afp_goaway(int sig)
     asp_kill(sig);
 #endif /* ! NO_DDP */
 
-    dsi_kill(sig);
+    if (server_children)
+        server_child_kill(server_children, CHILD_DSIFORK, sig);
+
     switch( sig ) {
+
     case SIGTERM :
         LOG(log_note, logtype_afpd, "AFP Server shutting down on SIGTERM");
+        AFPConfig *config;
+        for (config = configs; config; config = config->next)
+            if (config->server_cleanup)
+                config->server_cleanup(config);
+        server_unlock(default_options.pidfile);
+        exit(0);
         break;
+
     case SIGUSR1 :
-    case SIGHUP :
-        /* w/ a configuration file, we can force a re-read if we want */
         nologin++;
         auth_unload();
-        if (sig == SIGHUP || ((nologin + 1) & 1)) {
-            AFPConfig *config;
-
-            LOG(log_info, logtype_afpd, "re-reading configuration file");
-            for (config = configs; config; config = config->next)
-                if (config->server_cleanup)
-                    config->server_cleanup(config);
+        LOG(log_info, logtype_afpd, "disallowing logins");        
+        break;
 
-            /* 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(EXITERR_CONF);
-            }
-            set_fd(Ipc_fd);
-        } else {
-            LOG(log_info, logtype_afpd, "disallowing logins");
-        }
-        if (sig == SIGHUP) {
-            nologin = 0;
-        }
+    case SIGHUP :
+        /* w/ a configuration file, we can force a re-read if we want */
+        reloadconfig = 1;
         break;
+
     default :
         LOG(log_error, logtype_afpd, "afp_goaway: bad signal" );
     }
-    if ( sig == SIGTERM ) {
-        AFPConfig *config;
-
-        for (config = configs; config; config = config->next)
-            if (config->server_cleanup)
-                config->server_cleanup(config);
-
-        afp_exit(0);
-    }
     return;
 }
 
 static void child_handler(int sig _U_)
 {
-    server_child_handler(server_children);
+    int fd;
+    int status, i;
+    pid_t pid;
+  
+#ifndef WAIT_ANY
+#define WAIT_ANY (-1)
+#endif /* ! WAIT_ANY */
+
+    while ((pid = waitpid(WAIT_ANY, &status, WNOHANG)) > 0) {
+        for (i = 0; i < server_children->nforks; i++) {
+            if ((fd = server_child_remove(server_children, i, pid)) != -1) {
+                fdset_del_fd(&fdset, &polldata, &fdset_used, &fdset_size, fd);        
+                break;
+            }
+        }
+
+        if (WIFEXITED(status)) {
+            if (WEXITSTATUS(status))
+                LOG(log_info, logtype_afpd, "child[%d]: exited %d", pid, WEXITSTATUS(status));
+            else
+                LOG(log_info, logtype_afpd, "child[%d]: done", pid);
+        } else {
+            if (WIFSIGNALED(status))
+                LOG(log_info, logtype_afpd, "child[%d]: killed by signal %d", pid, WTERMSIG(status));
+            else
+                LOG(log_info, logtype_afpd, "child[%d]: died", pid);
+        }
+    }
 }
 
 int main(int ac, char **av)
@@ -165,9 +194,12 @@ int main(int ac, char **av)
     set_auth_parameters( ac, av );
 #endif /* TRU64 */
 
-#ifdef DEBUG1
+    /* Log SIGBUS/SIGSEGV SBT */
     fault_setup(NULL);
-#endif
+
+    /* Default log setup: log to syslog */
+    setuplog("default log_note");
+
     afp_options_init(&default_options);
     if (!afp_options_parse(ac, av, &default_options))
         exit(EXITERR_CONF);
@@ -185,6 +217,7 @@ int main(int ac, char **av)
     default: /* server */
         exit(0);
     }
+    atexit(afp_exit);
 
     /* install child handler for asp and dsi. we do this before afp_goaway
      * as afp_goaway references stuff from here. 
@@ -192,11 +225,10 @@ int main(int ac, char **av)
     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(EXITERR_SYS);
+        exit(EXITERR_SYS);
     }
 
     memset(&sv, 0, sizeof(sv));    
-#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
@@ -204,9 +236,8 @@ int main(int ac, char **av)
     sigemptyset( &sv.sa_mask );
     if (sigaction(SIGXFSZ, &sv, NULL ) < 0 ) {
         LOG(log_error, logtype_afpd, "main: sigaction: %s", strerror(errno) );
-        afp_exit(EXITERR_SYS);
+        exit(EXITERR_SYS);
     }
-#endif
 #endif
     
     sv.sa_handler = child_handler;
@@ -219,7 +250,7 @@ int main(int ac, char **av)
     sv.sa_flags = SA_RESTART;
     if ( sigaction( SIGCHLD, &sv, NULL ) < 0 ) {
         LOG(log_error, logtype_afpd, "main: sigaction: %s", strerror(errno) );
-        afp_exit(EXITERR_SYS);
+        exit(EXITERR_SYS);
     }
 
     sv.sa_handler = afp_goaway;
@@ -231,7 +262,7 @@ int main(int ac, char **av)
     sv.sa_flags = SA_RESTART;
     if ( sigaction( SIGUSR1, &sv, NULL ) < 0 ) {
         LOG(log_error, logtype_afpd, "main: sigaction: %s", strerror(errno) );
-        afp_exit(EXITERR_SYS);
+        exit(EXITERR_SYS);
     }
 
     sigemptyset( &sv.sa_mask );
@@ -242,7 +273,7 @@ int main(int ac, char **av)
     sv.sa_flags = SA_RESTART;
     if ( sigaction( SIGHUP, &sv, NULL ) < 0 ) {
         LOG(log_error, logtype_afpd, "main: sigaction: %s", strerror(errno) );
-        afp_exit(EXITERR_SYS);
+        exit(EXITERR_SYS);
     }
 
 
@@ -254,7 +285,7 @@ int main(int ac, char **av)
     sv.sa_flags = SA_RESTART;
     if ( sigaction( SIGTERM, &sv, NULL ) < 0 ) {
         LOG(log_error, logtype_afpd, "main: sigaction: %s", strerror(errno) );
-        afp_exit(EXITERR_SYS);
+        exit(EXITERR_SYS);
     }
 
     /* afpd.conf: not in config file: lockfile, connections, configfile
@@ -275,21 +306,20 @@ int main(int ac, char **av)
 #endif
     sigaddset(&sigs, SIGCHLD);
 
-    sigprocmask(SIG_BLOCK, &sigs, NULL);
+    pthread_sigmask(SIG_BLOCK, &sigs, NULL);
     if (!(configs = configinit(&default_options))) {
         LOG(log_error, logtype_afpd, "main: no servers configured");
-        afp_exit(EXITERR_CONF);
+        exit(EXITERR_CONF);
     }
-    sigprocmask(SIG_UNBLOCK, &sigs, NULL);
+    pthread_sigmask(SIG_UNBLOCK, &sigs, NULL);
 
     /* Register CNID  */
     cnid_init();
 
     /* watch atp, dsi sockets and ipc parent/child file descriptor. */
-    if ((ipc = server_ipc_create())) {
-        Ipc_fd = server_ipc_parent(ipc);
-    }
-    set_fd(Ipc_fd);
+    fd_set_listening_sockets();
+
+    afp_child_t *child;
 
     /* wait for an appleshare connection. parent remains in the loop
      * while the children get handled by afp_over_{asp,dsi}.  this is
@@ -298,27 +328,71 @@ int main(int ac, char **av)
      * afterwards. establishing timeouts for logins is a possible 
      * solution. */
     while (1) {
-        rfds = save_rfds;
-        sigprocmask(SIG_UNBLOCK, &sigs, NULL);
-        ret = select(FD_SETSIZE, &rfds, NULL, NULL, NULL);
-        sigprocmask(SIG_BLOCK, &sigs, NULL);
+        LOG(log_maxdebug, logtype_afpd, "main: polling %i fds", fdset_used);
+        pthread_sigmask(SIG_UNBLOCK, &sigs, NULL);
+        ret = poll(fdset, fdset_used, -1);
+        pthread_sigmask(SIG_BLOCK, &sigs, NULL);
+        int saveerrno = errno;
+
+        if (reloadconfig) {
+            nologin++;
+            auth_unload();
+
+            LOG(log_info, logtype_afpd, "re-reading configuration file");
+            for (config = configs; config; config = config->next)
+                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");
+                exit(EXITERR_CONF);
+            }
+            fd_reset_listening_sockets();
+            nologin = 0;
+            reloadconfig = 0;
+            errno = saveerrno;
+        }
+
+        if (ret == 0)
+            continue;
+        
         if (ret < 0) {
             if (errno == EINTR)
                 continue;
             LOG(log_error, logtype_afpd, "main: can't wait for input: %s", strerror(errno));
             break;
         }
-        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)) {
-                config->server_start(config, configs, server_children);
-            }
-        }
-    }
+
+        for (int i = 0; i < fdset_used; i++) {
+            if (fdset[i].revents & POLLIN) {
+                switch (polldata[i].fdtype) {
+                case LISTEN_FD:
+                    config = (AFPConfig *)polldata[i].data;
+                    /* config->server_start is afp_config.c:dsi_start() for DSI */
+                    if (child = config->server_start(config, configs, server_children)) {
+                        /* Add IPC fd to select fd set */
+                        fdset_add_fd(&fdset, &polldata, &fdset_used, &fdset_size, child->ipc_fds[0], IPC_FD, child);
+                    }
+                    break;
+                case IPC_FD:
+                    child = (afp_child_t *)polldata[i].data;
+                    LOG(log_debug, logtype_afpd, "main: IPC request from child[%u]", child->pid);
+                    if ((ret = ipc_server_read(server_children, child->ipc_fds[0])) == 0) {
+                        fdset_del_fd(&fdset, &polldata, &fdset_used, &fdset_size, child->ipc_fds[0]);
+                        close(child->ipc_fds[0]);
+                        child->ipc_fds[0] = -1;
+                    }
+                    break;
+                default:
+                    LOG(log_debug, logtype_afpd, "main: IPC request for unknown type");
+                    break;
+                } /* switch */
+            }  /* if */
+        } /* for (i)*/
+    } /* while (1) */
 
     return 0;
 }
index c00b76ba4c874c51227ef2100e64ce9d8a660bcf..91533e619a674d9748b5c1cc6f365c6d58952aae 100644 (file)
@@ -1,5 +1,5 @@
 /* 
- * $Id: mangle.c,v 1.19 2006-09-19 01:35:45 didg Exp $ 
+ * $Id: mangle.c,v 1.19.4.2 2010-02-01 14:25:45 franklahm Exp $ 
  *
  * Copyright (c) 2002. Joe Marcus Clarke (marcus@marcuscom.com)
  * All Rights Reserved.  See COPYRIGHT.
 
 #include <stdio.h>
 #include <ctype.h>
+
+#include <atalk/util.h>
+#include <atalk/bstradd.h>
+
 #include "mangle.h"
 #include "desktop.h"
-#include <atalk/util.h>  
+
 
 #define hextoint( c )   ( isdigit( c ) ? c - '0' : c + 10 - 'A' )
 #define isuxdigit(x)    (isdigit(x) || (isupper(x) && isxdigit(x)))
@@ -38,7 +42,7 @@ static size_t mangle_extension(const struct vol *vol, const char* uname,
   return 0;
 }
 
-static char *demangle_checks ( const struct vol *vol, char* uname, char * mfilename, size_t prefix, char * ext)
+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 +2];  /* for convert_charset dest_len parameter +2 */
@@ -48,18 +52,18 @@ static char *demangle_checks ( const struct vol *vol, char* uname, char * mfilen
     /* 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 + 2];  /* for convert_charset dest_len parameter +2 */
-      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;
-      }
+    char buf[MAX_EXT_LENGTH + 2];  /* for convert_charset dest_len parameter +2 */
+    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         */
@@ -169,8 +173,8 @@ private_demangle(const struct vol *vol, char *mfilename, cnid_t did, cnid_t *osx
     }
 
     /* 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) {
+    if ((dir = dirlookup(vol, id))) {
+        if (dir->d_pdid != did) {
             /* not in the same folder, there's a race with outdate cache
              * but we have to live with it, hopefully client will recover
             */
@@ -178,13 +182,12 @@ private_demangle(const struct vol *vol, char *mfilename, cnid_t did, cnid_t *osx
         }
         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;
+            if (strcmp(cfrombstr(dir->d_m_name), mfilename) == 0) {
+                return cfrombstr(dir->d_u_name);
             }
-        } 
-        else {
-           return demangle_checks (vol, dir->d_u_name, mfilename, prefix, t);
-       }
+        } else {
+            return demangle_checks(vol, cfrombstr(dir->d_u_name), mfilename, prefix, t);
+        }
     }
     else if (NULL != (u_name = cnid_resolve(vol->v_cdb, &id, buffer, len)) ) {
         if (id != did) {
index 49c014ccef9befec7be7f15068e5c7039e757139..f5f8a38de8d7fff65a380ac83674fe9c755c190a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: ofork.c,v 1.32 2010-03-12 15:16:49 franklahm Exp $
+ * $Id: ofork.c,v 1.32 2010/03/12 15:16:49 franklahm Exp $
  *
  * Copyright (c) 1996 Regents of The University of Michigan.
  * All Rights Reserved.  See COPYRIGHT.
 #include <string.h>
 #include <sys/stat.h> /* works around a bug */
 #include <sys/param.h>
-#include <atalk/logger.h>
 #include <errno.h>
 
+#include <atalk/logger.h>
 #include <atalk/util.h>
+#include <atalk/bstrlib.h>
+#include <atalk/bstradd.h>
 
 #include "globals.h"
 #include "volume.h"
@@ -32,9 +34,9 @@
 #define OFORK_HASHSIZE  64
 static struct ofork     *ofork_table[OFORK_HASHSIZE];
 
-static struct ofork    **oforks = NULL;
-static int             nforks = 0;
-static u_short         lastrefnum = 0;
+static struct ofork **oforks = NULL;
+static int          nforks = 0;
+static u_short      lastrefnum = 0;
 
 
 /* OR some of each character for the hash*/
@@ -45,7 +47,7 @@ static unsigned long hashfn(const struct file_key *key)
     while (*name) {
         i = ((i << 4) | (8*sizeof(i) - 4)) ^ *name++;
     }
-#endif    
+#endif
     return key->inode & (OFORK_HASHSIZE - 1);
 }
 
@@ -72,7 +74,7 @@ static void of_unhash(struct ofork *of)
 #ifdef DEBUG1
 void of_pforkdesc( FILE *f)
 {
-    int        ofrefnum;
+    int ofrefnum;
 
     if (!oforks)
         return;
@@ -87,14 +89,14 @@ void of_pforkdesc( FILE *f)
 
 int of_flush(const struct vol *vol)
 {
-    int        refnum;
+    int refnum;
 
     if (!oforks)
         return 0;
 
     for ( refnum = 0; refnum < nforks; refnum++ ) {
         if (oforks[ refnum ] != NULL && (oforks[refnum]->of_vol == vol) &&
-                flushfork( oforks[ refnum ] ) < 0 ) {
+            flushfork( oforks[ refnum ] ) < 0 ) {
             LOG(log_error, logtype_afpd, "of_flush: %s", strerror(errno) );
         }
     }
@@ -106,65 +108,51 @@ int of_rename(const struct vol *vol,
               struct dir *olddir, const char *oldpath _U_,
               struct dir *newdir, const char *newpath)
 {
-    struct ofork *of, *next, *d_ofork;
+    struct ofork *of, *next;
     int done = 0;
 
     if (!s_of)
         return AFP_OK;
-        
+
     next = ofork_table[hashfn(&s_of->key)];
     while ((of = next)) {
         next = next->next; /* so we can unhash and still be all right. */
 
-        if (vol == of->of_vol && olddir == of->of_dir &&
-                s_of->key.dev == of->key.dev && 
-                s_of->key.inode == of->key.inode ) {
-           if (!done) {
-               strlcpy( of_name(of), newpath, of->of_ad->ad_m_namelen);
-               done = 1;
-           }
-            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;
-                if (of->of_dir->d_ofork == of) {
-                    of->of_dir->d_ofork = (of == of->of_d_next) ? NULL : of->of_d_next;
-                }          
-                of->of_dir = newdir;
-                if (!(d_ofork = newdir->d_ofork)) {
-                    newdir->d_ofork = of;
-                    of->of_d_next = of->of_d_prev = of;
-                } else {
-                    of->of_d_next = d_ofork;
-                    of->of_d_prev = d_ofork->of_d_prev;
-                    of->of_d_prev->of_d_next = of;
-                    d_ofork->of_d_prev = of;
-                }
+        if (vol == of->of_vol
+            && olddir->d_did == of->of_did
+            && s_of->key.dev == of->key.dev
+            && s_of->key.inode == of->key.inode ) {
+            if (!done) {
+                strlcpy( of_name(of), newpath, of->of_ad->ad_m_namelen);
+                done = 1;
             }
+            if (newdir != olddir)
+                of->of_did = newdir->d_did;
         }
     }
 
     return AFP_OK;
 }
 
-#define min(a,b)       ((a)<(b)?(a):(b))
+#define min(a,b)    ((a)<(b)?(a):(b))
 
 struct ofork *
 of_alloc(struct vol *vol,
-    struct dir    *dir,
-    char          *path,
-    u_int16_t     *ofrefnum,
-    const int      eid,
-    struct adouble *ad,
-    struct stat    *st)
+         struct dir    *dir,
+         char      *path,
+         u_int16_t     *ofrefnum,
+         const int      eid,
+         struct adouble *ad,
+         struct stat    *st)
 {
-    struct ofork        *of, *d_ofork;
-    u_int16_t          refnum, of_refnum;
+    struct ofork        *of;
+    u_int16_t       refnum, of_refnum;
 
-    int                        i;
+    int         i;
 
     if (!oforks) {
         nforks = getdtablesize() - 10;
-       /* protect against insane ulimit -n */
+        /* protect against insane ulimit -n */
         nforks = min(nforks, 0xffff);
         oforks = (struct ofork **) calloc(nforks, sizeof(struct ofork *));
         if (!oforks)
@@ -180,22 +168,22 @@ of_alloc(struct vol *vol,
         }
     }
     /* grr, Apple and their 'uniquely identifies'
-          the next line is a protection against 
-          of_alloc()
-             refnum % nforks = 3 
-             lastrefnum = 3
-             oforks[3] != NULL 
-             refnum = 4
-             oforks[4] == NULL
-             return 4
-         
-          close(oforks[4])
-      
-          of_alloc()
-             refnum % nforks = 4
-             ...
-             return 4
-         same if lastrefnum++ rather than ++lastrefnum. 
+       the next line is a protection against
+       of_alloc()
+       refnum % nforks = 3
+       lastrefnum = 3
+       oforks[3] != NULL
+       refnum = 4
+       oforks[4] == NULL
+       return 4
+
+       close(oforks[4])
+
+       of_alloc()
+       refnum % nforks = 4
+       ...
+       return 4
+       same if lastrefnum++ rather than ++lastrefnum.
     */
     lastrefnum = refnum;
     if ( i == nforks ) {
@@ -205,7 +193,7 @@ of_alloc(struct vol *vol,
 
     of_refnum = refnum % nforks;
     if (( oforks[ of_refnum ] =
-                (struct ofork *)malloc( sizeof( struct ofork ))) == NULL ) {
+          (struct ofork *)malloc( sizeof( struct ofork ))) == NULL ) {
         LOG(log_error, logtype_afpd, "of_alloc: malloc: %s", strerror(errno) );
         return NULL;
     }
@@ -245,17 +233,7 @@ of_alloc(struct vol *vol,
 
     of->of_ad = ad;
     of->of_vol = vol;
-    of->of_dir = dir;
-
-    if (!(d_ofork = dir->d_ofork)) {
-        dir->d_ofork = of;
-        of->of_d_next = of->of_d_prev = of;
-    } else {
-        of->of_d_next = d_ofork;
-        of->of_d_prev = d_ofork->of_d_prev;
-        d_ofork->of_d_prev->of_d_next = of;
-        d_ofork->of_d_prev = of;
-    }
+    of->of_did = dir->d_did;
 
     *ofrefnum = refnum;
     of->of_refnum = refnum;
@@ -279,16 +257,23 @@ struct ofork *of_find(const u_int16_t ofrefnum )
 }
 
 /* -------------------------- */
-int of_stat  (struct path *path)
+int of_stat(struct path *path)
 {
-int ret;
+    int ret;
+
     path->st_errno = 0;
     path->st_valid = 1;
-    if ((ret = lstat(path->u_name, &path->st)) < 0)
+
+    if ((ret = lstat(path->u_name, &path->st)) < 0) {
+        LOG(log_debug, logtype_afpd, "of_stat('%s/%s': %s)",
+            cfrombstr(curdir->d_fullpath), path->u_name, strerror(errno));
        path->st_errno = errno;
-   return ret;
+    }
+
+    return ret;
 }
 
+
 #ifdef HAVE_RENAMEAT
 int of_fstatat(int dirfd, struct path *path)
 {
@@ -309,10 +294,12 @@ int of_fstatat(int dirfd, struct path *path)
    stat(".") works even if "." is deleted thus
    we have to stat ../name because we want to know if it's there
 */
-int of_statdir  (struct vol *vol, struct path *path)
+int of_statdir(struct vol *vol, struct path *path)
 {
-static char pathname[ MAXPATHLEN + 1] = "../";
-int ret;
+    static char pathname[ MAXPATHLEN + 1] = "../";
+    int ret;
+    size_t len;
+    struct dir *dir;
 
     if (*path->m_name) {
         /* not curdir */
@@ -321,20 +308,28 @@ int ret;
     path->st_errno = 0;
     path->st_valid = 1;
     /* FIXME, what about: we don't have r-x perm anymore ? */
-    strlcpy(pathname +3, path->d_dir->d_u_name, sizeof (pathname) -3);
+    len = blength(path->d_dir->d_u_name);
+    if (len > (MAXPATHLEN - 3))
+        len = MAXPATHLEN - 3;
+    strncpy(pathname + 3, cfrombstr(path->d_dir->d_u_name), len + 1);
+
+    LOG(log_debug, logtype_afpd, "of_statdir: stating: '%s'", pathname);
 
     if (!(ret = lstat(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)) 
+    if (errno == EACCES && (dir = dirlookup(vol, curdir->d_pdid))) {
+       if (movecwd(vol, dir)) 
            return -1;
        path->st_errno = 0;
-       if ((ret = lstat(path->d_dir->d_u_name, &path->st)) < 0) 
+
+       if ((ret = lstat(cfrombstr(path->d_dir->d_u_name), &path->st)) < 0) 
            path->st_errno = errno;
     }
+
     return ret;
 }
 
@@ -343,11 +338,11 @@ struct ofork *of_findname(struct path *path)
 {
     struct ofork *of;
     struct file_key key;
-    
+
     if (!path->st_valid) {
-       of_stat(path);
+        of_stat(path);
     }
-       
+
     if (path->st_errno)
         return NULL;
 
@@ -404,14 +399,6 @@ void of_dealloc( struct ofork *of)
         return;
 
     of_unhash(of);
-
-    /* detach ofork */
-    of->of_d_prev->of_d_next = of->of_d_next;
-    of->of_d_next->of_d_prev = of->of_d_prev;
-    if (of->of_dir->d_ofork == of) {
-        of->of_dir->d_ofork = (of == of->of_d_next) ? NULL : of->of_d_next;
-    }
-
     oforks[ of->of_refnum % nforks ] = NULL;
 
     /* decrease refcount */
@@ -431,12 +418,12 @@ void of_dealloc( struct ofork *of)
 int of_closefork(struct ofork *ofork)
 {
     struct timeval      tv;
-    int                        adflags, doflush = 0;
+    int         adflags, doflush = 0;
     int                 ret;
 
     adflags = 0;
     if ((ofork->of_flags & AFPFORK_DATA) && (ad_data_fileno( ofork->of_ad ) != -1)) {
-            adflags |= ADFLAGS_DF;
+        adflags |= ADFLAGS_DF;
     }
     if ( (ofork->of_flags & AFPFORK_OPEN) && ad_reso_fileno( ofork->of_ad ) != -1 ) {
         adflags |= ADFLAGS_HF;
@@ -447,10 +434,10 @@ int of_closefork(struct ofork *ofork)
             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++;
+                doflush++;
             }
             if ( doflush ) {
-                 ad_flush( ofork->of_ad );
+                ad_flush( ofork->of_ad );
             }
         }
     }
@@ -458,14 +445,14 @@ int of_closefork(struct ofork *ofork)
     if ( ad_close( ofork->of_ad, adflags ) < 0 ) {
         ret = -1;
     }
+
     of_dealloc( ofork );
     return ret;
 }
 
 /* ----------------------
 
-*/
+ */
 struct adouble *of_ad(const struct vol *vol, struct path *path, struct adouble *ad)
 {
     struct ofork        *of;
@@ -480,12 +467,12 @@ struct adouble *of_ad(const struct vol *vol, struct path *path, struct adouble *
     return adp;
 }
 
-/* ---------------------- 
+/* ----------------------
    close all forks for a volume
 */
 void of_closevol(const struct vol *vol)
 {
-    int        refnum;
+    int refnum;
 
     if (!oforks)
         return;
index b264bbb9b7ed8116706ff9394363c576713c87bb..28408658162948749d230d94f8f1c1764299a83a 100644 (file)
@@ -46,32 +46,26 @@ static   size_t maxstatuslen = 0;
 static void status_flags(char *data, const int notif, const int ipok,
                          const unsigned char passwdbits, const int dirsrvcs _U_, int flags)
 {
-    u_int16_t           status;
+    uint16_t           status;
+
+    status = AFPSRVRINFO_COPY
+           | AFPSRVRINFO_SRVSIGNATURE
+           | AFPSRVRINFO_SRVMSGS
+           | AFPSRVRINFO_FASTBOZO
+           | AFPSRVRINFO_SRVRDIR
+           | AFPSRVRINFO_SRVUTF8
+           | AFPSRVRINFO_EXTSLEEP;
 
-    status = AFPSRVRINFO_COPY;
     if (passwdbits & PASSWD_SET) /* some uams may not allow this. */
         status |= AFPSRVRINFO_PASSWD;
     if (passwdbits & PASSWD_NOSAVE)
         status |= AFPSRVRINFO_NOSAVEPASSWD;
-    status |= AFPSRVRINFO_SRVSIGNATURE;
-    /* only advertise tcp/ip if we have a valid address */
-    if (ipok)
+    if (ipok) /* only advertise tcp/ip if we have a valid address */        
         status |= AFPSRVRINFO_TCPIP;
-    status |= AFPSRVRINFO_SRVMSGS;
-    /* Allow the user to decide if we should support server notifications.
-     * With this turned off, the clients will poll for directory changes every
-     * 10 seconds.  This might be too costly to network resources, so make
-     * this an optional thing.  Default will be to _not_ support server
-     * notifications. */
-    if (notif) {
+    if (notif) /* Default is yes */        
         status |= AFPSRVRINFO_SRVNOTIFY;
-    }
-    status |= AFPSRVRINFO_FASTBOZO;
-    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 ... */
-
-    if (flags & OPTION_UUID)   /* 05122008 FIXME: can we set AFPSRVRINFO_UUID here ? see AFPSRVRINFO_SRVRDIR*/
-       status |= AFPSRVRINFO_UUID;
+    if (flags & OPTION_UUID)
+        status |= AFPSRVRINFO_UUID;
 
     status = htons(status);
     memcpy(data + AFPSTATUS_FLAGOFF, &status, sizeof(status));
@@ -397,13 +391,6 @@ static size_t status_utf8servername(char *data, int *nameoffset,
        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 */
@@ -560,7 +547,7 @@ void set_signature(struct afp_options *options) {
     char *servername_conf;
     int header = 0;
     char buf[1024], *p;
-    FILE *fp, *randomp;
+    FILE *fp = NULL, *randomp;
     size_t len;
     char *server_tmp;
     
@@ -663,14 +650,14 @@ server_signature_auto:
                 options->sigconffile, strerror(errno));
             goto server_signature_random;
         }
-    } else {                                                          /* conf file don't exist */
+    } else { /* conf file don't exist */
         if (( fd = creat(options->sigconffile, 0644 )) < 0 ) {
-            LOG(log_error, logtype_atalkd, "ERROR: Cannot create %s (%s). Using one-time signature.",
+            LOG(log_error, logtype_atalkd, "Cannot create %s (%s). Using one-time signature.",
                 options->sigconffile, strerror(errno));
             goto server_signature_random;
         }
         if (( fp = fdopen( fd, "w" )) == NULL ) {
-            LOG(log_error, logtype_atalkd, "ERROR: Cannot fdopen %s (%s). Using one-time signature.",
+            LOG(log_error, logtype_atalkd, "Cannot fdopen %s (%s). Using one-time signature.",
                 options->sigconffile, strerror(errno));
             close(fd);
             goto server_signature_random;
@@ -682,41 +669,9 @@ server_signature_auto:
 server_signature_random:
     
     /* generate signature from random number */
-    if ((randomp = fopen("/dev/urandom", "r")) != NULL) {   /* generate from /dev/urandom */
-        for (i=0 ; i<16 ; i++) {
-            (options->signature)[i] = fgetc(randomp);
-        }
-        LOG(log_note, logtype_afpd,
-            "generate %s's signature %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X from /dev/urandom",
-            server_tmp,
-            (options->signature)[ 0], (options->signature)[ 1],
-            (options->signature)[ 2], (options->signature)[ 3],
-            (options->signature)[ 4], (options->signature)[ 5],
-            (options->signature)[ 6], (options->signature)[ 7],
-            (options->signature)[ 8], (options->signature)[ 9],
-            (options->signature)[10], (options->signature)[11],
-            (options->signature)[12], (options->signature)[13],
-            (options->signature)[14], (options->signature)[15]);
-        
-    } else {                                   /* genarate from random() because cannot open /dev/urandom */
-        srandom((unsigned int)time(NULL) + (unsigned int)options + (unsigned int)server_tmp);
-        for (i=0 ; i<16 ; i++) {
-            (options->signature)[i] = random() & 0xFF;
-        }
-        LOG(log_note, logtype_afpd,
-            "generate %s's signature %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X from random()",
-            server_tmp,
-            (options->signature)[ 0], (options->signature)[ 1],
-            (options->signature)[ 2], (options->signature)[ 3],
-            (options->signature)[ 4], (options->signature)[ 5],
-            (options->signature)[ 6], (options->signature)[ 7],
-            (options->signature)[ 8], (options->signature)[ 9],
-            (options->signature)[10], (options->signature)[11],
-            (options->signature)[12], (options->signature)[13],
-            (options->signature)[14], (options->signature)[15]);
-    }
+    randombytes(options->signature, 16);
 
-    if (fp && header) {                                     /* conf file is created or size=0 */
+    if (fp && header) { /* conf file is created or size=0 */
         fprintf(fp, "# DON'T TOUCH NOR COPY THOUGHTLESSLY!\n");
         fprintf(fp, "# This file is auto-generated by afpd.\n");
         fprintf(fp, "# \n");
index 2e2c69e01212f56e25df986d83c46e478c42ad55..7dbd9ab77315f57eba5a8c4aa0d1c8bc0d360472 100644 (file)
@@ -1,6 +1,4 @@
 /*
- * $Id: switch.c,v 1.19 2009-10-15 10:43:13 didg Exp $
- *
  * Copyright (c) 1990,1991 Regents of The University of Michigan.
  * All Rights Reserved.
  *
@@ -46,7 +44,7 @@
 #include "filedir.h"
 #include "status.h"
 #include "misc.h"
-#ifdef HAVE_NFSv4_ACLS
+#ifdef HAVE_ACLS
 #include "acls.h"
 #endif
 
index 532a620155f7c748835f32a83a53aa882cdc6575..92173915c5f5cc5e7dfa8934c00f1a1ba34a1d85 100644 (file)
@@ -56,11 +56,7 @@ 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>
index 0df7ee54c7cf0fb19d05024ae5d1b8038ef06bcd..9b68c3d47d922f90086d7c12ee4c7f3a951ea8fc 100644 (file)
@@ -1,6 +1,4 @@
 /*
- * $Id: unix.c,v 1.61 2010-02-10 14:05:37 franklahm Exp $
- *
  * Copyright (c) 1990,1993 Regents of The University of Michigan.
  * All Rights Reserved.  See COPYRIGHT.
  */
@@ -45,12 +43,10 @@ char *strchr (), *strrchr ();
 #include "volume.h"
 #include "unix.h"
 #include "fork.h"
-
-#ifdef HAVE_NFSv4_ACLS
-extern void acltoownermode(char *path, struct stat *st,uid_t uid, struct maccess *ma);
+#ifdef HAVE_ACLS
+#include "acls.h"
 #endif
 
-
 /*
  * Get the free space on a partition.
  */
@@ -173,9 +169,8 @@ mode_t mode;
  * dir parameter is used by AFS
  */
 void accessmode(char *path, struct maccess *ma, struct dir *dir _U_, struct stat *st)
-
 {
-struct stat     sb;
+    struct stat     sb;
 
     ma->ma_user = ma->ma_owner = ma->ma_world = ma->ma_group = 0;
     if (!st) {
@@ -184,9 +179,8 @@ struct stat     sb;
         st = &sb;
     }
     utommode( st, ma );
-#ifdef HAVE_NFSv4_ACLS
-    /* 10.5 Finder looks at OS 9 mode, so we must do some mapping */
-    acltoownermode( path, st, uuid, ma);
+#ifdef HAVE_ACLS
+    acltoownermode(path, st, ma);
 #endif
 }
 
index 9a5a4dc771e036443c694b2d3428b8d50843261d..7596a75013dcdb973538987337ac05cd67a7fe73 100644 (file)
@@ -35,6 +35,7 @@ char *strchr (), *strrchr ();
 #include <sys/socket.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
+
 #include <atalk/asp.h>
 #include <atalk/dsi.h>
 #include <atalk/adouble.h>
@@ -43,7 +44,8 @@ char *strchr (), *strrchr ();
 #include <atalk/volinfo.h>
 #include <atalk/logger.h>
 #include <atalk/vfs.h>
-#include <atalk/ea.h>
+#include <atalk/uuid.h>
+
 #ifdef CNID_DB
 #include <atalk/cnid.h>
 #endif /* CNID_DB*/
@@ -56,6 +58,7 @@ char *strchr (), *strrchr ();
 #include "mangle.h"
 #include "fork.h"
 #include "hash.h"
+#include "acls.h"
 
 extern int afprun(int root, char *cmd, int *outfd);
 
@@ -74,6 +77,13 @@ extern int afprun(int root, char *cmd, int *outfd);
 #endif /* BYTE_ORDER == BIG_ENDIAN */
 #endif /* ! NO_LARGE_VOL_SUPPORT */
 
+#ifndef UUID_PRINTABLE_STRING_LENGTH
+#define UUID_PRINTABLE_STRING_LENGTH 37
+#endif
+
+/* Globals */
+struct vol *current_vol;        /* last volume from getvolbyvid() */
+
 static struct vol *Volumes = NULL;
 static u_int16_t    lastvid = 0;
 static char     *Trash = "\02\024Network Trash Folder";
@@ -173,7 +183,10 @@ static void volfree(struct vol_option *options, const struct vol_option *save)
 }
 
 
-/* handle variable substitutions. here's what we understand:
+#define is_var(a, b) (strncmp((a), (b), 2) == 0)
+
+/*
+ * Handle variable substitutions. here's what we understand:
  * $b   -> basename of path
  * $c   -> client ip/appletalk address
  * $d   -> volume pathname on server
@@ -187,17 +200,37 @@ static void volfree(struct vol_option *options, const struct vol_option *save)
  * $z   -> zone (may not exist)
  * $$   -> $
  *
+ * This get's called from readvolfile with
+ * path = NULL, volname = NULL for xlating the volumes path
+ * path = path, volname = NULL for xlating the volumes name
+ * ... and from volumes options parsing code when xlating eg dbpath with
+ * path = path, volname = volname
  *
+ * Using this information we can reject xlation of any variable depeninding on a login
+ * context which is not given in the afp master, where we must evaluate this whole stuff
+ * too for the Zeroconf announcements.
  */
-#define is_var(a, b) (strncmp((a), (b), 2) == 0)
-
-static char *volxlate(AFPObj *obj, char *dest, size_t destlen,
-                      char *src, struct passwd *pwd, char *path, char *volname)
+static char *volxlate(AFPObj *obj,
+                      char *dest,
+                      size_t destlen,
+                      char *src,
+                      struct passwd *pwd,
+                      char *path,
+                      char *volname)
 {
     char *p, *r;
     const char *q;
     int len;
     char *ret;
+    int afpmaster = 0;
+    int xlatevolname = 0;
+
+    if (parent_or_child == 0)
+        afpmaster = 1;
+
+    if (path && !volname)
+        /* cf above */
+        xlatevolname = 1;
 
     if (!src) {
         return NULL;
@@ -224,6 +257,8 @@ static char *volxlate(AFPObj *obj, char *dest, size_t destlen,
         /* now figure out what the variable is */
         q = NULL;
         if (is_var(p, "$b")) {
+            if (afpmaster && xlatevolname)
+                return NULL;
             if (path) {
                 if ((q = strrchr(path, '/')) == NULL)
                     q = path;
@@ -231,6 +266,8 @@ static char *volxlate(AFPObj *obj, char *dest, size_t destlen,
                     q++;
             }
         } else if (is_var(p, "$c")) {
+            if (afpmaster && xlatevolname)
+                return NULL;
             if (obj->proto == AFPPROTO_ASP) {
                 ASP asp = obj->handle;
 
@@ -248,18 +285,26 @@ static char *volxlate(AFPObj *obj, char *dest, size_t destlen,
                 destlen -= len;
             }
         } else if (is_var(p, "$d")) {
+            if (afpmaster && xlatevolname)
+                return NULL;
             q = path;
-        } else if (is_var(p, "$f")) {
+        } else if (pwd && is_var(p, "$f")) {
+            if (afpmaster && xlatevolname)
+                return NULL;
             if ((r = strchr(pwd->pw_gecos, ',')))
                 *r = '\0';
             q = pwd->pw_gecos;
-        } else if (is_var(p, "$g")) {
+        } else if (pwd && is_var(p, "$g")) {
+            if (afpmaster && xlatevolname)
+                return NULL;
             struct group *grp = getgrgid(pwd->pw_gid);
             if (grp)
                 q = grp->gr_name;
         } else if (is_var(p, "$h")) {
             q = obj->options.hostname;
         } else if (is_var(p, "$i")) {
+            if (afpmaster && xlatevolname)
+                return NULL;
             if (obj->proto == AFPPROTO_ASP) {
                 ASP asp = obj->handle;
 
@@ -278,13 +323,17 @@ static char *volxlate(AFPObj *obj, char *dest, size_t destlen,
                 q = obj->options.server;
             } else
                 q = obj->options.hostname;
-        } else if (is_var(p, "$u")) {
+        } else if (obj->username && is_var(p, "$u")) {
+            if (afpmaster && xlatevolname)
+                return NULL;
             char* sep = NULL;
             if ( obj->options.ntseparator && (sep = strchr(obj->username, obj->options.ntseparator[0])) != NULL)
                 q = sep+1;
             else
                 q = obj->username;
         } else if (is_var(p, "$v")) {
+            if (afpmaster && xlatevolname)
+                return NULL;
             if (volname) {
                 q = volname;
             }
@@ -445,8 +494,6 @@ static void volset(struct vol_option *options, struct vol_option *save,
                 options[VOLOPT_ROOTPREEXEC].i_value = 1;
             else if (strcasecmp(p, "upriv") == 0)
                 options[VOLOPT_FLAGS].i_value |= AFPVOL_UNIX_PRIV;
-            else if (strcasecmp(p, "acls") == 0)
-                options[VOLOPT_FLAGS].i_value |= AFPVOL_ACLS;
             else if (strcasecmp(p, "nodev") == 0)
                 options[VOLOPT_FLAGS].i_value |= AFPVOL_NODEV;
             else if (strcasecmp(p, "caseinsensitive") == 0)
@@ -457,7 +504,13 @@ static void volset(struct vol_option *options, struct vol_option *save,
                 options[VOLOPT_FLAGS].i_value &= ~AFPVOL_CACHE;
             else if (strcasecmp(p, "tm") == 0)
                 options[VOLOPT_FLAGS].i_value |= AFPVOL_TM;
-
+            else if (strcasecmp(p, "searchdb") == 0)
+                options[VOLOPT_FLAGS].i_value |= AFPVOL_SEARCHDB;
+/* Found this in branch dir-rewrite, maybe we want to use it sometimes */
+#if 0
+            else if (strcasecmp(p, "cdrom") == 0)
+                options[VOLOPT_FLAGS].i_value |= AFPVOL_CDROM | AFPVOL_RO;
+#endif
             p = strtok(NULL, ",");
         }
 
@@ -559,6 +612,8 @@ static int creatvol(AFPObj *obj, struct passwd *pwd,
     char        suffix[6]; /* max is #FFFF */
     u_int16_t   flags;
 
+    LOG(log_debug, logtype_afpd, "createvol: Volume '%s'", name);
+
     if ( name == NULL || *name == '\0' ) {
         if ((name = strrchr( path, '/' )) == NULL) {
             return -1;  /* Obviously not a fully qualified path */
@@ -599,7 +654,7 @@ static int creatvol(AFPObj *obj, struct passwd *pwd,
     if ( 0 >= ( u8mvlen = convert_string(CH_UTF8_MAC, CH_UCS2, tmpname, tmpvlen, u8mtmpname, AFPVOL_U8MNAMELEN*2)) )
         return -1;
 
-    LOG(log_debug, logtype_afpd, "createvol: Volume '%s' -> UTF8-MAC Name: '%s'", name, tmpname);
+    LOG(log_maxdebug, logtype_afpd, "createvol: Volume '%s' -> UTF8-MAC Name: '%s'", name, tmpname);
 
     /* Maccharset Volume Name */
     /* Firsty convert name from unixcharset to maccharset */
@@ -625,7 +680,7 @@ static int creatvol(AFPObj *obj, struct passwd *pwd,
     if ( 0 >= ( macvlen = convert_string(obj->options.maccharset, CH_UCS2, tmpname, tmpvlen, mactmpname, AFPVOL_U8MNAMELEN*2)) )
         return -1;
 
-    LOG(log_debug, logtype_afpd, "createvol: Volume '%s' ->  Longname: '%s'", name, tmpname);
+    LOG(log_maxdebug, logtype_afpd, "createvol: Volume '%s' ->  Longname: '%s'", name, tmpname);
 
     /* check duplicate */
     for ( volume = Volumes; volume; volume = volume->v_next ) {
@@ -678,14 +733,16 @@ static int creatvol(AFPObj *obj, struct passwd *pwd,
     /* os X start at 1 and use network order ie. 1 2 3 */
     volume->v_vid = ++lastvid;
     volume->v_vid = htons(volume->v_vid);
+#ifdef HAVE_ACLS
+    if (check_vol_acl_support(volume))
+        volume->v_flags |= AFPVOL_ACLS
+;
+#endif
 
     /* handle options */
     if (options) {
-        /* should we casefold? */
         volume->v_casefold = options[VOLOPT_CASEFOLD].i_value;
-
-        /* shift in some flags */
-        volume->v_flags = options[VOLOPT_FLAGS].i_value;
+        volume->v_flags |= options[VOLOPT_FLAGS].i_value;
 
         if (options[VOLOPT_EA_VFS].i_value)
             volume->v_vfs_ea = options[VOLOPT_EA_VFS].i_value;
@@ -807,6 +864,19 @@ static int creatvol(AFPObj *obj, struct passwd *pwd,
         check_ea_sys_support(volume);
     initvol_vfs(volume);
 
+    /* get/store uuid from file */
+    if (volume->v_flags & AFPVOL_TM) {
+        char *uuid = get_uuid(obj, volume->v_localname);
+        if (!uuid) {
+            LOG(log_error, logtype_afpd, "Volume '%s': couldn't get UUID",
+                volume->v_localname);
+        } else {
+            volume->v_uuid = uuid;
+            LOG(log_debug, logtype_afpd, "Volume '%s': UUID '%s'",
+                volume->v_localname, volume->v_uuid);
+        }
+    }
+
     volume->v_next = Volumes;
     Volumes = volume;
     return 0;
@@ -1074,7 +1144,10 @@ static int volfile_changed(struct afp_volume_name *p)
 
 /* ----------------------
  * 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
+ * the global volume list. This gets called from the forked afpd childs.
+ * The master now reads this too for Zeroconf announcements.
+ *
+ * If p2 is non-NULL, the file that is opened is
  * p1/p2
  *
  * Lines that begin with # and blank lines are ignored.
@@ -1082,8 +1155,9 @@ static int volfile_changed(struct afp_volume_name *p)
  *      <unix path> [<volume name>] [allow:<user>,<@group>,...] \
  *                           [codepage:<file>] [casefold:<num>]
  *      <extension> TYPE [CREATOR]
+ *
  */
-static int readvolfile(AFPObj *obj, struct afp_volume_name *p1, char *p2, int user, struct passwd *pwent)
+int readvolfile(AFPObj *obj, struct afp_volume_name *p1, char *p2, int user, struct passwd *pwent)
 {
     FILE        *fp;
     char        path[MAXPATHLEN + 1];
@@ -1092,12 +1166,12 @@ static int readvolfile(AFPObj *obj, struct afp_volume_name *p1, char *p2, int us
     char        buf[BUFSIZ];
     char        type[5], creator[5];
     char        *u, *p;
+    int         fd;
+    int         i;
     struct passwd   *pw;
     struct vol_option   save_options[VOLOPT_NUM];
     struct vol_option   options[VOLOPT_NUM];
-    int                 i;
     struct stat         st;
-    int                 fd;
 
     if (!p1->name)
         return -1;
@@ -1129,6 +1203,8 @@ static int readvolfile(AFPObj *obj, struct afp_volume_name *p1, char *p2, int us
         obj->options.umask);
     save_options[VOLOPT_UMASK].i_value = obj->options.umask;
 
+    LOG(log_debug, logtype_afpd, "readvolfile: \"%s\"", path);
+
     while ( myfgets( buf, sizeof( buf ), fp ) != NULL ) {
         initline( strlen( buf ), buf );
         parseline( sizeof( path ) - 1, path );
@@ -1174,29 +1250,16 @@ static int readvolfile(AFPObj *obj, struct afp_volume_name *p1, char *p2, int us
             /* send path through variable substitution */
             if (*path != '~') /* need to copy path to tmp */
                 strcpy(tmp, path);
-            if (!pwent)
+            if (!pwent && obj->username)
                 pwent = getpwnam(obj->username);
-            volxlate(obj, path, sizeof(path) - 1, tmp, pwent, NULL, NULL);
+
+            if (volxlate(obj, path, sizeof(path) - 1, tmp, pwent, NULL, NULL) == NULL)
+                continue;
 
             /* 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 options:
-             *   volname
-             *   codepage:x
-             *   casefold:x
-             *   allow:x,y,@z
-             *   deny:x,y,@z
-             *   rwlist:x,y,@z
-             *   rolist:x,y,@z
-             *   options:prodos,crlf,noadouble,ro...
-             *   dbpath:x
-             *   password:x
-             *   preexec:x
-             *
-             *   namemask:x,y,!z  (not implemented yet)
-             */
+             * re-write everything. */
+
             memcpy(options, save_options, sizeof(options));
             *volname = '\0';
 
@@ -1208,27 +1271,32 @@ static int readvolfile(AFPObj *obj, struct afp_volume_name *p1, char *p2, int us
                 volset(options, save_options, volname, sizeof(volname) - 1, tmp);
             }
 
-            /* check allow/deny lists:
+            /* check allow/deny lists (if not afpd master loading volumes for Zeroconf reg.):
                allow -> either no list (-1), or in list (1)
                deny -> either no list (-1), or not in list (0) */
-            if (accessvol(options[VOLOPT_ALLOW].c_value, obj->username) &&
-                (accessvol(options[VOLOPT_DENY].c_value, obj->username) < 1) &&
-                hostaccessvol(VOLOPT_ALLOWED_HOSTS, volname, options[VOLOPT_ALLOWED_HOSTS].c_value, obj) &&
-                (hostaccessvol(VOLOPT_DENIED_HOSTS, volname, options[VOLOPT_DENIED_HOSTS].c_value, obj) < 1)) {
+            if (parent_or_child == 0
+                ||
+                (accessvol(options[VOLOPT_ALLOW].c_value, obj->username) &&
+                 (accessvol(options[VOLOPT_DENY].c_value, obj->username) < 1) &&
+                 hostaccessvol(VOLOPT_ALLOWED_HOSTS, volname, options[VOLOPT_ALLOWED_HOSTS].c_value, obj) &&
+                 (hostaccessvol(VOLOPT_DENIED_HOSTS, volname, options[VOLOPT_DENIED_HOSTS].c_value, obj) < 1))) {
 
                 /* handle read-only behaviour. semantics:
                  * 1) neither the rolist nor the rwlist exist -> rw
                  * 2) rolist exists -> ro if user is in it.
                  * 3) rwlist exists -> ro unless user is in it. */
-                if (((options[VOLOPT_FLAGS].i_value & AFPVOL_RO) == 0) &&
-                    ((accessvol(options[VOLOPT_ROLIST].c_value,
-                                obj->username) == 1) ||
-                     !accessvol(options[VOLOPT_RWLIST].c_value,
-                                obj->username)))
+                if (parent_or_child == 1
+                    &&
+                    ((options[VOLOPT_FLAGS].i_value & AFPVOL_RO) == 0)
+                    &&
+                    ((accessvol(options[VOLOPT_ROLIST].c_value, obj->username) == 1) ||
+                     !accessvol(options[VOLOPT_RWLIST].c_value, obj->username)))
                     options[VOLOPT_FLAGS].i_value |= AFPVOL_RO;
 
                 /* do variable substitution for volname */
-                volxlate(obj, tmp, sizeof(tmp) - 1, volname, pwent, path, NULL);
+                if (volxlate(obj, tmp, sizeof(tmp) - 1, volname, pwent, path, NULL) == NULL)
+                    continue;
+
                 creatvol(obj, pwent, path, tmp, options, p2 != NULL);
             }
             volfree(options, save_options);
@@ -1274,6 +1342,8 @@ static void volume_free(struct vol *vol)
     free(vol->v_forceuid);
     free(vol->v_forcegid);
 #endif /* FORCE_UIDGID */
+    if (vol->v_uuid)
+        free(vol->v_uuid);
 }
 
 /* ------------------------------- */
@@ -1669,6 +1739,12 @@ void load_volumes(AFPObj *obj)
         free_volumes();
     }
 
+    if (parent_or_child == 0) {
+        LOG(log_debug, logtype_afpd, "load_volumes: AFP MASTER");
+    } else {
+        LOG(log_debug, logtype_afpd, "load_volumes: user: %s", obj->username);
+    }
+
     pwent = getpwnam(obj->username);
     if ( (obj->options.flags & OPTION_USERVOLFIRST) == 0 ) {
         readvolfile(obj, &obj->options.systemvol, NULL, 0, pwent);
@@ -1837,23 +1913,46 @@ static int volume_openDB(struct vol *volume)
             volume->v_path, volume->v_cnidscheme);
     }
 
-    LOG(log_info, logtype_afpd, "CNID server %s:%s",
+    LOG(log_info, logtype_afpd, "CNID server: %s:%s",
         volume->v_cnidserver ? volume->v_cnidserver : Cnid_srv,
         volume->v_cnidport ? volume->v_cnidport : Cnid_port);
-    
-    volume->v_cdb = cnid_open(volume->v_dbpath ? volume->v_dbpath : volume->v_path,
+
+#if 0
+/* Found this in branch dir-rewrite, maybe we want to use it sometimes */
+
+    /* Legacy pre 2.1 way of sharing eg CD-ROM */
+    if (strcmp(volume->v_cnidscheme, "last") == 0) {
+        /* "last" is gone. We support it by switching to in-memory "tdb" */
+        volume->v_cnidscheme = strdup("tdb");
+        flags |= CNID_FLAG_MEMORY;
+    }
+
+    /* New way of sharing CD-ROM */
+    if (volume->v_flags & AFPVOL_CDROM) {
+        flags |= CNID_FLAG_MEMORY;
+        if (strcmp(volume->v_cnidscheme, "tdb") != 0) {
+            free(volume->v_cnidscheme);
+            volume->v_cnidscheme = strdup("tdb");
+            LOG(log_info, logtype_afpd, "Volume %s is ejectable, switching to scheme %s.",
+                volume->v_path, volume->v_cnidscheme);
+        }
+    }
+#endif
+
+    volume->v_cdb = cnid_open(volume->v_path,
                               volume->v_umask,
                               volume->v_cnidscheme,
                               flags,
                               volume->v_cnidserver ? volume->v_cnidserver : Cnid_srv,
                               volume->v_cnidport ? volume->v_cnidport : Cnid_port);
 
-    if (!volume->v_cdb) {
+    if ( ! volume->v_cdb && ! (flags & CNID_FLAG_MEMORY)) {
+        /* The first attempt failed and it wasn't yet an attempt to open in-memory */
         LOG(log_error, logtype_afpd, "Can't open volume \"%s\" CNID backend \"%s\" ",
             volume->v_path, volume->v_cnidscheme);
-        flags |= CNID_FLAG_MEMORY;
         LOG(log_error, logtype_afpd, "Reopen volume %s using in memory temporary CNID DB.",
             volume->v_path);
+        flags |= CNID_FLAG_MEMORY;
         volume->v_cdb = cnid_open (volume->v_path, volume->v_umask, "tdb", flags, NULL, NULL);
 #ifdef SERVERTEXT
         /* kill ourself with SIGUSR2 aka msg pending */
@@ -1870,11 +1969,11 @@ static int volume_openDB(struct vol *volume)
     return (!volume->v_cdb)?-1:0;
 }
 
-/* 
-   Check if the underlying filesystem supports EAs for ea:sys volumes.
-   If not, switch to ea:ad.
-   As we can't check (requires write access) on ro-volumes, we switch ea:auto
-   volumes that are options:ro to ea:none.
+/*
+  Check if the underlying filesystem supports EAs for ea:sys volumes.
+  If not, switch to ea:ad.
+  As we can't check (requires write access) on ro-volumes, we switch ea:auto
+  volumes that are options:ro to ea:none.
 */
 static void check_ea_sys_support(struct vol *vol)
 {
@@ -2039,7 +2138,7 @@ int afp_openvol(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t
     if ((tmp = strdup(volume->v_path)) == NULL) {
         free(volume->v_path);
         return AFPERR_MISC;
-    } 
+    }
     free(volume->v_path);
     volume->v_path = tmp;
 #endif
@@ -2059,9 +2158,6 @@ int afp_openvol(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t
         volume->max_filename = MACFILELEN;
     }
 
-    volume->v_dir = volume->v_root = NULL;
-    volume->v_hash = NULL;
-
     volume->v_flags |= AFPVOL_OPEN;
     volume->v_cdb = NULL;
 
@@ -2080,22 +2176,23 @@ int afp_openvol(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t
     else if (*(vol_uname + 1) != '\0')
         vol_uname++;
 
-    if ((dir = dirnew(vol_mname, vol_uname) ) == NULL) {
+    if ((dir = dir_new(vol_mname,
+                       vol_uname,
+                       volume,
+                       DIRDID_ROOT_PARENT,
+                       DIRDID_ROOT,
+                       bfromcstr(volume->v_path),
+                       st.st_ctime)
+            ) == 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;
     }
     free(vol_mname);
+    volume->v_root = dir;
+    curdir = dir;
 
-    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;
-    volume->v_curdir = NULL;
-    volume->v_hash = dirhash();
-
-    curdir = volume->v_dir;
     if (volume_openDB(volume) < 0) {
         LOG(log_error, logtype_afpd, "Fatal error: cannot open CNID or invalid CNID backend for %s: %s",
             volume->v_path, volume->v_cnidscheme);
@@ -2134,16 +2231,15 @@ int afp_openvol(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t
         }
         else {
             p = Trash;
-            cname( volume, volume->v_dir, &p );
+            cname( volume, volume->v_root, &p );
         }
         return( AFP_OK );
     }
 
 openvol_err:
-    if (volume->v_dir) {
-        hash_free( volume->v_hash);
-        dirfree( volume->v_dir );
-        volume->v_dir = volume->v_root = NULL;
+    if (volume->v_root) {
+        dir_free( volume->v_root );
+        volume->v_root = NULL;
     }
 
     volume->v_flags &= ~AFPVOL_OPEN;
@@ -2161,9 +2257,8 @@ static void closevol(struct vol *vol)
     if (!vol)
         return;
 
-    hash_free( vol->v_hash);
-    dirfree( vol->v_root );
-    vol->v_dir = NULL;
+    dir_free( vol->v_root );
+    vol->v_root = NULL;
     if (vol->v_cdb != NULL) {
         cnid_close(vol->v_cdb);
         vol->v_cdb = NULL;
@@ -2204,7 +2299,7 @@ static void deletevol(struct vol *vol)
     if ( ovol != NULL ) {
         /* Even if chdir fails, we can't say afp_closevol fails. */
         if ( chdir( ovol->v_path ) == 0 ) {
-            curdir = ovol->v_dir;
+            curdir = ovol->v_root;
         }
     }
 
@@ -2231,6 +2326,7 @@ int afp_closevol(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_
     }
 
     deletevol(vol);
+    current_vol = NULL;
 
     return( AFP_OK );
 }
@@ -2253,6 +2349,8 @@ struct vol *getvolbyvid(const u_int16_t vid )
     set_uidgid ( vol );
 #endif /* FORCE_UIDGID */
 
+    current_vol = vol;
+
     return( vol );
 }
 
@@ -2510,7 +2608,7 @@ static int create_special_folder (const struct vol *vol, const struct _special_f
             free(q);
             return (-1);
         }
-        
+
         ad_setname(&ad, folder->name);
 
         ad_getattr(&ad, &attr);
@@ -2544,3 +2642,111 @@ static void handle_special_folders (const struct vol * vol)
     }
 }
 
+const struct vol *getvolumes(void)
+{
+    return Volumes;
+}
+
+void unload_volumes_and_extmap(void)
+{
+    LOG(log_debug, logtype_afpd, "unload_volumes_and_extmap");
+    free_extmap();
+    free_volumes();
+}
+
+/* 
+ * Get a volumes UUID from the config file.
+ * If there is none, it is generated and stored there.
+ *
+ * Returns pointer to allocated storage on success, NULL on error.
+ */
+char *get_uuid(const AFPObj *obj, const char *volname)
+{
+    char *volname_conf;
+    char buf[1024], uuid[UUID_PRINTABLE_STRING_LENGTH], *p;
+    FILE *fp;
+    struct stat tmpstat;
+    int fd;
+    
+    if ((fp = fopen(obj->options.uuidconf, "r")) != NULL) {  /* read open? */
+        /* scan in the conf file */
+        while (fgets(buf, sizeof(buf), fp) != NULL) { 
+            p = buf;
+            while (p && isblank(*p))
+                p++;
+            if (!p || (*p == '#') || (*p == '\n'))
+                continue;                             /* invalid line */
+            if (*p == '"') {
+                p++;
+                if ((volname_conf = strtok( p, "\"" )) == NULL)
+                    continue;                         /* syntax error */
+            } else {
+                if ((volname_conf = strtok( p, " \t" )) == NULL)
+                    continue;                         /* syntax error: invalid name */
+            }
+            p = strchr(p, '\0');
+            p++;
+            if (*p == '\0')
+                continue;                             /* syntax error */
+            
+            if (strcmp(volname, volname_conf) != 0)
+                continue;                             /* another volume name */
+                
+            while (p && isblank(*p))
+                p++;
+
+            if (sscanf(p, "%36s", uuid) == 1 ) {
+                for (int i=0; uuid[i]; i++)
+                    uuid[i] = toupper(uuid[i]);
+                LOG(log_debug, logtype_afpd, "get_uuid('%s'): UUID: '%s'", volname, uuid);
+                fclose(fp);
+                return strdup(uuid);
+            }
+        }
+    }
+
+    if (fp)
+        fclose(fp);
+
+    /*  not found or no file, reopen in append mode */
+
+    if (stat(obj->options.uuidconf, &tmpstat)) {                /* no file */
+        if (( fd = creat(obj->options.uuidconf, 0644 )) < 0 ) {
+            LOG(log_error, logtype_atalkd, "ERROR: Cannot create %s (%s).",
+                obj->options.uuidconf, strerror(errno));
+            return NULL;
+        }
+        if (( fp = fdopen( fd, "w" )) == NULL ) {
+            LOG(log_error, logtype_atalkd, "ERROR: Cannot fdopen %s (%s).",
+                obj->options.uuidconf, strerror(errno));
+            close(fd);
+            return NULL;
+        }
+    } else if ((fp = fopen(obj->options.uuidconf, "a+")) == NULL) { /* not found */
+        LOG(log_error, logtype_afpd, "Cannot create or append to %s (%s).",
+            obj->options.uuidconf, strerror(errno));
+        return NULL;
+    }
+    fseek(fp, 0L, SEEK_END);
+    if(ftell(fp) == 0) {                     /* size = 0 */
+        fprintf(fp, "# DON'T TOUCH NOR COPY THOUGHTLESSLY!\n");
+        fprintf(fp, "# This file is auto-generated by afpd\n");
+        fprintf(fp, "# and stores UUIDs for TM volumes.\n\n");
+    } else {
+        fseek(fp, -1L, SEEK_END);
+        if(fgetc(fp) != '\n') fputc('\n', fp); /* last char is \n? */
+    }                    
+    
+    /* generate uuid and write to file */
+    atalk_uuid_t id;
+    const char *cp;
+    randombytes((void *)id, 16);
+    cp = uuid_bin2string(id);
+
+    LOG(log_debug, logtype_afpd, "get_uuid('%s'): generated UUID '%s'", volname, cp);
+
+    fprintf(fp, "\"%s\"\t%36s\n", volname, cp);
+    fclose(fp);
+    
+    return strdup(uuid);
+}
index 63d090036bf713f955df7eecac383c772d7cbc4d..b33e9c313cf22713ccf738efcb3758b4b07a1dea 100644 (file)
@@ -1,6 +1,4 @@
 /*
- * $Id: volume.h,v 1.36 2009-10-15 10:43:13 didg Exp $
- *
  * Copyright (c) 1990,1994 Regents of The University of Michigan.
  * All Rights Reserved.  See COPYRIGHT.
  */
 #include "hash.h"
 #endif
 
-extern struct vol      *getvolbyvid (const u_int16_t);
+extern struct vol       *getvolbyvid (const u_int16_t);
 extern int              ustatfs_getvolspace (const struct vol *,
             VolSpace *, VolSpace *,
             u_int32_t *);
 extern void             setvoltime (AFPObj *, struct vol *);
 extern int              pollvoltime (AFPObj *);
 extern void             load_volumes (AFPObj *obj);
+extern int              readvolfile(AFPObj *obj,
+                                    struct afp_volume_name *p1,
+                                    char *p2,
+                                    int user,
+                                    struct passwd *pwent);
+extern const struct vol *getvolumes(void);
+extern void             unload_volumes_and_extmap(void);
+extern char             *get_uuid(const AFPObj *obj, const char *volname);
 
 /* FP functions */
 int afp_openvol      (AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf,  size_t *rbuflen);
@@ -39,4 +45,6 @@ int afp_closevol     (AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf,  size
 /* netatalk functions */
 extern void     close_all_vol   (void);
 
+struct vol *current_vol;        /* last volume from getvolbyvid() */
+
 #endif
index 3f254a3bf065db43197dc810d00e6dcd3c154456..802ad3abb64e90f620a319a678a22d25599a9978 100644 (file)
@@ -10,11 +10,11 @@ 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@
+                   dbd_rebuild_add.c dbd_dbcheck.c dbd_search.c
+cnid_dbd_LDADD = $(top_builddir)/libatalk/libatalk.la @BDB_LIBS@ @ACL_LIBS@
 
 cnid_metad_SOURCES = cnid_metad.c usockfd.c db_param.c
-cnid_metad_LDADD = $(top_builddir)/libatalk/libatalk.la
+cnid_metad_LDADD = $(top_builddir)/libatalk/libatalk.la @ACL_LIBS@
 
 dbd_SOURCES = cmd_dbd.c \
        cmd_dbd_scanvol.c \
@@ -26,7 +26,7 @@ dbd_SOURCES = cmd_dbd.c \
        dbd_rebuild_add.c \
        dbd_resolve.c \
        dbd_update.c
-dbd_LDADD = $(top_builddir)/libatalk/libatalk.la @BDB_LIBS@
+dbd_LDADD = $(top_builddir)/libatalk/libatalk.la @BDB_LIBS@ @ACL_LIBS@
 
 noinst_HEADERS = dbif.h pack.h db_param.h dbd.h usockfd.h comm.h cmd_dbd.h
 
index dc4c3923d90eeb1a0e47c3c24bb4b4df32d4333f..0b81b8ccefe3777a89700d3834bcc409d1da9f02 100644 (file)
@@ -1,6 +1,4 @@
 /* 
-   $Id: cmd_dbd.c,v 1.26 2010-04-20 16:46:20 hat001 Exp $
-
    Copyright (c) 2009 Frank Lahm <franklahm@gmail.com>
    
    This program is free software; you can redistribute it and/or modify
@@ -84,6 +82,7 @@
 
 int nocniddb = 0;               /* Dont open CNID database, only scan filesystem */
 volatile sig_atomic_t alarmed;
+struct volinfo volinfo; /* needed by pack.c:idxname() */
 
 static DBD *dbd;
 static int verbose;             /* Logging flag */
@@ -92,6 +91,8 @@ static struct db_param db_param = {
     NULL,                       /* Volume dirpath */
     1,                          /* bdb logfile autoremove */
     64 * 1024,                  /* bdb cachesize (64 MB) */
+    5000,                       /* maxlocks */
+    5000,                       /* maxlockobjs */
     -1,                         /* not used ... */
     -1,
     "",
@@ -99,7 +100,7 @@ static struct db_param db_param = {
     -1,
     -1
 };
-static char dbpath[PATH_MAX];   /* Path to the dbd database */
+static char dbpath[MAXPATHLEN+1];   /* Path to the dbd database */
 
 /* 
    Provide some logging
@@ -279,7 +280,6 @@ int main(int argc, char **argv)
     int dump=0, scan=0, rebuild=0, prep_upgrade=0, rebuildindexes=0, dumpindexes=0, force=0;
     dbd_flags_t flags = 0;
     char *volpath;
-    struct volinfo volinfo;
     int cdir;
 
     if (geteuid() != 0) {
@@ -380,12 +380,25 @@ int main(int argc, char **argv)
         exit(EXIT_FAILURE);        
     }
 
+    /* Enuser dbpath is there, create if necessary */
+    struct stat st;
+    if (stat(volinfo.v_dbpath, &st) != 0) {
+        if (errno != ENOENT) {
+            dbd_log( LOGSTD, "Can't stat dbpath \"%s\": %s", volinfo.v_dbpath, strerror(errno));
+            exit(EXIT_FAILURE);        
+        }
+        if ((mkdir(volinfo.v_dbpath, 0755)) != 0) {
+            dbd_log( LOGSTD, "Can't create dbpath \"%s\": %s", dbpath, strerror(errno));
+            exit(EXIT_FAILURE);
+        }        
+    }
+
     /* Put "/.AppleDB" at end of volpath, get path from volinfo file */
-    if ( (strlen(volinfo.v_dbpath) + strlen("/.AppleDB")) > (PATH_MAX - 1) ) {
+    if ( (strlen(volinfo.v_dbpath) + strlen("/.AppleDB")) > MAXPATHLEN ) {
         dbd_log( LOGSTD, "Volume pathname too long");
         exit(EXIT_FAILURE);        
     }
-    strncpy(dbpath, volinfo.v_dbpath, PATH_MAX - 9 - 1);
+    strncpy(dbpath, volinfo.v_dbpath, MAXPATHLEN - strlen("/.AppleDB"));
     strcat(dbpath, "/.AppleDB");
 
     /* Check or create dbpath */
@@ -412,7 +425,7 @@ int main(int argc, char **argv)
 
     /* Prepare upgrade ? */
     if (prep_upgrade) {
-        if (dbif_prep_upgrade(dbpath))
+        if (dbif_env_remove(dbpath))
             goto exit_failure;
         goto exit_success;
     }        
@@ -420,9 +433,13 @@ int main(int argc, char **argv)
     /* Check if -f is requested and wipe db if yes */
     if ((flags & DBD_FLAGS_FORCE) && rebuild && (volinfo.v_flags & AFPVOL_CACHE)) {
         char cmd[8 + MAXPATHLEN];
-        snprintf(cmd, 8 + MAXPATHLEN, "rm -f %s/*", dbpath);
+        snprintf(cmd, 8 + MAXPATHLEN, "rm -rf \"%s\"", dbpath);
         dbd_log( LOGDEBUG, "Removing old database of volume: '%s'", volpath);
         system(cmd);
+        if ((mkdir(dbpath, 0755)) != 0) {
+            dbd_log( LOGSTD, "Can't create dbpath \"%s\": %s", dbpath, strerror(errno));
+            exit(EXIT_FAILURE);
+        }
         dbd_log( LOGDEBUG, "Removed old database.");
     }
 
@@ -445,11 +462,6 @@ int main(int argc, char **argv)
             dbif_close(dbd);
             goto exit_failure;
         }
-
-        if (dbd_stamp(dbd) < 0) {
-            dbif_close(dbd);
-            goto exit_failure;
-        }
     }
 
     /* Now execute given command scan|rebuild|dump */
index a1d51b67dcdd77dddf648997f7cdefef2faebd19..ac6cde42112a9202214c869def22433fec056c0b 100644 (file)
@@ -25,8 +25,6 @@ typedef unsigned int dbd_flags_t;
 
 extern int nocniddb; /* Dont open CNID database, only scan filesystem */
 extern volatile sig_atomic_t alarmed;
-extern struct volinfo *volinfo;
-extern char cwdbuf[MAXPATHLEN+1];
 
 extern void dbd_log(enum logtype lt, char *fmt, ...);
 extern int cmd_dbd_scanvol(DBD *dbd, struct volinfo *volinfo, dbd_flags_t flags);
index 45d67ae1bd5b2c5dcfc09ce618fa3f95fb768372..240d4150d3312ef2dec686526e541f9b1a3ed0f3 100644 (file)
 #define ADDIR_OK (addir_ok == 0)
 #define ADFILE_OK (adfile_ok == 0)
 
-/* These must be accessible for cmd_dbd_* funcs */
-struct volinfo        *volinfo;
-char                  cwdbuf[MAXPATHLEN+1];
 
-/* Some static vars */
+static struct volinfo *myvolinfo;
+static char           cwdbuf[MAXPATHLEN+1];
 static DBD            *dbd;
 static DBD            *dbd_rebuild;
 static dbd_flags_t    dbd_flags;
@@ -85,22 +83,22 @@ static char *utompath(char *upath)
     u = upath;
     outlen = strlen(upath);
 
-    if ((volinfo->v_casefold & AFPVOL_UTOMUPPER))
+    if ((myvolinfo->v_casefold & AFPVOL_UTOMUPPER))
         flags |= CONV_TOUPPER;
-    else if ((volinfo->v_casefold & AFPVOL_UTOMLOWER))
+    else if ((myvolinfo->v_casefold & AFPVOL_UTOMLOWER))
         flags |= CONV_TOLOWER;
 
-    if ((volinfo->v_flags & AFPVOL_EILSEQ)) {
+    if ((myvolinfo->v_flags & AFPVOL_EILSEQ)) {
         flags |= CONV__EILSEQ;
     }
 
     /* convert charsets */
-    if ((size_t)-1 == ( outlen = convert_charset(volinfo->v_volcharset,
+    if ((size_t)-1 == ( outlen = convert_charset(myvolinfo->v_volcharset,
                                                  CH_UTF8_MAC,
-                                                 volinfo->v_maccharset,
+                                                 myvolinfo->v_maccharset,
                                                  u, outlen, mpath, MAXPATHLEN, &flags)) ) {
         dbd_log( LOGSTD, "Conversion from %s to %s for %s failed.",
-                 volinfo->v_volcodepage, volinfo->v_maccodepage, u);
+                 myvolinfo->v_volcodepage, myvolinfo->v_maccodepage, u);
         return NULL;
     }
 
@@ -126,17 +124,17 @@ static char *mtoupath(char *mpath)
     }
 
     /* set conversion flags */
-    if (!(volinfo->v_flags & AFPVOL_NOHEX))
+    if (!(myvolinfo->v_flags & AFPVOL_NOHEX))
         flags |= CONV_ESCAPEHEX;
-    if (!(volinfo->v_flags & AFPVOL_USEDOTS))
+    if (!(myvolinfo->v_flags & AFPVOL_USEDOTS))
         flags |= CONV_ESCAPEDOTS;
 
-    if ((volinfo->v_casefold & AFPVOL_MTOUUPPER))
+    if ((myvolinfo->v_casefold & AFPVOL_MTOUUPPER))
         flags |= CONV_TOUPPER;
-    else if ((volinfo->v_casefold & AFPVOL_MTOULOWER))
+    else if ((myvolinfo->v_casefold & AFPVOL_MTOULOWER))
         flags |= CONV_TOLOWER;
 
-    if ((volinfo->v_flags & AFPVOL_EILSEQ)) {
+    if ((myvolinfo->v_flags & AFPVOL_EILSEQ)) {
         flags |= CONV__EILSEQ;
     }
 
@@ -147,11 +145,11 @@ static char *mtoupath(char *mpath)
     outlen = MAXPATHLEN;
 
     if ((size_t)-1 == (outlen = convert_charset(CH_UTF8_MAC,
-                                                volinfo->v_volcharset,
-                                                volinfo->v_maccharset,
+                                                myvolinfo->v_volcharset,
+                                                myvolinfo->v_maccharset,
                                                 m, inplen, u, outlen, &flags)) ) {
         dbd_log( LOGSTD, "conversion from UTF8-MAC to %s for %s failed.",
-                 volinfo->v_volcodepage, mpath);
+                 myvolinfo->v_volcodepage, mpath);
         return NULL;
     }
 
@@ -224,8 +222,8 @@ static int check_symlink(const char *name, int *adflags)
       and can compare it with the currents volume path
     */
     int i = 0;
-    while (volinfo->v_path[i]) {
-        if ((pathbuf[i] == 0) || (volinfo->v_path[i] != pathbuf[i])) {
+    while (myvolinfo->v_path[i]) {
+        if ((pathbuf[i] == 0) || (myvolinfo->v_path[i] != pathbuf[i])) {
             dbd_log( LOGDEBUG, "extra-share symlink '%s/%s', following", cwdbuf, name);
             return 1;
         }
@@ -306,7 +304,7 @@ static int check_adfile(const char *fname, const struct stat *st)
     else
         adflags = ADFLAGS_DIR;
 
-    adname = volinfo->ad_path(fname, adflags);
+    adname = myvolinfo->ad_path(fname, adflags);
 
     if ((ret = access( adname, F_OK)) != 0) {
         if (errno != ENOENT) {
@@ -322,7 +320,7 @@ static int check_adfile(const char *fname, const struct stat *st)
             return -1;
 
         /* Create ad file */
-        ad_init(&ad, volinfo->v_adouble, volinfo->v_ad_options);
+        ad_init(&ad, myvolinfo->v_adouble, myvolinfo->v_ad_options);
 
         if ((ret = ad_open_metadata( fname, adflags, O_CREAT, &ad)) != 0) {
             dbd_log( LOGSTD, "Error creating AppleDouble file '%s/%s': %s",
@@ -342,7 +340,7 @@ static int check_adfile(const char *fname, const struct stat *st)
         chmod(adname, st->st_mode);
 #endif
     } else {
-        ad_init(&ad, volinfo->v_adouble, volinfo->v_ad_options);
+        ad_init(&ad, myvolinfo->v_adouble, myvolinfo->v_ad_options);
         if (ad_open_metadata( fname, adflags, O_RDONLY, &ad) != 0) {
             dbd_log( LOGSTD, "Error opening AppleDouble file for '%s/%s'", cwdbuf, fname);
             return -1;
@@ -472,10 +470,10 @@ static int check_addir(int volroot)
     }
 
     /* Check for ".Parent" */
-    if ( (adpar_ok = access(volinfo->ad_path(".", ADFLAGS_DIR), F_OK)) != 0) {
+    if ( (adpar_ok = access(myvolinfo->ad_path(".", ADFLAGS_DIR), F_OK)) != 0) {
         if (errno != ENOENT) {
             dbd_log(LOGSTD, "Access error on '%s/%s': %s",
-                    cwdbuf, volinfo->ad_path(".", ADFLAGS_DIR), strerror(errno));
+                    cwdbuf, myvolinfo->ad_path(".", ADFLAGS_DIR), strerror(errno));
             return -1;
         }
         dbd_log(LOGSTD, "Missing .AppleDouble/.Parent for '%s'", cwdbuf);
@@ -494,7 +492,7 @@ static int check_addir(int volroot)
         }
 
         /* Create ad dir and set name */
-        ad_init(&ad, volinfo->v_adouble, volinfo->v_ad_options);
+        ad_init(&ad, myvolinfo->v_adouble, myvolinfo->v_ad_options);
 
         if (ad_open_metadata( ".", ADFLAGS_DIR, O_CREAT, &ad) != 0) {
             dbd_log( LOGSTD, "Error creating AppleDouble dir in %s: %s", cwdbuf, strerror(errno));
@@ -515,7 +513,7 @@ static int check_addir(int volroot)
             return -1;
         }
         chown(ADv2_DIRNAME, st.st_uid, st.st_gid);
-        chown(volinfo->ad_path(".", ADFLAGS_DIR), st.st_uid, st.st_gid);
+        chown(myvolinfo->ad_path(".", ADFLAGS_DIR), st.st_uid, st.st_gid);
     }
 
     return 0;
@@ -534,7 +532,7 @@ static int check_eafile_in_adouble(const char *name)
     char *namep, *namedup = NULL;
 
     /* Check if this is an AFPVOL_EA_AD vol */
-    if (volinfo->v_vfs_ea == AFPVOL_EA_AD) {
+    if (myvolinfo->v_vfs_ea == AFPVOL_EA_AD) {
         /* Does the filename contain "::EA" ? */
         namedup = strdup(name);
         if ((namep = strstr(namedup, "::EA")) == NULL) {
@@ -677,8 +675,8 @@ static cnid_t check_cnid(const char *name, cnid_t did, struct stat *st, int adfi
 
     /* Get CNID from ad-file if volume is using AFPVOL_CACHE */
     ad_cnid = 0;
-    if ( (volinfo->v_flags & AFPVOL_CACHE) && ADFILE_OK) {
-        ad_init(&ad, volinfo->v_adouble, volinfo->v_ad_options);
+    if ( (myvolinfo->v_flags & AFPVOL_CACHE) && ADFILE_OK) {
+        ad_init(&ad, myvolinfo->v_adouble, myvolinfo->v_ad_options);
         if (ad_open_metadata( name, adflags, O_RDWR, &ad) != 0) {
             
             if (dbd_flags & DBD_FLAGS_CLEANUP)
@@ -712,7 +710,7 @@ static cnid_t check_cnid(const char *name, cnid_t did, struct stat *st, int adfi
     memset(&rply, 0, sizeof(struct cnid_dbd_rply));
     rqst.did = did;
     rqst.cnid = ad_cnid;
-    if ( ! (volinfo->v_flags & AFPVOL_NODEV))
+    if ( ! (myvolinfo->v_flags & AFPVOL_NODEV))
         rqst.dev = st->st_dev;
     rqst.ino = st->st_ino;
     rqst.type = S_ISDIR(st->st_mode)?1:0;
@@ -769,12 +767,12 @@ static cnid_t check_cnid(const char *name, cnid_t did, struct stat *st, int adfi
                 db_cnid = rply.cnid;
                 dbd_log(LOGSTD, "New CNID for '%s/%s': %u", cwdbuf, name, ntohl(db_cnid));
 
-                if ((volinfo->v_flags & AFPVOL_CACHE)
+                if ((myvolinfo->v_flags & AFPVOL_CACHE)
                     && ADFILE_OK
                     && ( ! (dbd_flags & DBD_FLAGS_SCAN))) {
                     dbd_log(LOGSTD, "Writing CNID data for '%s/%s' to AppleDouble file",
                             cwdbuf, name, ntohl(db_cnid));
-                    ad_init(&ad, volinfo->v_adouble, volinfo->v_ad_options);
+                    ad_init(&ad, myvolinfo->v_adouble, myvolinfo->v_ad_options);
                     if (ad_open_metadata( name, adflags, O_RDWR, &ad) != 0) {
                         dbd_log(LOGSTD, "Error opening AppleDouble file for '%s/%s': %s",
                                 cwdbuf, name, strerror(errno));
@@ -808,11 +806,11 @@ static cnid_t check_cnid(const char *name, cnid_t did, struct stat *st, int adfi
 
     if ((ad_cnid == 0) && db_cnid) {
         /* in db but zeroID in ad-file, write it to ad-file if AFPVOL_CACHE */
-        if ((volinfo->v_flags & AFPVOL_CACHE) && ADFILE_OK) {
+        if ((myvolinfo->v_flags & AFPVOL_CACHE) && ADFILE_OK) {
             if ( ! (dbd_flags & DBD_FLAGS_SCAN)) {
                 dbd_log(LOGSTD, "Writing CNID data for '%s/%s' to AppleDouble file",
                         cwdbuf, name, ntohl(db_cnid));
-                ad_init(&ad, volinfo->v_adouble, volinfo->v_ad_options);
+                ad_init(&ad, myvolinfo->v_adouble, myvolinfo->v_ad_options);
                 if (ad_open_metadata( name, adflags, O_RDWR, &ad) != 0) {
                     dbd_log(LOGSTD, "Error opening AppleDouble file for '%s/%s': %s",
                             cwdbuf, name, strerror(errno));
@@ -956,7 +954,7 @@ static int dbd_readdir(int volroot, cnid_t did)
         }
 
         /* Check EA files */
-        if (volinfo->v_vfs_ea == AFPVOL_EA_AD)
+        if (myvolinfo->v_vfs_ea == AFPVOL_EA_AD)
             check_eafiles(ep->d_name);
 
         /**************************************************************************
@@ -1003,22 +1001,22 @@ static int scanvol(struct volinfo *vi, dbd_flags_t flags)
     }
 
     /* Make this stuff accessible from all funcs easily */
-    volinfo = vi;
+    myvolinfo = vi;
     dbd_flags = flags;
 
     /* Init a fake struct vol with just enough so we can call ea_open and friends */
     volume.v_adouble = AD_VERSION2;
-    volume.v_vfs_ea = volinfo->v_vfs_ea;
+    volume.v_vfs_ea = myvolinfo->v_vfs_ea;
     initvol_vfs(&volume);
 
     /* Run with umask 0 */
     umask(0);
 
     /* Remove trailing slash from volume, chdir to vol */
-    if (volinfo->v_path[strlen(volinfo->v_path) - 1] == '/')
-        volinfo->v_path[strlen(volinfo->v_path) - 1] = 0;
-    strcpy(cwdbuf, volinfo->v_path);
-    chdir(volinfo->v_path);
+    if (myvolinfo->v_path[strlen(myvolinfo->v_path) - 1] == '/')
+        myvolinfo->v_path[strlen(myvolinfo->v_path) - 1] = 0;
+    strcpy(cwdbuf, myvolinfo->v_path);
+    chdir(myvolinfo->v_path);
 
     /* Start recursion */
     if (dbd_readdir(1, htonl(2)) < 0)  /* 2 = volumeroot CNID */
@@ -1073,7 +1071,12 @@ static void delete_orphaned_cnids(DBD *dbd, DBD *dbd_rebuild, dbd_flags_t flags)
                     dbd_log(LOGSTD, "Orphaned CNID in database: %u", dbd_cnid);
                     if ( ! (dbd_flags & DBD_FLAGS_SCAN)) {
                         rqst.cnid = htonl(dbd_cnid);
-                        ret = dbd_delete(dbd, &rqst, &rply, DBIF_CNID);
+                        if ((ret = dbd_delete(dbd, &rqst, &rply, DBIF_CNID)) == -1) {
+                            dbd_log(LOGSTD, "Error deleting CNID %u", dbd_cnid);
+                            (void)dbif_txn_abort(dbd);
+                            goto cleanup;
+                        }
+                        
                         dbif_txn_close(dbd, ret);
                         deleted++;
                     }
@@ -1089,10 +1092,14 @@ static void delete_orphaned_cnids(DBD *dbd, DBD *dbd_rebuild, dbd_flags_t flags)
 
         if (dbd_cnid < rebuild_cnid) {
             /* CNID is orphaned -> delete */
-            dbd_log(LOGSTD, "Orphaned CNID in database: %u.", dbd_cnid);
+            dbd_log(LOGSTD, "One orphaned CNID in database: %u.", dbd_cnid);
             if ( ! (dbd_flags & DBD_FLAGS_SCAN)) {
                 rqst.cnid = htonl(dbd_cnid);
-                ret = dbd_delete(dbd, &rqst, &rply, DBIF_CNID);
+                if ((ret = dbd_delete(dbd, &rqst, &rply, DBIF_CNID)) == -1) {
+                    dbd_log(LOGSTD, "Error deleting CNID %u", dbd_cnid);
+                    (void)dbif_txn_abort(dbd);
+                    goto cleanup;
+                }
                 dbif_txn_close(dbd, ret);
                 deleted++;
             }
@@ -1108,7 +1115,7 @@ static void delete_orphaned_cnids(DBD *dbd, DBD *dbd_rebuild, dbd_flags_t flags)
             dbif_idwalk(dbd_rebuild, NULL, 1); /* Close cursor */
             goto cleanup;
         }
-    }
+    } /* while ((dbif_idwalk(dbd, &dbd_cnid, 0)) == 1) */
 
 cleanup:
     dbif_idwalk(dbd, NULL, 1); /* Close cursor */
@@ -1119,7 +1126,7 @@ cleanup:
 /*
   Main func called from cmd_dbd.c
 */
-int cmd_dbd_scanvol(DBD *dbd_ref, struct volinfo *volinfo, dbd_flags_t flags)
+int cmd_dbd_scanvol(DBD *dbd_ref, struct volinfo *vi, dbd_flags_t flags)
 {
     int ret = 0;
     struct db_param db_param = { 0 };
@@ -1131,8 +1138,8 @@ int cmd_dbd_scanvol(DBD *dbd_ref, struct volinfo *volinfo, dbd_flags_t flags)
     dbd = dbd_ref;
 
     /* We only support unicode volumes ! */
-    if ( volinfo->v_volcharset != CH_UTF8) {
-        dbd_log( LOGSTD, "Not a Unicode volume: %s, %u != %u", volinfo->v_volcodepage, volinfo->v_volcharset, CH_UTF8);
+    if ( vi->v_volcharset != CH_UTF8) {
+        dbd_log( LOGSTD, "Not a Unicode volume: %s, %u != %u", vi->v_volcodepage, vi->v_volcharset, CH_UTF8);
         return -1;
     }
 
@@ -1156,7 +1163,7 @@ int cmd_dbd_scanvol(DBD *dbd_ref, struct volinfo *volinfo, dbd_flags_t flags)
         goto exit_cleanup;      /* Got signal, jump from dbd_readdir */
 
     /* scanvol */
-    if ( (scanvol(volinfo, flags)) != 0)
+    if ( (scanvol(vi, flags)) != 0)
         return -1;
 
     if (! nocniddb) {
index dc13fb759256e8b5fc2fd0356bab72571b9cdb73..0e32b8d5e12d83e20d92ddb3764286c4ad3d9b49 100644 (file)
@@ -1,6 +1,7 @@
 /*
  * Copyright (C) Joerg Lenneis 2003
- * Copyright (C) Frank Lahm 2010
+ * Copyright (C) Frank Lahm 2009, 2010
+ *
  * All Rights Reserved.  See COPYING.
  */
 
@@ -20,6 +21,8 @@
    Result:
                        via TCP socket
    4.       afpd          ------->         cnid_dbd
+
+   cnid_metad and cnid_dbd have been converted to non-blocking IO in 2010.
  */
 
 
 #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>
-#include <sys/ioctl.h>
 
 #ifndef WEXITSTATUS
 #define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
@@ -94,8 +88,8 @@
 #include <atalk/logger.h>
 #include <atalk/cnid_dbd_private.h>
 #include <atalk/paths.h>
+#include <atalk/volinfo.h>
 
-#include "db_param.h"
 #include "usockfd.h"
 
 #define DBHOME        ".AppleDB"
@@ -113,7 +107,7 @@ static volatile sig_atomic_t sigchild = 0;
 #define DEFAULTPORT  "4700"
 
 struct server {
-    char  *name;
+    struct volinfo *volinfo;
     pid_t pid;
     time_t tm;                    /* When respawned last */
     int count;                    /* Times respawned in the last TESTTIME secondes */
@@ -144,11 +138,11 @@ static void sigterm_handler(int sig)
     daemon_exit(0);
 }
 
-static struct server *test_usockfn(char *dir)
+static struct server *test_usockfn(struct volinfo *volinfo)
 {
     int i;
     for (i = 0; i < MAXVOLS; i++) {
-        if (srv[i].name && !strcmp(srv[i].name, dir)) {
+        if ((srv[i].volinfo) && (strcmp(srv[i].volinfo->v_path, volinfo->v_path) == 0)) {
             return &srv[i];
         }
     }
@@ -156,60 +150,7 @@ static struct server *test_usockfn(char *dir)
 }
 
 /* -------------------- */
-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)
+static int maybe_start_dbd(char *dbdpn, struct volinfo *volinfo)
 {
     pid_t pid;
     struct server *up;
@@ -218,31 +159,32 @@ static int maybe_start_dbd(char *dbdpn, char *dbdir, char *usockfn)
     time_t t;
     char buf1[8];
     char buf2[8];
+    char *volpath = volinfo->v_path;
 
-    LOG(log_maxdebug, logtype_cnid, "maybe_start_dbd: dbdir: '%s', UNIX socket file: '%s'", 
-        dbdir, usockfn);
+    LOG(log_debug, logtype_cnid, "maybe_start_dbd: Volume: \"%s\"", volpath);
 
-    up = test_usockfn(dbdir);
+    up = test_usockfn(volinfo);
     if (up && up->pid) {
         /* we already have a process, send our fd */
-        if (send_cred(up->control_fd, rqstfd) < 0) {
+        if (send_fd(up->control_fd, rqstfd) < 0) {
             /* FIXME */
             return -1;
         }
         return 0;
     }
 
-    LOG(log_maxdebug, logtype_cnid, "maybe_start_dbd: no cnid_dbd for that volume yet. Starting one ...");
+    LOG(log_maxdebug, logtype_cnid, "maybe_start_dbd: no cnid_dbd for that volume yet");
 
     time(&t);
     if (!up) {
         /* find an empty slot */
         for (i = 0; i < MAXVOLS; i++) {
-            if ( !srv[i].name ) {
+            if (srv[i].volinfo == NULL) {
                 up = &srv[i];
+                up->volinfo = volinfo;
+                retainvolinfo(volinfo);
                 up->tm = t;
                 up->count = 0;
-                up->name = strdup(dbdir);
                 break;
             }
         }
@@ -250,8 +192,7 @@ static int maybe_start_dbd(char *dbdpn, char *dbdir, char *usockfn)
             LOG(log_error, logtype_cnid, "no free slot for cnid_dbd child. Configured maximum: %d. Do you have so many volumes?", MAXVOLS);
             return -1;
         }
-    }
-    else {
+    } else {
         /* we have a slot but no process, check for respawn too fast */
         if ( (t < (up->tm + TESTTIME)) /* We're in the respawn time window */
              &&
@@ -311,11 +252,11 @@ static int maybe_start_dbd(char *dbdpn, char *dbdir, char *usockfn)
             /* 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, logconfig, NULL);
+            LOG(log_error, logtype_cnid, "try with -d %s", up->volinfo->v_path);
+            ret = execlp(dbdpn, dbdpn, "-d", volpath, buf1, buf2, logconfig, NULL);
         }
         else {
-            ret = execlp(dbdpn, dbdpn, dbdir, buf1, buf2, logconfig, NULL);
+            ret = execlp(dbdpn, dbdpn, volpath, buf1, buf2, logconfig, NULL);
         }
         /* Yikes! We're still here, so exec failed... */
         LOG(log_error, logtype_cnid, "Fatal error in exec: %s", strerror(errno));
@@ -331,12 +272,12 @@ static int maybe_start_dbd(char *dbdpn, char *dbdir, char *usockfn)
 }
 
 /* ------------------ */
-static int set_dbdir(char *dbdir, int len)
+static int set_dbdir(char *dbdir)
 {
+    int len;
     struct stat st;
 
-    if (!len)
-        return -1;
+    len = strlen(dbdir);
 
     if (stat(dbdir, &st) < 0 && mkdir(dbdir, 0755) < 0) {
         LOG(log_error, logtype_cnid, "set_dbdir: mkdir failed for %s", dbdir);
@@ -465,14 +406,13 @@ static void set_signal(void)
 /* ------------------ */
 int main(int argc, char *argv[])
 {
-    char  dbdir[MAXPATHLEN + 1];
+    char  volpath[MAXPATHLEN + 1];
     int   len, actual_len;
     pid_t pid;
     int   status;
     char  *dbdpn = _PATH_CNID_DBD;
     char  *host = DEFAULTHOST;
     char  *port = DEFAULTPORT;
-    struct db_param *dbp;
     int    i;
     int    cc;
     uid_t  uid = 0;
@@ -483,6 +423,7 @@ int main(int argc, char *argv[])
     char   *loglevel = NULL;
     char   *logfile  = NULL;
     sigset_t set;
+    struct volinfo *volinfo;
 
     set_processname("cnid_metad");
 
@@ -543,7 +484,7 @@ int main(int argc, char *argv[])
     }
 
     /* Check PID lockfile and become a daemon */
-    switch(server_lock("cnid_metad", _PATH_CNID_METAD_LOCK, 0)) {
+    switch(server_lock("cnid_metad", _PATH_CNID_METAD_LOCK, debug)) {
     case -1: /* error */
         daemon_exit(EXITERR_SYS);
     case 0: /* child */
@@ -602,9 +543,8 @@ int main(int argc, char *argv[])
         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 = readt(rqstfd, &len, sizeof(int), 1, 5);
+        ret = readt(rqstfd, &len, sizeof(int), 1, 4);
+
         if (!ret) {
             /* already close */
             goto loop_end;
@@ -626,7 +566,7 @@ int main(int argc, char *argv[])
             goto loop_end;
         }
 
-        actual_len = readt(rqstfd, dbdir, len, 1, 5);
+        actual_len = readt(rqstfd, volpath, len, 1, 5);
         if (actual_len < 0) {
             LOG(log_severe, logtype_cnid, "Read(2) error : %s", strerror(errno));
             goto loop_end;
@@ -635,17 +575,21 @@ int main(int argc, char *argv[])
             LOG(log_error, logtype_cnid, "error/short read (dir): %s", strerror(errno));
             goto loop_end;
         }
-        dbdir[len] = '\0';
+        volpath[len] = '\0';
 
-        if (set_dbdir(dbdir, len) < 0) {
+        /* Load .volinfo file */
+        if ((volinfo = allocvolinfo(volpath)) == NULL) {
+            LOG(log_severe, logtype_cnid, "allocvolinfo: %s", strerror(errno));
             goto loop_end;
         }
 
-        if ((dbp = db_param_read(dbdir, METAD)) == NULL) {
-            LOG(log_error, logtype_cnid, "Error reading config file");
+        if (set_dbdir(volinfo->v_dbpath) < 0) {
             goto loop_end;
         }
-        maybe_start_dbd(dbdpn, dbdir, dbp->usock_file);
+
+        maybe_start_dbd(dbdpn, volinfo);
+
+        (void)closevolinfo(volinfo);
 
     loop_end:
         close(rqstfd);
index 284ecae4c2fcb7f4f2664253c957de689eca5461..0a56be91087f79133e175591a44f908fad25e2f3 100644 (file)
@@ -1,7 +1,7 @@
 /*
- * $Id: comm.c,v 1.6 2009-10-19 08:09:07 didg Exp $
- *
  * Copyright (C) Joerg Lenneis 2003
+ * Copyright (C) Frank Lahm 2010
+ *
  * All Rights Reserved.  See COPYING.
  */
 
 #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
+#define _XPG4_2 1
 #include <sys/socket.h>
-#endif
-
 #include <sys/select.h>
-
 #include <assert.h>
 #include <time.h>
 
 #include <atalk/logger.h>
+#include <atalk/util.h>
 #include <atalk/cnid_dbd_private.h>
 
 #include "db_param.h"
@@ -87,51 +69,6 @@ static void invalidate_fd(int 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
@@ -181,7 +118,7 @@ static int check_fd(time_t timeout, const sigset_t *sigmask, time_t *now)
     if (FD_ISSET(control_fd, &readfds)) {
         int    l = 0;
 
-        fd = recv_cred(control_fd);
+        fd = recv_fd(control_fd, 0);
         if (fd < 0) {
             return -1;
         }
@@ -264,8 +201,16 @@ int comm_rcv(struct cnid_dbd_rqst *rqst, time_t timeout, const sigset_t *sigmask
 
     if (!cur_fd)
         return 0;
+
+    LOG(log_maxdebug, logtype_cnid, "comm_rcv: got data on fd %u", cur_fd);
+
+    if (setnonblock(cur_fd, 1) != 0) {
+        LOG(log_error, logtype_cnid, "comm_rcv: setnonblock: %s", strerror(errno));
+        return -1;
+    }
+
     nametmp = rqst->name;
-    if ((b = readt(cur_fd, rqst, sizeof(struct cnid_dbd_rqst), 1, 5))
+    if ((b = readt(cur_fd, rqst, sizeof(struct cnid_dbd_rqst), 1, CNID_DBD_TIMEOUT))
         != sizeof(struct cnid_dbd_rqst)) {
         if (b)
             LOG(log_error, logtype_cnid, "error reading message header: %s", strerror(errno));
@@ -274,7 +219,8 @@ int comm_rcv(struct cnid_dbd_rqst *rqst, time_t timeout, const sigset_t *sigmask
         return 0;
     }
     rqst->name = nametmp;
-    if (rqst->namelen && readt(cur_fd, rqst->name, rqst->namelen, 1, 5) != rqst->namelen) {
+    if (rqst->namelen && readt(cur_fd, rqst->name, rqst->namelen, 1, CNID_DBD_TIMEOUT)
+        != rqst->namelen) {
         LOG(log_error, logtype_cnid, "error reading message name: %s", strerror(errno));
         invalidate_fd(cur_fd);
         return 0;
@@ -283,6 +229,8 @@ int comm_rcv(struct cnid_dbd_rqst *rqst, time_t timeout, const sigset_t *sigmask
        needs zero terminated strings. */
     rqst->name[rqst->namelen] = '\0';
 
+    LOG(log_maxdebug, logtype_cnid, "comm_rcv: got %u bytes", b + rqst->namelen);
+
     return 1;
 }
 
index 614bd27da6adbeedbe166768f08fe811f6c49d7a..46d91fc18fab1c8e97c815e91393ea73c418426e 100644 (file)
@@ -1,6 +1,4 @@
 /*
- * $Id: comm.h,v 1.5 2009-10-19 08:09:07 didg Exp $
- *
  * Copyright (C) Joerg Lenneis 2003
  * All Rights Reserved.  See COPYING.
  */
@@ -8,6 +6,8 @@
 #ifndef CNID_DBD_COMM_H
 #define CNID_DBD_COMM_H 1
 
+/* number of seconds to try reading in readt */
+#define CNID_DBD_TIMEOUT 1
 
 #include <atalk/cnid_dbd_private.h>
 
index 029c21b00124ecafca0615c6cb30f1e1978e2bb7..e31e782759830629536f25a8d95dcffc7517b57c 100644 (file)
@@ -26,7 +26,9 @@
 #define MAXKEYLEN         64
 
 #define DEFAULT_LOGFILE_AUTOREMOVE 1
-#define DEFAULT_CACHESIZE          (8 * 1024)
+#define DEFAULT_CACHESIZE          (8 * 1024) /* KB, so 8 MB */
+#define DEFAULT_MAXLOCKS           5000
+#define DEFAULT_MAXLOCKOBJS        5000
 #define DEFAULT_FLUSH_FREQUENCY    1000
 #define DEFAULT_FLUSH_INTERVAL     1800
 #define DEFAULT_USOCK_FILE         "usock"
@@ -66,6 +68,8 @@ static void default_params(struct db_param *dbp, char *dir)
 {        
     dbp->logfile_autoremove  = DEFAULT_LOGFILE_AUTOREMOVE;
     dbp->cachesize           = DEFAULT_CACHESIZE;
+    dbp->maxlocks            = DEFAULT_MAXLOCKS;
+    dbp->maxlockobjs         = DEFAULT_MAXLOCKOBJS;
     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) {
@@ -98,7 +102,7 @@ static int parse_int(char *val)
    buffer overflow) nor elegant, we need to add support for whitespace in
    filenames as well. */
 
-struct db_param *db_param_read(char *dir, enum identity id)
+struct db_param *db_param_read(char *dir)
 {
     FILE *fp;
     static char key[MAXKEYLEN + 1];
@@ -145,33 +149,32 @@ struct db_param *db_param_read(char *dir, enum identity id)
                 LOG(log_info, logtype_cnid, "db_param: setting UNIX domain socket filename to %s", params.usock_file);
         }
 
-        /* Config for cnid_metad only */
-        if ( id == METAD ) {
-            /* Currently empty */
+        if (! strcmp(key, "fd_table_size")) {
+            params.fd_table_size = parse_int(val);
+            LOG(log_info, logtype_cnid, "db_param: setting max number of concurrent afpd connections per volume (fd_table_size) to %d", params.fd_table_size);
+        } else if (! strcmp(key, "logfile_autoremove")) {
+            params.logfile_autoremove = parse_int(val);
+            LOG(log_info, logtype_cnid, "db_param: setting logfile_autoremove to %d", params.logfile_autoremove);
+        } else if (! strcmp(key, "cachesize")) {
+            params.cachesize = parse_int(val);
+            LOG(log_info, logtype_cnid, "db_param: setting cachesize to %d", params.cachesize);
+        } else if (! strcmp(key, "maxlocks")) {
+            params.maxlocks = parse_int(val);
+            LOG(log_info, logtype_cnid, "db_param: setting maxlocks to %d", params.maxlocks);
+        } else if (! strcmp(key, "maxlockobjs")) {
+            params.maxlockobjs = parse_int(val);
+            LOG(log_info, logtype_cnid, "db_param: setting maxlockobjs to %d", params.maxlockobjs);
+        } else if (! strcmp(key, "flush_frequency")) {
+            params.flush_frequency = parse_int(val);
+            LOG(log_info, logtype_cnid, "db_param: setting flush_frequency to %d", params.flush_frequency);
+        } else if (! strcmp(key, "flush_interval")) {
+            params.flush_interval = parse_int(val);
+            LOG(log_info, logtype_cnid, "db_param: setting flush_interval to %d", params.flush_interval);
+        } else if (! strcmp(key, "idle_timeout")) {
+            params.idle_timeout = parse_int(val);
+            LOG(log_info, logtype_cnid, "db_param: setting idle timeout to %d", params.idle_timeout);
         }
 
-        /* Config for dbd only */
-        else if (id == CNID_DBD ) {
-            if (! strcmp(key, "fd_table_size")) {
-                params.fd_table_size = parse_int(val);
-                LOG(log_info, logtype_cnid, "db_param: setting max number of concurrent afpd connections per volume (fd_table_size) to %d", params.fd_table_size);
-            } else if (! strcmp(key, "logfile_autoremove")) {
-                params.logfile_autoremove = parse_int(val);
-                LOG(log_info, logtype_cnid, "db_param: setting logfile_autoremove to %d", params.logfile_autoremove);
-            } else if (! strcmp(key, "cachesize")) {
-                params.cachesize = parse_int(val);
-                LOG(log_info, logtype_cnid, "db_param: setting cachesize to %d", params.cachesize);
-            } else if (! strcmp(key, "flush_frequency")) {
-                params.flush_frequency = parse_int(val);
-                LOG(log_info, logtype_cnid, "db_param: setting flush_frequency to %d", params.flush_frequency);
-            } else if (! strcmp(key, "flush_interval")) {
-                params.flush_interval = parse_int(val);
-                LOG(log_info, logtype_cnid, "db_param: setting flush_interval to %d", params.flush_interval);
-            } else if (! strcmp(key, "idle_timeout")) {
-                params.idle_timeout = parse_int(val);
-                LOG(log_info, logtype_cnid, "db_param: setting idle timeout to %d", params.idle_timeout);
-            }
-        }
         if (parse_err)
             break;
     }
index ebcea6b823185494b937d31a78df6a0974e36a10..67ec62e4e18c8fc6f40c5f02c8e9f5aa72948621 100644 (file)
@@ -1,7 +1,6 @@
 /*
- * $Id: db_param.h,v 1.6 2009-12-21 07:32:01 franklahm Exp $
- *
  * Copyright (C) Joerg Lenneis 2003
+ * Copyright (C) Frank Lahm 2010
  * All Rights Reserved.  See COPYING.
  */
 
 #include <sys/param.h>
 #include <sys/cdefs.h>
 
-enum identity {
-    METAD,
-    CNID_DBD
-};
-
 struct db_param {
     char *dir;
     int logfile_autoremove;
     int cachesize;              /* in KB */
+    int maxlocks;
+    int maxlockobjs;
     int flush_interval;
     int flush_frequency;
     char usock_file[MAXPATHLEN + 1];    
@@ -28,8 +24,7 @@ struct db_param {
     int max_vols;
 };
 
-extern struct db_param *      db_param_read  (char *, enum identity);
-
+extern struct db_param *db_param_read  (char *);
 
 #endif /* CNID_DBD_DB_PARAM_H */
 
index 0dbff51dba97a4ac133c6ab20469470031c54987..b4f7e5d4a0013adfa8f50be1825d0e9ed7f664bc 100644 (file)
@@ -1,8 +1,6 @@
 /*
- * $Id: dbd.h,v 1.7 2009-11-25 14:59:15 franklahm Exp $
- *
  * Copyright (C) Joerg Lenneis 2003
- * Copyright (C) Frank Lahm 2009
+ * Copyright (C) Frank Lahm 2009, 2010
  * All Rights Reserved.  See COPYING.
  */
 
@@ -14,7 +12,6 @@
 extern int add_cnid(DBD *dbd, struct cnid_dbd_rqst *rqst, struct cnid_dbd_rply *rply);
 extern int get_cnid(DBD *dbd, struct cnid_dbd_rply *rply);
 
-extern int dbd_stamp(DBD *dbd);
 extern int dbd_add(DBD *dbd, struct cnid_dbd_rqst *, struct cnid_dbd_rply *, int nolookup);
 extern int dbd_lookup(DBD *dbd, struct cnid_dbd_rqst *, struct cnid_dbd_rply *, int roflag);
 extern int dbd_get(DBD *dbd, struct cnid_dbd_rqst *, struct cnid_dbd_rply *);
@@ -23,6 +20,7 @@ extern int dbd_update(DBD *dbd, struct cnid_dbd_rqst *, struct cnid_dbd_rply *);
 extern int dbd_delete(DBD *dbd, struct cnid_dbd_rqst *, struct cnid_dbd_rply *, int idx);
 extern int dbd_getstamp(DBD *dbd, struct cnid_dbd_rqst *, struct cnid_dbd_rply *);
 extern int dbd_rebuild_add(DBD *dbd, struct cnid_dbd_rqst *, struct cnid_dbd_rply *);
+extern int dbd_search(DBD *dbd, struct cnid_dbd_rqst *, struct cnid_dbd_rply *);
 extern int dbd_check_indexes(DBD *dbd, char *);
 
 #endif /* CNID_DBD_DBD_H */
index 85676b2e575f5f63722d53047c6d20cd82ff6023..6a818a3b325063f27fe37a0a412d6081bf6bb0b8 100644 (file)
@@ -1,7 +1,6 @@
 /*
- * $Id: dbd_add.c,v 1.8 2010-01-19 14:57:11 franklahm Exp $
- *
  * Copyright (C) Joerg Lenneis 2003
+ * Copyright (C) Frank Lahm 2010
  * All Rights Reserved.  See COPYING.
  */
 
@@ -83,21 +82,35 @@ int add_cnid(DBD *dbd, struct cnid_dbd_rqst *rqst, struct cnid_dbd_rply *rply)
 /* ---------------------- */
 int get_cnid(DBD *dbd, struct cnid_dbd_rply *rply)
 {
+    static cnid_t id;
+    static char buf[ROOTINFO_DATALEN];
     DBT rootinfo_key, rootinfo_data;
     int rc;
-    cnid_t hint, id;
-     
+    cnid_t hint;
+
     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(dbd, DBIF_CNID, &rootinfo_key, &rootinfo_data, 0)) <= 0) {
-        rply->result = CNID_DBD_RES_ERR_DB;
-        return -1;
+    if (id == 0) {
+        if ((rc = dbif_get(dbd, DBIF_CNID, &rootinfo_key, &rootinfo_data, 0)) < 0) {
+            rply->result = CNID_DBD_RES_ERR_DB;
+            return -1;
+        }
+        if (rc == 0) {
+            /* no rootinfo key yet */
+            memcpy(buf, ROOTINFO_DATA, ROOTINFO_DATALEN);
+            id = CNID_START - 1;
+        } else {
+            memcpy(buf, (char *)rootinfo_data.data, ROOTINFO_DATALEN);
+            memcpy(&hint, buf + CNID_TYPE_OFS, sizeof(hint));
+            id = ntohl(hint);
+            if (id < CNID_START - 1)
+                id = CNID_START - 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) {
@@ -105,12 +118,10 @@ int get_cnid(DBD *dbd, struct cnid_dbd_rply *rply)
         return -1;
     }
 
-#if 0
-    memcpy(buf, ROOTINFO_DATA, ROOTINFO_DATALEN);
-#endif    
+    rootinfo_data.data = buf;
     rootinfo_data.size = ROOTINFO_DATALEN;
     hint = htonl(id);
-    memcpy((char *)rootinfo_data.data +CNID_TYPE_OFS, &hint, sizeof(hint));
+    memcpy(buf + CNID_TYPE_OFS, &hint, sizeof(hint));
 
     if (dbif_put(dbd, DBIF_CNID, &rootinfo_key, &rootinfo_data, 0) < 0) {
         rply->result = CNID_DBD_RES_ERR_DB;
@@ -120,44 +131,6 @@ int get_cnid(DBD *dbd, struct cnid_dbd_rply *rply)
     return 0;
 }
 
-/* --------------- 
-*/
-int dbd_stamp(DBD *dbd)
-{
-    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(dbd, DBIF_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(dbd, 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(dbd, DBIF_CNID, &rootinfo_key, &rootinfo_data, 0) < 0) {
-            return -1;
-        }
-        return 0;
-    
-    case 1: /* we already have one */
-        return 0;
-    default:
-        return -1;
-    }
-    return -1;
-}
-
 /* ------------------------ */
 /* We need a nolookup version for `dbd` */
 int dbd_add(DBD *dbd, struct cnid_dbd_rqst *rqst, struct cnid_dbd_rply *rply, int nolookup)
index b7fc936aa893c2df3cfaa4b4cc5020882cf0f01a..ea75c4aba67799356636162a70c5c0a4194c63a4 100644 (file)
@@ -1,3 +1,4 @@
+
 /*
  * $Id: dbd_getstamp.c,v 1.4 2009-05-06 11:54:24 franklahm Exp $
  *
index 6008d152dc10e1d6f550fe915ade078f7094c0cb..17a42de0ff1a5f362885edd4826fd9bbbc6e0521 100644 (file)
@@ -50,8 +50,8 @@ int dbd_resolve(DBD *dbd, struct cnid_dbd_rqst *rqst, struct cnid_dbd_rply *rply
 
     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;
+    rply->namelen = data.size;
+    rply->name = (char *)data.data;
 
     LOG(log_debug, logtype_cnid, "dbd_resolve: Resolving CNID %u to did %u name %s",
         ntohl(rqst->cnid), ntohl(rply->did), rply->name);
diff --git a/etc/cnid_dbd/dbd_search.c b/etc/cnid_dbd/dbd_search.c
new file mode 100644 (file)
index 0000000..a2efc33
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) Frank Lahm 2010
+ * 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_search(DBD *dbd, struct cnid_dbd_rqst *rqst, struct cnid_dbd_rply *rply)
+{
+    DBT key;
+    int results;
+    static char resbuf[DBD_MAX_SRCH_RSLTS * sizeof(cnid_t)];
+
+    LOG(log_debug, logtype_cnid, "dbd_search(\"%s\"):", rqst->name);
+
+    memset(&key, 0, sizeof(key));
+    rply->name = resbuf;
+    rply->namelen = 0;
+
+    key.data = rqst->name;
+    key.size = rqst->namelen;
+
+    if ((results = dbif_search(dbd, &key, resbuf)) < 0) {
+        LOG(log_error, logtype_cnid, "dbd_search(\"%s\"): db error", rqst->name);
+        rply->result = CNID_DBD_RES_ERR_DB;
+        return -1;
+    }
+    if (results) {
+        LOG(log_debug, logtype_cnid, "dbd_search(\"%s\"): %d matches", rqst->name, results);
+        rply->namelen = results * sizeof(cnid_t);
+        rply->result = CNID_DBD_RES_OK;
+    } else {
+        LOG(log_debug, logtype_cnid, "dbd_search(\"%s\"): no matches", rqst->name);
+        rply->result = CNID_DBD_RES_NOTFOUND;
+    }
+
+    return 1;
+}
index ea22816b1cce8944dc53c865e2a38b914091dc96..22237cc49ba065c6642e0e3aa53b04a5b68a4253 100644 (file)
 #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 <atalk/logger.h>
+#include <atalk/util.h>
+
 #include "db_param.h"
 #include "dbif.h"
 #include "pack.h"
 
 #define DB_ERRLOGFILE "db_errlog"
 
-static char *old_dbfiles[] = {"cnid.db", NULL};
-
-/* --------------- */
-static int upgrade_required(const DBD *dbd)
+/*!
+ * Get the db stamp which is the st_ctime of the file "cnid2.db" and store it in buffer
+ */
+static int dbif_stamp(DBD *dbd, void *buffer, int size)
 {
-    int i;
-    int cwd = -1;
-    int ret = 0;
-    int found = 0;
     struct stat st;
+    int         rc,cwd;
 
-    if ( ! dbd->db_filename)
-        /* in memory db */
-        return 0;
+    if (size < 8)
+        return -1;
 
     /* Remember cwd */
     if ((cwd = open(".", O_RDONLY)) < 0) {
@@ -51,30 +48,182 @@ static int upgrade_required(const DBD *dbd)
     /* chdir to db_envhome */
     if ((chdir(dbd->db_envhome)) != 0) {
         LOG(log_error, logtype_cnid, "error chdiring to db_env '%s': %s", dbd->db_envhome, strerror(errno));        
+        return -1;
+    }
+
+    if ((rc = stat(dbd->db_table[DBIF_CNID].name, &st)) < 0) {
+        LOG(log_error, logtype_cnid, "error stating database %s: %s", dbd->db_table[DBIF_CNID].name, db_strerror(errno));
+        return -1;
+    }
+
+    LOG(log_maxdebug, logtype_cnid,"stamp: %s", asctime(localtime(&st.st_ctime)));
+
+    memset(buffer, 0, size);
+    memcpy(buffer, &st.st_ctime, sizeof(st.st_ctime));
+
+    if ((fchdir(cwd)) != 0) {
+        LOG(log_error, logtype_cnid, "error chdiring back: %s", strerror(errno));        
+        return -1;
+    }
+
+    return 0;
+}
+
+/*!
+ * Inititialize rootinfo key (which has CNID 0 as key)
+ *
+ * This also "stamps" the database, which means storing st.st_ctime of the
+ * "cnid2.db" file in the rootinfo data at the DEV offset
+ *
+ * @param dbd      (rw) database handle
+ * @param version  (r)  database version number
+ *
+ * @returns -1 on error, 0 on success
+ */
+static int dbif_init_rootinfo(DBD *dbd, int version)
+{
+    DBT key, data;
+    uint32_t v;
+    char buf[ROOTINFO_DATALEN];
+
+    LOG(log_debug, logtype_cnid, "Setting CNID database version to %u", version);
+
+    v = version;
+    v = htonl(v);
+
+    memset(&key, 0, sizeof(key));
+    memset(&data, 0, sizeof(data));
+    key.data = ROOTINFO_KEY;
+    key.size = ROOTINFO_KEYLEN;
+    data.data = buf;
+    data.size = ROOTINFO_DATALEN;
+
+    memcpy(buf, ROOTINFO_DATA, ROOTINFO_DATALEN);
+    memcpy(buf + CNID_DID_OFS, &v, sizeof(v));
+    if (dbif_stamp(dbd, buf + CNID_DEV_OFS, CNID_DEV_LEN) < 0)
+        return -1;
+
+    if (dbif_put(dbd, DBIF_CNID, &key, &data, 0) < 0)
+        return -1;
+    if (dbif_txn_commit(dbd) != 1) {
+        LOG(log_error, logtype_cnid, "dbif_init_rootinfo: cant commit txn");
+        return -1;
+    }
+
+    return 0;
+}
+
+/*!
+ * Return CNID database version number
+ *
+ * Returns version in *version
+ *
+ * @returns -1 on error, 0 if theres no rootinfo key yet, 1 if *version is returned
+ */
+static int dbif_getversion(DBD *dbd, uint32_t *version)
+{
+    DBT key, data;
+    int ret;
+
+    LOG(log_maxdebug, logtype_cnid, "dbif_getversion: reading version info");
+
+    *version = -1;
+    memset(&key, 0, sizeof(key));
+    memset(&data, 0, sizeof(data));
+    key.data = ROOTINFO_KEY;
+    key.size = ROOTINFO_KEYLEN;
+
+    switch (dbif_get(dbd, DBIF_CNID, &key, &data, 0)) {
+    case 1: /* found */
+        memcpy(version, (char *)data.data + CNID_DID_OFS, sizeof(uint32_t));
+        *version = ntohl(*version);
+        LOG(log_debug, logtype_cnid, "CNID database version %u", *version);
+        ret = 1;
+        break;
+    case 0: /* not found */
+        LOG(log_debug, logtype_cnid, "dbif_getversion: no version info found");
+        ret = 0;
+        break;
+    default:
+        LOG(log_error, logtype_cnid, "dbif_getversion: database error");
         ret = -1;
-        goto exit;
+        break;
     }
 
-    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 ret;
+}
+
+/*!
+ * Set CNID database version number
+ *
+ * Initializes rootinfo key as neccessary
+ * @returns -1 on error, 0 on success
+ */
+static int dbif_setversion(DBD *dbd, uint32_t version)
+{
+    int ret;
+    DBT key, data;
+    uint32_t v;
+
+    LOG(log_debug, logtype_cnid, "Setting CNID database version to %u", version);
+
+    v = version;
+    v = htonl(v);
+
+    memset(&key, 0, sizeof(key));
+    memset(&data, 0, sizeof(data));
+    key.data = ROOTINFO_KEY;
+    key.size = ROOTINFO_KEYLEN;
+
+    if ((ret = dbif_get(dbd, DBIF_CNID, &key, &data, 0)) == -1)
+        return -1;
+    if (ret == 0) {
+        /* No rootinfo key yet, init it */
+        if (dbif_init_rootinfo(dbd, CNID_VERSION) != 0)
+            return -1;
+        /* Now try again */
+        if (dbif_get(dbd, DBIF_CNID, &key, &data, 0) == -1)
+            return -1;
     }
+    memcpy((char *)data.data + CNID_DID_OFS, &v, sizeof(v));
+    data.size = ROOTINFO_DATALEN;
+    if (dbif_put(dbd, DBIF_CNID, &key, &data, 0) < 0)
+        return -1;
 
-exit:
-    if (cwd != -1) {
-        if ((fchdir(cwd)) != 0) {
-            LOG(log_error, logtype_cnid, "error chdiring back: %s", strerror(errno));        
-            ret = -1;
-        }
-        close(cwd);
+    return 0;
+}
+
+/*!
+ * Upgrade CNID database versions, initialize rootinfo key as as necessary in dbif_setversion()
+ *
+ * For now this does nothing, as upgrading from ver. 0 to 1 is done in dbif_open
+ */
+#define UNINTIALIZED_DB UINT32_MAX
+static int dbif_upgrade(DBD *dbd)
+{
+    uint32_t version = CNID_VERSION_UNINTIALIZED_DB;
+
+    if (dbif_getversion(dbd, &version) == -1)
+        return -1;
+    if (version == CNID_VERSION_UNINTIALIZED_DB) {
+        version = CNID_VERSION;
+        if (dbif_setversion(dbd, CNID_VERSION) != 0)
+            return -1;
     }
-    return (ret < 0 ? ret : found);
+
+    /* 
+     * Do upgrade stuff ...
+     */
+
+    /* Write current version to database */
+    if (version != CNID_VERSION) {
+        if (dbif_setversion(dbd, CNID_VERSION) != 0)
+            return -1;
+    }
+
+    LOG(log_debug, logtype_cnid, "Finished CNID database version upgrade check");
+
+    return 0;
 }
 
 /* --------------- */
@@ -172,42 +321,6 @@ exit:
     return ret;
 }
 
-/* --------------- */
-int dbif_stamp(DBD *dbd, void *buffer, int size)
-{
-    struct stat st;
-    int         rc,cwd;
-
-    if (size < 8)
-        return -1;
-
-    /* Remember cwd */
-    if ((cwd = open(".", O_RDONLY)) < 0) {
-        LOG(log_error, logtype_cnid, "error opening cwd: %s", strerror(errno));
-        return -1;
-    }
-
-    /* chdir to db_envhome */
-    if ((chdir(dbd->db_envhome)) != 0) {
-        LOG(log_error, logtype_cnid, "error chdiring to db_env '%s': %s", dbd->db_envhome, strerror(errno));        
-        return -1;
-    }
-
-    if ((rc = stat(dbd->db_table[DBIF_CNID].name, &st)) < 0) {
-        LOG(log_error, logtype_cnid, "error stating database %s: %s", dbd->db_table[DBIF_CNID].name, db_strerror(errno));
-        return -1;
-    }
-    memset(buffer, 0, size);
-    memcpy(buffer, &st.st_ctime, sizeof(st.st_ctime));
-
-    if ((fchdir(cwd)) != 0) {
-        LOG(log_error, logtype_cnid, "error chdiring back: %s", strerror(errno));        
-        return -1;
-    }
-
-    return 0;
-}
-
 /* --------------- */
 DBD *dbif_init(const char *envhome, const char *filename)
 {
@@ -238,14 +351,19 @@ DBD *dbif_init(const char *envhome, const char *filename)
     dbd->db_table[DBIF_CNID].name        = "cnid2.db";
     dbd->db_table[DBIF_IDX_DEVINO].name  = "devino.db";
     dbd->db_table[DBIF_IDX_DIDNAME].name = "didname.db";
+    dbd->db_table[DBIF_IDX_NAME].name    = "name.db";
 
     dbd->db_table[DBIF_CNID].type        = DB_BTREE;
     dbd->db_table[DBIF_IDX_DEVINO].type  = DB_BTREE;
     dbd->db_table[DBIF_IDX_DIDNAME].type = DB_BTREE;
+    dbd->db_table[DBIF_IDX_NAME].type    = DB_BTREE;
 
     dbd->db_table[DBIF_CNID].openflags        = DB_CREATE;
     dbd->db_table[DBIF_IDX_DEVINO].openflags  = DB_CREATE;
     dbd->db_table[DBIF_IDX_DIDNAME].openflags = DB_CREATE;
+    dbd->db_table[DBIF_IDX_NAME].openflags    = DB_CREATE;
+
+    dbd->db_table[DBIF_IDX_NAME].flags = DB_DUPSORT;
 
     return dbd;
 }
@@ -253,7 +371,7 @@ DBD *dbif_init(const char *envhome, const char *filename)
 /* 
    We must open the db_env with an absolute pathname, as `dbd` keeps chdir'ing, which
    breaks e.g. bdb logfile-rotation with relative pathnames.
-   But still we use relative paths with upgrade_required() and the DB_ERRLOGFILE
+   But still we use relative paths with DB_ERRLOGFILE
    in order to avoid creating absolute paths by copying. Both have no problem with
    a relative path.
 */
@@ -261,12 +379,6 @@ int dbif_env_open(DBD *dbd, struct db_param *dbp, uint32_t dbenv_oflags)
 {
     int ret;
 
-    /* Refuse to do anything if this is an old version of the CNID database */
-    if (upgrade_required(dbd)) {
-        LOG(log_error, logtype_cnid, "Found version 1 of the CNID database. Please upgrade to version 2");
-        return -1;
-    }
-
     if ((ret = db_env_create(&dbd->db_env, 0))) {
         LOG(log_error, logtype_cnid, "error creating DB environment: %s",
             db_strerror(ret));
@@ -324,6 +436,22 @@ int dbif_env_open(DBD *dbd, struct db_param *dbp, uint32_t dbenv_oflags)
         return -1;
     }
 
+    if ((ret = dbd->db_env->set_lk_max_locks(dbd->db_env, dbp->maxlocks))) {
+        LOG(log_error, logtype_cnid, "error setting DB environment maxlocks to %i: %s",
+            10000, db_strerror(ret));
+        dbd->db_env->close(dbd->db_env, 0);
+        dbd->db_env = NULL;
+        return -1;
+    }
+
+    if ((ret = dbd->db_env->set_lk_max_objects(dbd->db_env, dbp->maxlockobjs))) {
+        LOG(log_error, logtype_cnid, "error setting DB environment max lockobjects to %i: %s",
+            10000, db_strerror(ret));
+        dbd->db_env->close(dbd->db_env, 0);
+        dbd->db_env = NULL;
+        return -1;
+    }
+
     if ((ret = dbd->db_env->open(dbd->db_env, dbd->db_envhome, dbenv_oflags, 0))) {
         LOG(log_error, logtype_cnid, "error opening DB environment after recovery: %s",
             db_strerror(ret));
@@ -406,7 +534,7 @@ int dbif_open(DBD *dbd, struct db_param *dbp, int reindex)
                 LOG(log_error, logtype_cnid, "error forcing checkpoint: %s", db_strerror(ret));
                 return -1;
             }
-            LOG(log_debug, logtype_cnid, "Finished CNID database upgrade check");
+            LOG(log_debug, logtype_cnid, "Finished BerkeleyBD upgrade check");
         }
         
         if ((fchdir(cwd)) != 0) {
@@ -495,6 +623,38 @@ int dbif_open(DBD *dbd, struct db_param *dbp, int reindex)
     }
     if (reindex)
         LOG(log_info, logtype_cnid, "... done.");
+
+    if (reindex)
+        LOG(log_info, logtype_cnid, "Reindexing name index...");
+
+    /*
+     * Upgrading from version 0 to 1 requires adding the name index below which
+     * must be done by specifying the DB_CREATE flag
+     */
+    uint32_t version = CNID_VERSION;
+    if (dbd->db_envhome && !reindex) {
+        if (dbif_getversion(dbd, &version) == -1)
+            return -1;
+    }
+
+    if ((ret = dbd->db_table[0].db->associate(dbd->db_table[0].db, 
+                                              dbd->db_txn,
+                                              dbd->db_table[DBIF_IDX_NAME].db, 
+                                              idxname,
+                                              (reindex
+                                               || 
+                                               ((CNID_VERSION == CNID_VERSION_1) && (version == CNID_VERSION_0)))
+                                              ? DB_CREATE : 0)) != 0) {
+        LOG(log_error, logtype_cnid, "Failed to associate name index: %s", db_strerror(ret));
+        return -1;
+    }
+    if (reindex)
+        LOG(log_info, logtype_cnid, "... done.");
+
+    if ((dbd->db_envhome) && ((ret = dbif_upgrade(dbd)) != 0)) {
+        LOG(log_error, logtype_cnid, "Error upgrading CNID database to version %d", CNID_VERSION);
+        return -1;
+    }
     
     return 0;
 }
@@ -548,7 +708,7 @@ int dbif_close(DBD *dbd)
    In order to support silent database upgrades:
    destroy env at cnid_dbd shutdown.
  */
-int dbif_prep_upgrade(const char *path)
+int dbif_env_remove(const char *path)
 {
     int ret;
     DBD *dbd;
@@ -715,8 +875,10 @@ int dbif_del(DBD *dbd, const int dbi, DBT *key, u_int32_t flags)
                                      key,
                                      flags);
     
-    if (ret == DB_NOTFOUND || ret == DB_SECONDARY_BAD)
+    if (ret == DB_NOTFOUND) {
+        LOG(log_info, logtype_cnid, "key not found");
         return 0;
+    }
     if (ret) {
         LOG(log_error, logtype_cnid, "error deleting key/value from %s: %s",
             dbd->db_table[dbi].name, db_strerror(ret));
@@ -725,6 +887,60 @@ int dbif_del(DBD *dbd, const int dbi, DBT *key, u_int32_t flags)
         return 1;
 }
 
+/*!
+ * Search the database by name
+ *
+ * @param resbuf    (w) buffer for search results CNIDs, maxsize is assumed to be
+ *                      DBD_MAX_SRCH_RSLTS * sizefof(cnid_t)
+ *
+ * @returns -1 on error, 0 when nothing found, else the number of matches
+ */
+int dbif_search(DBD *dbd, DBT *key, char *resbuf)
+{
+    int ret = 0;
+    int count = 0;
+    DBC *cursorp = NULL;
+    DBT pkey, data;
+    char *cnids = resbuf;
+    cnid_t cnid;
+    char *namebkp = key->data;
+    int namelenbkp = key->size;
+
+    memset(&pkey, 0, sizeof(DBT));
+    memset(&data, 0, sizeof(DBT));
+
+    /* Get a cursor */
+    ret = dbd->db_table[DBIF_IDX_NAME].db->cursor(dbd->db_table[DBIF_IDX_NAME].db,
+                                                  NULL,
+                                                  &cursorp,
+                                                  0);
+    if (ret != 0) {
+        LOG(log_error, logtype_cnid, "Couldn't create cursor: %s", db_strerror(ret));
+        ret = -1;
+        goto exit;
+    }
+
+    ret = cursorp->pget(cursorp, key, &pkey, &data, DB_SET_RANGE);
+    while (count < DBD_MAX_SRCH_RSLTS && ret != DB_NOTFOUND) {
+        if (!((namelenbkp <= key->size) && (strncmp(namebkp, key->data, namelenbkp) == 0)))
+            break;
+        count++;
+        memcpy(cnids, pkey.data, sizeof(cnid_t));
+        memcpy(&cnid, pkey.data, sizeof(cnid_t));
+        cnids += sizeof(cnid_t);
+        LOG(log_debug, logtype_cnid, "match: CNID %" PRIu32, ntohl(cnid));
+
+        ret = cursorp->pget(cursorp, key, &pkey, &data, DB_NEXT);
+    }
+
+    ret = count;
+
+exit:
+    if (cursorp != NULL)
+        cursorp->close(cursorp);
+    return ret;
+}
+
 int dbif_txn_begin(DBD *dbd)
 {
     int ret;
@@ -871,7 +1087,7 @@ int dbif_copy_rootinfokey(DBD *srcdbd, DBD *destdbd)
 int dbif_dump(DBD *dbd, int dumpindexes)
 {
     int rc;
-    uint32_t max = 0, count = 0, cnid, type, did, lastid;
+    uint32_t max = 0, count = 0, cnid, type, did, lastid, version;
     uint64_t dev, ino;
     time_t stamp;
     DBC *cur;
@@ -898,11 +1114,15 @@ int dbif_dump(DBD *dbd, int dumpindexes)
 
         /* Rootinfo node ? */
         if (cnid == 0) {
-            memcpy(&stamp, (char *)data.data + 4, sizeof(time_t));
-            memcpy(&lastid, (char *)data.data + 20, sizeof(cnid_t));
+            memcpy(&stamp, (char *)data.data + CNID_DEV_OFS, sizeof(time_t));
+            memcpy(&lastid, (char *)data.data + CNID_TYPE_OFS, CNID_TYPE_LEN);
             lastid = ntohl(lastid);
+            memcpy(&version, (char *)data.data + CNID_DID_OFS, CNID_DID_LEN);
+            version = ntohl(version);
+
             strftime(timebuf, sizeof(timebuf), "%b %d %Y %H:%M:%S", localtime(&stamp));
-            printf("dbd stamp: 0x%08x (%s), next free CNID: %u\n", (unsigned int)stamp, timebuf, lastid + 1);
+            printf("CNID db version: %u, dbd stamp: 0x%08x (%s), next free CNID: %u\n",
+                   version, (unsigned int)stamp, timebuf, lastid + 1);
         } else {
             /* dev */
             memcpy(&dev, (char *)data.data + CNID_DEV_OFS, 8);
index e2903b284b7325c01991e3f1f588115b39d1b58e..9c886fb1f9d60e960c099cb0b5c4920ab2af575c 100644 (file)
 #include <atalk/adouble.h>
 #include "db_param.h"
 
-#define DBIF_DB_CNT 3
+#define DBIF_DB_CNT 4
  
 #define DBIF_CNID          0
 #define DBIF_IDX_DEVINO    1
 #define DBIF_IDX_DIDNAME   2
+#define DBIF_IDX_NAME      3
 
 /* Structures */
 typedef struct {
@@ -80,7 +81,7 @@ typedef struct {
     char     *db_envhome;
     char     *db_filename;
     FILE     *db_errlog;
-    db_table db_table[3];
+    db_table db_table[DBIF_DB_CNT];
 } DBD;
 
 /* Functions */
@@ -88,14 +89,14 @@ extern DBD *dbif_init(const char *envhome, const char *dbname);
 extern int dbif_env_open(DBD *dbd, struct db_param *dbp, uint32_t dbenv_oflags);
 extern int dbif_open(DBD *dbd, struct db_param *dbp, int reindex);
 extern int dbif_close(DBD *dbd);
-extern int dbif_prep_upgrade(const char *path);
+extern int dbif_env_remove(const char *path);
 
 extern int dbif_get(DBD *, const int, DBT *, DBT *, u_int32_t);
 extern int dbif_pget(DBD *, const int, DBT *, DBT *, DBT *, u_int32_t);
 extern int dbif_put(DBD *, const int, DBT *, DBT *, u_int32_t);
 extern int dbif_del(DBD *, const int, DBT *, u_int32_t);
 extern int dbif_count(DBD *, const int, u_int32_t *);
-extern int dbif_stamp(DBD *, void *, int);
+extern int dbif_search(DBD *dbd, DBT *key, char *resbuf);
 extern int dbif_copy_rootinfokey(DBD *srcdbd, DBD *destdbd);
 extern int dbif_txn_begin(DBD *);
 extern int dbif_txn_commit(DBD *);
index 42cf28489f14e61c055a73a73eb9a75a74742347..da4cd9a4e7085d764590140786580a3e82a3bb9d 100644 (file)
@@ -1,6 +1,4 @@
 /*
- * $Id: main.c,v 1.16 2009-11-25 14:59:15 franklahm Exp $
- *
  * Copyright (C) Joerg Lenneis 2003
  * Copyright (c) Frank Lahm 2009
  * All Rights Reserved.  See COPYING.
@@ -34,6 +32,7 @@
 #include <netatalk/endian.h>
 #include <atalk/cnid_dbd_private.h>
 #include <atalk/logger.h>
+#include <atalk/volinfo.h>
 
 #include "db_param.h"
 #include "dbif.h"
  */
 #define DBOPTIONS (DB_CREATE | DB_INIT_LOG | DB_INIT_MPOOL | DB_INIT_LOCK | DB_INIT_TXN | DB_RECOVER)
 
-static DBD *dbd;
+/* Global, needed by pack.c:idxname() */
+struct volinfo volinfo;
 
+static DBD *dbd;
 static int exit_sig = 0;
 
 static void sig_exit(int signo)
@@ -176,12 +177,15 @@ static int loop(struct db_param *dbp)
             case CNID_DBD_OP_REBUILD_ADD:
                 ret = dbd_rebuild_add(dbd, &rqst, &rply);
                 break;
+            case CNID_DBD_OP_SEARCH:
+                ret = dbd_search(dbd, &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) {
                 dbif_txn_abort(dbd);
                 return -1;
@@ -270,6 +274,7 @@ static int get_lock(void)
 
     if (fcntl(lockfd, F_SETLK, &lock) < 0) {
         if (errno == EACCES || errno == EAGAIN) {
+            LOG(log_error, logtype_cnid, "get_lock: locked");
             exit(0);
         } else {
             LOG(log_error, logtype_cnid, "main: fcntl F_WRLCK lockfile: %s", strerror(errno));
@@ -321,7 +326,7 @@ int main(int argc, char *argv[])
     struct db_param *dbp;
     int err = 0;
     int lockfd, ctrlfd, clntfd;
-    char *dir, *logconfig;
+    char *logconfig;
 
     set_processname("cnid_dbd");
 
@@ -331,30 +336,47 @@ int main(int argc, char *argv[])
         exit(1);
     }
 
-    dir = argv[1];
     ctrlfd = atoi(argv[2]);
     clntfd = atoi(argv[3]);
     logconfig = strdup(argv[4]);
     setuplog(logconfig);
 
-    switch_to_user(dir);
+    /* Load .volinfo file */
+    if (loadvolinfo(argv[1], &volinfo) == -1) {
+        LOG(log_error, logtype_cnid, "Cant load volinfo for \"%s\"", argv[1]);
+        exit(EXIT_FAILURE);
+    }
+    /* Put "/.AppleDB" at end of volpath, get path from volinfo file */
+    char dbpath[MAXPATHLEN+1];
+    if ((strlen(volinfo.v_dbpath) + strlen("/.AppleDB")) > MAXPATHLEN ) {
+        LOG(log_error, logtype_cnid, "CNID db pathname too long: \"%s\"", volinfo.v_dbpath);
+        exit(EXIT_FAILURE);
+    }
+    strncpy(dbpath, volinfo.v_dbpath, MAXPATHLEN - strlen("/.AppleDB"));
+    strcat(dbpath, "/.AppleDB");
+
+    if (vol_load_charsets(&volinfo) == -1) {
+        LOG(log_error, logtype_cnid, "Error loading charsets!");
+        exit(EXIT_FAILURE);
+    }
+    LOG(log_debug, logtype_cnid, "db dir: \"%s\"", dbpath);
+
+    switch_to_user(dbpath);
 
     /* 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 are in pselect */
     block_sigs_onoff(1);
 
-    if ((dbp = db_param_read(dir, CNID_DBD)) == NULL)
+    if ((dbp = db_param_read(dbpath)) == NULL)
         exit(1);
     LOG(log_maxdebug, logtype_cnid, "Finished parsing db_param config file");
 
-    if (NULL == (dbd = dbif_init(".", "cnid2.db")))
+    if (NULL == (dbd = dbif_init(dbpath, "cnid2.db")))
         exit(2);
 
     if (dbif_env_open(dbd, dbp, DBOPTIONS) < 0)
@@ -367,12 +389,6 @@ int main(int argc, char *argv[])
     }
     LOG(log_debug, logtype_cnid, "Finished opening BerkeleyDB databases");
 
-    if (dbd_stamp(dbd) < 0) {
-        dbif_close(dbd);
-        exit(5);
-    }
-    LOG(log_maxdebug, logtype_cnid, "Finished checking database stamp");
-
     if (comm_init(dbp, ctrlfd, clntfd) < 0) {
         dbif_close(dbd);
         exit(3);
@@ -384,7 +400,7 @@ int main(int argc, char *argv[])
     if (dbif_close(dbd) < 0)
         err++;
 
-    if (dbif_prep_upgrade(dir) < 0)
+    if (dbif_env_remove(dbpath) < 0)
         err++;
 
     free_lock(lockfd);
index 1b4a15be588646fff8814ff9f2557abc08d02f7e..2612469415eaa5582d71712bca82dc5b63c33770 100644 (file)
@@ -1,7 +1,6 @@
 /*
- * $Id: pack.c,v 1.6 2009-10-13 22:55:37 didg Exp $
- *
  * Copyright (C) Joerg Lenneis 2003
+ * Copyright (C) Frank Lahm 2010
  * All Rights Reserved.  See COPYING.
  */
 
 #include <netatalk/endian.h>
 
 #include <string.h>
-#ifdef HAVE_SYS_TYPES_H
-#include <sys/types.h>
-#endif /* HAVE_SYS_TYPES_H */
+#include <inttypes.h>
 #include <sys/param.h>
 #include <sys/cdefs.h>
 #include <db.h>
 
+#include <atalk/unicode.h>
+#include <atalk/volinfo.h>
+#include <atalk/logger.h>
 #include <atalk/cnid_dbd_private.h>
 #include "pack.h"
 
+/* in main.c for `cnid_dbd` or cmd_dbd.c for `dbd` */
+extern struct volinfo volinfo;
+
 /* --------------- */
 /*
  *  This implementation is portable, but could probably be faster by using htonl
@@ -72,6 +75,29 @@ int devino(DB *dbp _U_, const DBT *pkey _U_,  const DBT *pdata, DBT *skey)
     return (0);
 }
 
+/* --------------- */
+int idxname(DB *dbp _U_, const DBT *pkey _U_,  const DBT *pdata, DBT *skey)
+{
+    static char buffer[MAXPATHLEN +2];
+    uint16_t flags = CONV_TOLOWER;
+    memset(skey, 0, sizeof(DBT));
+
+    if (convert_charset(volinfo.v_volcharset,
+                        volinfo.v_volcharset,
+                        volinfo.v_maccharset,
+                        (char *)pdata->data + CNID_NAME_OFS,
+                        strlen((char *)pdata->data + CNID_NAME_OFS),
+                        buffer,
+                        MAXPATHLEN,
+                        &flags) == (size_t)-1) {
+        LOG(log_error, logtype_cnid, "idxname: conversion error");
+    }
+
+    skey->data = buffer;
+    skey->size = strlen(skey->data);
+    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. */
index fb6984991d666e9caad2011c14abb63ad0674931..e94ef0d9a11a827faf2aa3b3e4145ce52df0b52b 100644 (file)
@@ -1,7 +1,6 @@
 /*
- * $Id: pack.h,v 1.5 2009-05-04 09:09:43 franklahm Exp $
- *
  * Copyright (C) Joerg Lenneis 2003
+ * Copyright (C) Frank Lahm 2010
  * All Rights Reserved.  See COPYING.
  */
 
@@ -23,5 +22,6 @@
 extern unsigned char *pack_cnid_data(struct cnid_dbd_rqst *);
 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);
+extern int idxname(DB *dbp, const DBT *pkey, const DBT *pdata, DBT *skey);
 
 #endif /* CNID_DBD_PACK_H */
index 1817c0bc0a0756115a171d56af6f7e8941cda771..ceb6ff211ad6628693b18e48bb2c1fbec2925c03 100644 (file)
@@ -1,6 +1,4 @@
 /*
- * $Id: usockfd.c,v 1.6 2009-11-05 14:38:07 franklahm Exp $
- *
  * Copyright (C) Joerg Lenneis 2003
  * All Rights Reserved.  See COPYING.
  */
index 690005640a0dff0ec9449e2121798a8998302367..2bf09187b4c6cb996e3a729d0e9c776cabde0311 100644 (file)
@@ -4,8 +4,8 @@ atalkincludedir = $(includedir)/atalk
 atalkinclude_HEADERS = \
        adouble.h vfs.h aep.h afp.h asp.h atp.h boolean.h \
        cnid.h compat.h ddp.h dsi.h ldapconfig.h list.h logger.h \
-       nbp.h netddp.h pap.h paths.h rtmp.h server_child.h \
+       nbp.h netddp.h pap.h paths.h queue.h rtmp.h server_child.h \
        server_ipc.h tdb.h uam.h unicode.h util.h uuid.h volinfo.h \
        zip.h ea.h acl.h unix.h directory.h hash.h volume.h
 
-noinst_HEADERS = cnid_dbd_private.h cnid_private.h
+noinst_HEADERS = cnid_dbd_private.h cnid_private.h bstradd.h bstrlib.h errchk.h ftw.h
index c49ed0f49afdac9ace06dfb44c0f09f8d59b4a6d..53d10b19aa011383c1d8f40788f4984332e70b18 100644 (file)
@@ -1,5 +1,4 @@
 /*
-   $Id: acl.h,v 1.1 2009-10-14 15:04:01 franklahm Exp $
    Copyright (c) 2009 Frank Lahm <franklahm@gmail.com>
 
    This program is free software; you can redistribute it and/or modify
 #include "config.h"
 #endif /* HAVE_CONFIG_H */
 
-#ifdef HAVE_NFSv4_ACLS
+#ifdef HAVE_ACLS
+
+#ifdef HAVE_SOLARIS_ACLS
 #include <sys/acl.h>
-#endif  /* HAVE_NFSv4_ACLS */
+#endif  /* HAVE_SOLARIS_ACLS */
 
-/* Solaris NFSv4 ACL stuff */
-#ifdef HAVE_NFSv4_ACLS
+#ifdef HAVE_POSIX_ACLS
+#include <sys/types.h>
+#include <sys/acl.h>
+#endif /* HAVE_POSIX_ACLS */
 
+#ifdef HAVE_SOLARIS_ACLS
 #define chmod nfsv4_chmod
-
 extern int get_nfsv4_acl(const char *name, ace_t **retAces);
-extern int remove_acl(const char *name);
 extern int strip_trivial_aces(ace_t **saces, int sacecount);
 extern int strip_nontrivial_aces(ace_t **saces, int sacecount);
 extern ace_t *concat_aces(ace_t *aces1, int ace1count, ace_t *aces2, int ace2count);
 extern int nfsv4_chmod(char *name, mode_t mode);
-#endif /* HAVE_NFSv4_ACLS */
+#endif /* HAVE_SOLARIS_ACLS */
+
+extern int remove_acl_vfs(const char *name);
 
+#endif /* HAVE_ACLS */
 
-#endif  /* ATALK_ACL_H */
+#endif /* ATALK_ACL_H */
index 7f10c1d6889dba3f5a4acfe07ff8f88a82800c3c..18422eca680dc89c2950813d36cfe7ff97b50073 100644 (file)
   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
+#ifndef _XOPEN_SOURCE
 #define _XOPEN_SOURCE 500
 #endif
+#endif
 
 #include <sys/types.h>
 #include <sys/stat.h>
index b93eb8bce4ea0dd129ee25362ee8f4268cc0f57e..303e705047f58fa5b7b88a799222034dcb282670 100644 (file)
@@ -43,20 +43,19 @@ typedef u_int16_t AFPUserBytes;
 #define AFPTRANS_ALL          (AFPTRANS_DDP | AFPTRANS_TCP)
 
 /* server flags */
-#define AFPSRVRINFO_COPY        (1<<0)  /* supports copyfile */
-#define AFPSRVRINFO_PASSWD      (1<<1)  /* supports change password */
+#define AFPSRVRINFO_COPY         (1<<0)  /* supports copyfile */
+#define AFPSRVRINFO_PASSWD       (1<<1)  /* supports change password */
 #define AFPSRVRINFO_NOSAVEPASSWD (1<<2)  /* don't allow save password */
 #define AFPSRVRINFO_SRVMSGS      (1<<3)  /* supports server messages */
 #define AFPSRVRINFO_SRVSIGNATURE (1<<4)  /* supports server signature */
 #define AFPSRVRINFO_TCPIP        (1<<5)  /* supports tcpip */
 #define AFPSRVRINFO_SRVNOTIFY    (1<<6)  /* supports server notifications */ 
-
 #define AFPSRVRINFO_SRVRECONNECT (1<<7)  /* supports server reconnect */ 
 #define AFPSRVRINFO_SRVRDIR      (1<<8)  /* supports directories service */ 
-
 #define AFPSRVRINFO_SRVUTF8      (1<<9)  /* supports UTF8 names AFP 3.1 */ 
 #define AFPSRVRINFO_UUID         (1<<10) /* supports UUIDs */
-#define AFPSRVRINFO_FASTBOZO    (1<<15) /* fast copying */
+#define AFPSRVRINFO_EXTSLEEP     (1<<11) /* supports extended sleep */
+#define AFPSRVRINFO_FASTBOZO     (1<<15) /* fast copying */
 
 #define AFP_OK         0
 #define AFPERR_DID1     -4000   /* not an afp error DID is 1*/
@@ -129,6 +128,11 @@ typedef enum {
   AFPMESG_SERVER = 1
 } afpmessage_t;
 
+/* extended sleep flag */
+#define AFPZZZ_EXT_SLEEP  1
+#define AFPZZZ_EXT_WAKEUP 2
+
+
 /* AFP functions */
 #define AFP_BYTELOCK        1
 #define AFP_CLOSEVOL            2
@@ -213,4 +217,7 @@ typedef enum {
 #define AFP_SETACL              74
 #define AFP_ACCESS              75
 
+/* more defines */
+#define REPLAYCACHE_SIZE 128
+
 #endif
diff --git a/include/atalk/bstradd.h b/include/atalk/bstradd.h
new file mode 100644 (file)
index 0000000..310349b
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+   Copyright (c) 2010 Frank Lahm <franklahm@gmail.com>
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+*/
+
+/*!
+ * @file
+ * Additional functions for bstrlib.
+ */
+
+#ifndef ATALK_BSTRADD_H
+#define ATALK_BSTRADD_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <atalk/bstrlib.h>
+
+#define cfrombstr(b) ((char *)((b)->data))
+
+/* strip slashes from end of a bstring */
+#define BSTRING_STRIP_SLASH(a)                      \
+    do {                                            \
+        while (bchar((a), blength(a) - 1) == '/')   \
+            bdelete((a), blength(a) - 1, 1);        \
+    } while (0);
+
+typedef struct tagbstring static_bstring;
+
+extern bstring brefcstr(const char *str);
+extern int bunrefcstr(bstring b);
+
+extern struct bstrList *bstrListCreateMin(int min);
+extern int bstrListPush(struct bstrList *sl, bstring bs);
+extern bstring bstrListPop(struct bstrList *sl);
+extern bstring bjoinInv(const struct bstrList * bl, const_bstring sep);
+#endif /* ATALK_BSTRADD_H */
diff --git a/include/atalk/bstrlib.h b/include/atalk/bstrlib.h
new file mode 100644 (file)
index 0000000..0cd3719
--- /dev/null
@@ -0,0 +1,300 @@
+/*
+ * This source file is part of the bstring string library.  This code was
+ * written by Paul Hsieh in 2002-2008, and is covered by the BSD open source 
+ * license and the GPL. Refer to the accompanying documentation for details 
+ * on usage and license.
+ */
+
+/*!
+ * @file
+ * This file is the core module for implementing the bstring functions.
+ */
+
+#ifndef BSTRLIB_INCLUDE
+#define BSTRLIB_INCLUDE
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdarg.h>
+#include <string.h>
+#include <limits.h>
+#include <ctype.h>
+
+#if !defined (BSTRLIB_VSNP_OK) && !defined (BSTRLIB_NOVSNP)
+# if defined (__TURBOC__) && !defined (__BORLANDC__)
+#  define BSTRLIB_NOVSNP
+# endif
+#endif
+
+#define BSTR_ERR (-1)
+#define BSTR_OK (0)
+#define BSTR_BS_BUFF_LENGTH_GET (0)
+
+typedef struct tagbstring * bstring;
+typedef const struct tagbstring * const_bstring;
+
+/* Copy functions */
+#define cstr2bstr bfromcstr
+extern bstring bfromcstr (const char * str);
+extern bstring bfromcstralloc (int mlen, const char * str);
+extern bstring blk2bstr (const void * blk, int len);
+extern char * bstr2cstr (const_bstring s, char z);
+extern int bcstrfree (char * s);
+extern bstring bstrcpy (const_bstring b1);
+extern int bassign (bstring a, const_bstring b);
+extern int bassignmidstr (bstring a, const_bstring b, int left, int len);
+extern int bassigncstr (bstring a, const char * str);
+extern int bassignblk (bstring a, const void * s, int len);
+
+/* Destroy function */
+extern int bdestroy (bstring b);
+
+/* Space allocation hinting functions */
+extern int balloc (bstring s, int len);
+extern int ballocmin (bstring b, int len);
+
+/* Substring extraction */
+extern bstring bmidstr (const_bstring b, int left, int len);
+
+/* Various standard manipulations */
+extern int bconcat (bstring b0, const_bstring b1);
+extern int bconchar (bstring b0, char c);
+extern int bcatcstr (bstring b, const char * s);
+extern int bcatblk (bstring b, const void * s, int len);
+extern int binsert (bstring s1, int pos, const_bstring s2, unsigned char fill);
+extern int binsertch (bstring s1, int pos, int len, unsigned char fill);
+extern int breplace (bstring b1, int pos, int len, const_bstring b2, unsigned char fill);
+extern int bdelete (bstring s1, int pos, int len);
+extern int bsetstr (bstring b0, int pos, const_bstring b1, unsigned char fill);
+extern int btrunc (bstring b, int n);
+
+/* Scan/search functions */
+extern int bstricmp (const_bstring b0, const_bstring b1);
+extern int bstrnicmp (const_bstring b0, const_bstring b1, int n);
+extern int biseqcaseless (const_bstring b0, const_bstring b1);
+extern int bisstemeqcaselessblk (const_bstring b0, const void * blk, int len);
+extern int biseq (const_bstring b0, const_bstring b1);
+extern int bisstemeqblk (const_bstring b0, const void * blk, int len);
+extern int biseqcstr (const_bstring b, const char * s);
+extern int biseqcstrcaseless (const_bstring b, const char * s);
+extern int bstrcmp (const_bstring b0, const_bstring b1);
+extern int bstrncmp (const_bstring b0, const_bstring b1, int n);
+extern int binstr (const_bstring s1, int pos, const_bstring s2);
+extern int binstrr (const_bstring s1, int pos, const_bstring s2);
+extern int binstrcaseless (const_bstring s1, int pos, const_bstring s2);
+extern int binstrrcaseless (const_bstring s1, int pos, const_bstring s2);
+extern int bstrchrp (const_bstring b, int c, int pos);
+extern int bstrrchrp (const_bstring b, int c, int pos);
+#define bstrchr(b,c) bstrchrp ((b), (c), 0)
+#define bstrrchr(b,c) bstrrchrp ((b), (c), blength(b)-1)
+extern int binchr (const_bstring b0, int pos, const_bstring b1);
+extern int binchrr (const_bstring b0, int pos, const_bstring b1);
+extern int bninchr (const_bstring b0, int pos, const_bstring b1);
+extern int bninchrr (const_bstring b0, int pos, const_bstring b1);
+extern int bfindreplace (bstring b, const_bstring find, const_bstring repl, int pos);
+extern int bfindreplacecaseless (bstring b, const_bstring find, const_bstring repl, int pos);
+
+/* List of string container functions */
+struct bstrList {
+    int qty, mlen;
+    bstring * entry;
+};
+extern struct bstrList * bstrListCreate (void);
+extern int bstrListDestroy (struct bstrList * sl);
+extern int bstrListAlloc (struct bstrList * sl, int msz);
+extern int bstrListAllocMin (struct bstrList * sl, int msz);
+
+/* String split and join functions */
+extern struct bstrList * bsplit (const_bstring str, unsigned char splitChar);
+extern struct bstrList * bsplits (const_bstring str, const_bstring splitStr);
+extern struct bstrList * bsplitstr (const_bstring str, const_bstring splitStr);
+extern bstring bjoin (const struct bstrList * bl, const_bstring sep);
+extern int bsplitcb (const_bstring str, unsigned char splitChar, int pos,
+       int (* cb) (void * parm, int ofs, int len), void * parm);
+extern int bsplitscb (const_bstring str, const_bstring splitStr, int pos,
+       int (* cb) (void * parm, int ofs, int len), void * parm);
+extern int bsplitstrcb (const_bstring str, const_bstring splitStr, int pos,
+       int (* cb) (void * parm, int ofs, int len), void * parm);
+
+/* Miscellaneous functions */
+extern int bpattern (bstring b, int len);
+extern int btoupper (bstring b);
+extern int btolower (bstring b);
+extern int bltrimws (bstring b);
+extern int brtrimws (bstring b);
+extern int btrimws (bstring b);
+
+#if !defined (BSTRLIB_NOVSNP)
+extern bstring bformat (const char * fmt, ...);
+extern int bformata (bstring b, const char * fmt, ...);
+extern int bassignformat (bstring b, const char * fmt, ...);
+extern int bvcformata (bstring b, int count, const char * fmt, va_list arglist);
+
+#define bvformata(ret, b, fmt, lastarg) { \
+bstring bstrtmp_b = (b); \
+const char * bstrtmp_fmt = (fmt); \
+int bstrtmp_r = BSTR_ERR, bstrtmp_sz = 16; \
+       for (;;) { \
+               va_list bstrtmp_arglist; \
+               va_start (bstrtmp_arglist, lastarg); \
+               bstrtmp_r = bvcformata (bstrtmp_b, bstrtmp_sz, bstrtmp_fmt, bstrtmp_arglist); \
+               va_end (bstrtmp_arglist); \
+               if (bstrtmp_r >= 0) { /* Everything went ok */ \
+                       bstrtmp_r = BSTR_OK; \
+                       break; \
+               } else if (-bstrtmp_r <= bstrtmp_sz) { /* A real error? */ \
+                       bstrtmp_r = BSTR_ERR; \
+                       break; \
+               } \
+               bstrtmp_sz = -bstrtmp_r; /* Doubled or target size */ \
+       } \
+       ret = bstrtmp_r; \
+}
+
+#endif
+
+typedef int (*bNgetc) (void *parm);
+typedef size_t (* bNread) (void *buff, size_t elsize, size_t nelem, void *parm);
+
+/* Input functions */
+extern bstring bgetstream (bNgetc getcPtr, void * parm, char terminator);
+extern bstring bread (bNread readPtr, void * parm);
+extern int bgetsa (bstring b, bNgetc getcPtr, void * parm, char terminator);
+extern int bassigngets (bstring b, bNgetc getcPtr, void * parm, char terminator);
+extern int breada (bstring b, bNread readPtr, void * parm);
+
+/* Stream functions */
+extern struct bStream * bsopen (bNread readPtr, void * parm);
+extern void * bsclose (struct bStream * s);
+extern int bsbufflength (struct bStream * s, int sz);
+extern int bsreadln (bstring b, struct bStream * s, char terminator);
+extern int bsreadlns (bstring r, struct bStream * s, const_bstring term);
+extern int bsread (bstring b, struct bStream * s, int n);
+extern int bsreadlna (bstring b, struct bStream * s, char terminator);
+extern int bsreadlnsa (bstring r, struct bStream * s, const_bstring term);
+extern int bsreada (bstring b, struct bStream * s, int n);
+extern int bsunread (struct bStream * s, const_bstring b);
+extern int bspeek (bstring r, const struct bStream * s);
+extern int bssplitscb (struct bStream * s, const_bstring splitStr, 
+       int (* cb) (void * parm, int ofs, const_bstring entry), void * parm);
+extern int bssplitstrcb (struct bStream * s, const_bstring splitStr, 
+       int (* cb) (void * parm, int ofs, const_bstring entry), void * parm);
+extern int bseof (const struct bStream * s);
+
+struct tagbstring {
+       int mlen;
+       int slen;
+       unsigned char * data;
+};
+
+/* Accessor macros */
+#define blengthe(b, e)      (((b) == (void *)0 || (b)->slen < 0) ? (int)(e) : ((b)->slen))
+#define blength(b)          (blengthe ((b), 0))
+#define bdataofse(b, o, e)  (((b) == (void *)0 || (b)->data == (void*)0) ? (char *)(e) : ((char *)(b)->data) + (o))
+#define bdataofs(b, o)      (bdataofse ((b), (o), (void *)0))
+#define bdatae(b, e)        (bdataofse (b, 0, e))
+#define bdata(b)            (bdataofs (b, 0))
+#define bchare(b, p, e)     ((((unsigned)(p)) < (unsigned)blength(b)) ? ((b)->data[(p)]) : (e))
+#define bchar(b, p)         bchare ((b), (p), '\0')
+
+/* Static constant string initialization macro */
+#define bsStaticMlen(q,m)   {(m), (int) sizeof(q)-1, (unsigned char *) ("" q "")}
+#if defined(_MSC_VER)
+# define bsStatic(q)        bsStaticMlen(q,-32)
+#endif
+#ifndef bsStatic
+# define bsStatic(q)        bsStaticMlen(q,-__LINE__)
+#endif
+
+/* Static constant block parameter pair */
+#define bsStaticBlkParms(q) ((void *)("" q "")), ((int) sizeof(q)-1)
+
+/* Reference building macros */
+#define cstr2tbstr btfromcstr
+#define btfromcstr(t,s) {                                            \
+    (t).data = (unsigned char *) (s);                                \
+    (t).slen = ((t).data) ? ((int) (strlen) ((char *)(t).data)) : 0; \
+    (t).mlen = -1;                                                   \
+}
+#define blk2tbstr(t,s,l) {            \
+    (t).data = (unsigned char *) (s); \
+    (t).slen = l;                     \
+    (t).mlen = -1;                    \
+}
+#define btfromblk(t,s,l) blk2tbstr(t,s,l)
+#define bmid2tbstr(t,b,p,l) {                                                \
+    const_bstring bstrtmp_s = (b);                                           \
+    if (bstrtmp_s && bstrtmp_s->data && bstrtmp_s->slen >= 0) {              \
+        int bstrtmp_left = (p);                                              \
+        int bstrtmp_len  = (l);                                              \
+        if (bstrtmp_left < 0) {                                              \
+            bstrtmp_len += bstrtmp_left;                                     \
+            bstrtmp_left = 0;                                                \
+        }                                                                    \
+        if (bstrtmp_len > bstrtmp_s->slen - bstrtmp_left)                    \
+            bstrtmp_len = bstrtmp_s->slen - bstrtmp_left;                    \
+        if (bstrtmp_len <= 0) {                                              \
+            (t).data = (unsigned char *)"";                                  \
+            (t).slen = 0;                                                    \
+        } else {                                                             \
+            (t).data = bstrtmp_s->data + bstrtmp_left;                       \
+            (t).slen = bstrtmp_len;                                          \
+        }                                                                    \
+    } else {                                                                 \
+        (t).data = (unsigned char *)"";                                      \
+        (t).slen = 0;                                                        \
+    }                                                                        \
+    (t).mlen = -__LINE__;                                                    \
+}
+#define btfromblkltrimws(t,s,l) {                                            \
+    int bstrtmp_idx = 0, bstrtmp_len = (l);                                  \
+    unsigned char * bstrtmp_s = (s);                                         \
+    if (bstrtmp_s && bstrtmp_len >= 0) {                                     \
+        for (; bstrtmp_idx < bstrtmp_len; bstrtmp_idx++) {                   \
+            if (!isspace (bstrtmp_s[bstrtmp_idx])) break;                    \
+        }                                                                    \
+    }                                                                        \
+    (t).data = bstrtmp_s + bstrtmp_idx;                                      \
+    (t).slen = bstrtmp_len - bstrtmp_idx;                                    \
+    (t).mlen = -__LINE__;                                                    \
+}
+#define btfromblkrtrimws(t,s,l) {                                            \
+    int bstrtmp_len = (l) - 1;                                               \
+    unsigned char * bstrtmp_s = (s);                                         \
+    if (bstrtmp_s && bstrtmp_len >= 0) {                                     \
+        for (; bstrtmp_len >= 0; bstrtmp_len--) {                            \
+            if (!isspace (bstrtmp_s[bstrtmp_len])) break;                    \
+        }                                                                    \
+    }                                                                        \
+    (t).data = bstrtmp_s;                                                    \
+    (t).slen = bstrtmp_len + 1;                                              \
+    (t).mlen = -__LINE__;                                                    \
+}
+#define btfromblktrimws(t,s,l) {                                             \
+    int bstrtmp_idx = 0, bstrtmp_len = (l) - 1;                              \
+    unsigned char * bstrtmp_s = (s);                                         \
+    if (bstrtmp_s && bstrtmp_len >= 0) {                                     \
+        for (; bstrtmp_idx <= bstrtmp_len; bstrtmp_idx++) {                  \
+            if (!isspace (bstrtmp_s[bstrtmp_idx])) break;                    \
+        }                                                                    \
+        for (; bstrtmp_len >= bstrtmp_idx; bstrtmp_len--) {                  \
+            if (!isspace (bstrtmp_s[bstrtmp_len])) break;                    \
+        }                                                                    \
+    }                                                                        \
+    (t).data = bstrtmp_s + bstrtmp_idx;                                      \
+    (t).slen = bstrtmp_len + 1 - bstrtmp_idx;                                \
+    (t).mlen = -__LINE__;                                                    \
+}
+
+/* Write protection macros */
+#define bwriteprotect(t)     { if ((t).mlen >=  0) (t).mlen = -1; }
+#define bwriteallow(t)       { if ((t).mlen == -1) (t).mlen = (t).slen + ((t).slen == 0); }
+#define biswriteprotected(t) ((t).mlen <= 0)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
index 8dcb33fbcae5bdb89d038dbd954f9b7aa29025c3..d7df70e1d164ddd82c5c61f44f9e07996500607a 100644 (file)
@@ -1,9 +1,8 @@
-/* 
- * $Id: cnid.h,v 1.15 2010-03-31 09:47:32 franklahm Exp $
- *
+/*
  * Copyright (c) 2003 the Netatalk Team
  * Copyright (c) 2003 Rafal Lewczuk <rlewczuk@pronet.pl>
- * 
+ * Copyright (c) 2010 Frank Lahm
+ *
  * 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
  *
  */
 
-/* 
- * This file contains all generic CNID related stuff 
+/*
+ * This file contains all generic CNID related stuff
  * declarations. Included:
- * - CNID factory, which retrieves (eventually instantiates) 
+ * - 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.
@@ -33,8 +32,8 @@
 #define CNID_FLAG_BLOCK        0x08      /* block signals in update. */
 #define CNID_FLAG_NODEV        0x10      /* don't use device number only inode */
 #define CNID_FLAG_LAZY_INIT    0x20      /* */
-#define CNID_FLAG_MEMORY       0x40     /* this is a memory only db */
-#define CNID_FLAG_INODE        0x80     /* in cnid_add the inode is authoritative */
+#define CNID_FLAG_MEMORY       0x40  /* this is a memory only db */
+#define CNID_FLAG_INODE        0x80  /* in cnid_add the inode is authoritative */
 
 #define CNID_INVALID   0
 /* first valid ID */
  * 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 size_t, 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  size_t);
-       cnid_t (*cnid_lookup)(struct _cnid_db *cdb, const struct stat *st, const cnid_t did,
-                       char *name, const size_t);
-       cnid_t (*cnid_nextid)(struct _cnid_db *cdb);
-       char *(*cnid_resolve)(struct _cnid_db *cdb, cnid_t *id, void *buffer, size_t len);
-       int (*cnid_update)(struct _cnid_db *cdb, const cnid_t id, const struct stat *st, 
-                       const cnid_t did, char *name, const size_t len);        
-       void (*cnid_close)(struct _cnid_db *cdb);
-       int  (*cnid_getstamp)(struct _cnid_db *cdb, void *buffer, const size_t len);
-        cnid_t (*cnid_rebuild_add)(struct _cnid_db *, const struct stat *, const cnid_t,
-                        char *, const size_t, cnid_t);
+    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 size_t, 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  size_t);
+    cnid_t (*cnid_lookup)      (struct _cnid_db *cdb, const struct stat *st, const cnid_t did,
+                                char *name, const size_t);
+    cnid_t (*cnid_nextid)      (struct _cnid_db *cdb);
+    char * (*cnid_resolve)     (struct _cnid_db *cdb, cnid_t *id, void *buffer, size_t len);
+    int    (*cnid_update)      (struct _cnid_db *cdb, const cnid_t id, const struct stat *st,
+                                const cnid_t did, char *name, const size_t len);
+    void   (*cnid_close)       (struct _cnid_db *cdb);
+    int    (*cnid_getstamp)    (struct _cnid_db *cdb, void *buffer, const size_t len);
+    cnid_t (*cnid_rebuild_add) (struct _cnid_db *, const struct stat *, const cnid_t,
+                                char *, const size_t, cnid_t);
+    int    (*cnid_find)        (struct _cnid_db *cdb, char *name, size_t namelen,
+                                void *buffer, size_t buflen);
 };
 typedef struct _cnid_db cnid_db;
 
-/* 
+/*
  * Consolidation of args passedn from main cnid_open to modules cnid_XXX_open, so
  * that it's easier to add aditional args as required.
  */
@@ -88,10 +88,10 @@ struct cnid_open_args {
  * 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)(struct cnid_open_args *args);
-       u_int32_t flags;            /* Flags describing some CNID backend aspects. */
+    char *name;
+    struct list_head db_list;   /* CNID modules are also stored on a bidirectional list. */
+    struct _cnid_db *(*cnid_open)(struct cnid_open_args *args);
+    u_int32_t flags;            /* Flags describing some CNID backend aspects. */
 
 };
 typedef struct _cnid_module cnid_module;
@@ -107,98 +107,22 @@ struct _cnid_db *cnid_open(const char *volpath,
                            mode_t mask,
                            char *type,
                            int flags,
-                           const char *cnidsrv, /* Only for dbd */
-                           const char *cnidport); /* Only for dbd */
-
-cnid_t cnid_add(struct _cnid_db *cdb, const struct stat *st, const cnid_t did, 
-                       char *name, const size_t 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 size_t len);
-
-int    cnid_getstamp(struct _cnid_db *cdb, void *buffer, const size_t len);
-
-cnid_t cnid_lookup(struct _cnid_db *cdb, const struct stat *st, const cnid_t did,
-                       char *name, const size_t len);
-
-char *cnid_resolve(struct _cnid_db *cdb, cnid_t *id, void *buffer, size_t len);
-
-int cnid_update   (struct _cnid_db *cdb, const cnid_t id, const struct stat *st, 
-                       const cnid_t did, char *name, const size_t len);
-
+                           const char *cnidsrv,
+                           const char *cnidport);
+cnid_t cnid_add        (struct _cnid_db *cdb, const struct stat *st, const cnid_t did,
+                        const char *name, const size_t 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 size_t len);
+int    cnid_getstamp   (struct _cnid_db *cdb, void *buffer, const size_t len);
+cnid_t cnid_lookup     (struct _cnid_db *cdb, const struct stat *st, const cnid_t did,
+                        char *name, const size_t len);
+char  *cnid_resolve    (struct _cnid_db *cdb, cnid_t *id, void *buffer, size_t len);
+int    cnid_update     (struct _cnid_db *cdb, const cnid_t id, const struct stat *st,
+                        const cnid_t did, char *name, const size_t len);
 cnid_t cnid_rebuild_add(struct _cnid_db *cdb, const struct stat *st, const cnid_t did,
                         char *name, const size_t len, cnid_t hint);
-
-
-/* This function closes a CNID database and frees all resources assigned to it. */ 
-void cnid_close(struct _cnid_db *db);
+int    cnid_find       (struct _cnid_db *cdb, const char *name, size_t namelen,
+                        void *buffer, size_t buflen);
+void   cnid_close      (struct _cnid_db *db);
 
 #endif
-
-/*
- * $Log: cnid.h,v $
- * Revision 1.15  2010-03-31 09:47:32  franklahm
- * clustering support: new per volume option cnidserver
- *
- * Revision 1.14  2009/11/28 13:09:25  didg
- * guard against confused DB returning junk values
- *
- * Revision 1.13  2009/11/24 12:18:19  didg
- * add a flag parameter to cnid open functions
- *
- * Revision 1.12  2005/09/07 15:23:21  didg
- *
- * lazy init dbd database, help with pre tiger OS and a lot of volumes.
- *
- * Revision 1.11  2005/05/03 14:55:12  didg
- *
- * remove gcc warning
- *
- * 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).
- *
- */
-
index 4e4847a7eb4ab5bb84bd913036e4a784ad928569..36dee3d8264890402fa6cc7b0f7d233c08efa706 100644 (file)
 #define CNID_DBD_OP_MANGLE_GET  0x0a
 #define CNID_DBD_OP_GETSTAMP    0x0b
 #define CNID_DBD_OP_REBUILD_ADD 0x0c
+#define CNID_DBD_OP_SEARCH      0x0d
 
 #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_DBD_RES_SRCH_CNT      0x05
+#define CNID_DBD_RES_SRCH_DONE     0x06
+
+#define DBD_MAX_SRCH_RSLTS 100
 
 struct cnid_dbd_rqst {
     int     op;
     cnid_t  cnid;
     dev_t   dev;
     ino_t   ino;
-    u_int32_t type;
+    uint32_t type;
     cnid_t  did;
-    char   *name;
+    char    *name;
     size_t  namelen;
 };
 
@@ -46,7 +51,7 @@ struct cnid_dbd_rply {
     int     result;    
     cnid_t  cnid;
     cnid_t  did;
-    char   *name;
+    char    *name;
     size_t  namelen;
 };
 
index 6525ce4898c63508bb6c8cb97979cfea61800fdd..f5f825faa362f806e124cf3e0e32280166756a9c 100644 (file)
 #define CNID_INO_LEN             8
  
 #define CNID_DEVINO_OFS          CNID_LEN
-#define CNID_DEVINO_LEN          (CNID_DEV_LEN +CNID_INO_LEN)
+#define CNID_DEVINO_LEN          (CNID_DEV_LEN + CNID_INO_LEN)
  
-#define CNID_TYPE_OFS            (CNID_DEVINO_OFS +CNID_DEVINO_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_OFS             (CNID_TYPE_OFS + CNID_TYPE_LEN)
 #define CNID_DID_LEN             CNID_LEN
  
 #define CNID_NAME_OFS            (CNID_DID_OFS + CNID_DID_LEN)
 #define ROOTINFO_KEYLEN 4
 
 /* 
-   Rootinfo data:
-   4 unused bytes (cnid) 
-   8 bytes, in first 4 bytes db stamp: struct stat.st_ctime of database file (dev)
-   8 unused bytes (inode)
+   Rootinfo data, fields as they are used by normal entries for CNIDs (for reference):
+   4 bytes: CNID 
+   8 bytes: dev
+   8 bytes: inode
    4 bytes: is a file/directory (type)
-   4 unused bytes (did)
-   9 bytes name "RootInfo"
+   4 bytes: DID
+   x bytes: name
+
+   Contents in Rootinfo entry:
+   4 bytes: 0
+   8 bytes: db stamp: struct stat.st_ctime of database file
+   8 bytes: unused
+   4 bytes: last used CNID
+   4 bytes: version as htonl(uint32_t)
+   9 bytes: name "RootInfo"
 */
 #define ROOTINFO_DATA    "\0\0\0\0" \
                          "\0\0\0\0\0\0\0\0" \
                          "RootInfo"
 #define ROOTINFO_DATALEN (3*4 + 2*8 + 9)
 
+/* 
+ * CNID version history:
+ * 0: up to Netatalk 2.1.x
+ * 1: starting with 2.2, additional name index, used in cnid_find
+ */
+#define CNID_VERSION_0               0
+#define CNID_VERSION_1               1
+#define CNID_VERSION_UNINTIALIZED_DB UINT32_MAX
+
+/* Current CNID version */
+#define CNID_VERSION CNID_VERSION_1
+
 #endif
index 17e5d08762468e2555d2b2396a5baba3e052da93..d15c048940e772229334e10f5f50aad76eefb9da 100644 (file)
@@ -1,6 +1,4 @@
 /*
- * $Id: directory.h,v 1.3 2010-01-10 10:58:25 franklahm Exp $
- *
  * Copyright (c) 1990,1991 Regents of The University of Michigan.
  * All Rights Reserved.
  *
 #include <sys/types.h>
 #include <netatalk/endian.h>
 #include <dirent.h>
+#include <stdint.h>
 
 #include <atalk/cnid.h>
-#include <atalk/directory.h>
+#include <atalk/bstrlib.h>
+#include <atalk/queue.h>
 
 /* setgid directories */
 #ifndef DIRBITS
 # endif /* AFS */
 #endif /* DIRBITS */
 
-/* the did tree is now a red-black tree while the parent/child
- * tree is a circular doubly-linked list. how exciting. */
-struct dir {
-    struct dir *d_left, *d_right, *d_back; /* for red-black tree */
-    int                d_color;
-    struct dir  *d_parent, *d_child; /* parent-child */
-    struct dir  *d_prev, *d_next;    /* siblings */
-    void        *d_ofork;            /* oforks using this directory. */
-    u_int32_t   d_did;
-    int                d_flags;
-
-    time_t      ctime;                /* inode ctime */
-    u_int32_t   offcnt;               /* offspring count */
+/* reserved directory id's */
+#define DIRDID_ROOT_PARENT    htonl(1)  /* parent directory of root */
+#define DIRDID_ROOT           htonl(2)  /* root directory */
 
-    char       *d_m_name;            /* mac name */
-    char        *d_u_name;            /* unix name */
-    ucs2_t     *d_m_name_ucs2;       /* mac name as UCS2 */
+struct dir {
+    bstring     d_fullpath;          /* complete unix path to dir */
+    bstring     d_m_name;            /* mac name */
+    bstring     d_u_name;            /* unix name                                          */
+                                     /* be careful here! if d_m_name == d_u_name, d_u_name */
+                                     /* will just point to the same storage as d_m_name !! */
+    ucs2_t      *d_m_name_ucs2;       /* mac name as UCS2 */
+    qnode_t     *qidx_node;           /* pointer to position in queue index */
+    time_t      ctime;                /* inode ctime, used and modified by reenumeration */
+    time_t      ctime_dircache;       /* inode ctime, used and modified by dircache */
+    int         d_flags;              /* directory flags */
+    cnid_t      d_pdid;               /* CNID of parent directory */
+    cnid_t      d_did;                /* CNID of directory */
+    uint32_t    offcnt;               /* offspring count */
+    uint16_t    d_vid;                /* only needed in the dircache, because
+                                         we put all directories in one cache. */
 };
 
 struct path {
     int         m_type;             /* mac name type (long name, unicode */
-    char       *m_name;            /* mac name */
+    char        *m_name;            /* mac name */
     char        *u_name;            /* unix name */
-    cnid_t     id;                 /* file id (only for getmetadata) */
+    cnid_t      id;                 /* file id (only for getmetadata) */
     struct dir  *d_dir;             /* */
     int         st_valid;           /* does st_errno and st set */
     int         st_errno;
@@ -83,5 +86,4 @@ static inline int path_isadir(struct path *o_path)
 #endif
 }
 
-
 #endif /* ATALK_DIRECTORY_H */
index 82da7a1595e517b0b0eea4ad761b4cb68d9dbd43..dc32f6e3779496edffa20d9ddcbd88992db82f41 100644 (file)
@@ -61,12 +61,10 @@ typedef struct DSI {
   dsi_proto protocol;
   struct dsi_block header;
   struct sockaddr_storage server, client;
-  
   struct itimerval timer;
-
-  int     in_write;      /* in the middle of writing multiple packets, signal handlers
-                          * can't write to the socket 
-                         */
+  int      tickle;        /* tickle count */
+  int     in_write;      /* in the middle of writing multiple packets,
+                             signal handlers can't write to the socket */
   int      msg_request;   /* pending message to the client */
   int      down_request;  /* pending SIGUSR1 down in 5 mn */
 
@@ -77,9 +75,7 @@ typedef struct DSI {
   size_t statuslen;
   size_t datalen, cmdlen;
   off_t  read_count, write_count;
-  int asleep; /* client won't reply AFP 0x7a ? */
-  /* inited = initialized?, child = a child?, noreply = send reply? */
-  char child, inited, noreply;
+  uint32_t flags;             /* DSI flags like DSI_SLEEPING, DSI_DISCONNECTED */
   const char *program; 
   int socket, serversock;
 
@@ -94,6 +90,10 @@ typedef struct DSI {
   char srvloc_url[512];
 #endif 
 
+#ifdef USE_ZEROCONF
+  int zeroconf_registered;
+#endif
+
   /* buffer for OSX deadlock */
   char *buffer;
   char *start;
@@ -111,6 +111,7 @@ typedef struct DSI {
 /* DSI session options */
 #define DSIOPT_SERVQUANT 0x00   /* server request quantum */
 #define DSIOPT_ATTNQUANT 0x01   /* attention quantum */
+#define DSIOPT_REPLCSIZE 0x02   /* AFP replaycache size supported by the server (that's us) */
 
 /* DSI Commands */
 #define DSIFUNC_CLOSE   1       /* DSICloseSession */
@@ -144,6 +145,17 @@ typedef struct DSI {
 /* default port number */
 #define DSI_AFPOVERTCP_PORT 548
 
+/* DSI session State flags */
+#define DSI_DATA             (1 << 0) /* we have received a DSI command */
+#define DSI_RUNNING          (1 << 1) /* we have received a AFP command */
+#define DSI_SLEEPING         (1 << 2) /* we're sleeping after FPZzz */
+#define DSI_EXTSLEEP         (1 << 3) /* we're sleeping after FPZzz */
+#define DSI_DISCONNECTED     (1 << 4) /* we're in diconnected state after a socket error */
+#define DSI_DIE              (1 << 5) /* SIGUSR1, going down in 5 minutes */
+#define DSI_NOREPLY          (1 << 6) /* in dsi_write we generate our own replies */
+#define DSI_RECONSOCKET      (1 << 7) /* we have a new socket from primary reconnect */
+#define DSI_RECONINPROG      (1 << 8) /* used in the new session in reconnect */
+
 /* basic initialization: dsi_init.c */
 extern DSI *dsi_init (const dsi_proto /*protocol*/,
                          const char * /*program*/, 
@@ -153,7 +165,7 @@ extern DSI *dsi_init (const dsi_proto /*protocol*/,
 extern void dsi_setstatus (DSI *, char *, const size_t);
 
 /* in dsi_getsess.c */
-extern DSI *dsi_getsession (DSI *, server_child *, const int);
+extern afp_child_t *dsi_getsession (DSI *, server_child *, const int);
 extern void dsi_kill (int);
 
 
@@ -164,7 +176,6 @@ extern int  dsi_cmdreply (DSI *, const int);
 extern int dsi_tickle (DSI *);
 extern void dsi_getstatus (DSI *);
 extern void dsi_close (DSI *);
-extern void dsi_sleep (DSI *, const int );
 
 #define DSI_NOWAIT 1
 /* low-level stream commands -- in dsi_stream.c */
index 00d987de77b27bd37fcc69d3949e65416af386b9..c0165a1a257f210999055d8a271bc81dadf9e2a8 100644 (file)
@@ -20,7 +20,7 @@
 #include <config.h>
 #endif
 
-#ifdef HAVE_NFSv4_ACLS
+#ifdef HAVE_SOLARIS_ACLS
 #include <sys/acl.h>
 #endif
 
diff --git a/include/atalk/errchk.h b/include/atalk/errchk.h
new file mode 100644 (file)
index 0000000..64a1276
--- /dev/null
@@ -0,0 +1,163 @@
+/*
+   Copyright (c) 2010 Frank Lahm <franklahm@gmail.com>
+
+   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.
+ */
+
+#ifndef ERRCHECK_H
+#define ERRCHECK_H
+
+#define EC_INIT int ret = 0
+#define EC_STATUS(a) ret = (a)
+#define EC_FAIL ret = -1; goto cleanup
+#define EC_CLEANUP cleanup
+#define EC_EXIT return ret
+
+/* 
+ * Check out doc/DEVELOPER for more infos.
+ *
+ * We have these macros:
+ * EC_ZERO, EC_ZERO_LOG, EC_ZERO_LOGSTR, EC_ZERO_LOG_ERR, EC_ZERO_CUSTOM
+ * EC_NEG1, EC_NEG1_LOG, EC_NEG1_LOGSTR, EC_NEG1_LOG_ERR, EC_NEG1_CUSTOM
+ * EC_NULL, EC_NULL_LOG, EC_NULL_LOGSTR, EC_NULL_LOG_ERR, EC_NULL_CUSTOM
+ *
+ * A boileplate function template is:
+
+   int func(void)
+   {
+       EC_INIT;
+
+       ...your code here...
+
+       EC_STATUS(0);
+
+   EC_CLEANUP:
+       EC_EXIT;
+   }
+ */
+
+/* check for return val 0 which is ok, every other is an error, prints errno */
+#define EC_ZERO_LOG(a)                                                  \
+    do {                                                                \
+        if ((a) != 0) {                                                 \
+            LOG(log_error, logtype_default, "%s failed: %s", #a, strerror(errno)); \
+            ret = -1;                                                   \
+            goto cleanup;                                               \
+        }                                                               \
+    } while (0)
+
+#define EC_ZERO_LOGSTR(a, b, ...)                                       \
+    do {                                                                \
+        if ((a) != 0) {                                                 \
+            LOG(log_error, logtype_default, b, __VA_ARGS__);            \
+            ret = -1;                                                   \
+            goto cleanup;                                               \
+        }                                                               \
+    } while (0)
+
+#define EC_ZERO_LOG_ERR(a, b)                                           \
+    do {                                                                \
+        if ((a) != 0) {                                                 \
+            LOG(log_error, logtype_default, "%s failed: %s", #a, strerror(errno)); \
+            ret = (b);                                                  \
+            goto cleanup;                                               \
+        }                                                               \
+    } while (0)
+
+#define EC_ZERO(a)                              \
+    do {                                        \
+        if ((a) != 0) {                         \
+            ret = -1;                           \
+            goto cleanup;                       \
+        }                                       \
+    } while (0)
+
+#define EC_ZERO_ERR(a,b )                       \
+    do {                                        \
+        if ((a) != 0) {                         \
+            ret = b;                            \
+            goto cleanup;                       \
+        }                                       \
+    } while (0)
+
+/* check for return val 0 which is ok, every other is an error, prints errno */
+#define EC_NEG1_LOG(a)                                                  \
+    do {                                                                \
+        if ((a) == -1) {                                                \
+            LOG(log_error, logtype_default, "%s failed: %s", #a, strerror(errno)); \
+            ret = -1;                                                   \
+            goto cleanup;                                               \
+        }                                                               \
+    } while (0)
+
+#define EC_NEG1_LOGSTR(a, b, ...)                               \
+    do {                                                        \
+        if ((a) == -1) {                                        \
+            LOG(log_error, logtype_default, b, __VA_ARGS__);    \
+            ret = -1;                                           \
+            goto cleanup;                                       \
+        }                                                       \
+    } while (0)
+
+#define EC_NEG1_LOG_ERR(a, b)                                           \
+    do {                                                                \
+        if ((a) == -1) {                                                \
+            LOG(log_error, logtype_default, "%s failed: %s", #a, strerror(errno)); \
+            ret = b;                                                    \
+            goto cleanup;                                               \
+        }                                                               \
+    } while (0)
+
+#define EC_NEG1(a)                              \
+    do {                                        \
+        if ((a) == -1) {                        \
+            ret = -1;                           \
+            goto cleanup;                       \
+        }                                       \
+    } while (0)
+
+/* check for return val != NULL, prints errno */
+#define EC_NULL_LOG(a)                                                  \
+    do {                                                                \
+        if ((a) == NULL) {                                              \
+            LOG(log_error, logtype_default, "%s failed: %s", #a, strerror(errno)); \
+            ret = -1;                                                   \
+            goto cleanup;                                               \
+        }                                                               \
+    } while (0)
+
+#define EC_NULL_LOGSTR(a, b, ...)                                       \
+    do {                                                                \
+        if ((a) == NULL) {                                              \
+            LOG(log_error, logtype_default, b , __VA_ARGS__);           \
+            ret = -1;                                                   \
+            goto cleanup;                                               \
+        } \
+    } while (0)
+
+#define EC_NULL_LOG_ERR(a, b)                                           \
+    do {                                                                \
+        if ((a) == NULL) {                                              \
+            LOG(log_error, logtype_default, "%s failed: %s", #a, strerror(errno)); \
+            ret = b;                                                    \
+            goto cleanup;                                               \
+        }                                                               \
+    } while (0)
+
+#define EC_NULL(a)                              \
+    do {                                        \
+        if ((a) == NULL) {                      \
+            ret = -1;                           \
+            goto cleanup;                       \
+        }                                       \
+    } while (0)
+
+#endif /* ERRCHECK_H */
diff --git a/include/atalk/ftw.h b/include/atalk/ftw.h
new file mode 100644 (file)
index 0000000..157efc5
--- /dev/null
@@ -0,0 +1,109 @@
+/* Copyright (C) 1992,1996-1999,2003,2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+/*
+ *     X/Open Portability Guide 4.2: ftw.h
+ */
+
+#ifndef _ATALK_FTW_H
+#define        _ATALK_FTW_H    1
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+/* Values for the FLAG argument to the user function passed to `ftw'
+   and 'nftw'.  */
+enum
+{
+  FTW_F,               /* Regular file.  */
+#define FTW_F   FTW_F
+  FTW_D,               /* Directory.  */
+#define FTW_D   FTW_D
+  FTW_DNR,             /* Unreadable directory.  */
+#define FTW_DNR         FTW_DNR
+  FTW_NS,              /* Unstatable file.  */
+#define FTW_NS  FTW_NS
+  FTW_SL,              /* Symbolic link.  */
+# define FTW_SL         FTW_SL
+
+/* These flags are only passed from the `nftw' function.  */
+  FTW_DP,              /* Directory, all subdirs have been visited. */
+# define FTW_DP         FTW_DP
+  FTW_SLN              /* Symbolic link naming non-existing file.  */
+# define FTW_SLN FTW_SLN
+};
+
+
+/* Flags for fourth argument of `nftw'.  */
+enum
+{
+  FTW_PHYS = 1,                /* Perform physical walk, ignore symlinks.  */
+# define FTW_PHYS      FTW_PHYS
+  FTW_MOUNT = 2,       /* Report only files on same file system as the
+                          argument.  */
+# define FTW_MOUNT     FTW_MOUNT
+  FTW_CHDIR = 4,       /* Change to current directory while processing it.  */
+# define FTW_CHDIR     FTW_CHDIR
+  FTW_DEPTH = 8,       /* Report files in directory before directory itself.*/
+# define FTW_DEPTH     FTW_DEPTH
+  FTW_ACTIONRETVAL = 16        /* Assume callback to return FTW_* values instead of
+                          zero to continue and non-zero to terminate.  */
+#  define FTW_ACTIONRETVAL FTW_ACTIONRETVAL
+};
+
+/* Return values from callback functions.  */
+enum
+{
+  FTW_CONTINUE = 0,    /* Continue with next sibling or for FTW_D with the
+                          first child.  */
+# define FTW_CONTINUE  FTW_CONTINUE
+  FTW_STOP = 1,                /* Return from `ftw' or `nftw' with FTW_STOP as return
+                          value.  */
+# define FTW_STOP      FTW_STOP
+  FTW_SKIP_SUBTREE = 2,        /* Only meaningful for FTW_D: Don't walk through the
+                          subtree, instead just continue with its next
+                          sibling. */
+# define FTW_SKIP_SUBTREE FTW_SKIP_SUBTREE
+  FTW_SKIP_SIBLINGS = 3,/* Continue with FTW_DP callback for current directory
+                           (if FTW_DEPTH) and then its siblings.  */
+# define FTW_SKIP_SIBLINGS FTW_SKIP_SIBLINGS
+};
+
+/* Structure used for fourth argument to callback function for `nftw'.  */
+struct FTW
+  {
+    int base;
+    int level;
+  };
+
+/* Convenient types for callback functions.  */
+typedef int (*nftw_func_t) (const char *filename,
+                            const struct stat *status,
+                            int flag,
+                            struct FTW *info);
+#define NFTW_FUNC_T nftw_func_t
+
+typedef void (*dir_notification_func_t) (void);
+
+extern int nftw(const char *dir,
+                nftw_func_t func,
+                dir_notification_func_t up,
+                int descriptors,
+                int flag);
+
+#endif /* ATALK_FTW_H */
index 2fb2ca292113c784141cf3a8f31d0169f7356852..70f9f628c7c61c0c0fe7018b91bfceb884865f43 100644 (file)
@@ -1,4 +1,4 @@
-#ifdef HAVE_NFSv4_ACLS
+#ifdef HAVE_ACLS
 
 #ifndef LDAPCONFIG_H
 #define LDAPCONFIG_H
@@ -37,6 +37,6 @@ extern struct ldap_pref ldap_prefs[];
 extern struct pref_array prefs_array[];
 extern int ldap_config_valid;
 
-#endif
+#endif /* LDAPCONFIG_H */
 
-#endif
+#endif /* HAVE_ACLS */
diff --git a/include/atalk/queue.h b/include/atalk/queue.h
new file mode 100644 (file)
index 0000000..a3f433e
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+   Copyright (c) 2010 Frank Lahm
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   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 ATALK_QUEUE_H
+#define ATALK_QUEUE_H
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+typedef struct qnode {
+    struct qnode *prev;
+    struct qnode *next;
+    void *data;
+} qnode_t;
+
+typedef qnode_t q_t;
+
+extern q_t *queue_init(void);
+extern void queue_destroy(q_t *q, void (*callback)(void *));
+#define queue_free(q) queue_destroy((q), free)
+extern qnode_t *enqueue(q_t *q, void *data);
+extern qnode_t *prequeue(q_t *q, void *data);
+extern void *dequeue(q_t *q);
+
+#endif  /* ATALK_QUEUE_H */
index 8479367bb4f42b2c8786d0ce4a48145aef07b659..b45a3a42daf088c958618a69a6f350c4ff6653a4 100644 (file)
@@ -23,17 +23,30 @@ typedef struct server_child {
   int count, nsessions, nforks;
 } server_child;
 
+typedef struct server_child_data {
+  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 */
+  uint32_t  time;              /* client boot time (from the mac client) */
+  int       killed;            /* 1 if we already tried to kill the client */
+  uint32_t  idlen;             /* clientid len (from the Mac client) */
+  char      *clientid;  /* clientid (from the Mac client) */
+  int       ipc_fds[2]; /* socketpair for IPC bw */
+  struct server_child_data **prevp, *next;
+} afp_child_t;
+
+extern int parent_or_child;
+
 /* server_child.c */
 extern server_child *server_child_alloc (const int, const int);
-extern int server_child_add (server_child *, const int, const pid_t);
-extern int server_child_remove (server_child *, const int, const pid_t);
+extern afp_child_t *server_child_add (server_child *, int, pid_t, uint ipc_fds[2]);
+extern int  server_child_remove (server_child *, const int, const pid_t);
 extern void server_child_free (server_child *);
 
 extern void server_child_kill (server_child *, const int, const int);
-extern void server_child_kill_one (server_child *children, const int forkid, const pid_t, const uid_t);
 extern void server_child_kill_one_by_id (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 int  server_child_transfer_session(server_child *children, int forkid, pid_t, uid_t, int, uint16_t);
 extern void server_child_setup (server_child *, const int, void (*)(const pid_t));
 extern void server_child_handler (server_child *);
 extern void server_reset_signal (void);
index eb899f8c891564cb7fe2a509c9a0531eba6d8475..332897a0993bd2f34ca3be79f942bfd75fe27818 100644 (file)
@@ -1,16 +1,12 @@
+#ifndef ATALK_SERVER_IPC_H
+#define ATALK_SERVER_IPC_H
 
 #include <atalk/server_child.h>
 
-#define IPC_KILLTOKEN   1
-#define IPC_GETSESSION  2
-
-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(u_int16_t command, int len, void *token);
-
-
-
+#define IPC_DISCOLDSESSION   0
+#define IPC_GETSESSION       1
 
+int ipc_server_read(server_child *children, int fd);
+int ipc_child_write(int fd, uint16_t command, int len, void *token);
 
+#endif /* IPC_GETSESSION_LOGIN */
index 13929953dd3ba9411cbbd816e37924fc0269a058..457b0c8a97a9dda25f01750705a06b6f50c417b1 100644 (file)
@@ -1,7 +1,3 @@
-/*
- * $Id: util.h,v 1.21 2010-02-28 22:29:16 didg Exp $
- */
-
 /*!
  * @file
  * Netatalk utility functions
@@ -20,6 +16,7 @@
 #ifdef HAVE_UNISTD_H
 #include <unistd.h>
 #endif /* HAVE_UNISTD_H */
+#include <poll.h>
 #include <netatalk/at.h>
 #include <atalk/unicode.h>
 
 #define EXITERR_CONF 2  /* error in config files/cmd line parameters */
 #define EXITERR_SYS  3  /* local system error */
 
+/* Print a SBT and exit */
+#define AFP_PANIC(why) \
+    do {                                            \
+        netatalk_panic(why);                        \
+        abort();                                    \
+    } while(0);
+
+/* LOG assert errors */
+#ifndef NDEBUG
+#define AFP_ASSERT(b) \
+    do {                                                                \
+        if (!(b)) {                                                     \
+            AFP_PANIC(#b);                                              \
+        } \
+    } while(0);
+#else
+#define AFP_ASSERT(b)
+#endif /* NDEBUG */
+
+#define STRCMP(a,b,c) (strcmp(a,c) b 0)
 
 #ifdef WITH_SENDFILE
 extern ssize_t sys_sendfile (int __out_fd, int __in_fd, off_t *__offset,size_t __count);
@@ -44,9 +61,9 @@ extern int atalk_aton     (char *, struct at_addr *);
 extern void bprint        (char *, int);
 extern int strdiacasecmp  (const char *, const char *);
 extern int strndiacasecmp (const char *, const char *, size_t);
-extern pid_t server_lock  (char * /*program*/, char * /*file*/, 
-                              int /*debug*/);
+extern pid_t server_lock  (char * /*program*/, char * /*file*/, int /*debug*/);
 extern void fault_setup          (void (*fn)(void *));
+extern void netatalk_panic(const char *why);
 #define server_unlock(x)  (unlink(x))
 
 /* strlcpy and strlcat are used by pam modules */
@@ -112,16 +129,41 @@ extern int lock_reg(int fd, int cmd, int type, off_t offest, int whence, off_t l
 
 extern int setnonblock(int fd, int cmd);
 extern ssize_t readt(int socket, void *data, const size_t length, int setnonblocking, int timeout);
+extern ssize_t writet(int socket, void *data, const size_t length, int setnonblocking, int timeout);
 extern const char *getip_string(const struct sockaddr *sa);
 extern unsigned int getip_port(const struct sockaddr *sa);
 extern void apply_ip_mask(struct sockaddr *ai, int maskbits);
 extern int compare_ip(const struct sockaddr *sa1, const struct sockaddr *sa2);
 
+/* Structures and functions dealing with dynamic pollfd arrays */
+enum fdtype {IPC_FD, LISTEN_FD};
+struct polldata {
+    enum fdtype fdtype; /* IPC fd or listening socket fd                 */
+    void *data;         /* pointer to AFPconfig for listening socket and *
+                         * pointer to afp_child_t for IPC fd             */
+};
+
+extern void fdset_add_fd(struct pollfd **fdsetp,
+                         struct polldata **polldatap,
+                         int *fdset_usedp,
+                         int *fdset_sizep,
+                         int fd,
+                         enum fdtype fdtype,
+                         void *data);
+extern void fdset_del_fd(struct pollfd **fdsetp,
+                         struct polldata **polldatap,
+                         int *fdset_usedp,
+                         int *fdset_sizep,
+                         int fd);
+extern int send_fd(int socket, int fd);
+extern int recv_fd(int fd, int nonblocking);
+
 /******************************************************************
  * unix.c
  *****************************************************************/
 
 extern const char *getcwdpath(void);
+extern char *stripped_slashes_basename(char *p);
 extern int lchdir(const char *dir);
-
+extern void randombytes(void *buf, int n);
 #endif  /* _ATALK_UTIL_H */
index 3103c1d1a8f9380276666e73943423ea67008f15..a9432675af5dd2dac68dd0d5352676a6a0d9213e 100644 (file)
@@ -1,5 +1,4 @@
 /*
-   $Id: uuid.h,v 1.1 2009-02-02 11:55:01 franklahm Exp $
    Copyright (c) 2008,2009 Frank Lahm <franklahm@gmail.com>
 
    This program is free software; you can redistribute it and/or modify
 #define UUID_BINSIZE 16
 #define UUID_STRINGSIZE 36
 
-typedef char *uuidp_t;
-typedef char uuid_t[UUID_BINSIZE];
+typedef unsigned char *uuidp_t;
+typedef unsigned char atalk_uuid_t[UUID_BINSIZE];
 
-typedef enum {UUID_USER = 1, UUID_GROUP} uuidtype_t;
+typedef enum {UUID_USER = 1, UUID_GROUP, UUID_LOCAL} uuidtype_t;
 extern char *uuidtype[];
 
 /* afp_options.c needs these. defined in libatalk/ldap.c */
@@ -42,9 +41,10 @@ extern char *ldap_uid_attr;
  ********************************************************/
 
 extern int getuuidfromname( const char *name, uuidtype_t type, uuidp_t uuid);
-extern int getnamefromuuid( uuidp_t uuidp, char **name, uuidtype_t *type);
+extern int getnamefromuuid( const uuidp_t uuidp, char **name, uuidtype_t *type);
+
 extern void localuuid_from_id(unsigned char *buf, uuidtype_t type, unsigned int id);
-extern int uuid_bin2string( uuidp_t uuidp, char **uuidstring);
+extern const char *uuid_bin2string(unsigned char *uuid);
 extern void uuid_string2bin( const char *uuidstring, uuidp_t uuid);
 
 #endif /* AFP_UUID_H */
index de1c008ce22d2f1b50e82d752cab64d195896fdf..0bd5079655c56c0dea583c537bfd1d3da1247070 100644 (file)
@@ -27,6 +27,7 @@
 
 #include <atalk/adouble.h>
 #include <atalk/volume.h>
+#include <atalk/acl.h>
 
 #define VFS_FUNC_ARGS_VALIDUPATH const struct vol *vol, const char *name
 #define VFS_FUNC_VARS_VALIDUPATH vol, name
 #define VFS_FUNC_ARGS_COPYFILE const struct vol *vol, int sfd, const char *src, const char *dst
 #define VFS_FUNC_VARS_COPYFILE vol, sfd, src, dst
 
+#ifdef HAVE_SOLARIS_ACLS
 #define VFS_FUNC_ARGS_ACL const struct vol *vol, const char *path, int cmd, int count, void *aces
 #define VFS_FUNC_VARS_ACL vol, path, cmd, count, aces
+#endif
+#ifdef HAVE_POSIX_ACLS
+#define VFS_FUNC_ARGS_ACL const struct vol *vol, const char *path, acl_type_t type, int count, acl_t acl
+#define VFS_FUNC_VARS_ACL vol, path, type, count, acl
+#endif
 
 #define VFS_FUNC_ARGS_REMOVE_ACL const struct vol *vol, const char *path, int dir
 #define VFS_FUNC_VARS_REMOVE_ACL vol, path, dir
@@ -101,9 +108,11 @@ struct vfs_ops {
     int (*vfs_renamefile)    (VFS_FUNC_ARGS_RENAMEFILE);
     int (*vfs_copyfile)      (VFS_FUNC_ARGS_COPYFILE);
 
+#ifdef HAVE_ACLS
     /* ACLs */
     int (*vfs_acl)           (VFS_FUNC_ARGS_ACL);
     int (*vfs_remove_acl)    (VFS_FUNC_ARGS_REMOVE_ACL);
+#endif
 
     /* Extended Attributes */
     int (*vfs_ea_getsize)    (VFS_FUNC_ARGS_EA_GETSIZE);
index 410b6b2aa0ddb10c1b22dfc25b2f96d46ceb7573..0f3a4024a6a36faedc4993783a731369e56237b3 100644 (file)
@@ -1,7 +1,3 @@
-/*
- * $Id: volinfo.h,v 1.10 2009-12-03 12:47:37 franklahm Exp $
- */
-
 #ifndef _ATALK_VOLINFO_H
 #define _ATALK_VOLINFO_H 1
 
@@ -18,6 +14,9 @@ typedef struct {
 } vol_opt_name_t;
 
 struct volinfo {
+    int                 retaincount;
+    int                 malloced;
+
     char                *v_name;
     char                *v_path;
     int                 v_flags;
@@ -33,10 +32,13 @@ struct volinfo {
     int                 v_vfs_ea;
     char                *(*ad_path)(const char *, int);
     char                *v_dbd_host;
-    int                 v_dbd_port;
+    char                *v_dbd_port;
 };
 
+struct volinfo *allocvolinfo(char *path);
 extern int loadvolinfo(char *path, struct volinfo *vol);
+extern void retainvolinfo(struct volinfo *vol);
+extern int closevolinfo(struct volinfo *vol);
 extern int savevolinfo(const struct vol *vol, const char *Cnid_srv, const char *Cnid_port);
 extern int vol_load_charsets(struct volinfo *vol);
 
index f1b2084b0c9fb6ebf47e01103fc898d20f110741..c2db33db7ccc6d1a4a6268e7a64f5cfdab12e0ad 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: volume.h,v 1.17 2010-04-10 08:24:54 franklahm Exp $
+ * $Id: volume.h,v 1.16 2010/03/31 09:47:32 franklahm Exp $
  *
  * Copyright (c) 1990,1994 Regents of The University of Michigan.
  * All Rights Reserved.  See COPYRIGHT.
@@ -27,9 +27,7 @@ struct vol {
     u_int16_t       v_vid;
     int             v_flags;
     char            *v_path;
-    struct dir      *v_dir, *v_root;
-    struct dir      *v_curdir;  /* cache */
-    hash_t          *v_hash;
+    struct dir      *v_root;
     time_t          v_mtime;
 
     charset_t       v_volcharset;
@@ -87,7 +85,7 @@ struct vol {
     char            *v_postexec;
     int             v_root_preexec_close;
     int             v_preexec_close;
-
+    char            *v_uuid;    /* For TimeMachine zeroconf record */
 #ifdef FORCE_UIDGID
     char            *v_forceuid;
     char            *v_forcegid;
@@ -108,7 +106,7 @@ struct vol {
 
 /*
   Flags that alter volume behaviour.
-  Keep in sync with include/atalk/volinfo.h and libatalk/util/volinfo.c
+  Keep in sync with libatalk/util/volinfo.c
 */
 #define AFPVOL_A2VOL     (1 << 5)   /* prodos volume */
 #define AFPVOL_CRLF      (1 << 6)   /* cr/lf translation */
@@ -135,8 +133,13 @@ struct vol {
 
 #define AFPVOL_CACHE     (1 << 21)   /* Use adouble v2 CNID caching. Default: yes */
 #define AFPVOL_INV_DOTS  (1 << 22)   /* dots files are invisible */
-#define AFPVOL_TM        (1 << 24)   /* Supports TimeMachine */
-#define AFPVOL_ACLS      (1 << 25)   /* Volume supports ACLS */
+#define AFPVOL_TM        (1 << 23)   /* Supports TimeMachine */
+#define AFPVOL_ACLS      (1 << 24)   /* Volume supports ACLS */
+#define AFPVOL_SEARCHDB  (1 << 25)   /* Use fast CNID db search instead of filesystem */
+/* Found this in branch dir-rewrite, maybe we want to use it sometimes */
+#if 0
+#define AFPVOL_CDROM     (1 << XX)   /* Ejectable media eg CD -> in memory CNID db */
+#endif
 
 /* Extended Attributes vfs indirection  */
 #define AFPVOL_EA_NONE           0   /* No EAs */
@@ -194,11 +197,7 @@ int wincheck(const struct vol *vol, const char *path);
 #define VOLPBIT_XBTOTAL 10
 #define VOLPBIT_BSIZE   11        /* block size */
 
-#ifdef AFP3x
 #define utf8_encoding() (afp_version >= 30)
-#else
-#define utf8_encoding() (0)
-#endif
 
 #define vol_noadouble(vol) (((vol)->v_flags & AFPVOL_NOADOUBLE) ? 1 : 0)
 #define vol_nodev(vol) (((vol)->v_flags & AFPVOL_NODEV) ? 1 : 0)
index 5fcf448399e1064f000a9860cfa09d8f59281bba..4c7500d6dd033db505b49ddc9114e2c403a55473 100644 (file)
@@ -1,16 +1,18 @@
 
 # Makefile.am for libatalk/
 
-SUBDIRS = acl adouble asp atp compat cnid dsi nbp netddp tdb util unicode vfs
+SUBDIRS = acl adouble asp atp bstring compat cnid dsi nbp netddp tdb util unicode vfs
 
 lib_LTLIBRARIES = libatalk.la
 
 libatalk_la_SOURCES = dummy.c
 
 libatalk_la_LIBADD  = \
+       acl/libacl.la \
        adouble/libadouble.la   \
        asp/libasp.la           \
        atp/libatp.la           \
+       bstring/libbstring.la \
        compat/libcompat.la     \
        dsi/libdsi.la           \
        nbp/libnbp.la           \
@@ -18,12 +20,14 @@ libatalk_la_LIBADD  = \
        util/libutil.la         \
        tdb/libtdb.la       \
        unicode/libunicode.la \
-       vfs/libvfs.la @LIBATALK_ACLS@
+       vfs/libvfs.la
 
 libatalk_la_DEPENDENCIES = \
+       acl/libacl.la \
        adouble/libadouble.la   \
        asp/libasp.la           \
        atp/libatp.la           \
+       bstring/libbstring.la \
        compat/libcompat.la     \
        dsi/libdsi.la           \
        nbp/libnbp.la           \
@@ -31,7 +35,7 @@ libatalk_la_DEPENDENCIES = \
        util/libutil.la         \
        tdb/libtdb.la       \
        unicode/libunicode.la \
-       vfs/libvfs.la @LIBATALK_ACLS@
+       vfs/libvfs.la
 
 libatalk_la_LDFLAGS = -static
 
index fe9f63011ea808e1fec7187200d5a2c37d1fad6a..e7f9753aca68a1400cd41dd409dc5744e8478463 100644 (file)
@@ -2,17 +2,12 @@
 
 noinst_HEADERS = aclldap.h cache.h
 
-if USE_NFSv4_ACLS
-
 noinst_LTLIBRARIES = libacl.la
-libacl_la_SOURCES = \
-       ldap.c          \
-       uuid.c          \
-       cache.c         \
-       ldap_config.c \
-       unix.c
-
-libacl_la_LDFLAGS = -lldap
+libacl_la_SOURCES = cache.c unix.c uuid.c
+libacl_la_LDFLAGS =
 
+if HAVE_LDAP
+libacl_la_SOURCES += ldap.c ldap_config.c
+libacl_la_LDFLAGS += -lldap
 endif
 
index 085ed0b4f28eda751a54f2969db1ec1a34272718..b4adea9f43a37874692a5b0c89468dbb26f82836 100644 (file)
@@ -1,5 +1,4 @@
 /*
-   $Id: aclldap.h,v 1.1 2009-02-02 11:55:01 franklahm Exp $
    Copyright (c) 2008,2009 Frank Lahm <franklahm@gmail.com>
 
    This program is free software; you can redistribute it and/or modify
  * Interface
  ********************************************************/
 
-/* 
- *   name: give me his name
- *   type: and type of USER or GROUP
- *   uuid_string: returns pointer to allocated string
- * returns 0 on success !=0 on errror  
- */
 extern int ldap_getuuidfromname( const char *name, uuidtype_t type, char **uuid_string);
-
-/* 
- *   uuipd: give me his uuid
- *   name:  returns pointer to allocated string
- *   type:  returns type: USER or GROUP
- * returns 0 on success !=0 on errror
- */
-extern int ldap_getnamefromuuid( uuidp_t uuidp, char **name, uuidtype_t *type); 
+extern int ldap_getnamefromuuid( const char *uuidstr, char **name, uuidtype_t *type); 
 
 #endif /* ACLLDAP_H */
index 7613880ba35fb236a845cabb7f65c0f2204c8bd6..585bb4801e8d4a727531f6ef3a4bff19f9d7c001 100644 (file)
@@ -48,22 +48,19 @@ static int dumpcache() {
     int i;
     int ret = 0;
     cacheduser_t *entry;
-    char *uuidstring = NULL;
     char timestr[200];
     struct tm *tmp = NULL;
 
     for ( i=0 ; i<256; i++) {
         if ((entry = namecache[i]) != NULL) {
             do {
-                uuid_bin2string(entry->uuid, &uuidstring);
                 tmp = localtime(&entry->creationtime);
                 if (tmp == NULL)
                     continue;
                 if (strftime(timestr, 200, "%c", tmp) == 0)
                     continue;
                 LOG(log_debug9, logtype_default, "namecache{%d}: name:%s, uuid:%s, type: %s, cached: %s",
-                    i, entry->name, uuidstring, uuidtype[entry->type], timestr);
-                free(uuidstring);
+                    i, entry->name, uuid_bin2string(entry->uuid), uuidtype[entry->type], timestr);
             } while ((entry = entry->next) != NULL);
         }
     }
@@ -71,15 +68,14 @@ static int dumpcache() {
     for ( i=0; i<256; i++) {
         if ((entry = uuidcache[i]) != NULL) {
             do {
-                uuid_bin2string(entry->uuid, &uuidstring);
+
                 tmp = localtime(&entry->creationtime);
                 if (tmp == NULL)
                     continue;
                 if (strftime(timestr, 200, "%c", tmp) == 0)
                     continue;
                 LOG(log_debug9, logtype_default, "uuidcache{%d}: uuid:%s, name:%s, type: %s, cached: %s",
-                    i, uuidstring, entry->name, uuidtype[entry->type], timestr);
-                free(uuidstring);
+                    i, uuid_bin2string(entry->uuid), entry->name, uuidtype[entry->type], timestr);
             } while ((entry = entry->next) != NULL);
         }
     }
@@ -102,7 +98,7 @@ static unsigned char hashstring(unsigned char *str) {
     return index;
 }
 
-/* hash uuid_t into unsigned char */
+/* hash atalk_uuid_t into unsigned char */
 static unsigned char hashuuid(uuidp_t uuid) {
     unsigned char index = 83;
     int i;
index 379ee73772f1ac99271827aa4096645afbceaae1..724ac4d5ba8e59d59bf4aa2f73c2cc3450165765 100644 (file)
@@ -1,5 +1,4 @@
 /*
-  $Id: ldap.c,v 1.7 2010-04-23 11:37:06 franklahm Exp $
   Copyright (c) 2008,2009 Frank Lahm <franklahm@gmail.com>
 
   This program is free software; you can redistribute it and/or modify
 #include "config.h"
 #endif /* HAVE_CONFIG_H */
 
+#ifdef HAVE_LDAP
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <sys/time.h>
 #include <string.h>
 #include <errno.h>
+#define LDAP_DEPRECATED 1
 #include <ldap.h>
 
 #include <atalk/logger.h>
@@ -247,9 +249,16 @@ cleanup:
  * Interface
  ********************************************************/
 
-/* 
- * returns allocated storage in uuid_string, caller must free it
- * returns 0 on success, -1 on error or not found
+/*! 
+ * Search UUID for name in LDAP
+ *
+ * Caller must free uuid_string when done with it
+ *
+ * @param name        (r) name to search
+ * @param type        (r) type of USER or GROUP
+ * @param uuid_string (w) result as pointer to allocated UUID-string
+ *
+ * @returns 0 on success, -1 on error or not found
  */
 int ldap_getuuidfromname( const char *name, uuidtype_t type, char **uuid_string) {
     int ret;
@@ -258,6 +267,9 @@ int ldap_getuuidfromname( const char *name, uuidtype_t type, char **uuid_string)
     char *attributes[]  = { ldap_uuid_attr, NULL};
     char *ldap_attr;
 
+    if (!ldap_config_valid)
+        return -1;
+
     /* make filter */
     if (type == UUID_GROUP)
         ldap_attr = ldap_group_attr;
@@ -283,13 +295,22 @@ int ldap_getuuidfromname( const char *name, uuidtype_t type, char **uuid_string)
  * LDAP search wrapper
  * returns allocated storage in name, caller must free it
  * returns 0 on success, -1 on error or not found
+ * 
+ * @param uuidstr  (r) uuid to search as ascii string
+ * @param name     (w) return pointer to name as allocated string
+ * @param type     (w) return type: USER or GROUP
+ *
+ * returns 0 on success, -1 on errror
  */
-int ldap_getnamefromuuid( char *uuidstr, char **name, uuidtype_t *type) {
+int ldap_getnamefromuuid( const char *uuidstr, char **name, uuidtype_t *type) {
     int ret;
     int len;
     char filter[256];       /* this should really be enough. we dont want to malloc everything! */
     char *attributes[]  = { NULL, NULL};
 
+    if (!ldap_config_valid)
+        return -1;
+
     /* make filter */
     len = snprintf( filter, 256, "%s=%s", ldap_uuid_attr, uuidstr);
     if (len >= 256 || len == -1) {
@@ -315,3 +336,4 @@ int ldap_getnamefromuuid( char *uuidstr, char **name, uuidtype_t *type) {
 
     return -1;
 }
+#endif  /* HAVE_LDAP */
index c302751b6eb850127b0689dd3bb9c4473eec8b0e..da37fb97027638370904806aba70aeef27003061 100644 (file)
@@ -1,5 +1,4 @@
 /*
-  $Id: ldap_config.c,v 1.4 2009-11-28 11:10:37 franklahm Exp $
   Copyright (c) 2009 Frank Lahm <franklahm@gmail.com>
 
   This program is free software; you can redistribute it and/or modify
 #include "config.h"
 #endif /* HAVE_CONFIG_H */
 
-#ifdef HAVE_NFSv4_ACLS
+#ifdef HAVE_LDAP
 
 #include <stdio.h>
+#include <stdlib.h>
 #include <errno.h>
 #include <string.h>
 #include <ctype.h>
@@ -124,7 +124,7 @@ int acl_ldap_readconfig(char *name)
 
     while(ldap_prefs[i].pref != NULL) {
         if ( ldap_prefs[i].valid != 0) {
-            LOG(log_error, logtype_afpd,"afp_ldap.conf: Missing option: \"%s\"", ldap_prefs[i].name);
+            LOG(log_debug, logtype_afpd,"afp_ldap.conf: Missing option: \"%s\"", ldap_prefs[i].name);
             ldap_config_valid = 0;
             break;
         }
@@ -133,16 +133,16 @@ int acl_ldap_readconfig(char *name)
 
     if (ldap_config_valid) {
         if (ldap_auth_method == LDAP_AUTH_NONE)
-            LOG(log_debug, logtype_afpd,"ldappref: Pref is ok. Using anonymous bind.");
+            LOG(log_debug, logtype_afpd,"afp_ldap.conf: Using anonymous bind.");
         else if (ldap_auth_method == LDAP_AUTH_SIMPLE)
-            LOG(log_debug, logtype_afpd,"ldappref: Pref is ok. Using simple bind.");
+            LOG(log_debug, logtype_afpd,"afp_ldap.conf: Using simple bind.");
         else {
             ldap_config_valid = 0;
-            LOG(log_error, logtype_afpd,"ldappref: Pref not ok. SASL not yet supported.");
+            LOG(log_error, logtype_afpd,"afp_ldap.conf: SASL not yet supported.");
         }
     } else
-        LOG(log_error, logtype_afpd,"ldappref: Pref is not ok.");
+        LOG(log_info, logtype_afpd,"afp_ldap.conf: not used");
     fclose(f);
     return 0;
 }
-#endif
+#endif /* HAVE_LDAP */
index c08ae8d6929b5cb241a7c1b3dacf2d03abdb85e8..be422aac38c7498d89e56c0f004f8cbe0374cff2 100644 (file)
@@ -16,7 +16,7 @@
 #include "config.h"
 #endif /* HAVE_CONFIG_H */
 
-#ifdef HAVE_NFSv4_ACLS
+#ifdef HAVE_SOLARIS_ACLS
 
 #include <unistd.h>
 #include <sys/types.h>
@@ -43,13 +43,24 @@ int get_nfsv4_acl(const char *name, ace_t **retAces)
 
     *retAces = NULL;
     /* Only call acl() for regular files and directories, otherwise just return 0 */
-    if (lstat(name, &st) != 0)
+    if (lstat(name, &st) != 0) {
+        LOG(log_warning, logtype_afpd, "get_nfsv4_acl(\"%s/%s\"): %s", getcwdpath(), name, strerror(errno));
         return -1;
-    if ( ! (S_ISREG(st.st_mode) || S_ISDIR(st.st_mode)))
+    }
+
+    if (S_ISLNK(st.st_mode))
+        /* sorry, no ACLs for symlinks */
         return 0;
 
-    if ((ace_count = acl(name, ACE_GETACLCNT, 0, NULL)) == 0)
+    if ( ! (S_ISREG(st.st_mode) || S_ISDIR(st.st_mode))) {
+        LOG(log_warning, logtype_afpd, "get_nfsv4_acl(\"%s/%s\"): special", getcwdpath(), name);
         return 0;
+    }
+
+    if ((ace_count = acl(name, ACE_GETACLCNT, 0, NULL)) == 0) {
+        LOG(log_warning, logtype_afpd, "get_nfsv4_acl(\"%s/%s\"): 0 ACEs", getcwdpath(), name);
+        return 0;
+    }
 
     if (ace_count == -1) {
         LOG(log_error, logtype_afpd, "get_nfsv4_acl: acl('%s/%s', ACE_GETACLCNT): ace_count %i, error: %s",
@@ -241,10 +252,9 @@ exit:
     if (cacl) free(cacl);
 
     LOG(log_debug, logtype_afpd, "nfsv4_chmod(\"%s/%s\", %04o): result: %u",
-        ret, getcwdpath(), name, mode);
+        getcwdpath(), name, mode, ret);
 
     return ret;
 }
 
-
-#endif /* HAVE_NFSv4_ACLS */
+#endif /* HAVE_SOLARIS_ACLS */
index 8943fd82817bb2b862ed9b581ae67a977bcc6133..074d9deb8a76c1da0343292b6250d940ee09d5c2 100644 (file)
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
+#include <inttypes.h>
+#include <sys/types.h>
+#include <pwd.h>
+#include <grp.h>
 
 #include <atalk/logger.h>
 #include <atalk/afp.h>
@@ -29,7 +33,7 @@
 #include "aclldap.h"
 #include "cache.h"
 
-char *uuidtype[] = {"NULL","USER", "GROUP"};
+char *uuidtype[] = {"NULL","USER", "GROUP", "LOCAL"};
 
 /********************************************************
  * Public helper function
@@ -96,39 +100,27 @@ void uuid_string2bin( const char *uuidstring, uuidp_t uuid) {
 
 }
 
-/* 
- * convert 16 byte binary uuid to neat ascii represantation including dashes
- * string is allocated and pointer returned. caller must freee.
+/*! 
+ * Convert 16 byte binary uuid to neat ascii represantation including dashes.
+ * 
+ * Returns pointer to static buffer.
  */
-int uuid_bin2string( uuidp_t uuid, char **uuidstring) {
-    char ascii[16] = { "0123456789ABCDEF" };
-    int nibble = 1;
+const char *uuid_bin2string(unsigned char *uuid) {
+    static char uuidstring[UUID_STRINGSIZE + 1];
+
     int i = 0;
     unsigned char c;
-    char *s;
-
-    *uuidstring = calloc(1, UUID_STRINGSIZE + 1);
-    if (*uuidstring == NULL) {
-        LOG(log_error, logtype_default, "uuid_bin2string: %s: error calloc'ing",strerror(errno));
-        return -1;
-    }
-    s = *uuidstring;
 
     while (i < UUID_STRINGSIZE) {
         c = *uuid;
-        if (nibble)
-            c = c >> 4;
-        else {
-            c &= 0x0f;
-            uuid++;
-        }
-        s[i] = ascii[c];
-        nibble ^= 1;
-        i++;
+        uuid++;
+        sprintf(uuidstring + i, "%02X", c);
+        i += 2;
         if (i==8 || i==13 || i==18 || i==23)
-            s[i++] = '-';
+            uuidstring[i++] = '-';
     }
-    return 0;
+    uuidstring[i] = 0;
+    return uuidstring;
 }
 
 /********************************************************
@@ -143,69 +135,102 @@ int uuid_bin2string( uuidp_t uuid, char **uuidstring) {
  */  
 int getuuidfromname( const char *name, uuidtype_t type, uuidp_t uuid) {
     int ret = 0;
+#ifdef HAVE_LDAP
     char *uuid_string = NULL;
-
+#endif
     ret = search_cachebyname( name, type, uuid);
-    if (ret == 0) {     /* found in cache */
-#ifdef DEBUG
-        uuid_bin2string( uuid, &uuid_string);
+    if (ret == 0) {
+        /* found in cache */
         LOG(log_debug, logtype_afpd, "getuuidfromname{cache}: name: %s, type: %s -> UUID: %s",
-            name, uuidtype[type], uuid_string);
-#else
-        LOG(log_debug, logtype_afpd, "getuuidfromname{cache}: name: %s, type: %s",
-            name, uuidtype[type]);
+            name, uuidtype[type], uuid_bin2string(uuid));
+    } else  {
+        /* if not found in cache */
+#ifdef HAVE_LDAP
+        if ((ret = ldap_getuuidfromname( name, type, &uuid_string)) == 0) {
+            uuid_string2bin( uuid_string, uuid);
+            LOG(log_debug, logtype_afpd, "getuuidfromname{local}: name: %s, type: %s -> UUID: %s",
+                name, uuidtype[type], uuid_bin2string(uuid));
+        } else {
+            LOG(log_debug, logtype_afpd, "getuuidfromname(\"%s\",t:%u): no result from ldap search",
+                name, type);
+        }
 #endif
-    } else  {                   /* if not found in cache */
-        ret = ldap_getuuidfromname( name, type, &uuid_string);
         if (ret != 0) {
-            LOG(log_info, logtype_afpd, "getuuidfromname: no result from ldap_getuuidfromname");
-            goto cleanup;
+            /* Build a local UUID */
+            if (type == UUID_USER) {
+                struct passwd *pwd;
+                if ((pwd = getpwnam(name)) == NULL) {
+                    LOG(log_error, logtype_afpd, "getuuidfromname(\"%s\",t:%u): unknown user",
+                        name, uuidtype[type]);
+                    goto cleanup;
+                }
+                localuuid_from_id(uuid, UUID_USER, pwd->pw_uid);
+            } else {
+                struct group *grp;
+                if ((grp = getgrnam(name)) == NULL) {
+                    LOG(log_error, logtype_afpd, "getuuidfromname(\"%s\",t:%u): unknown user",
+                        name, uuidtype[type]);
+                    goto cleanup;
+                }
+                localuuid_from_id(uuid, UUID_GROUP, grp->gr_gid);
+            }
+            LOG(log_debug, logtype_afpd, "getuuidfromname{local}: name: %s, type: %s -> UUID: %s",
+                name, uuidtype[type], uuid_bin2string(uuid));
         }
-        uuid_string2bin( uuid_string, uuid);
+        ret = 0;
         add_cachebyname( name, uuid, type, 0);
-        LOG(log_debug, logtype_afpd, "getuuidfromname{LDAP}: name: %s, type: %s -> UUID: %s",name, uuidtype[type], uuid_string);
     }
 
 cleanup:
-    free(uuid_string);
+#ifdef HAVE_LDAP
+    if (uuid_string) free(uuid_string);
+#endif
     return ret;
 }
 
-/* 
+
+/*
  * uuidp: pointer to a uuid
  * name: returns allocated buffer from ldap_getnamefromuuid
- * type: returns USER or GROUP
+ * type: returns USER, GROUP or LOCAL
  * return 0 on success !=0 on errror
  *
  * Caller must free name appropiately.
  */
-int getnamefromuuid( uuidp_t uuidp, char **name, uuidtype_t *type) {
+int getnamefromuuid(const uuidp_t uuidp, char **name, uuidtype_t *type) {
     int ret;
-    char *uuid_string = NULL;
 
     ret = search_cachebyuuid( uuidp, name, type);
-    if (ret == 0) {     /* found in cache */
-#ifdef DEBUG
-        uuid_bin2string( uuidp, &uuid_string);
+    if (ret == 0) {
+        /* found in cache */
         LOG(log_debug9, logtype_afpd, "getnamefromuuid{cache}: UUID: %s -> name: %s, type:%s",
-            uuid_string, *name, uuidtype[*type]);
-        free(uuid_string);
-        uuid_string = NULL;
-#endif
-    } else  {                   /* if not found in cache */
-        uuid_bin2string( uuidp, &uuid_string);
-        ret = ldap_getnamefromuuid( uuid_string, name, type);
+            uuid_bin2string(uuidp), *name, uuidtype[*type]);
+    } else {
+        /* not found in cache */
+
+        /* Check if UUID is a client local one */
+        if (memcmp(uuidp, local_user_uuid, 12) == 0
+            || memcmp(uuidp, local_group_uuid, 12) == 0) {
+            LOG(log_debug, logtype_afpd, "getnamefromuuid: local UUID: %" PRIu32 "",
+                ntohl(*(uint32_t *)(uuidp + 12)));
+            *type = UUID_LOCAL;
+            *name = strdup("UUID_LOCAL");
+            return 0;
+        }
+
+#ifdef HAVE_LDAP
+        ret = ldap_getnamefromuuid(uuid_bin2string(uuidp), name, type);
         if (ret != 0) {
             LOG(log_warning, logtype_afpd, "getnamefromuuid(%s): no result from ldap_getnamefromuuid",
-                uuid_string);
+                uuid_bin2string(uuidp));
             goto cleanup;
         }
         add_cachebyuuid( uuidp, *name, *type, 0);
         LOG(log_debug, logtype_afpd, "getnamefromuuid{LDAP}: UUID: %s -> name: %s, type:%s",
-            uuid_string, *name, uuidtype[*type]);
+            uuid_bin2string(uuidp), *name, uuidtype[*type]);
+#endif
     }
 
 cleanup:
-    free(uuid_string);
     return ret;
 }
index 51d87846820c0f34c92b36af9b5556faace25b98..5a1d585494af94c6811ff3efcf01714a3b9052d1 100644 (file)
@@ -266,6 +266,7 @@ ASP asp_getsession(ASP asp, server_child *server_children,
                            &(atp_sockaddr(asp->asp_atp)->sat_addr))) == NULL) 
          return NULL;
 
+    int dummy[2];
        switch ((pid = fork())) {
        case 0 : /* child */
          server_reset_signal();
@@ -296,29 +297,26 @@ ASP asp_getsession(ASP asp, server_child *server_children,
          break;
          
        default : /* parent process */
-         /* we need atomic setting or pb with tickle_handler 
-         */ 
-         switch (server_child_add(children, CHILD_ASPFORK, pid)) {
-         case 0: /* added child */
-           if ((asp_ac_tmp = (struct asp_child *) 
-                malloc(sizeof(struct asp_child)))) {
-             asp_ac_tmp->ac_pid = pid;
-             asp_ac_tmp->ac_state = ACSTATE_OK;
-             asp_ac_tmp->ac_sat = sat;
-             asp_ac_tmp->ac_sat.sat_port = asp->cmdbuf[1];
-             
-             asp->cmdbuf[0] = atp_sockaddr(atp)->sat_port;
-             asp->cmdbuf[1] = sid;
-             set_asp_ac(sid, asp_ac_tmp);
-             asperr = ASPERR_OK;
-             break;
-           } /* fall through if malloc fails */
-         case -1: /* bad error */
+         /* we need atomic setting or pb with tickle_handler */ 
+      if (server_child_add(children, CHILD_ASPFORK, pid, dummy)) {
+           if ((asp_ac_tmp = malloc(sizeof(struct asp_child))) == NULL) {
+            kill(pid, SIGQUIT); 
+            break;
+        }
+        asp_ac_tmp->ac_pid = pid;
+        asp_ac_tmp->ac_state = ACSTATE_OK;
+        asp_ac_tmp->ac_sat = sat;
+        asp_ac_tmp->ac_sat.sat_port = asp->cmdbuf[1];
+           
+        asp->cmdbuf[0] = atp_sockaddr(atp)->sat_port;
+        asp->cmdbuf[1] = sid;
+        set_asp_ac(sid, asp_ac_tmp);
+        asperr = ASPERR_OK;
+        break;
+      } else {
            kill(pid, SIGQUIT); 
            break;
-         default: /* non-fatal error */
-           break;
-         }
+      }
          atp_close(atp);
          break;
        }
diff --git a/libatalk/bstring/.gitignore b/libatalk/bstring/.gitignore
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/bstring/Makefile.am b/libatalk/bstring/Makefile.am
new file mode 100644 (file)
index 0000000..39f78c3
--- /dev/null
@@ -0,0 +1,6 @@
+# Makefile.am for libatalk/adouble/
+
+noinst_LTLIBRARIES = libbstring.la
+
+libbstring_la_SOURCES = bstrlib.c bstradd.c
+
diff --git a/libatalk/bstring/bstradd.c b/libatalk/bstring/bstradd.c
new file mode 100644 (file)
index 0000000..7b59b2e
--- /dev/null
@@ -0,0 +1,208 @@
+/*
+  $Id: bstradd.c,v 1.1.2.1 2010-02-01 10:56:08 franklahm Exp $
+  Copyright (c) 2010 Frank Lahm <franklahm@gmail.com>
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+*/
+
+/*!
+ * @file
+ * Additional functions for bstrlib
+ */
+
+#include <stdio.h>
+#include <stddef.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include <atalk/bstrlib.h>
+
+/* Optionally include a mechanism for debugging memory */
+
+#if defined(MEMORY_DEBUG) || defined(BSTRLIB_MEMORY_DEBUG)
+#include "memdbg.h"
+#endif
+
+#ifndef bstr__alloc
+#define bstr__alloc(x) malloc (x)
+#endif
+
+#ifndef bstr__free
+#define bstr__free(p) free (p)
+#endif
+
+#ifndef bstr__realloc
+#define bstr__realloc(p,x) realloc ((p), (x))
+#endif
+
+#ifndef bstr__memcpy
+#define bstr__memcpy(d,s,l) memcpy ((d), (s), (l))
+#endif
+
+#ifndef bstr__memmove
+#define bstr__memmove(d,s,l) memmove ((d), (s), (l))
+#endif
+
+#ifndef bstr__memset
+#define bstr__memset(d,c,l) memset ((d), (c), (l))
+#endif
+
+#ifndef bstr__memcmp
+#define bstr__memcmp(d,c,l) memcmp ((d), (c), (l))
+#endif
+
+#ifndef bstr__memchr
+#define bstr__memchr(s,c,l) memchr ((s), (c), (l))
+#endif
+
+/*************************************************************************
+ * Stuff for making bstrings referencing c-strings
+ ************************************************************************/
+
+/*!
+ * @brief Create a bstring referencing "str"
+ *
+ * This is usefull if a well know code path uses string, often doing strlen on string.
+ * By converting to bstring which carries the strlen, the repeated computation can be avoided.
+ */
+bstring brefcstr (char *str) {
+    bstring b;
+    int i;
+    size_t j;
+
+       if (str == NULL)
+        return NULL;
+       j = strlen(str);
+
+       b = (bstring)bstr__alloc(sizeof(struct tagbstring));
+       if (NULL == b)
+        return NULL;
+
+       b->slen = (int) j;
+    b->mlen = -1;
+    b->data = str;
+
+       return b;
+}
+
+/*!
+ * @brief Free up the bstring, WITHOUT freeing the pointed to c-string!
+ */
+int bunrefcstr (bstring b) {
+       if (b == NULL || b->slen < 0 || b->mlen > 0 || b->data == NULL)
+               return BSTR_ERR;
+
+       /* In case there is any stale usage, there is one more chance to 
+          notice this error. */
+
+       b->slen = -1;
+       b->mlen = -__LINE__;
+       b->data = NULL;
+
+       bstr__free (b);
+       return BSTR_OK;
+}
+
+/*************************************************************************
+ * stuff for bstrList
+ ************************************************************************/
+
+/*!
+ * @brief Create an empty list with preallocated storage for at least 'min' members
+ */
+struct bstrList *bstrListCreateMin(int min)
+{
+    struct bstrList *sl = NULL;
+
+    if ((sl = bstrListCreate()) == NULL)
+        return NULL;
+
+    if ((bstrListAlloc(sl, min)) != BSTR_OK) {
+        bstrListDestroy(sl);
+        return NULL;
+    }
+
+    return sl;
+}
+
+/*!
+ * @brief Push a bstring to the end of a list
+ */
+int bstrListPush(struct bstrList *sl, bstring bs)
+{
+    if (sl->qty == sl->mlen) {
+        if ((bstrListAlloc(sl, sl->qty + 1)) != BSTR_OK)
+            return BSTR_ERR;
+    }
+
+    sl->entry[sl->qty] = bs;
+    sl->qty++;
+    return BSTR_OK;
+}
+
+/*!
+ * @brief Pop a bstring from the end of a list
+ */
+bstring bstrListPop(struct bstrList *sl)
+{
+    return NULL;
+}
+
+/*!
+ * @brief Inverse bjoin
+ */
+bstring bjoinInv(const struct bstrList * bl, const_bstring sep) {
+    bstring b;
+    int i, j, c, v;
+
+    if (bl == NULL || bl->qty < 0)
+        return NULL;
+    if (sep != NULL && (sep->slen < 0 || sep->data == NULL))
+        return NULL;
+
+    for (i = 0, c = 1; i < bl->qty; i++) {
+        v = bl->entry[i]->slen;
+        if (v < 0)
+            return NULL;/* Invalid input */
+        c += v;
+        if (c < 0)
+            return NULL;/* Wrap around ?? */
+    }
+
+    if (sep != NULL)
+        c += (bl->qty - 1) * sep->slen;
+
+    b = (bstring) bstr__alloc (sizeof (struct tagbstring));
+    if (NULL == b)
+        return NULL; /* Out of memory */
+    b->data = (unsigned char *) bstr__alloc (c);
+    if (b->data == NULL) {
+        bstr__free (b);
+        return NULL;
+    }
+
+    b->mlen = c;
+    b->slen = c-1;
+
+    for (i = bl->qty - 1, c = 0, j = 0; i >= 0; i--, j++) {
+        if (j > 0 && sep != NULL) {
+            bstr__memcpy (b->data + c, sep->data, sep->slen);
+            c += sep->slen;
+        }
+        v = bl->entry[i]->slen;
+        bstr__memcpy (b->data + c, bl->entry[i]->data, v);
+        c += v;
+    }
+    b->data[c] = (unsigned char) '\0';
+    return b;
+}
diff --git a/libatalk/bstring/bstrlib.c b/libatalk/bstring/bstrlib.c
new file mode 100644 (file)
index 0000000..29e113e
--- /dev/null
@@ -0,0 +1,2956 @@
+/*
+ * This source file is part of the bstring string library.  This code was
+ * written by Paul Hsieh in 2002-2008, and is covered by the BSD open source 
+ * license and the GPL. Refer to the accompanying documentation for details 
+ * on usage and license.
+ */
+
+/*
+ * bstrlib.c
+ *
+ * This file is the core module for implementing the bstring functions.
+ */
+
+#include <stdio.h>
+#include <stddef.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include <atalk/bstrlib.h>
+
+/* Optionally include a mechanism for debugging memory */
+
+#if defined(MEMORY_DEBUG) || defined(BSTRLIB_MEMORY_DEBUG)
+#include "memdbg.h"
+#endif
+
+#ifndef bstr__alloc
+#define bstr__alloc(x) malloc (x)
+#endif
+
+#ifndef bstr__free
+#define bstr__free(p) free (p)
+#endif
+
+#ifndef bstr__realloc
+#define bstr__realloc(p,x) realloc ((p), (x))
+#endif
+
+#ifndef bstr__memcpy
+#define bstr__memcpy(d,s,l) memcpy ((d), (s), (l))
+#endif
+
+#ifndef bstr__memmove
+#define bstr__memmove(d,s,l) memmove ((d), (s), (l))
+#endif
+
+#ifndef bstr__memset
+#define bstr__memset(d,c,l) memset ((d), (c), (l))
+#endif
+
+#ifndef bstr__memcmp
+#define bstr__memcmp(d,c,l) memcmp ((d), (c), (l))
+#endif
+
+#ifndef bstr__memchr
+#define bstr__memchr(s,c,l) memchr ((s), (c), (l))
+#endif
+
+/* Just a length safe wrapper for memmove. */
+
+#define bBlockCopy(D,S,L) { if ((L) > 0) bstr__memmove ((D),(S),(L)); }
+
+/* Compute the snapped size for a given requested size.  By snapping to powers
+   of 2 like this, repeated reallocations are avoided. */
+static int snapUpSize (int i) {
+       if (i < 8) {
+               i = 8;
+       } else {
+               unsigned int j;
+               j = (unsigned int) i;
+
+               j |= (j >>  1);
+               j |= (j >>  2);
+               j |= (j >>  4);
+               j |= (j >>  8);         /* Ok, since int >= 16 bits */
+#if (UINT_MAX != 0xffff)
+               j |= (j >> 16);         /* For 32 bit int systems */
+#if (UINT_MAX > 0xffffffffUL)
+               j |= (j >> 32);         /* For 64 bit int systems */
+#endif
+#endif
+               /* Least power of two greater than i */
+               j++;
+               if ((int) j >= i) i = (int) j;
+       }
+       return i;
+}
+
+/*  int balloc (bstring b, int len)
+ *
+ *  Increase the size of the memory backing the bstring b to at least len.
+ */
+int balloc (bstring b, int olen) {
+       int len;
+       if (b == NULL || b->data == NULL || b->slen < 0 || b->mlen <= 0 || 
+           b->mlen < b->slen || olen <= 0) {
+               return BSTR_ERR;
+       }
+
+       if (olen >= b->mlen) {
+               unsigned char * x;
+
+               if ((len = snapUpSize (olen)) <= b->mlen) return BSTR_OK;
+
+               /* Assume probability of a non-moving realloc is 0.125 */
+               if (7 * b->mlen < 8 * b->slen) {
+
+                       /* If slen is close to mlen in size then use realloc to reduce
+                          the memory defragmentation */
+
+                       reallocStrategy:;
+
+                       x = (unsigned char *) bstr__realloc (b->data, (size_t) len);
+                       if (x == NULL) {
+
+                               /* Since we failed, try allocating the tighest possible 
+                                  allocation */
+
+                               if (NULL == (x = (unsigned char *) bstr__realloc (b->data, (size_t) (len = olen)))) {
+                                       return BSTR_ERR;
+                               }
+                       }
+               } else {
+
+                       /* If slen is not close to mlen then avoid the penalty of copying
+                          the extra bytes that are allocated, but not considered part of
+                          the string */
+
+                       if (NULL == (x = (unsigned char *) bstr__alloc ((size_t) len))) {
+
+                               /* Perhaps there is no available memory for the two 
+                                  allocations to be in memory at once */
+
+                               goto reallocStrategy;
+
+                       } else {
+                               if (b->slen) bstr__memcpy ((char *) x, (char *) b->data, (size_t) b->slen);
+                               bstr__free (b->data);
+                       }
+               }
+               b->data = x;
+               b->mlen = len;
+               b->data[b->slen] = (unsigned char) '\0';
+       }
+
+       return BSTR_OK;
+}
+
+/*  int ballocmin (bstring b, int len)
+ *
+ *  Set the size of the memory backing the bstring b to len or b->slen+1,
+ *  whichever is larger.  Note that repeated use of this function can degrade
+ *  performance.
+ */
+int ballocmin (bstring b, int len) {
+       unsigned char * s;
+
+       if (b == NULL || b->data == NULL || (b->slen+1) < 0 || b->mlen <= 0 || 
+           b->mlen < b->slen || len <= 0) {
+               return BSTR_ERR;
+       }
+
+       if (len < b->slen + 1) len = b->slen + 1;
+
+       if (len != b->mlen) {
+               s = (unsigned char *) bstr__realloc (b->data, (size_t) len);
+               if (NULL == s) return BSTR_ERR;
+               s[b->slen] = (unsigned char) '\0';
+               b->data = s;
+               b->mlen = len;
+       }
+
+       return BSTR_OK;
+}
+
+/*  bstring bfromcstr (const char * str)
+ *
+ *  Create a bstring which contains the contents of the '\0' terminated char *
+ *  buffer str.
+ */
+bstring bfromcstr (const char * str) {
+bstring b;
+int i;
+size_t j;
+
+       if (str == NULL) return NULL;
+       j = (strlen) (str);
+       i = snapUpSize ((int) (j + (2 - (j != 0))));
+       if (i <= (int) j) return NULL;
+
+       b = (bstring) bstr__alloc (sizeof (struct tagbstring));
+       if (NULL == b) return NULL;
+       b->slen = (int) j;
+       if (NULL == (b->data = (unsigned char *) bstr__alloc (b->mlen = i))) {
+               bstr__free (b);
+               return NULL;
+       }
+
+       bstr__memcpy (b->data, str, j+1);
+       return b;
+}
+
+/*  bstring bfromcstralloc (int mlen, const char * str)
+ *
+ *  Create a bstring which contains the contents of the '\0' terminated char *
+ *  buffer str.  The memory buffer backing the string is at least len 
+ *  characters in length.
+ */
+bstring bfromcstralloc (int mlen, const char * str) {
+bstring b;
+int i;
+size_t j;
+
+       if (str == NULL) return NULL;
+       j = (strlen) (str);
+       i = snapUpSize ((int) (j + (2 - (j != 0))));
+       if (i <= (int) j) return NULL;
+
+       b = (bstring) bstr__alloc (sizeof (struct tagbstring));
+       if (b == NULL) return NULL;
+       b->slen = (int) j;
+       if (i < mlen) i = mlen;
+
+       if (NULL == (b->data = (unsigned char *) bstr__alloc (b->mlen = i))) {
+               bstr__free (b);
+               return NULL;
+       }
+
+       bstr__memcpy (b->data, str, j+1);
+       return b;
+}
+
+/*  bstring blk2bstr (const void * blk, int len)
+ *
+ *  Create a bstring which contains the content of the block blk of length 
+ *  len.
+ */
+bstring blk2bstr (const void * blk, int len) {
+bstring b;
+int i;
+
+       if (blk == NULL || len < 0) return NULL;
+       b = (bstring) bstr__alloc (sizeof (struct tagbstring));
+       if (b == NULL) return NULL;
+       b->slen = len;
+
+       i = len + (2 - (len != 0));
+       i = snapUpSize (i);
+
+       b->mlen = i;
+
+       b->data = (unsigned char *) bstr__alloc ((size_t) b->mlen);
+       if (b->data == NULL) {
+               bstr__free (b);
+               return NULL;
+       }
+
+       if (len > 0) bstr__memcpy (b->data, blk, (size_t) len);
+       b->data[len] = (unsigned char) '\0';
+
+       return b;
+}
+
+/*  char * bstr2cstr (const_bstring s, char z)
+ *
+ *  Create a '\0' terminated char * buffer which is equal to the contents of 
+ *  the bstring s, except that any contained '\0' characters are converted 
+ *  to the character in z. This returned value should be freed with a 
+ *  bcstrfree () call, by the calling application.
+ */
+char * bstr2cstr (const_bstring b, char z) {
+int i, l;
+char * r;
+
+       if (b == NULL || b->slen < 0 || b->data == NULL) return NULL;
+       l = b->slen;
+       r = (char *) bstr__alloc ((size_t) (l + 1));
+       if (r == NULL) return r;
+
+       for (i=0; i < l; i ++) {
+               r[i] = (char) ((b->data[i] == '\0') ? z : (char) (b->data[i]));
+       }
+
+       r[l] = (unsigned char) '\0';
+
+       return r;
+}
+
+/*  int bcstrfree (char * s)
+ *
+ *  Frees a C-string generated by bstr2cstr ().  This is normally unnecessary
+ *  since it just wraps a call to bstr__free (), however, if bstr__alloc () 
+ *  and bstr__free () have been redefined as a macros within the bstrlib 
+ *  module (via defining them in memdbg.h after defining 
+ *  BSTRLIB_MEMORY_DEBUG) with some difference in behaviour from the std 
+ *  library functions, then this allows a correct way of freeing the memory 
+ *  that allows higher level code to be independent from these macro 
+ *  redefinitions.
+ */
+int bcstrfree (char * s) {
+       if (s) {
+               bstr__free (s);
+               return BSTR_OK;
+       }
+       return BSTR_ERR;
+}
+
+/*  int bconcat (bstring b0, const_bstring b1)
+ *
+ *  Concatenate the bstring b1 to the bstring b0.
+ */
+int bconcat (bstring b0, const_bstring b1) {
+int len, d;
+bstring aux = (bstring) b1;
+
+       if (b0 == NULL || b1 == NULL || b0->data == NULL || b1->data == NULL) return BSTR_ERR;
+
+       d = b0->slen;
+       len = b1->slen;
+       if ((d | (b0->mlen - d) | len | (d + len)) < 0) return BSTR_ERR;
+
+       if (b0->mlen <= d + len + 1) {
+               ptrdiff_t pd = b1->data - b0->data;
+               if (0 <= pd && pd < b0->mlen) {
+                       if (NULL == (aux = bstrcpy (b1))) return BSTR_ERR;
+               }
+               if (balloc (b0, d + len + 1) != BSTR_OK) {
+                       if (aux != b1) bdestroy (aux);
+                       return BSTR_ERR;
+               }
+       }
+
+       bBlockCopy (&b0->data[d], &aux->data[0], (size_t) len);
+       b0->data[d + len] = (unsigned char) '\0';
+       b0->slen = d + len;
+       if (aux != b1) bdestroy (aux);
+       return BSTR_OK;
+}
+
+/*  int bconchar (bstring b, char c)
+/ *
+ *  Concatenate the single character c to the bstring b.
+ */
+int bconchar (bstring b, char c) {
+int d;
+
+       if (b == NULL) return BSTR_ERR;
+       d = b->slen;
+       if ((d | (b->mlen - d)) < 0 || balloc (b, d + 2) != BSTR_OK) return BSTR_ERR;
+       b->data[d] = (unsigned char) c;
+       b->data[d + 1] = (unsigned char) '\0';
+       b->slen++;
+       return BSTR_OK;
+}
+
+/*  int bcatcstr (bstring b, const char * s)
+ *
+ *  Concatenate a char * string to a bstring.
+ */
+int bcatcstr (bstring b, const char * s) {
+char * d;
+int i, l;
+
+       if (b == NULL || b->data == NULL || b->slen < 0 || b->mlen < b->slen
+        || b->mlen <= 0 || s == NULL) return BSTR_ERR;
+
+       /* Optimistically concatenate directly */
+       l = b->mlen - b->slen;
+       d = (char *) &b->data[b->slen];
+       for (i=0; i < l; i++) {
+               if ((*d++ = *s++) == '\0') {
+                       b->slen += i;
+                       return BSTR_OK;
+               }
+       }
+       b->slen += i;
+
+       /* Need to explicitely resize and concatenate tail */
+       return bcatblk (b, (const void *) s, (int) strlen (s));
+}
+
+/*  int bcatblk (bstring b, const void * s, int len)
+ *
+ *  Concatenate a fixed length buffer to a bstring.
+ */
+int bcatblk (bstring b, const void * s, int len) {
+int nl;
+
+       if (b == NULL || b->data == NULL || b->slen < 0 || b->mlen < b->slen
+        || b->mlen <= 0 || s == NULL || len < 0) return BSTR_ERR;
+
+       if (0 > (nl = b->slen + len)) return BSTR_ERR; /* Overflow? */
+       if (b->mlen <= nl && 0 > balloc (b, nl + 1)) return BSTR_ERR;
+
+       bBlockCopy (&b->data[b->slen], s, (size_t) len);
+       b->slen = nl;
+       b->data[nl] = (unsigned char) '\0';
+       return BSTR_OK;
+}
+
+/*  bstring bstrcpy (const_bstring b)
+ *
+ *  Create a copy of the bstring b.
+ */
+bstring bstrcpy (const_bstring b) {
+bstring b0;
+int i,j;
+
+       /* Attempted to copy an invalid string? */
+       if (b == NULL || b->slen < 0 || b->data == NULL) return NULL;
+
+       b0 = (bstring) bstr__alloc (sizeof (struct tagbstring));
+       if (b0 == NULL) {
+               /* Unable to allocate memory for string header */
+               return NULL;
+       }
+
+       i = b->slen;
+       j = snapUpSize (i + 1);
+
+       b0->data = (unsigned char *) bstr__alloc (j);
+       if (b0->data == NULL) {
+               j = i + 1;
+               b0->data = (unsigned char *) bstr__alloc (j);
+               if (b0->data == NULL) {
+                       /* Unable to allocate memory for string data */
+                       bstr__free (b0);
+                       return NULL;
+               }
+       }
+
+       b0->mlen = j;
+       b0->slen = i;
+
+       if (i) bstr__memcpy ((char *) b0->data, (char *) b->data, i);
+       b0->data[b0->slen] = (unsigned char) '\0';
+
+       return b0;
+}
+
+/*  int bassign (bstring a, const_bstring b)
+ *
+ *  Overwrite the string a with the contents of string b.
+ */
+int bassign (bstring a, const_bstring b) {
+       if (b == NULL || b->data == NULL || b->slen < 0)
+               return BSTR_ERR;
+       if (b->slen != 0) {
+               if (balloc (a, b->slen) != BSTR_OK) return BSTR_ERR;
+               bstr__memmove (a->data, b->data, b->slen);
+       } else {
+               if (a == NULL || a->data == NULL || a->mlen < a->slen || 
+                   a->slen < 0 || a->mlen == 0) 
+                       return BSTR_ERR;
+       }
+       a->data[b->slen] = (unsigned char) '\0';
+       a->slen = b->slen;
+       return BSTR_OK;
+}
+
+/*  int bassignmidstr (bstring a, const_bstring b, int left, int len)
+ *
+ *  Overwrite the string a with the middle of contents of string b 
+ *  starting from position left and running for a length len.  left and 
+ *  len are clamped to the ends of b as with the function bmidstr.
+ */
+int bassignmidstr (bstring a, const_bstring b, int left, int len) {
+       if (b == NULL || b->data == NULL || b->slen < 0)
+               return BSTR_ERR;
+
+       if (left < 0) {
+               len += left;
+               left = 0;
+       }
+
+       if (len > b->slen - left) len = b->slen - left;
+
+       if (a == NULL || a->data == NULL || a->mlen < a->slen ||
+           a->slen < 0 || a->mlen == 0)
+               return BSTR_ERR;
+
+       if (len > 0) {
+               if (balloc (a, len) != BSTR_OK) return BSTR_ERR;
+               bstr__memmove (a->data, b->data + left, len);
+               a->slen = len;
+       } else {
+               a->slen = 0;
+       }
+       a->data[a->slen] = (unsigned char) '\0';
+       return BSTR_OK;
+}
+
+/*  int bassigncstr (bstring a, const char * str)
+ *
+ *  Overwrite the string a with the contents of char * string str.  Note that 
+ *  the bstring a must be a well defined and writable bstring.  If an error 
+ *  occurs BSTR_ERR is returned however a may be partially overwritten.
+ */
+int bassigncstr (bstring a, const char * str) {
+int i;
+size_t len;
+       if (a == NULL || a->data == NULL || a->mlen < a->slen ||
+           a->slen < 0 || a->mlen == 0 || NULL == str) 
+               return BSTR_ERR;
+
+       for (i=0; i < a->mlen; i++) {
+               if ('\0' == (a->data[i] = str[i])) {
+                       a->slen = i;
+                       return BSTR_OK;
+               }
+       }
+
+       a->slen = i;
+       len = strlen (str + i);
+       if (len > INT_MAX || i + len + 1 > INT_MAX ||
+           0 > balloc (a, (int) (i + len + 1))) return BSTR_ERR;
+       bBlockCopy (a->data + i, str + i, (size_t) len + 1);
+       a->slen += (int) len;
+       return BSTR_OK;
+}
+
+/*  int bassignblk (bstring a, const void * s, int len)
+ *
+ *  Overwrite the string a with the contents of the block (s, len).  Note that 
+ *  the bstring a must be a well defined and writable bstring.  If an error 
+ *  occurs BSTR_ERR is returned and a is not overwritten.
+ */
+int bassignblk (bstring a, const void * s, int len) {
+       if (a == NULL || a->data == NULL || a->mlen < a->slen ||
+           a->slen < 0 || a->mlen == 0 || NULL == s || len + 1 < 1) 
+               return BSTR_ERR;
+       if (len + 1 > a->mlen && 0 > balloc (a, len + 1)) return BSTR_ERR;
+       bBlockCopy (a->data, s, (size_t) len);
+       a->data[len] = (unsigned char) '\0';
+       a->slen = len;
+       return BSTR_OK;
+}
+
+/*  int btrunc (bstring b, int n)
+ *
+ *  Truncate the bstring to at most n characters.
+ */
+int btrunc (bstring b, int n) {
+       if (n < 0 || b == NULL || b->data == NULL || b->mlen < b->slen ||
+           b->slen < 0 || b->mlen <= 0) return BSTR_ERR;
+       if (b->slen > n) {
+               b->slen = n;
+               b->data[n] = (unsigned char) '\0';
+       }
+       return BSTR_OK;
+}
+
+#define   upcase(c) (toupper ((unsigned char) c))
+#define downcase(c) (tolower ((unsigned char) c))
+#define   wspace(c) (isspace ((unsigned char) c))
+
+/*  int btoupper (bstring b)
+ *
+ *  Convert contents of bstring to upper case.
+ */
+int btoupper (bstring b) {
+int i, len;
+       if (b == NULL || b->data == NULL || b->mlen < b->slen ||
+           b->slen < 0 || b->mlen <= 0) return BSTR_ERR;
+       for (i=0, len = b->slen; i < len; i++) {
+               b->data[i] = (unsigned char) upcase (b->data[i]);
+       }
+       return BSTR_OK;
+}
+
+/*  int btolower (bstring b)
+ *
+ *  Convert contents of bstring to lower case.
+ */
+int btolower (bstring b) {
+int i, len;
+       if (b == NULL || b->data == NULL || b->mlen < b->slen ||
+           b->slen < 0 || b->mlen <= 0) return BSTR_ERR;
+       for (i=0, len = b->slen; i < len; i++) {
+               b->data[i] = (unsigned char) downcase (b->data[i]);
+       }
+       return BSTR_OK;
+}
+
+/*  int bstricmp (const_bstring b0, const_bstring b1)
+ *
+ *  Compare two strings without differentiating between case.  The return 
+ *  value is the difference of the values of the characters where the two 
+ *  strings first differ after lower case transformation, otherwise 0 is 
+ *  returned indicating that the strings are equal.  If the lengths are 
+ *  different, then a difference from 0 is given, but if the first extra 
+ *  character is '\0', then it is taken to be the value UCHAR_MAX+1.
+ */
+int bstricmp (const_bstring b0, const_bstring b1) {
+int i, v, n;
+
+       if (bdata (b0) == NULL || b0->slen < 0 || 
+           bdata (b1) == NULL || b1->slen < 0) return SHRT_MIN;
+       if ((n = b0->slen) > b1->slen) n = b1->slen;
+       else if (b0->slen == b1->slen && b0->data == b1->data) return BSTR_OK;
+
+       for (i = 0; i < n; i ++) {
+               v  = (char) downcase (b0->data[i])
+                  - (char) downcase (b1->data[i]);
+               if (0 != v) return v;
+       }
+
+       if (b0->slen > n) {
+               v = (char) downcase (b0->data[n]);
+               if (v) return v;
+               return UCHAR_MAX + 1;
+       }
+       if (b1->slen > n) {
+               v = - (char) downcase (b1->data[n]);
+               if (v) return v;
+               return - (int) (UCHAR_MAX + 1);
+       }
+       return BSTR_OK;
+}
+
+/*  int bstrnicmp (const_bstring b0, const_bstring b1, int n)
+ *
+ *  Compare two strings without differentiating between case for at most n
+ *  characters.  If the position where the two strings first differ is
+ *  before the nth position, the return value is the difference of the values
+ *  of the characters, otherwise 0 is returned.  If the lengths are different
+ *  and less than n characters, then a difference from 0 is given, but if the 
+ *  first extra character is '\0', then it is taken to be the value 
+ *  UCHAR_MAX+1.
+ */
+int bstrnicmp (const_bstring b0, const_bstring b1, int n) {
+int i, v, m;
+
+       if (bdata (b0) == NULL || b0->slen < 0 || 
+           bdata (b1) == NULL || b1->slen < 0 || n < 0) return SHRT_MIN;
+       m = n;
+       if (m > b0->slen) m = b0->slen;
+       if (m > b1->slen) m = b1->slen;
+
+       if (b0->data != b1->data) {
+               for (i = 0; i < m; i ++) {
+                       v  = (char) downcase (b0->data[i]);
+                       v -= (char) downcase (b1->data[i]);
+                       if (v != 0) return b0->data[i] - b1->data[i];
+               }
+       }
+
+       if (n == m || b0->slen == b1->slen) return BSTR_OK;
+
+       if (b0->slen > m) {
+               v = (char) downcase (b0->data[m]);
+               if (v) return v;
+               return UCHAR_MAX + 1;
+       }
+
+       v = - (char) downcase (b1->data[m]);
+       if (v) return v;
+       return - (int) (UCHAR_MAX + 1);
+}
+
+/*  int biseqcaseless (const_bstring b0, const_bstring b1)
+ *
+ *  Compare two strings for equality without differentiating between case.  
+ *  If the strings differ other than in case, 0 is returned, if the strings 
+ *  are the same, 1 is returned, if there is an error, -1 is returned.  If 
+ *  the length of the strings are different, this function is O(1).  '\0' 
+ *  termination characters are not treated in any special way.
+ */
+int biseqcaseless (const_bstring b0, const_bstring b1) {
+int i, n;
+
+       if (bdata (b0) == NULL || b0->slen < 0 || 
+           bdata (b1) == NULL || b1->slen < 0) return BSTR_ERR;
+       if (b0->slen != b1->slen) return BSTR_OK;
+       if (b0->data == b1->data || b0->slen == 0) return 1;
+       for (i=0, n=b0->slen; i < n; i++) {
+               if (b0->data[i] != b1->data[i]) {
+                       unsigned char c = (unsigned char) downcase (b0->data[i]);
+                       if (c != (unsigned char) downcase (b1->data[i])) return 0;
+               }
+       }
+       return 1;
+}
+
+/*  int bisstemeqcaselessblk (const_bstring b0, const void * blk, int len)
+ *
+ *  Compare beginning of string b0 with a block of memory of length len 
+ *  without differentiating between case for equality.  If the beginning of b0
+ *  differs from the memory block other than in case (or if b0 is too short), 
+ *  0 is returned, if the strings are the same, 1 is returned, if there is an 
+ *  error, -1 is returned.  '\0' characters are not treated in any special 
+ *  way.
+ */
+int bisstemeqcaselessblk (const_bstring b0, const void * blk, int len) {
+int i;
+
+       if (bdata (b0) == NULL || b0->slen < 0 || NULL == blk || len < 0)
+               return BSTR_ERR;
+       if (b0->slen < len) return BSTR_OK;
+       if (b0->data == (const unsigned char *) blk || len == 0) return 1;
+
+       for (i = 0; i < len; i ++) {
+               if (b0->data[i] != ((const unsigned char *) blk)[i]) {
+                       if (downcase (b0->data[i]) != 
+                           downcase (((const unsigned char *) blk)[i])) return 0;
+               }
+       }
+       return 1;
+}
+
+/*
+ * int bltrimws (bstring b)
+ *
+ * Delete whitespace contiguous from the left end of the string.
+ */
+int bltrimws (bstring b) {
+int i, len;
+
+       if (b == NULL || b->data == NULL || b->mlen < b->slen ||
+           b->slen < 0 || b->mlen <= 0) return BSTR_ERR;
+
+       for (len = b->slen, i = 0; i < len; i++) {
+               if (!wspace (b->data[i])) {
+                       return bdelete (b, 0, i);
+               }
+       }
+
+       b->data[0] = (unsigned char) '\0';
+       b->slen = 0;
+       return BSTR_OK;
+}
+
+/*
+ * int brtrimws (bstring b)
+ *
+ * Delete whitespace contiguous from the right end of the string.
+ */
+int brtrimws (bstring b) {
+int i;
+
+       if (b == NULL || b->data == NULL || b->mlen < b->slen ||
+           b->slen < 0 || b->mlen <= 0) return BSTR_ERR;
+
+       for (i = b->slen - 1; i >= 0; i--) {
+               if (!wspace (b->data[i])) {
+                       if (b->mlen > i) b->data[i+1] = (unsigned char) '\0';
+                       b->slen = i + 1;
+                       return BSTR_OK;
+               }
+       }
+
+       b->data[0] = (unsigned char) '\0';
+       b->slen = 0;
+       return BSTR_OK;
+}
+
+/*
+ * int btrimws (bstring b)
+ *
+ * Delete whitespace contiguous from both ends of the string.
+ */
+int btrimws (bstring b) {
+int i, j;
+
+       if (b == NULL || b->data == NULL || b->mlen < b->slen ||
+           b->slen < 0 || b->mlen <= 0) return BSTR_ERR;
+
+       for (i = b->slen - 1; i >= 0; i--) {
+               if (!wspace (b->data[i])) {
+                       if (b->mlen > i) b->data[i+1] = (unsigned char) '\0';
+                       b->slen = i + 1;
+                       for (j = 0; wspace (b->data[j]); j++) {}
+                       return bdelete (b, 0, j);
+               }
+       }
+
+       b->data[0] = (unsigned char) '\0';
+       b->slen = 0;
+       return BSTR_OK;
+}
+
+/*  int biseq (const_bstring b0, const_bstring b1)
+ *
+ *  Compare the string b0 and b1.  If the strings differ, 0 is returned, if 
+ *  the strings are the same, 1 is returned, if there is an error, -1 is 
+ *  returned.  If the length of the strings are different, this function is
+ *  O(1).  '\0' termination characters are not treated in any special way.
+ */
+int biseq (const_bstring b0, const_bstring b1) {
+       if (b0 == NULL || b1 == NULL || b0->data == NULL || b1->data == NULL ||
+               b0->slen < 0 || b1->slen < 0) return BSTR_ERR;
+       if (b0->slen != b1->slen) return BSTR_OK;
+       if (b0->data == b1->data || b0->slen == 0) return 1;
+       return !bstr__memcmp (b0->data, b1->data, b0->slen);
+}
+
+/*  int bisstemeqblk (const_bstring b0, const void * blk, int len)
+ *
+ *  Compare beginning of string b0 with a block of memory of length len for 
+ *  equality.  If the beginning of b0 differs from the memory block (or if b0 
+ *  is too short), 0 is returned, if the strings are the same, 1 is returned, 
+ *  if there is an error, -1 is returned.  '\0' characters are not treated in 
+ *  any special way.
+ */
+int bisstemeqblk (const_bstring b0, const void * blk, int len) {
+int i;
+
+       if (bdata (b0) == NULL || b0->slen < 0 || NULL == blk || len < 0)
+               return BSTR_ERR;
+       if (b0->slen < len) return BSTR_OK;
+       if (b0->data == (const unsigned char *) blk || len == 0) return 1;
+
+       for (i = 0; i < len; i ++) {
+               if (b0->data[i] != ((const unsigned char *) blk)[i]) return BSTR_OK;
+       }
+       return 1;
+}
+
+/*  int biseqcstr (const_bstring b, const char *s)
+ *
+ *  Compare the bstring b and char * string s.  The C string s must be '\0' 
+ *  terminated at exactly the length of the bstring b, and the contents 
+ *  between the two must be identical with the bstring b with no '\0' 
+ *  characters for the two contents to be considered equal.  This is 
+ *  equivalent to the condition that their current contents will be always be 
+ *  equal when comparing them in the same format after converting one or the 
+ *  other.  If the strings are equal 1 is returned, if they are unequal 0 is 
+ *  returned and if there is a detectable error BSTR_ERR is returned.
+ */
+int biseqcstr (const_bstring b, const char * s) {
+int i;
+       if (b == NULL || s == NULL || b->data == NULL || b->slen < 0) return BSTR_ERR;
+       for (i=0; i < b->slen; i++) {
+               if (s[i] == '\0' || b->data[i] != (unsigned char) s[i]) return BSTR_OK;
+       }
+       return s[i] == '\0';
+}
+
+/*  int biseqcstrcaseless (const_bstring b, const char *s)
+ *
+ *  Compare the bstring b and char * string s.  The C string s must be '\0' 
+ *  terminated at exactly the length of the bstring b, and the contents 
+ *  between the two must be identical except for case with the bstring b with 
+ *  no '\0' characters for the two contents to be considered equal.  This is 
+ *  equivalent to the condition that their current contents will be always be 
+ *  equal ignoring case when comparing them in the same format after 
+ *  converting one or the other.  If the strings are equal, except for case, 
+ *  1 is returned, if they are unequal regardless of case 0 is returned and 
+ *  if there is a detectable error BSTR_ERR is returned.
+ */
+int biseqcstrcaseless (const_bstring b, const char * s) {
+int i;
+       if (b == NULL || s == NULL || b->data == NULL || b->slen < 0) return BSTR_ERR;
+       for (i=0; i < b->slen; i++) {
+               if (s[i] == '\0' || 
+                   (b->data[i] != (unsigned char) s[i] && 
+                    downcase (b->data[i]) != (unsigned char) downcase (s[i])))
+                       return BSTR_OK;
+       }
+       return s[i] == '\0';
+}
+
+/*  int bstrcmp (const_bstring b0, const_bstring b1)
+ *
+ *  Compare the string b0 and b1.  If there is an error, SHRT_MIN is returned, 
+ *  otherwise a value less than or greater than zero, indicating that the 
+ *  string pointed to by b0 is lexicographically less than or greater than 
+ *  the string pointed to by b1 is returned.  If the the string lengths are 
+ *  unequal but the characters up until the length of the shorter are equal 
+ *  then a value less than, or greater than zero, indicating that the string 
+ *  pointed to by b0 is shorter or longer than the string pointed to by b1 is 
+ *  returned.  0 is returned if and only if the two strings are the same.  If 
+ *  the length of the strings are different, this function is O(n).  Like its
+ *  standard C library counter part strcmp, the comparison does not proceed 
+ *  past any '\0' termination characters encountered.
+ */
+int bstrcmp (const_bstring b0, const_bstring b1) {
+int i, v, n;
+
+       if (b0 == NULL || b1 == NULL || b0->data == NULL || b1->data == NULL ||
+               b0->slen < 0 || b1->slen < 0) return SHRT_MIN;
+       n = b0->slen; if (n > b1->slen) n = b1->slen;
+       if (b0->slen == b1->slen && (b0->data == b1->data || b0->slen == 0))
+               return BSTR_OK;
+
+       for (i = 0; i < n; i ++) {
+               v = ((char) b0->data[i]) - ((char) b1->data[i]);
+               if (v != 0) return v;
+               if (b0->data[i] == (unsigned char) '\0') return BSTR_OK;
+       }
+
+       if (b0->slen > n) return 1;
+       if (b1->slen > n) return -1;
+       return BSTR_OK;
+}
+
+/*  int bstrncmp (const_bstring b0, const_bstring b1, int n)
+ *
+ *  Compare the string b0 and b1 for at most n characters.  If there is an 
+ *  error, SHRT_MIN is returned, otherwise a value is returned as if b0 and 
+ *  b1 were first truncated to at most n characters then bstrcmp was called
+ *  with these new strings are paremeters.  If the length of the strings are 
+ *  different, this function is O(n).  Like its standard C library counter 
+ *  part strcmp, the comparison does not proceed past any '\0' termination 
+ *  characters encountered.
+ */
+int bstrncmp (const_bstring b0, const_bstring b1, int n) {
+int i, v, m;
+
+       if (b0 == NULL || b1 == NULL || b0->data == NULL || b1->data == NULL ||
+               b0->slen < 0 || b1->slen < 0) return SHRT_MIN;
+       m = n;
+       if (m > b0->slen) m = b0->slen;
+       if (m > b1->slen) m = b1->slen;
+
+       if (b0->data != b1->data) {
+               for (i = 0; i < m; i ++) {
+                       v = ((char) b0->data[i]) - ((char) b1->data[i]);
+                       if (v != 0) return v;
+                       if (b0->data[i] == (unsigned char) '\0') return BSTR_OK;
+               }
+       }
+
+       if (n == m || b0->slen == b1->slen) return BSTR_OK;
+
+       if (b0->slen > m) return 1;
+       return -1;
+}
+
+/*  bstring bmidstr (const_bstring b, int left, int len)
+ *
+ *  Create a bstring which is the substring of b starting from position left
+ *  and running for a length len (clamped by the end of the bstring b.)  If
+ *  b is detectably invalid, then NULL is returned.  The section described 
+ *  by (left, len) is clamped to the boundaries of b.
+ */
+bstring bmidstr (const_bstring b, int left, int len) {
+
+       if (b == NULL || b->slen < 0 || b->data == NULL) return NULL;
+
+       if (left < 0) {
+               len += left;
+               left = 0;
+       }
+
+       if (len > b->slen - left) len = b->slen - left;
+
+       if (len <= 0) return bfromcstr ("");
+       return blk2bstr (b->data + left, len);
+}
+
+/*  int bdelete (bstring b, int pos, int len)
+ *
+ *  Removes characters from pos to pos+len-1 inclusive and shifts the tail of 
+ *  the bstring starting from pos+len to pos.  len must be positive for this 
+ *  call to have any effect.  The section of the string described by (pos, 
+ *  len) is clamped to boundaries of the bstring b.
+ */
+int bdelete (bstring b, int pos, int len) {
+       /* Clamp to left side of bstring */
+       if (pos < 0) {
+               len += pos;
+               pos = 0;
+       }
+
+       if (len < 0 || b == NULL || b->data == NULL || b->slen < 0 || 
+           b->mlen < b->slen || b->mlen <= 0) 
+               return BSTR_ERR;
+       if (len > 0 && pos < b->slen) {
+               if (pos + len >= b->slen) {
+                       b->slen = pos;
+               } else {
+                       bBlockCopy ((char *) (b->data + pos),
+                                   (char *) (b->data + pos + len), 
+                                   b->slen - (pos+len));
+                       b->slen -= len;
+               }
+               b->data[b->slen] = (unsigned char) '\0';
+       }
+       return BSTR_OK;
+}
+
+/*  int bdestroy (bstring b)
+ *
+ *  Free up the bstring.  Note that if b is detectably invalid or not writable
+ *  then no action is performed and BSTR_ERR is returned.  Like a freed memory
+ *  allocation, dereferences, writes or any other action on b after it has 
+ *  been bdestroyed is undefined.
+ */
+int bdestroy (bstring b) {
+       if (b == NULL || b->slen < 0 || b->mlen <= 0 || b->mlen < b->slen ||
+           b->data == NULL)
+               return BSTR_ERR;
+
+       bstr__free (b->data);
+
+       /* In case there is any stale usage, there is one more chance to 
+          notice this error. */
+
+       b->slen = -1;
+       b->mlen = -__LINE__;
+       b->data = NULL;
+
+       bstr__free (b);
+       return BSTR_OK;
+}
+
+/*  int binstr (const_bstring b1, int pos, const_bstring b2)
+ *
+ *  Search for the bstring b2 in b1 starting from position pos, and searching 
+ *  forward.  If it is found then return with the first position where it is 
+ *  found, otherwise return BSTR_ERR.  Note that this is just a brute force 
+ *  string searcher that does not attempt clever things like the Boyer-Moore 
+ *  search algorithm.  Because of this there are many degenerate cases where 
+ *  this can take much longer than it needs to.
+ */
+int binstr (const_bstring b1, int pos, const_bstring b2) {
+int j, ii, ll, lf;
+unsigned char * d0;
+unsigned char c0;
+register unsigned char * d1;
+register unsigned char c1;
+register int i;
+
+       if (b1 == NULL || b1->data == NULL || b1->slen < 0 ||
+           b2 == NULL || b2->data == NULL || b2->slen < 0) return BSTR_ERR;
+       if (b1->slen == pos) return (b2->slen == 0)?pos:BSTR_ERR;
+       if (b1->slen < pos || pos < 0) return BSTR_ERR;
+       if (b2->slen == 0) return pos;
+
+       /* No space to find such a string? */
+       if ((lf = b1->slen - b2->slen + 1) <= pos) return BSTR_ERR;
+
+       /* An obvious alias case */
+       if (b1->data == b2->data && pos == 0) return 0;
+
+       i = pos;
+
+       d0 = b2->data;
+       d1 = b1->data;
+       ll = b2->slen;
+
+       /* Peel off the b2->slen == 1 case */
+       c0 = d0[0];
+       if (1 == ll) {
+               for (;i < lf; i++) if (c0 == d1[i]) return i;
+               return BSTR_ERR;
+       }
+
+       c1 = c0;
+       j = 0;
+       lf = b1->slen - 1;
+
+       ii = -1;
+       if (i < lf) do {
+               /* Unrolled current character test */
+               if (c1 != d1[i]) {
+                       if (c1 != d1[1+i]) {
+                               i += 2;
+                               continue;
+                       }
+                       i++;
+               }
+
+               /* Take note if this is the start of a potential match */
+               if (0 == j) ii = i;
+
+               /* Shift the test character down by one */
+               j++;
+               i++;
+
+               /* If this isn't past the last character continue */
+               if (j < ll) {
+                       c1 = d0[j];
+                       continue;
+               }
+
+               N0:;
+
+               /* If no characters mismatched, then we matched */
+               if (i == ii+j) return ii;
+
+               /* Shift back to the beginning */
+               i -= j;
+               j  = 0;
+               c1 = c0;
+       } while (i < lf);
+
+       /* Deal with last case if unrolling caused a misalignment */
+       if (i == lf && ll == j+1 && c1 == d1[i]) goto N0;
+
+       return BSTR_ERR;
+}
+
+/*  int binstrr (const_bstring b1, int pos, const_bstring b2)
+ *
+ *  Search for the bstring b2 in b1 starting from position pos, and searching 
+ *  backward.  If it is found then return with the first position where it is 
+ *  found, otherwise return BSTR_ERR.  Note that this is just a brute force 
+ *  string searcher that does not attempt clever things like the Boyer-Moore 
+ *  search algorithm.  Because of this there are many degenerate cases where 
+ *  this can take much longer than it needs to.
+ */
+int binstrr (const_bstring b1, int pos, const_bstring b2) {
+int j, i, l;
+unsigned char * d0, * d1;
+
+       if (b1 == NULL || b1->data == NULL || b1->slen < 0 ||
+           b2 == NULL || b2->data == NULL || b2->slen < 0) return BSTR_ERR;
+       if (b1->slen == pos && b2->slen == 0) return pos;
+       if (b1->slen < pos || pos < 0) return BSTR_ERR;
+       if (b2->slen == 0) return pos;
+
+       /* Obvious alias case */
+       if (b1->data == b2->data && pos == 0 && b2->slen <= b1->slen) return 0;
+
+       i = pos;
+       if ((l = b1->slen - b2->slen) < 0) return BSTR_ERR;
+
+       /* If no space to find such a string then snap back */
+       if (l + 1 <= i) i = l;
+       j = 0;
+
+       d0 = b2->data;
+       d1 = b1->data;
+       l  = b2->slen;
+
+       for (;;) {
+               if (d0[j] == d1[i + j]) {
+                       j ++;
+                       if (j >= l) return i;
+               } else {
+                       i --;
+                       if (i < 0) break;
+                       j=0;
+               }
+       }
+
+       return BSTR_ERR;
+}
+
+/*  int binstrcaseless (const_bstring b1, int pos, const_bstring b2)
+ *
+ *  Search for the bstring b2 in b1 starting from position pos, and searching 
+ *  forward but without regard to case.  If it is found then return with the 
+ *  first position where it is found, otherwise return BSTR_ERR.  Note that 
+ *  this is just a brute force string searcher that does not attempt clever 
+ *  things like the Boyer-Moore search algorithm.  Because of this there are 
+ *  many degenerate cases where this can take much longer than it needs to.
+ */
+int binstrcaseless (const_bstring b1, int pos, const_bstring b2) {
+int j, i, l, ll;
+unsigned char * d0, * d1;
+
+       if (b1 == NULL || b1->data == NULL || b1->slen < 0 ||
+           b2 == NULL || b2->data == NULL || b2->slen < 0) return BSTR_ERR;
+       if (b1->slen == pos) return (b2->slen == 0)?pos:BSTR_ERR;
+       if (b1->slen < pos || pos < 0) return BSTR_ERR;
+       if (b2->slen == 0) return pos;
+
+       l = b1->slen - b2->slen + 1;
+
+       /* No space to find such a string? */
+       if (l <= pos) return BSTR_ERR;
+
+       /* An obvious alias case */
+       if (b1->data == b2->data && pos == 0) return BSTR_OK;
+
+       i = pos;
+       j = 0;
+
+       d0 = b2->data;
+       d1 = b1->data;
+       ll = b2->slen;
+
+       for (;;) {
+               if (d0[j] == d1[i + j] || downcase (d0[j]) == downcase (d1[i + j])) {
+                       j ++;
+                       if (j >= ll) return i;
+               } else {
+                       i ++;
+                       if (i >= l) break;
+                       j=0;
+               }
+       }
+
+       return BSTR_ERR;
+}
+
+/*  int binstrrcaseless (const_bstring b1, int pos, const_bstring b2)
+ *
+ *  Search for the bstring b2 in b1 starting from position pos, and searching 
+ *  backward but without regard to case.  If it is found then return with the 
+ *  first position where it is found, otherwise return BSTR_ERR.  Note that 
+ *  this is just a brute force string searcher that does not attempt clever 
+ *  things like the Boyer-Moore search algorithm.  Because of this there are 
+ *  many degenerate cases where this can take much longer than it needs to.
+ */
+int binstrrcaseless (const_bstring b1, int pos, const_bstring b2) {
+int j, i, l;
+unsigned char * d0, * d1;
+
+       if (b1 == NULL || b1->data == NULL || b1->slen < 0 ||
+           b2 == NULL || b2->data == NULL || b2->slen < 0) return BSTR_ERR;
+       if (b1->slen == pos && b2->slen == 0) return pos;
+       if (b1->slen < pos || pos < 0) return BSTR_ERR;
+       if (b2->slen == 0) return pos;
+
+       /* Obvious alias case */
+       if (b1->data == b2->data && pos == 0 && b2->slen <= b1->slen) return BSTR_OK;
+
+       i = pos;
+       if ((l = b1->slen - b2->slen) < 0) return BSTR_ERR;
+
+       /* If no space to find such a string then snap back */
+       if (l + 1 <= i) i = l;
+       j = 0;
+
+       d0 = b2->data;
+       d1 = b1->data;
+       l  = b2->slen;
+
+       for (;;) {
+               if (d0[j] == d1[i + j] || downcase (d0[j]) == downcase (d1[i + j])) {
+                       j ++;
+                       if (j >= l) return i;
+               } else {
+                       i --;
+                       if (i < 0) break;
+                       j=0;
+               }
+       }
+
+       return BSTR_ERR;
+}
+
+
+/*  int bstrchrp (const_bstring b, int c, int pos)
+ *
+ *  Search for the character c in b forwards from the position pos 
+ *  (inclusive).
+ */
+int bstrchrp (const_bstring b, int c, int pos) {
+unsigned char * p;
+
+       if (b == NULL || b->data == NULL || b->slen <= pos || pos < 0) return BSTR_ERR;
+       p = (unsigned char *) bstr__memchr ((b->data + pos), (unsigned char) c, (b->slen - pos));
+       if (p) return (int) (p - b->data);
+       return BSTR_ERR;
+}
+
+/*  int bstrrchrp (const_bstring b, int c, int pos)
+ *
+ *  Search for the character c in b backwards from the position pos in string 
+ *  (inclusive).
+ */
+int bstrrchrp (const_bstring b, int c, int pos) {
+int i;
+       if (b == NULL || b->data == NULL || b->slen <= pos || pos < 0) return BSTR_ERR;
+       for (i=pos; i >= 0; i--) {
+               if (b->data[i] == (unsigned char) c) return i;
+       }
+       return BSTR_ERR;
+}
+
+#if !defined (BSTRLIB_AGGRESSIVE_MEMORY_FOR_SPEED_TRADEOFF)
+#define LONG_LOG_BITS_QTY (3)
+#define LONG_BITS_QTY (1 << LONG_LOG_BITS_QTY)
+#define LONG_TYPE unsigned char
+
+#define CFCLEN ((1 << CHAR_BIT) / LONG_BITS_QTY)
+struct charField { LONG_TYPE content[CFCLEN]; };
+#define testInCharField(cf,c) ((cf)->content[(c) >> LONG_LOG_BITS_QTY] & (((long)1) << ((c) & (LONG_BITS_QTY-1))))
+#define setInCharField(cf,idx) { \
+       unsigned int c = (unsigned int) (idx); \
+       (cf)->content[c >> LONG_LOG_BITS_QTY] |= (LONG_TYPE) (1ul << (c & (LONG_BITS_QTY-1))); \
+}
+
+#else
+
+#define CFCLEN (1 << CHAR_BIT)
+struct charField { unsigned char content[CFCLEN]; };
+#define testInCharField(cf,c) ((cf)->content[(unsigned char) (c)])
+#define setInCharField(cf,idx) (cf)->content[(unsigned int) (idx)] = ~0
+
+#endif
+
+/* Convert a bstring to charField */
+static int buildCharField (struct charField * cf, const_bstring b) {
+int i;
+       if (b == NULL || b->data == NULL || b->slen <= 0) return BSTR_ERR;
+       memset ((void *) cf->content, 0, sizeof (struct charField));
+       for (i=0; i < b->slen; i++) {
+               setInCharField (cf, b->data[i]);
+       }
+       return BSTR_OK;
+}
+
+static void invertCharField (struct charField * cf) {
+int i;
+       for (i=0; i < CFCLEN; i++) cf->content[i] = ~cf->content[i];
+}
+
+/* Inner engine for binchr */
+static int binchrCF (const unsigned char * data, int len, int pos, const struct charField * cf) {
+int i;
+       for (i=pos; i < len; i++) {
+               unsigned char c = (unsigned char) data[i];
+               if (testInCharField (cf, c)) return i;
+       }
+       return BSTR_ERR;
+}
+
+/*  int binchr (const_bstring b0, int pos, const_bstring b1);
+ *
+ *  Search for the first position in b0 starting from pos or after, in which 
+ *  one of the characters in b1 is found and return it.  If such a position 
+ *  does not exist in b0, then BSTR_ERR is returned.
+ */
+int binchr (const_bstring b0, int pos, const_bstring b1) {
+struct charField chrs;
+       if (pos < 0 || b0 == NULL || b0->data == NULL ||
+           b0->slen <= pos) return BSTR_ERR;
+       if (1 == b1->slen) return bstrchrp (b0, b1->data[0], pos);
+       if (0 > buildCharField (&chrs, b1)) return BSTR_ERR;
+       return binchrCF (b0->data, b0->slen, pos, &chrs);
+}
+
+/* Inner engine for binchrr */
+static int binchrrCF (const unsigned char * data, int pos, const struct charField * cf) {
+int i;
+       for (i=pos; i >= 0; i--) {
+               unsigned int c = (unsigned int) data[i];
+               if (testInCharField (cf, c)) return i;
+       }
+       return BSTR_ERR;
+}
+
+/*  int binchrr (const_bstring b0, int pos, const_bstring b1);
+ *
+ *  Search for the last position in b0 no greater than pos, in which one of 
+ *  the characters in b1 is found and return it.  If such a position does not 
+ *  exist in b0, then BSTR_ERR is returned.
+ */
+int binchrr (const_bstring b0, int pos, const_bstring b1) {
+struct charField chrs;
+       if (pos < 0 || b0 == NULL || b0->data == NULL || b1 == NULL ||
+           b0->slen < pos) return BSTR_ERR;
+       if (pos == b0->slen) pos--;
+       if (1 == b1->slen) return bstrrchrp (b0, b1->data[0], pos);
+       if (0 > buildCharField (&chrs, b1)) return BSTR_ERR;
+       return binchrrCF (b0->data, pos, &chrs);
+}
+
+/*  int bninchr (const_bstring b0, int pos, const_bstring b1);
+ *
+ *  Search for the first position in b0 starting from pos or after, in which 
+ *  none of the characters in b1 is found and return it.  If such a position 
+ *  does not exist in b0, then BSTR_ERR is returned.
+ */
+int bninchr (const_bstring b0, int pos, const_bstring b1) {
+struct charField chrs;
+       if (pos < 0 || b0 == NULL || b0->data == NULL || 
+           b0->slen <= pos) return BSTR_ERR;
+       if (buildCharField (&chrs, b1) < 0) return BSTR_ERR;
+       invertCharField (&chrs);
+       return binchrCF (b0->data, b0->slen, pos, &chrs);
+}
+
+/*  int bninchrr (const_bstring b0, int pos, const_bstring b1);
+ *
+ *  Search for the last position in b0 no greater than pos, in which none of 
+ *  the characters in b1 is found and return it.  If such a position does not 
+ *  exist in b0, then BSTR_ERR is returned.
+ */
+int bninchrr (const_bstring b0, int pos, const_bstring b1) {
+struct charField chrs;
+       if (pos < 0 || b0 == NULL || b0->data == NULL || 
+           b0->slen < pos) return BSTR_ERR;
+       if (pos == b0->slen) pos--;
+       if (buildCharField (&chrs, b1) < 0) return BSTR_ERR;
+       invertCharField (&chrs);
+       return binchrrCF (b0->data, pos, &chrs);
+}
+
+/*  int bsetstr (bstring b0, int pos, bstring b1, unsigned char fill)
+ *
+ *  Overwrite the string b0 starting at position pos with the string b1. If 
+ *  the position pos is past the end of b0, then the character "fill" is 
+ *  appended as necessary to make up the gap between the end of b0 and pos.
+ *  If b1 is NULL, it behaves as if it were a 0-length string.
+ */
+int bsetstr (bstring b0, int pos, const_bstring b1, unsigned char fill) {
+int d, newlen;
+ptrdiff_t pd;
+bstring aux = (bstring) b1;
+
+       if (pos < 0 || b0 == NULL || b0->slen < 0 || NULL == b0->data || 
+           b0->mlen < b0->slen || b0->mlen <= 0) return BSTR_ERR;
+       if (b1 != NULL && (b1->slen < 0 || b1->data == NULL)) return BSTR_ERR;
+
+       d = pos;
+
+       /* Aliasing case */
+       if (NULL != aux) {
+               if ((pd = (ptrdiff_t) (b1->data - b0->data)) >= 0 && pd < (ptrdiff_t) b0->mlen) {
+                       if (NULL == (aux = bstrcpy (b1))) return BSTR_ERR;
+               }
+               d += aux->slen;
+       }
+
+       /* Increase memory size if necessary */
+       if (balloc (b0, d + 1) != BSTR_OK) {
+               if (aux != b1) bdestroy (aux);
+               return BSTR_ERR;
+       }
+
+       newlen = b0->slen;
+
+       /* Fill in "fill" character as necessary */
+       if (pos > newlen) {
+               bstr__memset (b0->data + b0->slen, (int) fill, (size_t) (pos - b0->slen));
+               newlen = pos;
+       }
+
+       /* Copy b1 to position pos in b0. */
+       if (aux != NULL) {
+               bBlockCopy ((char *) (b0->data + pos), (char *) aux->data, aux->slen);
+               if (aux != b1) bdestroy (aux);
+       }
+
+       /* Indicate the potentially increased size of b0 */
+       if (d > newlen) newlen = d;
+
+       b0->slen = newlen;
+       b0->data[newlen] = (unsigned char) '\0';
+
+       return BSTR_OK;
+}
+
+/*  int binsert (bstring b1, int pos, bstring b2, unsigned char fill)
+ *
+ *  Inserts the string b2 into b1 at position pos.  If the position pos is 
+ *  past the end of b1, then the character "fill" is appended as necessary to 
+ *  make up the gap between the end of b1 and pos.  Unlike bsetstr, binsert
+ *  does not allow b2 to be NULL.
+ */
+int binsert (bstring b1, int pos, const_bstring b2, unsigned char fill) {
+int d, l;
+ptrdiff_t pd;
+bstring aux = (bstring) b2;
+
+       if (pos < 0 || b1 == NULL || b2 == NULL || b1->slen < 0 || 
+           b2->slen < 0 || b1->mlen < b1->slen || b1->mlen <= 0) return BSTR_ERR;
+
+       /* Aliasing case */
+       if ((pd = (ptrdiff_t) (b2->data - b1->data)) >= 0 && pd < (ptrdiff_t) b1->mlen) {
+               if (NULL == (aux = bstrcpy (b2))) return BSTR_ERR;
+       }
+
+       /* Compute the two possible end pointers */
+       d = b1->slen + aux->slen;
+       l = pos + aux->slen;
+       if ((d|l) < 0) return BSTR_ERR;
+
+       if (l > d) {
+               /* Inserting past the end of the string */
+               if (balloc (b1, l + 1) != BSTR_OK) {
+                       if (aux != b2) bdestroy (aux);
+                       return BSTR_ERR;
+               }
+               bstr__memset (b1->data + b1->slen, (int) fill, (size_t) (pos - b1->slen));
+               b1->slen = l;
+       } else {
+               /* Inserting in the middle of the string */
+               if (balloc (b1, d + 1) != BSTR_OK) {
+                       if (aux != b2) bdestroy (aux);
+                       return BSTR_ERR;
+               }
+               bBlockCopy (b1->data + l, b1->data + pos, d - l);
+               b1->slen = d;
+       }
+       bBlockCopy (b1->data + pos, aux->data, aux->slen);
+       b1->data[b1->slen] = (unsigned char) '\0';
+       if (aux != b2) bdestroy (aux);
+       return BSTR_OK;
+}
+
+/*  int breplace (bstring b1, int pos, int len, bstring b2, 
+ *                unsigned char fill)
+ *
+ *  Replace a section of a string from pos for a length len with the string b2.
+ *  fill is used is pos > b1->slen.
+ */
+int breplace (bstring b1, int pos, int len, const_bstring b2, 
+                         unsigned char fill) {
+int pl, ret;
+ptrdiff_t pd;
+bstring aux = (bstring) b2;
+
+       if (pos < 0 || len < 0 || (pl = pos + len) < 0 || b1 == NULL || 
+           b2 == NULL || b1->data == NULL || b2->data == NULL || 
+           b1->slen < 0 || b2->slen < 0 || b1->mlen < b1->slen ||
+           b1->mlen <= 0) return BSTR_ERR;
+
+       /* Straddles the end? */
+       if (pl >= b1->slen) {
+               if ((ret = bsetstr (b1, pos, b2, fill)) < 0) return ret;
+               if (pos + b2->slen < b1->slen) {
+                       b1->slen = pos + b2->slen;
+                       b1->data[b1->slen] = (unsigned char) '\0';
+               }
+               return ret;
+       }
+
+       /* Aliasing case */
+       if ((pd = (ptrdiff_t) (b2->data - b1->data)) >= 0 && pd < (ptrdiff_t) b1->slen) {
+               if (NULL == (aux = bstrcpy (b2))) return BSTR_ERR;
+       }
+
+       if (aux->slen > len) {
+               if (balloc (b1, b1->slen + aux->slen - len) != BSTR_OK) {
+                       if (aux != b2) bdestroy (aux);
+                       return BSTR_ERR;
+               }
+       }
+
+       if (aux->slen != len) bstr__memmove (b1->data + pos + aux->slen, b1->data + pos + len, b1->slen - (pos + len));
+       bstr__memcpy (b1->data + pos, aux->data, aux->slen);
+       b1->slen += aux->slen - len;
+       b1->data[b1->slen] = (unsigned char) '\0';
+       if (aux != b2) bdestroy (aux);
+       return BSTR_OK;
+}
+
+/*  int bfindreplace (bstring b, const_bstring find, const_bstring repl, 
+ *                    int pos)
+ *
+ *  Replace all occurrences of a find string with a replace string after a
+ *  given point in a bstring.
+ */
+
+typedef int (*instr_fnptr) (const_bstring s1, int pos, const_bstring s2);
+
+static int findreplaceengine (bstring b, const_bstring find, const_bstring repl, int pos, instr_fnptr instr) {
+int i, ret, slen, mlen, delta, acc;
+int * d;
+int static_d[32];
+ptrdiff_t pd;
+bstring auxf = (bstring) find;
+bstring auxr = (bstring) repl;
+
+       if (b == NULL || b->data == NULL || find == NULL ||
+           find->data == NULL || repl == NULL || repl->data == NULL || 
+           pos < 0 || find->slen <= 0 || b->mlen < 0 || b->slen > b->mlen || 
+           b->mlen <= 0 || b->slen < 0 || repl->slen < 0) return BSTR_ERR;
+       if (pos > b->slen - find->slen) return BSTR_OK;
+
+       /* Alias with find string */
+       pd = (ptrdiff_t) (find->data - b->data);
+       if ((ptrdiff_t) (pos - find->slen) < pd && pd < (ptrdiff_t) b->slen) {
+               if (NULL == (auxf = bstrcpy (find))) return BSTR_ERR;
+       }
+
+       /* Alias with repl string */
+       pd = (ptrdiff_t) (repl->data - b->data);
+       if ((ptrdiff_t) (pos - repl->slen) < pd && pd < (ptrdiff_t) b->slen) {
+               if (NULL == (auxr = bstrcpy (repl))) {
+                       if (auxf != find) bdestroy (auxf);
+                       return BSTR_ERR;
+               }
+       }
+
+       delta = auxf->slen - auxr->slen;
+
+       /* in-place replacement since find and replace strings are of equal 
+          length */
+       if (delta == 0) {
+               while ((pos = instr (b, pos, auxf)) >= 0) {
+                       bstr__memcpy (b->data + pos, auxr->data, auxr->slen);
+                       pos += auxf->slen;
+               }
+               if (auxf != find) bdestroy (auxf);
+               if (auxr != repl) bdestroy (auxr);
+               return BSTR_OK;
+       }
+
+       /* shrinking replacement since auxf->slen > auxr->slen */
+       if (delta > 0) {
+               acc = 0;
+
+               while ((i = instr (b, pos, auxf)) >= 0) {
+                       if (acc && i > pos)
+                               bstr__memmove (b->data + pos - acc, b->data + pos, i - pos);
+                       if (auxr->slen)
+                               bstr__memcpy (b->data + i - acc, auxr->data, auxr->slen);
+                       acc += delta;
+                       pos = i + auxf->slen;
+               }
+
+               if (acc) {
+                       i = b->slen;
+                       if (i > pos)
+                               bstr__memmove (b->data + pos - acc, b->data + pos, i - pos);
+                       b->slen -= acc;
+                       b->data[b->slen] = (unsigned char) '\0';
+               }
+
+               if (auxf != find) bdestroy (auxf);
+               if (auxr != repl) bdestroy (auxr);
+               return BSTR_OK;
+       }
+
+       /* expanding replacement since find->slen < repl->slen.  Its a lot 
+          more complicated. */
+
+       mlen = 32;
+       d = (int *) static_d; /* Avoid malloc for trivial cases */
+       acc = slen = 0;
+
+       while ((pos = instr (b, pos, auxf)) >= 0) {
+               if (slen + 1 >= mlen) {
+                       int sl;
+                       int * t;
+                       mlen += mlen;
+                       sl = sizeof (int *) * mlen;
+                       if (static_d == d) d = NULL;
+                       if (sl < mlen || NULL == (t = (int *) bstr__realloc (d, sl))) {
+                               ret = BSTR_ERR;
+                               goto done;
+                       }
+                       if (NULL == d) bstr__memcpy (t, static_d, sizeof (static_d));
+                       d = t;
+               }
+               d[slen] = pos;
+               slen++;
+               acc -= delta;
+               pos += auxf->slen;
+               if (pos < 0 || acc < 0) {
+                       ret = BSTR_ERR;
+                       goto done;
+               }
+       }
+       d[slen] = b->slen;
+
+       if (BSTR_OK == (ret = balloc (b, b->slen + acc + 1))) {
+               b->slen += acc;
+               for (i = slen-1; i >= 0; i--) {
+                       int s, l;
+                       s = d[i] + auxf->slen;
+                       l = d[i+1] - s;
+                       if (l) {
+                               bstr__memmove (b->data + s + acc, b->data + s, l);
+                       }
+                       if (auxr->slen) {
+                               bstr__memmove (b->data + s + acc - auxr->slen, 
+                                        auxr->data, auxr->slen);
+                       }
+                       acc += delta;           
+               }
+               b->data[b->slen] = (unsigned char) '\0';
+       }
+
+       done:;
+       if (static_d == d) d = NULL;
+       bstr__free (d);
+       if (auxf != find) bdestroy (auxf);
+       if (auxr != repl) bdestroy (auxr);
+       return ret;
+}
+
+/*  int bfindreplace (bstring b, const_bstring find, const_bstring repl, 
+ *                    int pos)
+ *
+ *  Replace all occurrences of a find string with a replace string after a
+ *  given point in a bstring.
+ */
+int bfindreplace (bstring b, const_bstring find, const_bstring repl, int pos) {
+       return findreplaceengine (b, find, repl, pos, binstr);
+}
+
+/*  int bfindreplacecaseless (bstring b, const_bstring find, const_bstring repl, 
+ *                    int pos)
+ *
+ *  Replace all occurrences of a find string, ignoring case, with a replace 
+ *  string after a given point in a bstring.
+ */
+int bfindreplacecaseless (bstring b, const_bstring find, const_bstring repl, int pos) {
+       return findreplaceengine (b, find, repl, pos, binstrcaseless);
+}
+
+/*  int binsertch (bstring b, int pos, int len, unsigned char fill)
+ *
+ *  Inserts the character fill repeatedly into b at position pos for a 
+ *  length len.  If the position pos is past the end of b, then the 
+ *  character "fill" is appended as necessary to make up the gap between the 
+ *  end of b and the position pos + len.
+ */
+int binsertch (bstring b, int pos, int len, unsigned char fill) {
+int d, l, i;
+
+       if (pos < 0 || b == NULL || b->slen < 0 || b->mlen < b->slen ||
+           b->mlen <= 0 || len < 0) return BSTR_ERR;
+
+       /* Compute the two possible end pointers */
+       d = b->slen + len;
+       l = pos + len;
+       if ((d|l) < 0) return BSTR_ERR;
+
+       if (l > d) {
+               /* Inserting past the end of the string */
+               if (balloc (b, l + 1) != BSTR_OK) return BSTR_ERR;
+               pos = b->slen;
+               b->slen = l;
+       } else {
+               /* Inserting in the middle of the string */
+               if (balloc (b, d + 1) != BSTR_OK) return BSTR_ERR;
+               for (i = d - 1; i >= l; i--) {
+                       b->data[i] = b->data[i - len];
+               }
+               b->slen = d;
+       }
+
+       for (i=pos; i < l; i++) b->data[i] = fill;
+       b->data[b->slen] = (unsigned char) '\0';
+       return BSTR_OK;
+}
+
+/*  int bpattern (bstring b, int len)
+ *
+ *  Replicate the bstring, b in place, end to end repeatedly until it 
+ *  surpasses len characters, then chop the result to exactly len characters. 
+ *  This function operates in-place.  The function will return with BSTR_ERR 
+ *  if b is NULL or of length 0, otherwise BSTR_OK is returned.
+ */
+int bpattern (bstring b, int len) {
+int i, d;
+
+       d = blength (b);
+       if (d <= 0 || len < 0 || balloc (b, len + 1) != BSTR_OK) return BSTR_ERR;
+       if (len > 0) {
+               if (d == 1) return bsetstr (b, len, NULL, b->data[0]);
+               for (i = d; i < len; i++) b->data[i] = b->data[i - d];
+       }
+       b->data[len] = (unsigned char) '\0';
+       b->slen = len;
+       return BSTR_OK;
+}
+
+#define BS_BUFF_SZ (1024)
+
+/*  int breada (bstring b, bNread readPtr, void * parm)
+ *
+ *  Use a finite buffer fread-like function readPtr to concatenate to the 
+ *  bstring b the entire contents of file-like source data in a roughly 
+ *  efficient way.
+ */
+int breada (bstring b, bNread readPtr, void * parm) {
+int i, l, n;
+
+       if (b == NULL || b->mlen <= 0 || b->slen < 0 || b->mlen < b->slen ||
+           b->mlen <= 0 || readPtr == NULL) return BSTR_ERR;
+
+       i = b->slen;
+       for (n=i+16; ; n += ((n < BS_BUFF_SZ) ? n : BS_BUFF_SZ)) {
+               if (BSTR_OK != balloc (b, n + 1)) return BSTR_ERR;
+               l = (int) readPtr ((void *) (b->data + i), 1, n - i, parm);
+               i += l;
+               b->slen = i;
+               if (i < n) break;
+       }
+
+       b->data[i] = (unsigned char) '\0';
+       return BSTR_OK;
+}
+
+/*  bstring bread (bNread readPtr, void * parm)
+ *
+ *  Use a finite buffer fread-like function readPtr to create a bstring 
+ *  filled with the entire contents of file-like source data in a roughly 
+ *  efficient way.
+ */
+bstring bread (bNread readPtr, void * parm) {
+bstring buff;
+
+       if (0 > breada (buff = bfromcstr (""), readPtr, parm)) {
+               bdestroy (buff);
+               return NULL;
+       }
+       return buff;
+}
+
+/*  int bassigngets (bstring b, bNgetc getcPtr, void * parm, char terminator)
+ *
+ *  Use an fgetc-like single character stream reading function (getcPtr) to 
+ *  obtain a sequence of characters which are concatenated to the end of the
+ *  bstring b.  The stream read is terminated by the passed in terminator 
+ *  parameter.
+ *
+ *  If getcPtr returns with a negative number, or the terminator character 
+ *  (which is appended) is read, then the stream reading is halted and the 
+ *  function returns with a partial result in b.  If there is an empty partial
+ *  result, 1 is returned.  If no characters are read, or there is some other 
+ *  detectable error, BSTR_ERR is returned.
+ */
+int bassigngets (bstring b, bNgetc getcPtr, void * parm, char terminator) {
+int c, d, e;
+
+       if (b == NULL || b->mlen <= 0 || b->slen < 0 || b->mlen < b->slen ||
+           b->mlen <= 0 || getcPtr == NULL) return BSTR_ERR;
+       d = 0;
+       e = b->mlen - 2;
+
+       while ((c = getcPtr (parm)) >= 0) {
+               if (d > e) {
+                       b->slen = d;
+                       if (balloc (b, d + 2) != BSTR_OK) return BSTR_ERR;
+                       e = b->mlen - 2;
+               }
+               b->data[d] = (unsigned char) c;
+               d++;
+               if (c == terminator) break;
+       }
+
+       b->data[d] = (unsigned char) '\0';
+       b->slen = d;
+
+       return d == 0 && c < 0;
+}
+
+/*  int bgetsa (bstring b, bNgetc getcPtr, void * parm, char terminator)
+ *
+ *  Use an fgetc-like single character stream reading function (getcPtr) to 
+ *  obtain a sequence of characters which are concatenated to the end of the
+ *  bstring b.  The stream read is terminated by the passed in terminator 
+ *  parameter.
+ *
+ *  If getcPtr returns with a negative number, or the terminator character 
+ *  (which is appended) is read, then the stream reading is halted and the 
+ *  function returns with a partial result concatentated to b.  If there is 
+ *  an empty partial result, 1 is returned.  If no characters are read, or 
+ *  there is some other detectable error, BSTR_ERR is returned.
+ */
+int bgetsa (bstring b, bNgetc getcPtr, void * parm, char terminator) {
+int c, d, e;
+
+       if (b == NULL || b->mlen <= 0 || b->slen < 0 || b->mlen < b->slen ||
+           b->mlen <= 0 || getcPtr == NULL) return BSTR_ERR;
+       d = b->slen;
+       e = b->mlen - 2;
+
+       while ((c = getcPtr (parm)) >= 0) {
+               if (d > e) {
+                       b->slen = d;
+                       if (balloc (b, d + 2) != BSTR_OK) return BSTR_ERR;
+                       e = b->mlen - 2;
+               }
+               b->data[d] = (unsigned char) c;
+               d++;
+               if (c == terminator) break;
+       }
+
+       b->data[d] = (unsigned char) '\0';
+       b->slen = d;
+
+       return d == 0 && c < 0;
+}
+
+/*  bstring bgetstream (bNgetc getcPtr, void * parm, char terminator)
+ *
+ *  Use an fgetc-like single character stream reading function (getcPtr) to 
+ *  obtain a sequence of characters which are concatenated into a bstring.  
+ *  The stream read is terminated by the passed in terminator function.
+ *
+ *  If getcPtr returns with a negative number, or the terminator character 
+ *  (which is appended) is read, then the stream reading is halted and the 
+ *  result obtained thus far is returned.  If no characters are read, or 
+ *  there is some other detectable error, NULL is returned.
+ */
+bstring bgetstream (bNgetc getcPtr, void * parm, char terminator) {
+bstring buff;
+
+       if (0 > bgetsa (buff = bfromcstr (""), getcPtr, parm, terminator) || 0 >= buff->slen) {
+               bdestroy (buff);
+               buff = NULL;
+       }
+       return buff;
+}
+
+struct bStream {
+       bstring buff;           /* Buffer for over-reads */
+       void * parm;            /* The stream handle for core stream */
+       bNread readFnPtr;       /* fread compatible fnptr for core stream */
+       int isEOF;              /* track file's EOF state */
+       int maxBuffSz;
+};
+
+/*  struct bStream * bsopen (bNread readPtr, void * parm)
+ *
+ *  Wrap a given open stream (described by a fread compatible function 
+ *  pointer and stream handle) into an open bStream suitable for the bstring 
+ *  library streaming functions.
+ */
+struct bStream * bsopen (bNread readPtr, void * parm) {
+struct bStream * s;
+
+       if (readPtr == NULL) return NULL;
+       s = (struct bStream *) bstr__alloc (sizeof (struct bStream));
+       if (s == NULL) return NULL;
+       s->parm = parm;
+       s->buff = bfromcstr ("");
+       s->readFnPtr = readPtr;
+       s->maxBuffSz = BS_BUFF_SZ;
+       s->isEOF = 0;
+       return s;
+}
+
+/*  int bsbufflength (struct bStream * s, int sz)
+ *
+ *  Set the length of the buffer used by the bStream.  If sz is zero, the 
+ *  length is not set.  This function returns with the previous length.
+ */
+int bsbufflength (struct bStream * s, int sz) {
+int oldSz;
+       if (s == NULL || sz < 0) return BSTR_ERR;
+       oldSz = s->maxBuffSz;
+       if (sz > 0) s->maxBuffSz = sz;
+       return oldSz;
+}
+
+int bseof (const struct bStream * s) {
+       if (s == NULL || s->readFnPtr == NULL) return BSTR_ERR;
+       return s->isEOF && (s->buff->slen == 0);
+}
+
+/*  void * bsclose (struct bStream * s)
+ *
+ *  Close the bStream, and return the handle to the stream that was originally
+ *  used to open the given stream.
+ */
+void * bsclose (struct bStream * s) {
+void * parm;
+       if (s == NULL) return NULL;
+       s->readFnPtr = NULL;
+       if (s->buff) bdestroy (s->buff);
+       s->buff = NULL;
+       parm = s->parm;
+       s->parm = NULL;
+       s->isEOF = 1;
+       bstr__free (s);
+       return parm;
+}
+
+/*  int bsreadlna (bstring r, struct bStream * s, char terminator)
+ *
+ *  Read a bstring terminated by the terminator character or the end of the
+ *  stream from the bStream (s) and return it into the parameter r.  This 
+ *  function may read additional characters from the core stream that are not 
+ *  returned, but will be retained for subsequent read operations.
+ */
+int bsreadlna (bstring r, struct bStream * s, char terminator) {
+int i, l, ret, rlo;
+char * b;
+struct tagbstring x;
+
+       if (s == NULL || s->buff == NULL || r == NULL || r->mlen <= 0 ||
+           r->slen < 0 || r->mlen < r->slen) return BSTR_ERR;
+       l = s->buff->slen;
+       if (BSTR_OK != balloc (s->buff, s->maxBuffSz + 1)) return BSTR_ERR;
+       b = (char *) s->buff->data;
+       x.data = (unsigned char *) b;
+
+       /* First check if the current buffer holds the terminator */
+       b[l] = terminator; /* Set sentinel */
+       for (i=0; b[i] != terminator; i++) ;
+       if (i < l) {
+               x.slen = i + 1;
+               ret = bconcat (r, &x);
+               s->buff->slen = l;
+               if (BSTR_OK == ret) bdelete (s->buff, 0, i + 1);
+               return BSTR_OK;
+       }
+
+       rlo = r->slen;
+
+       /* If not then just concatenate the entire buffer to the output */
+       x.slen = l;
+       if (BSTR_OK != bconcat (r, &x)) return BSTR_ERR;
+
+       /* Perform direct in-place reads into the destination to allow for
+          the minimum of data-copies */
+       for (;;) {
+               if (BSTR_OK != balloc (r, r->slen + s->maxBuffSz + 1)) return BSTR_ERR;
+               b = (char *) (r->data + r->slen);
+               l = (int) s->readFnPtr (b, 1, s->maxBuffSz, s->parm);
+               if (l <= 0) {
+                       r->data[r->slen] = (unsigned char) '\0';
+                       s->buff->slen = 0;
+                       s->isEOF = 1;
+                       /* If nothing was read return with an error message */
+                       return BSTR_ERR & -(r->slen == rlo);
+               }
+               b[l] = terminator; /* Set sentinel */
+               for (i=0; b[i] != terminator; i++) ;
+               if (i < l) break;
+               r->slen += l;
+       }
+
+       /* Terminator found, push over-read back to buffer */
+       i++;
+       r->slen += i;
+       s->buff->slen = l - i;
+       bstr__memcpy (s->buff->data, b + i, l - i);
+       r->data[r->slen] = (unsigned char) '\0';
+       return BSTR_OK;
+}
+
+/*  int bsreadlnsa (bstring r, struct bStream * s, bstring term)
+ *
+ *  Read a bstring terminated by any character in the term string or the end 
+ *  of the stream from the bStream (s) and return it into the parameter r.  
+ *  This function may read additional characters from the core stream that 
+ *  are not returned, but will be retained for subsequent read operations.
+ */
+int bsreadlnsa (bstring r, struct bStream * s, const_bstring term) {
+int i, l, ret, rlo;
+unsigned char * b;
+struct tagbstring x;
+struct charField cf;
+
+       if (s == NULL || s->buff == NULL || r == NULL || term == NULL ||
+           term->data == NULL || r->mlen <= 0 || r->slen < 0 ||
+           r->mlen < r->slen) return BSTR_ERR;
+       if (term->slen == 1) return bsreadlna (r, s, term->data[0]);
+       if (term->slen < 1 || buildCharField (&cf, term)) return BSTR_ERR;
+
+       l = s->buff->slen;
+       if (BSTR_OK != balloc (s->buff, s->maxBuffSz + 1)) return BSTR_ERR;
+       b = (unsigned char *) s->buff->data;
+       x.data = b;
+
+       /* First check if the current buffer holds the terminator */
+       b[l] = term->data[0]; /* Set sentinel */
+       for (i=0; !testInCharField (&cf, b[i]); i++) ;
+       if (i < l) {
+               x.slen = i + 1;
+               ret = bconcat (r, &x);
+               s->buff->slen = l;
+               if (BSTR_OK == ret) bdelete (s->buff, 0, i + 1);
+               return BSTR_OK;
+       }
+
+       rlo = r->slen;
+
+       /* If not then just concatenate the entire buffer to the output */
+       x.slen = l;
+       if (BSTR_OK != bconcat (r, &x)) return BSTR_ERR;
+
+       /* Perform direct in-place reads into the destination to allow for
+          the minimum of data-copies */
+       for (;;) {
+               if (BSTR_OK != balloc (r, r->slen + s->maxBuffSz + 1)) return BSTR_ERR;
+               b = (unsigned char *) (r->data + r->slen);
+               l = (int) s->readFnPtr (b, 1, s->maxBuffSz, s->parm);
+               if (l <= 0) {
+                       r->data[r->slen] = (unsigned char) '\0';
+                       s->buff->slen = 0;
+                       s->isEOF = 1;
+                       /* If nothing was read return with an error message */
+                       return BSTR_ERR & -(r->slen == rlo);
+               }
+
+               b[l] = term->data[0]; /* Set sentinel */
+               for (i=0; !testInCharField (&cf, b[i]); i++) ;
+               if (i < l) break;
+               r->slen += l;
+       }
+
+       /* Terminator found, push over-read back to buffer */
+       i++;
+       r->slen += i;
+       s->buff->slen = l - i;
+       bstr__memcpy (s->buff->data, b + i, l - i);
+       r->data[r->slen] = (unsigned char) '\0';
+       return BSTR_OK;
+}
+
+/*  int bsreada (bstring r, struct bStream * s, int n)
+ *
+ *  Read a bstring of length n (or, if it is fewer, as many bytes as is 
+ *  remaining) from the bStream.  This function may read additional 
+ *  characters from the core stream that are not returned, but will be 
+ *  retained for subsequent read operations.  This function will not read
+ *  additional characters from the core stream beyond virtual stream pointer.
+ */
+int bsreada (bstring r, struct bStream * s, int n) {
+int l, ret, orslen;
+char * b;
+struct tagbstring x;
+
+       if (s == NULL || s->buff == NULL || r == NULL || r->mlen <= 0
+        || r->slen < 0 || r->mlen < r->slen || n <= 0) return BSTR_ERR;
+
+       n += r->slen;
+       if (n <= 0) return BSTR_ERR;
+
+       l = s->buff->slen;
+
+       orslen = r->slen;
+
+       if (0 == l) {
+               if (s->isEOF) return BSTR_ERR;
+               if (r->mlen > n) {
+                       l = (int) s->readFnPtr (r->data + r->slen, 1, n - r->slen, s->parm);
+                       if (0 >= l || l > n - r->slen) {
+                               s->isEOF = 1;
+                               return BSTR_ERR;
+                       }
+                       r->slen += l;
+                       r->data[r->slen] = (unsigned char) '\0';
+                       return 0;
+               }
+       }
+
+       if (BSTR_OK != balloc (s->buff, s->maxBuffSz + 1)) return BSTR_ERR;
+       b = (char *) s->buff->data;
+       x.data = (unsigned char *) b;
+
+       do {
+               if (l + r->slen >= n) {
+                       x.slen = n - r->slen;
+                       ret = bconcat (r, &x);
+                       s->buff->slen = l;
+                       if (BSTR_OK == ret) bdelete (s->buff, 0, x.slen);
+                       return BSTR_ERR & -(r->slen == orslen);
+               }
+
+               x.slen = l;
+               if (BSTR_OK != bconcat (r, &x)) break;
+
+               l = n - r->slen;
+               if (l > s->maxBuffSz) l = s->maxBuffSz;
+
+               l = (int) s->readFnPtr (b, 1, l, s->parm);
+
+       } while (l > 0);
+       if (l < 0) l = 0;
+       if (l == 0) s->isEOF = 1;
+       s->buff->slen = l;
+       return BSTR_ERR & -(r->slen == orslen);
+}
+
+/*  int bsreadln (bstring r, struct bStream * s, char terminator)
+ *
+ *  Read a bstring terminated by the terminator character or the end of the
+ *  stream from the bStream (s) and return it into the parameter r.  This 
+ *  function may read additional characters from the core stream that are not 
+ *  returned, but will be retained for subsequent read operations.
+ */
+int bsreadln (bstring r, struct bStream * s, char terminator) {
+       if (s == NULL || s->buff == NULL || r == NULL || r->mlen <= 0)
+               return BSTR_ERR;
+       if (BSTR_OK != balloc (s->buff, s->maxBuffSz + 1)) return BSTR_ERR;
+       r->slen = 0;
+       return bsreadlna (r, s, terminator);
+}
+
+/*  int bsreadlns (bstring r, struct bStream * s, bstring term)
+ *
+ *  Read a bstring terminated by any character in the term string or the end 
+ *  of the stream from the bStream (s) and return it into the parameter r.  
+ *  This function may read additional characters from the core stream that 
+ *  are not returned, but will be retained for subsequent read operations.
+ */
+int bsreadlns (bstring r, struct bStream * s, const_bstring term) {
+       if (s == NULL || s->buff == NULL || r == NULL || term == NULL 
+        || term->data == NULL || r->mlen <= 0) return BSTR_ERR;
+       if (term->slen == 1) return bsreadln (r, s, term->data[0]);
+       if (term->slen < 1) return BSTR_ERR;
+       if (BSTR_OK != balloc (s->buff, s->maxBuffSz + 1)) return BSTR_ERR;
+       r->slen = 0;
+       return bsreadlnsa (r, s, term);
+}
+
+/*  int bsread (bstring r, struct bStream * s, int n)
+ *
+ *  Read a bstring of length n (or, if it is fewer, as many bytes as is 
+ *  remaining) from the bStream.  This function may read additional 
+ *  characters from the core stream that are not returned, but will be 
+ *  retained for subsequent read operations.  This function will not read
+ *  additional characters from the core stream beyond virtual stream pointer.
+ */
+int bsread (bstring r, struct bStream * s, int n) {
+       if (s == NULL || s->buff == NULL || r == NULL || r->mlen <= 0
+        || n <= 0) return BSTR_ERR;
+       if (BSTR_OK != balloc (s->buff, s->maxBuffSz + 1)) return BSTR_ERR;
+       r->slen = 0;
+       return bsreada (r, s, n);
+}
+
+/*  int bsunread (struct bStream * s, const_bstring b)
+ *
+ *  Insert a bstring into the bStream at the current position.  These 
+ *  characters will be read prior to those that actually come from the core 
+ *  stream.
+ */
+int bsunread (struct bStream * s, const_bstring b) {
+       if (s == NULL || s->buff == NULL) return BSTR_ERR;
+       return binsert (s->buff, 0, b, (unsigned char) '?');
+}
+
+/*  int bspeek (bstring r, const struct bStream * s)
+ *
+ *  Return the currently buffered characters from the bStream that will be 
+ *  read prior to reads from the core stream.
+ */
+int bspeek (bstring r, const struct bStream * s) {
+       if (s == NULL || s->buff == NULL) return BSTR_ERR;
+       return bassign (r, s->buff);
+}
+
+/*  bstring bjoin (const struct bstrList * bl, const_bstring sep);
+ *
+ *  Join the entries of a bstrList into one bstring by sequentially 
+ *  concatenating them with the sep string in between.  If there is an error 
+ *  NULL is returned, otherwise a bstring with the correct result is returned.
+ */
+bstring bjoin (const struct bstrList * bl, const_bstring sep) {
+bstring b;
+int i, c, v;
+
+       if (bl == NULL || bl->qty < 0) return NULL;
+       if (sep != NULL && (sep->slen < 0 || sep->data == NULL)) return NULL;
+
+       for (i = 0, c = 1; i < bl->qty; i++) {
+               v = bl->entry[i]->slen;
+               if (v < 0) return NULL; /* Invalid input */
+               c += v;
+               if (c < 0) return NULL; /* Wrap around ?? */
+       }
+
+       if (sep != NULL) c += (bl->qty - 1) * sep->slen;
+
+       b = (bstring) bstr__alloc (sizeof (struct tagbstring));
+       if (NULL == b) return NULL; /* Out of memory */
+       b->data = (unsigned char *) bstr__alloc (c);
+       if (b->data == NULL) {
+               bstr__free (b);
+               return NULL;
+       }
+
+       b->mlen = c;
+       b->slen = c-1;
+
+       for (i = 0, c = 0; i < bl->qty; i++) {
+               if (i > 0 && sep != NULL) {
+                       bstr__memcpy (b->data + c, sep->data, sep->slen);
+                       c += sep->slen;
+               }
+               v = bl->entry[i]->slen;
+               bstr__memcpy (b->data + c, bl->entry[i]->data, v);
+               c += v;
+       }
+       b->data[c] = (unsigned char) '\0';
+       return b;
+}
+
+#define BSSSC_BUFF_LEN (256)
+
+/*  int bssplitscb (struct bStream * s, const_bstring splitStr, 
+ *     int (* cb) (void * parm, int ofs, const_bstring entry), void * parm)
+ *
+ *  Iterate the set of disjoint sequential substrings read from a stream 
+ *  divided by any of the characters in splitStr.  An empty splitStr causes 
+ *  the whole stream to be iterated once.
+ *
+ *  Note: At the point of calling the cb function, the bStream pointer is 
+ *  pointed exactly at the position right after having read the split 
+ *  character.  The cb function can act on the stream by causing the bStream
+ *  pointer to move, and bssplitscb will continue by starting the next split
+ *  at the position of the pointer after the return from cb.
+ *
+ *  However, if the cb causes the bStream s to be destroyed then the cb must
+ *  return with a negative value, otherwise bssplitscb will continue in an 
+ *  undefined manner.
+ */
+int bssplitscb (struct bStream * s, const_bstring splitStr, 
+       int (* cb) (void * parm, int ofs, const_bstring entry), void * parm) {
+struct charField chrs;
+bstring buff;
+int i, p, ret;
+
+       if (cb == NULL || s == NULL || s->readFnPtr == NULL 
+        || splitStr == NULL || splitStr->slen < 0) return BSTR_ERR;
+
+       if (NULL == (buff = bfromcstr (""))) return BSTR_ERR;
+
+       if (splitStr->slen == 0) {
+               while (bsreada (buff, s, BSSSC_BUFF_LEN) >= 0) ;
+               if ((ret = cb (parm, 0, buff)) > 0) 
+                       ret = 0;
+       } else {
+               buildCharField (&chrs, splitStr);
+               ret = p = i = 0;
+               for (;;) {
+                       if (i >= buff->slen) {
+                               bsreada (buff, s, BSSSC_BUFF_LEN);
+                               if (i >= buff->slen) {
+                                       if (0 < (ret = cb (parm, p, buff))) ret = 0;
+                                       break;
+                               }
+                       }
+                       if (testInCharField (&chrs, buff->data[i])) {
+                               struct tagbstring t;
+                               unsigned char c;
+
+                               blk2tbstr (t, buff->data + i + 1, buff->slen - (i + 1));
+                               if ((ret = bsunread (s, &t)) < 0) break;
+                               buff->slen = i;
+                               c = buff->data[i];
+                               buff->data[i] = (unsigned char) '\0';
+                               if ((ret = cb (parm, p, buff)) < 0) break;
+                               buff->data[i] = c;
+                               buff->slen = 0;
+                               p += i + 1;
+                               i = -1;
+                       }
+                       i++;
+               }
+       }
+
+       bdestroy (buff);
+       return ret;
+}
+
+/*  int bssplitstrcb (struct bStream * s, const_bstring splitStr, 
+ *     int (* cb) (void * parm, int ofs, const_bstring entry), void * parm)
+ *
+ *  Iterate the set of disjoint sequential substrings read from a stream 
+ *  divided by the entire substring splitStr.  An empty splitStr causes 
+ *  each character of the stream to be iterated.
+ *
+ *  Note: At the point of calling the cb function, the bStream pointer is 
+ *  pointed exactly at the position right after having read the split 
+ *  character.  The cb function can act on the stream by causing the bStream
+ *  pointer to move, and bssplitscb will continue by starting the next split
+ *  at the position of the pointer after the return from cb.
+ *
+ *  However, if the cb causes the bStream s to be destroyed then the cb must
+ *  return with a negative value, otherwise bssplitscb will continue in an 
+ *  undefined manner.
+ */
+int bssplitstrcb (struct bStream * s, const_bstring splitStr, 
+       int (* cb) (void * parm, int ofs, const_bstring entry), void * parm) {
+bstring buff;
+int i, p, ret;
+
+       if (cb == NULL || s == NULL || s->readFnPtr == NULL 
+        || splitStr == NULL || splitStr->slen < 0) return BSTR_ERR;
+
+       if (splitStr->slen == 1) return bssplitscb (s, splitStr, cb, parm);
+
+       if (NULL == (buff = bfromcstr (""))) return BSTR_ERR;
+
+       if (splitStr->slen == 0) {
+               for (i=0; bsreada (buff, s, BSSSC_BUFF_LEN) >= 0; i++) {
+                       if ((ret = cb (parm, 0, buff)) < 0) {
+                               bdestroy (buff);
+                               return ret;
+                       }
+                       buff->slen = 0;
+               }
+               return BSTR_OK;
+       } else {
+               ret = p = i = 0;
+               for (i=p=0;;) {
+                       if ((ret = binstr (buff, 0, splitStr)) >= 0) {
+                               struct tagbstring t;
+                               blk2tbstr (t, buff->data, ret);
+                               i = ret + splitStr->slen;
+                               if ((ret = cb (parm, p, &t)) < 0) break;
+                               p += i;
+                               bdelete (buff, 0, i);
+                       } else {
+                               bsreada (buff, s, BSSSC_BUFF_LEN);
+                               if (bseof (s)) {
+                                       if ((ret = cb (parm, p, buff)) > 0) ret = 0;
+                                       break;
+                               }
+                       }
+               }
+       }
+
+       bdestroy (buff);
+       return ret;
+}
+
+/*  int bstrListCreate (void)
+ *
+ *  Create a bstrList.
+ */
+struct bstrList * bstrListCreate (void) {
+struct bstrList * sl = (struct bstrList *) bstr__alloc (sizeof (struct bstrList));
+       if (sl) {
+               sl->entry = (bstring *) bstr__alloc (1*sizeof (bstring));
+               if (!sl->entry) {
+                       bstr__free (sl);
+                       sl = NULL;
+               } else {
+                       sl->qty = 0;
+                       sl->mlen = 1;
+               }
+       }
+       return sl;
+}
+
+/*  int bstrListDestroy (struct bstrList * sl)
+ *
+ *  Destroy a bstrList that has been created by bsplit, bsplits or bstrListCreate.
+ */
+int bstrListDestroy (struct bstrList * sl) {
+int i;
+       if (sl == NULL || sl->qty < 0) return BSTR_ERR;
+       for (i=0; i < sl->qty; i++) {
+               if (sl->entry[i]) {
+                       bdestroy (sl->entry[i]);
+                       sl->entry[i] = NULL;
+               }
+       }
+       sl->qty  = -1;
+       sl->mlen = -1;
+       bstr__free (sl->entry);
+       sl->entry = NULL;
+       bstr__free (sl);
+       return BSTR_OK;
+}
+
+/*  int bstrListAlloc (struct bstrList * sl, int msz)
+ *
+ *  Ensure that there is memory for at least msz number of entries for the
+ *  list.
+ */
+int bstrListAlloc (struct bstrList * sl, int msz) {
+bstring * l;
+int smsz;
+size_t nsz;
+       if (!sl || msz <= 0 || !sl->entry || sl->qty < 0 || sl->mlen <= 0 || sl->qty > sl->mlen) return BSTR_ERR;
+       if (sl->mlen >= msz) return BSTR_OK;
+       smsz = snapUpSize (msz);
+       nsz = ((size_t) smsz) * sizeof (bstring);
+       if (nsz < (size_t) smsz) return BSTR_ERR;
+       l = (bstring *) bstr__realloc (sl->entry, nsz);
+       if (!l) {
+               smsz = msz;
+               nsz = ((size_t) smsz) * sizeof (bstring);
+               l = (bstring *) bstr__realloc (sl->entry, nsz);
+               if (!l) return BSTR_ERR;
+       }
+       sl->mlen = smsz;
+       sl->entry = l;
+       return BSTR_OK;
+}
+
+/*  int bstrListAllocMin (struct bstrList * sl, int msz)
+ *
+ *  Try to allocate the minimum amount of memory for the list to include at
+ *  least msz entries or sl->qty whichever is greater.
+ */
+int bstrListAllocMin (struct bstrList * sl, int msz) {
+bstring * l;
+size_t nsz;
+       if (!sl || msz <= 0 || !sl->entry || sl->qty < 0 || sl->mlen <= 0 || sl->qty > sl->mlen) return BSTR_ERR;
+       if (msz < sl->qty) msz = sl->qty;
+       if (sl->mlen == msz) return BSTR_OK;
+       nsz = ((size_t) msz) * sizeof (bstring);
+       if (nsz < (size_t) msz) return BSTR_ERR;
+       l = (bstring *) bstr__realloc (sl->entry, nsz);
+       if (!l) return BSTR_ERR;
+       sl->mlen = msz;
+       sl->entry = l;
+       return BSTR_OK;
+}
+
+/*  int bsplitcb (const_bstring str, unsigned char splitChar, int pos,
+ *     int (* cb) (void * parm, int ofs, int len), void * parm)
+ *
+ *  Iterate the set of disjoint sequential substrings over str divided by the
+ *  character in splitChar.
+ *
+ *  Note: Non-destructive modification of str from within the cb function 
+ *  while performing this split is not undefined.  bsplitcb behaves in 
+ *  sequential lock step with calls to cb.  I.e., after returning from a cb 
+ *  that return a non-negative integer, bsplitcb continues from the position 
+ *  1 character after the last detected split character and it will halt 
+ *  immediately if the length of str falls below this point.  However, if the 
+ *  cb function destroys str, then it *must* return with a negative value, 
+ *  otherwise bsplitcb will continue in an undefined manner.
+ */
+int bsplitcb (const_bstring str, unsigned char splitChar, int pos,
+       int (* cb) (void * parm, int ofs, int len), void * parm) {
+int i, p, ret;
+
+       if (cb == NULL || str == NULL || pos < 0 || pos > str->slen) 
+               return BSTR_ERR;
+
+       p = pos;
+       do {
+               for (i=p; i < str->slen; i++) {
+                       if (str->data[i] == splitChar) break;
+               }
+               if ((ret = cb (parm, p, i - p)) < 0) return ret;
+               p = i + 1;
+       } while (p <= str->slen);
+       return BSTR_OK;
+}
+
+/*  int bsplitscb (const_bstring str, const_bstring splitStr, int pos,
+ *     int (* cb) (void * parm, int ofs, int len), void * parm)
+ *
+ *  Iterate the set of disjoint sequential substrings over str divided by any 
+ *  of the characters in splitStr.  An empty splitStr causes the whole str to
+ *  be iterated once.
+ *
+ *  Note: Non-destructive modification of str from within the cb function 
+ *  while performing this split is not undefined.  bsplitscb behaves in 
+ *  sequential lock step with calls to cb.  I.e., after returning from a cb 
+ *  that return a non-negative integer, bsplitscb continues from the position 
+ *  1 character after the last detected split character and it will halt 
+ *  immediately if the length of str falls below this point.  However, if the 
+ *  cb function destroys str, then it *must* return with a negative value, 
+ *  otherwise bsplitscb will continue in an undefined manner.
+ */
+int bsplitscb (const_bstring str, const_bstring splitStr, int pos,
+       int (* cb) (void * parm, int ofs, int len), void * parm) {
+struct charField chrs;
+int i, p, ret;
+
+       if (cb == NULL || str == NULL || pos < 0 || pos > str->slen 
+        || splitStr == NULL || splitStr->slen < 0) return BSTR_ERR;
+       if (splitStr->slen == 0) {
+               if ((ret = cb (parm, 0, str->slen)) > 0) ret = 0;
+               return ret;
+       }
+
+       if (splitStr->slen == 1) 
+               return bsplitcb (str, splitStr->data[0], pos, cb, parm);
+
+       buildCharField (&chrs, splitStr);
+
+       p = pos;
+       do {
+               for (i=p; i < str->slen; i++) {
+                       if (testInCharField (&chrs, str->data[i])) break;
+               }
+               if ((ret = cb (parm, p, i - p)) < 0) return ret;
+               p = i + 1;
+       } while (p <= str->slen);
+       return BSTR_OK;
+}
+
+/*  int bsplitstrcb (const_bstring str, const_bstring splitStr, int pos,
+ *     int (* cb) (void * parm, int ofs, int len), void * parm)
+ *
+ *  Iterate the set of disjoint sequential substrings over str divided by the 
+ *  substring splitStr.  An empty splitStr causes the whole str to be 
+ *  iterated once.
+ *
+ *  Note: Non-destructive modification of str from within the cb function 
+ *  while performing this split is not undefined.  bsplitstrcb behaves in 
+ *  sequential lock step with calls to cb.  I.e., after returning from a cb 
+ *  that return a non-negative integer, bsplitscb continues from the position 
+ *  1 character after the last detected split character and it will halt 
+ *  immediately if the length of str falls below this point.  However, if the 
+ *  cb function destroys str, then it *must* return with a negative value, 
+ *  otherwise bsplitscb will continue in an undefined manner.
+ */
+int bsplitstrcb (const_bstring str, const_bstring splitStr, int pos,
+       int (* cb) (void * parm, int ofs, int len), void * parm) {
+int i, p, ret;
+
+       if (cb == NULL || str == NULL || pos < 0 || pos > str->slen 
+        || splitStr == NULL || splitStr->slen < 0) return BSTR_ERR;
+
+       if (0 == splitStr->slen) {
+               for (i=pos; i < str->slen; i++) {
+                       if ((ret = cb (parm, i, 1)) < 0) return ret;
+               }
+               return BSTR_OK;
+       }
+
+       if (splitStr->slen == 1) 
+               return bsplitcb (str, splitStr->data[0], pos, cb, parm);
+
+       for (i=p=pos; i <= str->slen - splitStr->slen; i++) {
+               if (0 == bstr__memcmp (splitStr->data, str->data + i, splitStr->slen)) {
+                       if ((ret = cb (parm, p, i - p)) < 0) return ret;
+                       i += splitStr->slen;
+                       p = i;
+               }
+       }
+       if ((ret = cb (parm, p, str->slen - p)) < 0) return ret;
+       return BSTR_OK;
+}
+
+struct genBstrList {
+       bstring b;
+       struct bstrList * bl;
+};
+
+static int bscb (void * parm, int ofs, int len) {
+struct genBstrList * g = (struct genBstrList *) parm;
+       if (g->bl->qty >= g->bl->mlen) {
+               int mlen = g->bl->mlen * 2;
+               bstring * tbl;
+
+               while (g->bl->qty >= mlen) {
+                       if (mlen < g->bl->mlen) return BSTR_ERR;
+                       mlen += mlen;
+               }
+
+               tbl = (bstring *) bstr__realloc (g->bl->entry, sizeof (bstring) * mlen);
+               if (tbl == NULL) return BSTR_ERR;
+
+               g->bl->entry = tbl;
+               g->bl->mlen = mlen;
+       }
+
+       g->bl->entry[g->bl->qty] = bmidstr (g->b, ofs, len);
+       g->bl->qty++;
+       return BSTR_OK;
+}
+
+/*  struct bstrList * bsplit (const_bstring str, unsigned char splitChar)
+ *
+ *  Create an array of sequential substrings from str divided by the character
+ *  splitChar.  
+ */
+struct bstrList * bsplit (const_bstring str, unsigned char splitChar) {
+struct genBstrList g;
+
+       if (str == NULL || str->data == NULL || str->slen < 0) return NULL;
+
+       g.bl = (struct bstrList *) bstr__alloc (sizeof (struct bstrList));
+       if (g.bl == NULL) return NULL;
+       g.bl->mlen = 4;
+       g.bl->entry = (bstring *) bstr__alloc (g.bl->mlen * sizeof (bstring));
+       if (NULL == g.bl->entry) {
+               bstr__free (g.bl);
+               return NULL;
+       }
+
+       g.b = (bstring) str;
+       g.bl->qty = 0;
+       if (bsplitcb (str, splitChar, 0, bscb, &g) < 0) {
+               bstrListDestroy (g.bl);
+               return NULL;
+       }
+       return g.bl;
+}
+
+/*  struct bstrList * bsplitstr (const_bstring str, const_bstring splitStr)
+ *
+ *  Create an array of sequential substrings from str divided by the entire
+ *  substring splitStr.
+ */
+struct bstrList * bsplitstr (const_bstring str, const_bstring splitStr) {
+struct genBstrList g;
+
+       if (str == NULL || str->data == NULL || str->slen < 0) return NULL;
+
+       g.bl = (struct bstrList *) bstr__alloc (sizeof (struct bstrList));
+       if (g.bl == NULL) return NULL;
+       g.bl->mlen = 4;
+       g.bl->entry = (bstring *) bstr__alloc (g.bl->mlen * sizeof (bstring));
+       if (NULL == g.bl->entry) {
+               bstr__free (g.bl);
+               return NULL;
+       }
+
+       g.b = (bstring) str;
+       g.bl->qty = 0;
+       if (bsplitstrcb (str, splitStr, 0, bscb, &g) < 0) {
+               bstrListDestroy (g.bl);
+               return NULL;
+       }
+       return g.bl;
+}
+
+/*  struct bstrList * bsplits (const_bstring str, bstring splitStr)
+ *
+ *  Create an array of sequential substrings from str divided by any of the 
+ *  characters in splitStr.  An empty splitStr causes a single entry bstrList
+ *  containing a copy of str to be returned.
+ */
+struct bstrList * bsplits (const_bstring str, const_bstring splitStr) {
+struct genBstrList g;
+
+       if (     str == NULL ||      str->slen < 0 ||      str->data == NULL ||
+           splitStr == NULL || splitStr->slen < 0 || splitStr->data == NULL)
+               return NULL;
+
+       g.bl = (struct bstrList *) bstr__alloc (sizeof (struct bstrList));
+       if (g.bl == NULL) return NULL;
+       g.bl->mlen = 4;
+       g.bl->entry = (bstring *) bstr__alloc (g.bl->mlen * sizeof (bstring));
+       if (NULL == g.bl->entry) {
+               bstr__free (g.bl);
+               return NULL;
+       }
+       g.b = (bstring) str;
+       g.bl->qty = 0;
+
+       if (bsplitscb (str, splitStr, 0, bscb, &g) < 0) {
+               bstrListDestroy (g.bl);
+               return NULL;
+       }
+       return g.bl;
+}
+
+#if defined (__TURBOC__) && !defined (__BORLANDC__)
+# ifndef BSTRLIB_NOVSNP
+#  define BSTRLIB_NOVSNP
+# endif
+#endif
+
+/* Give WATCOM C/C++, MSVC some latitude for their non-support of vsnprintf */
+#if defined(__WATCOMC__) || defined(_MSC_VER)
+#define exvsnprintf(r,b,n,f,a) {r = _vsnprintf (b,n,f,a);}
+#else
+#ifdef BSTRLIB_NOVSNP
+/* This is just a hack.  If you are using a system without a vsnprintf, it is 
+   not recommended that bformat be used at all. */
+#define exvsnprintf(r,b,n,f,a) {vsprintf (b,f,a); r = -1;}
+#define START_VSNBUFF (256)
+#else
+
+#ifdef __GNUC__
+/* Something is making gcc complain about this prototype not being here, so 
+   I've just gone ahead and put it in. */
+extern int vsnprintf (char *buf, size_t count, const char *format, va_list arg);
+#endif
+
+#define exvsnprintf(r,b,n,f,a) {r = vsnprintf (b,n,f,a);}
+#endif
+#endif
+
+#if !defined (BSTRLIB_NOVSNP)
+
+#ifndef START_VSNBUFF
+#define START_VSNBUFF (16)
+#endif
+
+/* On IRIX vsnprintf returns n-1 when the operation would overflow the target 
+   buffer, WATCOM and MSVC both return -1, while C99 requires that the 
+   returned value be exactly what the length would be if the buffer would be
+   large enough.  This leads to the idea that if the return value is larger 
+   than n, then changing n to the return value will reduce the number of
+   iterations required. */
+
+/*  int bformata (bstring b, const char * fmt, ...)
+ *
+ *  After the first parameter, it takes the same parameters as printf (), but 
+ *  rather than outputting results to stdio, it appends the results to 
+ *  a bstring which contains what would have been output. Note that if there 
+ *  is an early generation of a '\0' character, the bstring will be truncated 
+ *  to this end point.
+ */
+int bformata (bstring b, const char * fmt, ...) {
+va_list arglist;
+bstring buff;
+int n, r;
+
+       if (b == NULL || fmt == NULL || b->data == NULL || b->mlen <= 0 
+        || b->slen < 0 || b->slen > b->mlen) return BSTR_ERR;
+
+       /* Since the length is not determinable beforehand, a search is
+          performed using the truncating "vsnprintf" call (to avoid buffer
+          overflows) on increasing potential sizes for the output result. */
+
+       if ((n = (int) (2*strlen (fmt))) < START_VSNBUFF) n = START_VSNBUFF;
+       if (NULL == (buff = bfromcstralloc (n + 2, ""))) {
+               n = 1;
+               if (NULL == (buff = bfromcstralloc (n + 2, ""))) return BSTR_ERR;
+       }
+
+       for (;;) {
+               va_start (arglist, fmt);
+               exvsnprintf (r, (char *) buff->data, n + 1, fmt, arglist);
+               va_end (arglist);
+
+               buff->data[n] = (unsigned char) '\0';
+               buff->slen = (int) (strlen) ((char *) buff->data);
+
+               if (buff->slen < n) break;
+
+               if (r > n) n = r; else n += n;
+
+               if (BSTR_OK != balloc (buff, n + 2)) {
+                       bdestroy (buff);
+                       return BSTR_ERR;
+               }
+       }
+
+       r = bconcat (b, buff);
+       bdestroy (buff);
+       return r;
+}
+
+/*  int bassignformat (bstring b, const char * fmt, ...)
+ *
+ *  After the first parameter, it takes the same parameters as printf (), but 
+ *  rather than outputting results to stdio, it outputs the results to 
+ *  the bstring parameter b. Note that if there is an early generation of a 
+ *  '\0' character, the bstring will be truncated to this end point.
+ */
+int bassignformat (bstring b, const char * fmt, ...) {
+va_list arglist;
+bstring buff;
+int n, r;
+
+       if (b == NULL || fmt == NULL || b->data == NULL || b->mlen <= 0 
+        || b->slen < 0 || b->slen > b->mlen) return BSTR_ERR;
+
+       /* Since the length is not determinable beforehand, a search is
+          performed using the truncating "vsnprintf" call (to avoid buffer
+          overflows) on increasing potential sizes for the output result. */
+
+       if ((n = (int) (2*strlen (fmt))) < START_VSNBUFF) n = START_VSNBUFF;
+       if (NULL == (buff = bfromcstralloc (n + 2, ""))) {
+               n = 1;
+               if (NULL == (buff = bfromcstralloc (n + 2, ""))) return BSTR_ERR;
+       }
+
+       for (;;) {
+               va_start (arglist, fmt);
+               exvsnprintf (r, (char *) buff->data, n + 1, fmt, arglist);
+               va_end (arglist);
+
+               buff->data[n] = (unsigned char) '\0';
+               buff->slen = (int) (strlen) ((char *) buff->data);
+
+               if (buff->slen < n) break;
+
+               if (r > n) n = r; else n += n;
+
+               if (BSTR_OK != balloc (buff, n + 2)) {
+                       bdestroy (buff);
+                       return BSTR_ERR;
+               }
+       }
+
+       r = bassign (b, buff);
+       bdestroy (buff);
+       return r;
+}
+
+/*  bstring bformat (const char * fmt, ...)
+ *
+ *  Takes the same parameters as printf (), but rather than outputting results
+ *  to stdio, it forms a bstring which contains what would have been output.
+ *  Note that if there is an early generation of a '\0' character, the 
+ *  bstring will be truncated to this end point.
+ */
+bstring bformat (const char * fmt, ...) {
+va_list arglist;
+bstring buff;
+int n, r;
+
+       if (fmt == NULL) return NULL;
+
+       /* Since the length is not determinable beforehand, a search is
+          performed using the truncating "vsnprintf" call (to avoid buffer
+          overflows) on increasing potential sizes for the output result. */
+
+       if ((n = (int) (2*strlen (fmt))) < START_VSNBUFF) n = START_VSNBUFF;
+       if (NULL == (buff = bfromcstralloc (n + 2, ""))) {
+               n = 1;
+               if (NULL == (buff = bfromcstralloc (n + 2, ""))) return NULL;
+       }
+
+       for (;;) {
+               va_start (arglist, fmt);
+               exvsnprintf (r, (char *) buff->data, n + 1, fmt, arglist);
+               va_end (arglist);
+
+               buff->data[n] = (unsigned char) '\0';
+               buff->slen = (int) (strlen) ((char *) buff->data);
+
+               if (buff->slen < n) break;
+
+               if (r > n) n = r; else n += n;
+
+               if (BSTR_OK != balloc (buff, n + 2)) {
+                       bdestroy (buff);
+                       return NULL;
+               }
+       }
+
+       return buff;
+}
+
+/*  int bvcformata (bstring b, int count, const char * fmt, va_list arglist)
+ *
+ *  The bvcformata function formats data under control of the format control 
+ *  string fmt and attempts to append the result to b.  The fmt parameter is 
+ *  the same as that of the printf function.  The variable argument list is 
+ *  replaced with arglist, which has been initialized by the va_start macro.
+ *  The size of the output is upper bounded by count.  If the required output
+ *  exceeds count, the string b is not augmented with any contents and a value
+ *  below BSTR_ERR is returned.  If a value below -count is returned then it
+ *  is recommended that the negative of this value be used as an update to the
+ *  count in a subsequent pass.  On other errors, such as running out of 
+ *  memory, parameter errors or numeric wrap around BSTR_ERR is returned.  
+ *  BSTR_OK is returned when the output is successfully generated and 
+ *  appended to b.
+ *
+ *  Note: There is no sanity checking of arglist, and this function is
+ *  destructive of the contents of b from the b->slen point onward.  If there 
+ *  is an early generation of a '\0' character, the bstring will be truncated 
+ *  to this end point.
+ */
+int bvcformata (bstring b, int count, const char * fmt, va_list arg) {
+int n, r, l;
+
+       if (b == NULL || fmt == NULL || count <= 0 || b->data == NULL
+        || b->mlen <= 0 || b->slen < 0 || b->slen > b->mlen) return BSTR_ERR;
+
+       if (count > (n = b->slen + count) + 2) return BSTR_ERR;
+       if (BSTR_OK != balloc (b, n + 2)) return BSTR_ERR;
+
+       exvsnprintf (r, (char *) b->data + b->slen, count + 2, fmt, arg);
+
+       /* Did the operation complete successfully within bounds? */
+
+       if (n >= (l = b->slen + (int) (strlen) ((const char *) b->data + b->slen))) {
+               b->slen = l;
+               return BSTR_OK;
+       }
+
+       /* Abort, since the buffer was not large enough.  The return value 
+          tries to help set what the retry length should be. */
+
+       b->data[b->slen] = '\0';
+       if (r > count+1) l = r; else {
+               l = count+count;
+               if (count > l) l = INT_MAX;
+       }
+       n = -l;
+       if (n > BSTR_ERR-1) n = BSTR_ERR-1;
+       return n;
+}
+
+#endif
index 75b41c112984dcd5bf827acc9189c724d1dc5f7e..cd3ca24fda0587571a63c6498934b8f12f1ce153 100644 (file)
@@ -11,7 +11,7 @@ libcnid_cdb_la_SOURCES = cnid_cdb_add.c \
                         cnid_cdb_rebuild_add.c \
                         cnid_cdb.h
 libcnid_cdb_la_CFLAGS = @BDB_CFLAGS@
-libcnid_cdb_la_LIBADD = @BDB_LIBS@
+libcnid_cdb_la_LIBADD = @BDB_LIBS@ @PTHREAD_LIBS@
 
 if USE_CDB_BACKEND
 noinst_LTLIBRARIES = libcnid_cdb.la
index bf501fd5e9e52aa5bcc9fd7c85314771b5379307..10ecc78d8c34efaf51365820954b1ff5d06c0f6a 100644 (file)
@@ -1,7 +1,4 @@
 /*
-
- * $Id: cnid_cdb_open.c,v 1.5 2010-03-31 09:47:32 franklahm Exp $
- *
  * Copyright (c) 1999. Adrian Sun (asun@zoology.washington.edu)
  * All Rights Reserved. See COPYRIGHT.
  *
@@ -40,6 +37,8 @@
 #endif /* HAVE_CONFIG_H */
 
 #ifdef CNID_BACKEND_CDB
+
+#include <atalk/cnid_private.h>
 #include "cnid_cdb_private.h"
 
 #ifndef MIN
 #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
@@ -355,42 +346,27 @@ struct _cnid_db *cnid_cdb_open(struct cnid_open_args *args)
         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;
+    /* Check for version. "cdb" only supports CNID_VERSION_0, cf cnid_private.h */
 
-    if ((rc = db->db_didname->pget(db->db_didname, NULL, &key, &pkey, &data, 0)) != 0) {
-        int ret;
-        {
-            u_int32_t version = htonl(DBVERSION);
+    DBT key, data;
+    uint32_t version;
 
-            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);
+    memset(&key, 0, sizeof(key));
+    memset(&data, 0, sizeof(data));
+    key.data = ROOTINFO_KEY;
+    key.size = ROOTINFO_KEYLEN;
+
+    if ((rc = db->db_cnid->get(db->db_cnid, NULL, &key, &data, 0)) == 0) {
+        /* If not found, ignore it */
+        memcpy(&version, data.data + CNID_DID_OFS, sizeof(version));
+        version = ntohl(version);
+        LOG(log_debug, logtype_default, "CNID db version %u", version);
+        if (version != CNID_VERSION_0) {
+            LOG(log_error, logtype_default, "Unsupported CNID db version %u, use CNID backend \"dbd\"", version);
             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;
index 9231cf5508f72648af2dd114da9143879cb0b978..68136f9f196594325119d762eae8ec1154f06397 100644 (file)
@@ -1,6 +1,4 @@
 /* 
- * $Id: cnid.c,v 1.13 2010-03-31 09:47:32 franklahm Exp $
- *
  * Copyright (c) 2003 the Netatalk Team
  * Copyright (c) 2003 Rafal Lewczuk <rlewczuk@pronet.pl>
  * 
@@ -166,7 +164,7 @@ struct _cnid_db *cnid_open(const char *volpath, mode_t mask, char *type, int fla
 static void block_signal( u_int32_t flags)
 {
     if ((flags & CNID_FLAG_BLOCK)) {
-        sigprocmask(SIG_BLOCK, &sigblockset, NULL);
+        pthread_sigmask(SIG_BLOCK, &sigblockset, NULL);
     }
 }
 
@@ -174,7 +172,7 @@ static void block_signal( u_int32_t flags)
 static void unblock_signal(u_int32_t flags)
 {
     if ((flags & CNID_FLAG_BLOCK)) {
-        sigprocmask(SIG_UNBLOCK, &sigblockset, NULL);
+        pthread_sigmask(SIG_UNBLOCK, &sigblockset, NULL);
     }
 }
 
@@ -216,7 +214,7 @@ u_int32_t flags;
 
 /* --------------- */
 cnid_t cnid_add(struct _cnid_db *cdb, const struct stat *st, const cnid_t did, 
-                       char *name, const size_t len, cnid_t hint)
+                const char *name, const size_t len, cnid_t hint)
 {
 cnid_t ret;
 
@@ -272,9 +270,9 @@ time_t t;
 
 /* --------------- */
 cnid_t cnid_lookup(struct _cnid_db *cdb, const struct stat *st, const cnid_t did,
-                       char *name, const size_t len)
+                   char *name, const size_t len)
 {
-cnid_t ret;
+    cnid_t ret;
 
     block_signal(cdb->flags);
     ret = valide(cdb->cnid_lookup(cdb, st, did, name, len));
@@ -282,6 +280,22 @@ cnid_t ret;
     return ret;
 }
 
+/* --------------- */
+int cnid_find(struct _cnid_db *cdb, const char *name, size_t namelen, void *buffer, size_t buflen)
+{
+    int ret;
+    
+    if (cdb->cnid_find == NULL) {
+        LOG(log_error, logtype_cnid, "cnid_find not supported by CNID backend");        
+        return -1;
+    }
+
+    block_signal(cdb->flags);
+    ret = cdb->cnid_find(cdb, name, namelen, buffer, buflen);
+    unblock_signal(cdb->flags);
+    return ret;
+}
+
 /* --------------- */
 char *cnid_resolve(struct _cnid_db *cdb, cnid_t *id, void *buffer, size_t len)
 {
index dadc4e127a57bf30d5351d28c865135cc7bda21c..990248e45e439a22bc4de87377ae8fbe7e1e95f7 100644 (file)
@@ -156,7 +156,7 @@ static int tsock_getfd(const char *host, const char *port)
                             strerror(errno));
                     }
                     close(sock);
-                    sock=-1;
+                    sock = -1;
                     continue;
                 }
             } else {
@@ -454,6 +454,7 @@ static struct _cnid_db *cnid_dbd_new(const char *volpath)
     cdb->cnid_delete = cnid_dbd_delete;
     cdb->cnid_get = cnid_dbd_get;
     cdb->cnid_lookup = cnid_dbd_lookup;
+    cdb->cnid_find = cnid_dbd_find;
     cdb->cnid_nextid = NULL;
     cdb->cnid_resolve = cnid_dbd_resolve;
     cdb->cnid_getstamp = cnid_dbd_getstamp;
@@ -679,11 +680,9 @@ char *cnid_dbd_resolve(struct _cnid_db *cdb, cnid_t *id, void *buffer, size_t le
     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;
+    /* Pass buffer to transmit so it can stuff the reply data there */
+    rply.name = (char *)buffer;
+    rply.namelen = len;
 
     if (transmit(db, &rqst, &rply) < 0) {
         errno = CNID_ERR_DB;
@@ -694,7 +693,7 @@ char *cnid_dbd_resolve(struct _cnid_db *cdb, cnid_t *id, void *buffer, size_t le
     switch (rply.result) {
     case CNID_DBD_RES_OK:
         *id = rply.did;
-        name = rply.name;
+        name = rply.name + CNID_NAME_OFS;
         LOG(log_debug, logtype_cnid, "cnid_dbd_resolve: resolved did: %u, name: '%s'", ntohl(*id), name);
         break;
     case CNID_DBD_RES_NOTFOUND:
@@ -791,6 +790,61 @@ cnid_t cnid_dbd_lookup(struct _cnid_db *cdb, const struct stat *st, const cnid_t
     return id;
 }
 
+/* ---------------------- */
+int cnid_dbd_find(struct _cnid_db *cdb, char *name, size_t namelen, void *buffer, size_t buflen)
+{
+    CNID_private *db;
+    struct cnid_dbd_rqst rqst;
+    struct cnid_dbd_rply rply;
+    int count;
+
+    if (!cdb || !(db = cdb->_private) || !name) {
+        LOG(log_error, logtype_cnid, "cnid_find: Parameter error");
+        errno = CNID_ERR_PARAM;
+        return CNID_INVALID;
+    }
+
+    if (namelen > MAXPATHLEN) {
+        LOG(log_error, logtype_cnid, "cnid_find: Path name is too long");
+        errno = CNID_ERR_PATH;
+        return CNID_INVALID;
+    }
+
+    LOG(log_debug, logtype_cnid, "cnid_find(\"%s\")", name);
+
+    RQST_RESET(&rqst);
+    rqst.op = CNID_DBD_OP_SEARCH;
+
+    rqst.name = name;
+    rqst.namelen = namelen;
+
+    rply.name = buffer;
+    rply.namelen = buflen;
+
+    if (transmit(db, &rqst, &rply) < 0) {
+        errno = CNID_ERR_DB;
+        return CNID_INVALID;
+    }
+
+    switch (rply.result) {
+    case CNID_DBD_RES_OK:
+        count = rply.namelen / sizeof(cnid_t);
+        LOG(log_debug, logtype_cnid, "cnid_find: got %d matches", count);
+        break;
+    case CNID_DBD_RES_NOTFOUND:
+        count = 0;
+        break;
+    case CNID_DBD_RES_ERR_DB:
+        errno = CNID_ERR_DB;
+        count = -1;
+        break;
+    default:
+        abort();
+    }
+
+    return count;
+}
+
 /* ---------------------- */
 int cnid_dbd_update(struct _cnid_db *cdb, const cnid_t id, const struct stat *st,
                     const cnid_t did, char *name, const size_t len)
index 6d43f9a0a27ccd1bfc5bd7dad71a3572fc72e719..1f645908358b442633beae7e730e9789be690975 100644 (file)
@@ -1,7 +1,6 @@
 /*
- * $Id: cnid_dbd.h,v 1.6 2010-03-31 09:47:32 franklahm Exp $
- *
  * Copyright (C) Joerg Lenneis 2003
+ * Copyright (C) Frank Lahm 2010
  * All Rights Reserved.  See COPYING.
  */
 
 
 extern struct _cnid_module cnid_dbd_module;
 extern struct _cnid_db *cnid_dbd_open (struct cnid_open_args *args);
-extern void cnid_dbd_close (struct _cnid_db *);
-extern cnid_t cnid_dbd_add (struct _cnid_db *, const struct stat *, const cnid_t,
-                           char *, const size_t, cnid_t);
-extern cnid_t cnid_dbd_get (struct _cnid_db *, const cnid_t, char *, const size_t); 
-extern char *cnid_dbd_resolve (struct _cnid_db *, cnid_t *, void *, size_t ); 
-extern int cnid_dbd_getstamp (struct _cnid_db *, void *, const size_t ); 
-extern cnid_t cnid_dbd_lookup (struct _cnid_db *, const struct stat *, const cnid_t,
-                              char *, const size_t);
-extern int cnid_dbd_update (struct _cnid_db *, const cnid_t, const struct stat *,
-                           const cnid_t, char *, size_t);
-extern int cnid_dbd_delete (struct _cnid_db *, const cnid_t);
-extern cnid_t cnid_dbd_rebuild_add (struct _cnid_db *, const struct stat *,
-                const cnid_t, char *, const size_t, cnid_t);
+extern void   cnid_dbd_close      (struct _cnid_db *);
+extern cnid_t cnid_dbd_add        (struct _cnid_db *, const struct stat *, const cnid_t,
+                                   char *, const size_t, cnid_t);
+extern cnid_t cnid_dbd_get        (struct _cnid_db *, const cnid_t, char *, const size_t); 
+extern char  *cnid_dbd_resolve    (struct _cnid_db *, cnid_t *, void *, size_t ); 
+extern int    cnid_dbd_getstamp   (struct _cnid_db *, void *, const size_t ); 
+extern cnid_t cnid_dbd_lookup     (struct _cnid_db *, const struct stat *, const cnid_t,
+                                   char *, const size_t);
+extern int    cnid_dbd_find       (struct _cnid_db *cdb, char *name, size_t namelen,
+                                   void *buffer, size_t buflen);
+extern int    cnid_dbd_update     (struct _cnid_db *, const cnid_t, const struct stat *,
+                                   const cnid_t, char *, size_t);
+extern int    cnid_dbd_delete     (struct _cnid_db *, const cnid_t);
+extern cnid_t cnid_dbd_rebuild_add(struct _cnid_db *, const struct stat *,
+                                   const cnid_t, char *, const size_t, cnid_t);
 
 /* FIXME: These functions could be static in cnid_dbd.c */
 
index 608996b28aa3565a94952f2dc5bba680bf0a29d6..0f887e45ec40b5d3d513f249a02002e219b68a43 100644 (file)
@@ -63,7 +63,7 @@ pselect(int count, fd_set * restrict rfds, fd_set * restrict wfds,
         tvp = 0;
 
     if (mask != 0) {
-        rv = sigprocmask(SIG_SETMASK, mask, &omask);
+        rv = pthread_sigmask(SIG_SETMASK, mask, &omask);
         if (rv != 0)
             return rv;
     }
@@ -71,7 +71,7 @@ pselect(int count, fd_set * restrict rfds, fd_set * restrict wfds,
     rv = select(count, rfds, wfds, efds, tvp);
     if (mask != 0) {
         sverrno = errno;
-        sigprocmask(SIG_SETMASK, &omask, (sigset_t *)0);
+        pthread_sigmask(SIG_SETMASK, &omask, (sigset_t *)0);
         errno = sverrno;
     }
 
index 8a9eaddedaac355cf484fc997ead9973da3311b8..9aef79b53534aeabd9598c622c001b7b8f4904bc 100644 (file)
@@ -34,7 +34,7 @@ int dsi_attention(DSI *dsi, AFPUserBytes flags)
   u_int32_t len, nlen;
   u_int16_t id;
 
-  if (dsi->asleep)
+  if (dsi->flags & DSI_SLEEPING)
       return 1;
 
   if (dsi->in_write) {
index 23c9cf46ce9898faf04b5b0a3dd19fe891d300b3..d409814f5f82c038e736368b8b2bad3ca3138f06 100644 (file)
@@ -17,7 +17,7 @@
 void dsi_close(DSI *dsi)
 {
   /* server generated. need to set all the fields. */
-  if (!dsi->asleep) {
+  if (!(dsi->flags & DSI_SLEEPING)) {
       dsi->header.dsi_flags = DSIFL_REQUEST;
       dsi->header.dsi_command = DSIFUNC_CLOSE;
       dsi->header.dsi_requestID = htons(dsi_serverID(dsi));
index bde7318f28a6e7baa86d5868a3aa5ca03f6c5ffd..747a880a6442c247299a0e7d85643c8106eff448 100644 (file)
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
-#ifdef HAVE_UNISTD_H
 #include <unistd.h>
-#endif /* HAVE_UNISTD_H */
 #include <signal.h>
+#include <sys/types.h>
+#include <sys/socket.h>
 
 /* POSIX.1 sys/wait.h check */
 #include <sys/types.h>
 #include <atalk/dsi.h>
 #include <atalk/server_child.h>
 
-static server_child *children = NULL;
-
-void dsi_kill(int sig)
-{
-  if (children)
-    server_child_kill(children, CHILD_DSIFORK, sig);
-}
-
 /* hand off the command. return child connection to the main program */
-DSI *dsi_getsession(DSI *dsi, server_child *serv_children, 
-                   const int tickleval)
+afp_child_t *dsi_getsession(DSI *dsi, server_child *serv_children, int tickleval)
 {
   pid_t pid;
-  
-  /* do a couple things on first entry */
-  if (!dsi->inited) {
-    if (!(children = serv_children))
-      return NULL;
-    dsi->inited = 1;
+  unsigned int ipc_fds[2];  
+  afp_child_t *child;
+
+  if (socketpair(PF_UNIX, SOCK_STREAM, 0, ipc_fds) < 0) {
+      LOG(log_error, logtype_afpd, "dsi_getsess: %s", strerror(errno));
+      exit( EXITERR_CLNT );
   }
-  
-  switch (pid = dsi->proto_open(dsi)) {
+
+  if (setnonblock(ipc_fds[0], 1) != 0 || setnonblock(ipc_fds[1], 1) != 0) {
+      LOG(log_error, logtype_afpd, "dsi_getsess: setnonblock: %s", strerror(errno));
+      exit(EXITERR_CLNT);
+  }
+
+  switch (pid = dsi->proto_open(dsi)) { /* in libatalk/dsi/dsi_tcp.c */
   case -1:
     /* if we fail, just return. it might work later */
     LOG(log_error, logtype_dsi, "dsi_getsess: %s", strerror(errno));
-    return dsi;
+    return NULL;
 
   case 0: /* child. mostly handled below. */
-    dsi->child = 1;
     break;
 
   default: /* parent */
     /* using SIGQUIT is hokey, but the child might not have
      * re-established its signal handler for SIGTERM yet. */
-    if (server_child_add(children, CHILD_DSIFORK, pid) < 0) {
+    if ((child = server_child_add(serv_children, CHILD_DSIFORK, pid, ipc_fds)) < 0) {
       LOG(log_error, logtype_dsi, "dsi_getsess: %s", strerror(errno));
       dsi->header.dsi_flags = DSIFL_REPLY;
       dsi->header.dsi_code = DSIERR_SERVBUSY;
@@ -79,14 +74,13 @@ DSI *dsi_getsession(DSI *dsi, server_child *serv_children,
       dsi->header.dsi_code = DSIERR_OK;
       kill(pid, SIGQUIT);
     }
-
     dsi->proto_close(dsi);
-    return dsi;
+    return child;
   }
   
   /* child: check number of open connections. this is one off the
    * actual count. */
-  if ((children->count >= children->nsessions) &&
+  if ((serv_children->count >= serv_children->nsessions) &&
       (dsi->header.dsi_command == DSIFUNC_OPEN)) {
     LOG(log_info, logtype_dsi, "dsi_getsess: too many connections");
     dsi->header.dsi_flags = DSIFL_REPLY;
@@ -97,8 +91,7 @@ DSI *dsi_getsession(DSI *dsi, server_child *serv_children,
 
   /* get rid of some stuff */
   close(dsi->serversock);
-  server_child_free(children); 
-  children = NULL;
+  server_child_free(serv_children); 
 
   switch (dsi->header.dsi_command) {
   case DSIFUNC_STAT: /* send off status and return */
@@ -129,7 +122,10 @@ DSI *dsi_getsession(DSI *dsi, server_child *serv_children,
     dsi->timer.it_interval.tv_usec = dsi->timer.it_value.tv_usec = 0;
     signal(SIGPIPE, SIG_IGN); /* we catch these ourselves */
     dsi_opensession(dsi);
-    return dsi;
+    if ((child = calloc(1, sizeof(afp_child_t))) == NULL)
+        exit(EXITERR_SYS);
+    child->ipc_fds[1] = ipc_fds[1];
+    return child;
     break;
 
   default: /* just close */
index 92b5029495066375868e1fe9db6148070ec840ba..e8818e6134bd81f5809a80e2b416284005cbbf72 100644 (file)
@@ -19,6 +19,7 @@
 void dsi_opensession(DSI *dsi)
 {
   u_int32_t i = 0; /* this serves double duty. it must be 4-bytes long */
+  int offs;
 
   /* parse options */
   while (i < dsi->cmdlen) {
@@ -39,7 +40,10 @@ void dsi_opensession(DSI *dsi)
   dsi->header.dsi_flags = DSIFL_REPLY;
   dsi->header.dsi_code = 0;
   /* dsi->header.dsi_command = DSIFUNC_OPEN;*/
-  dsi->cmdlen = 2 + sizeof(i); /* length of data. dsi_send uses it. */
+
+  dsi->cmdlen = 2 * (2 + sizeof(i)); /* length of data. dsi_send uses it. */
+
+  /* DSI Option Server Request Quantum */
   dsi->commands[0] = DSIOPT_SERVQUANT;
   dsi->commands[1] = sizeof(i);
   i = htonl(( dsi->server_quantum < DSI_SERVQUANT_MIN || 
@@ -47,5 +51,11 @@ void dsi_opensession(DSI *dsi)
            DSI_SERVQUANT_DEF : dsi->server_quantum);
   memcpy(dsi->commands + 2, &i, sizeof(i));
 
+  /* AFP replaycache size option */
+  offs = 2 + sizeof(i);
+  dsi->commands[offs] = DSIOPT_REPLCSIZE;
+  dsi->commands[offs+1] = sizeof(i);
+  i = htonl(REPLAYCACHE_SIZE);
+  memcpy(dsi->commands + offs + 2, &i, sizeof(i));
   dsi_send(dsi);
 }
index 55345ba868738d20ee798ab5ce58e33f1bd69934..fc86c0a1339944d011cecc7c10b8fbbbcc88ea44 100644 (file)
@@ -36,7 +36,7 @@ ssize_t dsi_readinit(DSI *dsi, void *buf, const size_t buflen,
                    const size_t size, const int err)
 {
 
-  dsi->noreply = 1; /* we will handle our own replies */
+  dsi->flags |= DSI_NOREPLY; /* we will handle our own replies */
   dsi->header.dsi_flags = DSIFL_REPLY;
   /*dsi->header.dsi_command = DSIFUNC_CMD;*/
   dsi->header.dsi_len = htonl(size);
index ee595bbd3274a80ab02a09c70a7a4d215f80b3c4..75e94237a242b29d5d594f60ecf263f4ae4499a5 100644 (file)
@@ -302,18 +302,20 @@ size_t dsi_stream_read(DSI *dsi, void *data, const size_t length)
 {
   size_t stored;
   ssize_t len;
-  
+
   stored = 0;
   while (stored < length) {
     len = buf_read(dsi, (u_int8_t *) data + stored, length - stored);
-    if (len == -1 && errno == EINTR)
+    if (len == -1 && errno == EINTR) {
       continue;
-    else if (len > 0)
+    } else if (len > 0) {
       stored += len;
-    else { /* eof or error */
+    else { /* eof or error */
       /* 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_dsi, "dsi_stream_read(%d): %s", len, (len < 0)?strerror(errno):"unexpected EOF");
+          if (! (dsi->flags & DSI_DISCONNECTED))
+              LOG(log_error, logtype_dsi, "dsi_stream_read(fd: %i): len:%d, %s",
+                  dsi->socket, len, (len < 0) ? strerror(errno) : "unexpected EOF");
       }
       break;
     }
@@ -353,13 +355,6 @@ static size_t dsi_buffered_stream_read(DSI *dsi, u_int8_t *data, const size_t le
   return len;
 }
 
-/* ---------------------------------------
-*/
-void dsi_sleep(DSI *dsi, const int state)
-{
-    dsi->asleep = state;
-}
-
 /* ---------------------------------------
 */
 static void block_sig(DSI *dsi)
index 1bb81b4cfe2c0372c029033e83085f5bade37a05..0c60303ecb6159c5310d44d28f59242876e69e2d 100644 (file)
@@ -127,6 +127,9 @@ static int dsi_tcp_open(DSI *dsi)
         u_int8_t block[DSI_BLOCKSIZ];
         size_t stored;
 
+        /* Immediateyl mark globally that we're a child now */
+        parent_or_child = 1;
+
         /* reset signals */
         server_reset_signal();
 
@@ -218,7 +221,7 @@ static int dsi_tcp_open(DSI *dsi)
 #define IFF_SLAVE 0
 #endif
 
-static void guess_interface(DSI *dsi, const char *hostname)
+static void guess_interface(DSI *dsi, const char *hostname, const char *port)
 {
     int fd;
     char **start, **list;
@@ -250,11 +253,11 @@ static void guess_interface(DSI *dsi, const char *hostname)
 
         memset(&dsi->server, 0, sizeof(struct sockaddr_storage));
         sa->sin_family = AF_INET;
-        sa->sin_port = htons(548);
+        sa->sin_port = htons(atoi(port));
         sa->sin_addr = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
 
-        LOG(log_info, logtype_dsi, "dsi_tcp: '%s' on interface '%s' will be used instead.",
-                  getip_string((struct sockaddr *)&dsi->server), ifr.ifr_name);
+        LOG(log_info, logtype_dsi, "dsi_tcp: '%s:%s' on interface '%s' will be used instead.",
+            getip_string((struct sockaddr *)&dsi->server), port, ifr.ifr_name);
         goto iflist_done;
     }
     LOG(log_info, logtype_dsi, "dsi_tcp (Chooser will not select afp/tcp) "
@@ -408,7 +411,7 @@ int dsi_tcp_init(DSI *dsi, const char *hostname, const char *address,
     freeaddrinfo(servinfo);
 
 interfaces:
-    guess_interface(dsi, hostname);
+    guess_interface(dsi, hostname, port ? port : "548");
     return 1;
 }
 
index 02aa0536577e2126ad64256b80f0d3e079ceb69b..2a996539a968ba0201c8c19d1f62e9a53a8f7c25 100644 (file)
@@ -23,9 +23,8 @@ int dsi_tickle(DSI *dsi)
 {
   char block[DSI_BLOCKSIZ];
   u_int16_t id;
-  int ret;
   
-  if (dsi->asleep || dsi->in_write)
+  if ((dsi->flags & DSI_SLEEPING) || dsi->in_write)
       return 1;
 
   id = htons(dsi_serverID(dsi));
@@ -36,11 +35,6 @@ int dsi_tickle(DSI *dsi)
   memcpy(block + 2, &id, sizeof(id));
   /* code = len = reserved = 0 */
 
-  ret = dsi_stream_write(dsi, block, DSI_BLOCKSIZ, DSI_NOWAIT);
-  /* we don't really care if we can't send a tickle, it will fail
-   * elsewhere
-  */
-  ret = (ret == -1 || ret == DSI_BLOCKSIZ);
-  return ret;
+  return dsi_stream_write(dsi, block, DSI_BLOCKSIZ, DSI_NOWAIT);
 }
 
index 9eba06920d19e7b651f9e794c19a77049152b70e..c925b00d74204a8792e911a43a30332134f17aca 100644 (file)
@@ -1,9 +1,30 @@
-/* This file is generated by contrib/misc/make-precompose.h.pl UnicodeData.txt */
 /* DO NOT EDIT BY HAND!!!                                           */
+/* This file is generated by                                        */
+/*              contrib/misc/make-precompose.h.pl UnicodeData.txt   */
 
 /* UnicodeData.txt is got from                                      */
 /* http://www.unicode.org/Public/UNIDATA/UnicodeData.txt            */
 
+#define SBASE 0xAC00
+#define LBASE 0x1100
+#define VBASE 0x1161
+#define TBASE 0x11A7
+#define LCOUNT 19
+#define VCOUNT 21
+#define TCOUNT 28
+#define NCOUNT 588     /* (VCOUNT * TCOUNT) */
+#define SCOUNT 11172   /* (LCOUNT * NCOUNT) */
+
+#define PRECOMP_COUNT 955
+#define DECOMP_COUNT 955
+#define MAXCOMBLEN 3
+
+#define PRECOMP_SP_COUNT 16
+#define DECOMP_SP_COUNT 16
+#define MAXCOMBSPLEN 4
+
+#define COMBBUFLEN 4  /* max(MAXCOMBLEN,MAXCOMBSPLEN) */
+
 static const struct {
   unsigned int replacement;
   unsigned int base;
@@ -1009,6 +1030,9 @@ static const struct {
   { 0x000030FE, 0x000030FD, 0x00003099 },     /* KATAKANA VOICED ITERATION MARK */
   { 0x0000FB2C, 0x0000FB49, 0x000005C1 },     /* HEBREW LETTER SHIN WITH DAGESH AND SHIN DOT */
   { 0x0000FB2D, 0x0000FB49, 0x000005C2 },     /* HEBREW LETTER SHIN WITH DAGESH AND SIN DOT */
+/*{ 0x0001109A, 0x00011099, 0x000110BA },*/   /* KAITHI LETTER DDDHA */
+/*{ 0x0001109C, 0x0001109B, 0x000110BA },*/   /* KAITHI LETTER RHA */
+/*{ 0x000110AB, 0x000110A5, 0x000110BA },*/   /* KAITHI LETTER VA */
 /*{ 0x0001D15E, 0x0001D157, 0x0001D165 },*/   /* MUSICAL SYMBOL HALF NOTE */
 /*{ 0x0001D15F, 0x0001D158, 0x0001D165 },*/   /* MUSICAL SYMBOL QUARTER NOTE */
 /*{ 0x0001D160, 0x0001D15F, 0x0001D16E },*/   /* MUSICAL SYMBOL EIGHTH NOTE */
@@ -2029,6 +2053,9 @@ static const struct {
   { 0x0000FB4C, 0x000005D1, 0x000005BF },     /* HEBREW LETTER BET WITH RAFE */
   { 0x0000FB4D, 0x000005DB, 0x000005BF },     /* HEBREW LETTER KAF WITH RAFE */
   { 0x0000FB4E, 0x000005E4, 0x000005BF },     /* HEBREW LETTER PE WITH RAFE */
+/*{ 0x0001109A, 0x00011099, 0x000110BA },*/   /* KAITHI LETTER DDDHA */
+/*{ 0x0001109C, 0x0001109B, 0x000110BA },*/   /* KAITHI LETTER RHA */
+/*{ 0x000110AB, 0x000110A5, 0x000110BA },*/   /* KAITHI LETTER VA */
 /*{ 0x0001D15E, 0x0001D157, 0x0001D165 },*/   /* MUSICAL SYMBOL HALF NOTE */
 /*{ 0x0001D15F, 0x0001D158, 0x0001D165 },*/   /* MUSICAL SYMBOL QUARTER NOTE */
 /*{ 0x0001D160, 0x0001D15F, 0x0001D16E },*/   /* MUSICAL SYMBOL EIGHTH NOTE */
@@ -2044,4 +2071,50 @@ static const struct {
 /*{ 0x0001D1C0, 0x0001D1BC, 0x0001D16F },*/   /* MUSICAL SYMBOL FUSA BLACK */
 };
 
+static const struct {
+  unsigned int replacement_sp;
+  unsigned int base_sp;
+  unsigned int comb_sp;
+} precompositions_sp[] = {
+  { 0xD804DC9A, 0xD804DC99, 0xD804DCBA },     /* KAITHI LETTER DDDHA */
+  { 0xD804DC9C, 0xD804DC9B, 0xD804DCBA },     /* KAITHI LETTER RHA */
+  { 0xD804DCAB, 0xD804DCA5, 0xD804DCBA },     /* KAITHI LETTER VA */
+  { 0xD834DD5E, 0xD834DD57, 0xD834DD65 },     /* MUSICAL SYMBOL HALF NOTE */
+  { 0xD834DD5F, 0xD834DD58, 0xD834DD65 },     /* MUSICAL SYMBOL QUARTER NOTE */
+  { 0xD834DD60, 0xD834DD5F, 0xD834DD6E },     /* MUSICAL SYMBOL EIGHTH NOTE */
+  { 0xD834DD61, 0xD834DD5F, 0xD834DD6F },     /* MUSICAL SYMBOL SIXTEENTH NOTE */
+  { 0xD834DD62, 0xD834DD5F, 0xD834DD70 },     /* MUSICAL SYMBOL THIRTY-SECOND NOTE */
+  { 0xD834DD63, 0xD834DD5F, 0xD834DD71 },     /* MUSICAL SYMBOL SIXTY-FOURTH NOTE */
+  { 0xD834DD64, 0xD834DD5F, 0xD834DD72 },     /* MUSICAL SYMBOL ONE HUNDRED TWENTY-EIGHTH NOTE */
+  { 0xD834DDBB, 0xD834DDB9, 0xD834DD65 },     /* MUSICAL SYMBOL MINIMA */
+  { 0xD834DDBC, 0xD834DDBA, 0xD834DD65 },     /* MUSICAL SYMBOL MINIMA BLACK */
+  { 0xD834DDBD, 0xD834DDBB, 0xD834DD6E },     /* MUSICAL SYMBOL SEMIMINIMA WHITE */
+  { 0xD834DDBF, 0xD834DDBB, 0xD834DD6F },     /* MUSICAL SYMBOL FUSA WHITE */
+  { 0xD834DDBE, 0xD834DDBC, 0xD834DD6E },     /* MUSICAL SYMBOL SEMIMINIMA BLACK */
+  { 0xD834DDC0, 0xD834DDBC, 0xD834DD6F },     /* MUSICAL SYMBOL FUSA BLACK */
+};
+
+static const struct {
+  unsigned int replacement_sp;
+  unsigned int base_sp;
+  unsigned int comb_sp;
+} decompositions_sp[] = {
+  { 0xD804DC9A, 0xD804DC99, 0xD804DCBA },     /* KAITHI LETTER DDDHA */
+  { 0xD804DC9C, 0xD804DC9B, 0xD804DCBA },     /* KAITHI LETTER RHA */
+  { 0xD804DCAB, 0xD804DCA5, 0xD804DCBA },     /* KAITHI LETTER VA */
+  { 0xD834DD5E, 0xD834DD57, 0xD834DD65 },     /* MUSICAL SYMBOL HALF NOTE */
+  { 0xD834DD5F, 0xD834DD58, 0xD834DD65 },     /* MUSICAL SYMBOL QUARTER NOTE */
+  { 0xD834DD60, 0xD834DD5F, 0xD834DD6E },     /* MUSICAL SYMBOL EIGHTH NOTE */
+  { 0xD834DD61, 0xD834DD5F, 0xD834DD6F },     /* MUSICAL SYMBOL SIXTEENTH NOTE */
+  { 0xD834DD62, 0xD834DD5F, 0xD834DD70 },     /* MUSICAL SYMBOL THIRTY-SECOND NOTE */
+  { 0xD834DD63, 0xD834DD5F, 0xD834DD71 },     /* MUSICAL SYMBOL SIXTY-FOURTH NOTE */
+  { 0xD834DD64, 0xD834DD5F, 0xD834DD72 },     /* MUSICAL SYMBOL ONE HUNDRED TWENTY-EIGHTH NOTE */
+  { 0xD834DDBB, 0xD834DDB9, 0xD834DD65 },     /* MUSICAL SYMBOL MINIMA */
+  { 0xD834DDBC, 0xD834DDBA, 0xD834DD65 },     /* MUSICAL SYMBOL MINIMA BLACK */
+  { 0xD834DDBD, 0xD834DDBB, 0xD834DD6E },     /* MUSICAL SYMBOL SEMIMINIMA WHITE */
+  { 0xD834DDBE, 0xD834DDBC, 0xD834DD6E },     /* MUSICAL SYMBOL SEMIMINIMA BLACK */
+  { 0xD834DDBF, 0xD834DDBB, 0xD834DD6F },     /* MUSICAL SYMBOL FUSA WHITE */
+  { 0xD834DDC0, 0xD834DDBC, 0xD834DD6F },     /* MUSICAL SYMBOL FUSA BLACK */
+};
+
 /* EOF */
index 26342cb74df39056cdf26f958832d8eabc72ea0d..c3146d0c65caed582f04cea18babfe9fc5fcaf22 100644 (file)
@@ -71,13 +71,12 @@ struct charset_functions charset_utf8_mac =
        NULL, NULL
 };
 
-/* ------------------- Convert from UTF-8 to UCS-2 -------------------*/
+/* ------------------- Convert from UTF-8 to UTF-16 -------------------*/
 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;
+       unsigned int codepoint;
        int len;
 
        while (*inbytesleft >= 1 && *outbytesleft >= 2) {
@@ -115,10 +114,8 @@ static size_t utf8_pull(void *cd _U_, char **inbuf, size_t *inbytesleft,
                        }
                        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);
+                       SSVAL(*outbuf,0,(((codepoint - 0x10000) >> 10) + 0xD800)); /* hi  */
+                       SSVAL(*outbuf,2,(0xDC00 + (codepoint & 0x03FF)));          /* low */
                        len = 4;
                        (*inbuf)  += 4;
                        (*inbytesleft)  -= 4;
@@ -150,13 +147,13 @@ badseq:
        return -1;
 }
 
-/* --------------------- Convert from UCS-2 to UTF-8 -----------*/
+/* --------------------- Convert from UTF-16 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;
+       unsigned int codepoint;
        int olen, ilen;
 
        while (*inbytesleft >= 2 && *outbytesleft >= 1) {
@@ -205,9 +202,8 @@ static size_t utf8_push(void *cd _U_, char **inbuf, size_t *inbytesleft,
                                errno = EINVAL;
                                return -1;
                        }
-                       surrogatepair = IVAL((*inbuf),0);
-                       low = (ucs2_t)surrogatepair;
-                       hi = (ucs2_t)(surrogatepair >> 16);
+                       hi =  SVAL((*inbuf),0);
+                       low = SVAL((*inbuf),2);
                        if ( 0xd800 <= hi && hi <= 0xdbff && 0xdc00 <= low && low <= 0xdfff) {
                                codepoint = ((hi - 0xd800) << 10) + (low - 0xdc00) + 0x10000;
                                c[3] = GETUTF8TRAILBYTE(codepoint, 0);
index 45ffcd93f19db8a9ccb0e6ee9ec942c83eac16c8..ef48f21b27841b3d2920cf19972e7c5b2e95ad18 100644 (file)
 #include "precompose.h"
 #include "byteorder.h"
 
-#define HANGUL_SBASE 0xAC00
-#define HANGUL_LBASE 0x1100
-#define HANGUL_VBASE 0x1161
-#define HANGUL_TBASE 0x11A7
-#define HANGUL_LCOUNT 19
-#define HANGUL_VCOUNT 21
-#define HANGUL_TCOUNT 28
-#define HANGUL_NCOUNT (HANGUL_VCOUNT * HANGUL_TCOUNT)   /* 588 */
-#define HANGUL_SCOUNT (HANGUL_LCOUNT * HANGUL_NCOUNT)   /* 11172 */
-
-#define MAXCOMBLEN 3
-
+/*******************************************************************
+ Convert a wide character to upper/lower case.
+********************************************************************/
 ucs2_t toupper_w(ucs2_t val)
 {
        if ( val >= 0x0040 && val <= 0x007F)
@@ -78,16 +69,16 @@ ucs2_t tolower_w(ucs2_t val)
 ********************************************************************/
 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;
+       int ret = 0;
+       while (*s) {
+               ucs2_t v = tolower_w(*s);
+               if (v != *s) {
+                       *s = v;
+                       ret = 1;
+               }
+               s++;
+       }
+       return ret;
 }
 
 /*******************************************************************
@@ -96,16 +87,16 @@ int strlower_w(ucs2_t *s)
 ********************************************************************/
 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;
+       int ret = 0;
+       while (*s) {
+               ucs2_t v = toupper_w(*s);
+               if (v != *s) {
+                       *s = v;
+                       ret = 1;
+               }
+               s++;
+       }
+       return ret;
 }
 
 
@@ -179,18 +170,18 @@ ucs2_t *strcasechr_w(const ucs2_t *s, ucs2_t c)
 
 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 */
+       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;
+       size_t n = 0;
+       while ((n < len) && *b && *a == *b) { a++; b++; n++;}
+       return (len - n)?(*a - *b):0;
 }
 
 /*******************************************************************
@@ -236,8 +227,8 @@ 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));
+       while (*b && toupper_w(*a) == toupper_w(*b)) { a++; b++; }
+       return (tolower_w(*a) - tolower_w(*b));
 }
 
 /*******************************************************************
@@ -245,9 +236,9 @@ 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;
+       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;
 }
 
 /*******************************************************************
@@ -256,24 +247,24 @@ duplicate string
 /* if len == 0 then duplicate the whole string */
 ucs2_t *strndup_w(const ucs2_t *src, size_t len)
 {
-        ucs2_t *dest;
+       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;
-        }
+       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;
+       memcpy(dest, src, len * sizeof(ucs2_t));
+       dest[len] = 0;
 
-        return dest;
+       return dest;
 }
 
 ucs2_t *strdup_w(const ucs2_t *src)
 {
-        return strndup_w(src, 0);
+       return strndup_w(src, 0);
 }
 
 /*******************************************************************
@@ -282,16 +273,16 @@ copy a string with max len
 
 ucs2_t *strncpy_w(ucs2_t *dest, const ucs2_t *src, const size_t max)
 {
-        size_t len;
+       size_t len;
 
-        if (!dest || !src) return NULL;
+       if (!dest || !src) return NULL;
 
-        for (len = 0; (src[len] != 0) && (len < max); len++)
-                dest[len] = src[len];
-        while (len < max)
-                dest[len++] = 0;
+       for (len = 0; (src[len] != 0) && (len < max); len++)
+               dest[len] = src[len];
+       while (len < max)
+               dest[len++] = 0;
 
-        return dest;
+       return dest;
 }
 
 
@@ -301,261 +292,383 @@ 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;
+       size_t start;
+       size_t len;
 
-        if (!dest || !src) return NULL;
+       if (!dest || !src) return NULL;
 
-        start = strlen_w(dest);
-        len = strnlen_w(src, max);
+       start = strlen_w(dest);
+       len = strnlen_w(src, max);
 
-        memcpy(&dest[start], src, len*sizeof(ucs2_t));
-        dest[start+len] = 0;
+       memcpy(&dest[start], src, len*sizeof(ucs2_t));
+       dest[start+len] = 0;
 
-        return dest;
+       return dest;
 }
 
 
 ucs2_t *strcat_w(ucs2_t *dest, const ucs2_t *src)
 {
-        size_t start;
-        size_t len;
+       size_t start;
+       size_t len;
 
-        if (!dest || !src) return NULL;
+       if (!dest || !src) return NULL;
 
-        start = strlen_w(dest);
-        len = strlen_w(src);
+       start = strlen_w(dest);
+       len = strlen_w(src);
 
-        memcpy(&dest[start], src, len*sizeof(ucs2_t));
-        dest[start+len] = 0;
+       memcpy(&dest[start], src, len*sizeof(ucs2_t));
+       dest[start+len] = 0;
 
-        return dest;
+       return dest;
 }
 
 
-/* ------------------------ */
+/*******************************************************************
+binary search for pre|decomposition
+********************************************************************/
+
 static 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;
+       int min = 0;
+       int max = PRECOMP_COUNT - 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;
+}
+
+/* ------------------------ */
+static u_int32_t do_precomposition_sp(unsigned int base_sp, unsigned int comb_sp) 
+{
+       int min = 0;
+       int max = PRECOMP_SP_COUNT - 1;
+       int mid;
+       u_int64_t sought_sp = ((u_int64_t)base_sp << 32) | (u_int64_t)comb_sp, that_sp;
+
+       /* binary search */
+       while (max >= min) {
+               mid = (min + max) / 2;
+               that_sp = ((u_int64_t)precompositions_sp[mid].base_sp << 32) | ((u_int64_t)precompositions_sp[mid].comb_sp);
+               if (that_sp < sought_sp) {
+                       min = mid + 1;
+               } else if (that_sp > sought_sp) {
+                       max = mid - 1;
+               } else {
+                       return precompositions_sp[mid].replacement_sp;
+               }
+       }
+       /* no match */
+       return 0;
 }
 
 /* -------------------------- */
 static 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;
+       int min = 0;
+       int max = DECOMP_COUNT - 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]; */
+/* -------------------------- */
+static u_int64_t do_decomposition_sp(unsigned int base_sp) 
+{
+       int min = 0;
+       int max = DECOMP_SP_COUNT - 1;
+       int mid;
+       u_int32_t sought_sp = base_sp;
+       u_int32_t that_sp;
+       u_int64_t result_sp;
+
+       /* binary search */
+       while (max >= min) {
+               mid = (min + max) / 2;
+               that_sp = decompositions_sp[mid].replacement_sp;
+               if (that_sp < sought_sp) {
+                       min = mid + 1;
+               } else if (that_sp > sought_sp) {
+                       max = mid - 1;
+               } else {
+                       result_sp = ((u_int64_t)decompositions_sp[mid].base_sp << 32) | ((u_int64_t)decompositions_sp[mid].comb_sp);
+                       return result_sp;
+               }
+       }
+       /* no match */
+       return 0;
+}
+
+/*******************************************************************
+pre|decomposition
+
+   we can't use static, this stuff needs to be reentrant
+   static char comp[MAXPATHLEN +1];
+
+   We don't implement Singleton and Canonical Ordering.
+   We ignore CompositionExclusions.txt.
+   because they cause the problem of the roundtrip
+   such as Dancing Icon.
+
+   exclude U2000-U2FFF, UFE30-UFE4F and U2F800-U2FA1F ranges
+   in precompose.h from composition according to AFP 3.x spec
+********************************************************************/
 
 size_t precompose_w (ucs2_t *name, size_t inplen, ucs2_t *comp, size_t *outlen)
 {
        size_t i;
        ucs2_t base, comb;
+       u_int32_t base_sp, comb_sp;
        ucs2_t *in, *out;
-       ucs2_t hangul_lindex, hangul_vindex;
+       ucs2_t lindex, vindex;
        ucs2_t result;
+       u_int32_t result_sp;
        size_t o_len = *outlen;
-
-       if (!inplen || (inplen & 1) || inplen > o_len)
-               return (size_t)-1;
        
-       /*   Actually,                                                 */
-       /*   Decomposition and Canonical Ordering are necessary here.  */
-       /*                                                             */
-       /*         Ex. in = CanonicalOrdering(decompose_w(name))       */
-       /*                                                             */
-       /*   A new mapping table is needed for CanonicalOrdering.      */
+       if (!inplen || (inplen & 1) || inplen > o_len)
+               return (size_t)-1;
        
-       i = 0;
-       in  = name;
+       i = 0;
+       in  = name;
        out = comp;
-    
-       base = *in;
-       while (*outlen > 2) {
-               i += 2;
-               in++;
-               if (i == inplen) {
-                       *out = base;
+       
+       base = *in;
+       while (*outlen > 2) {
+               i += 2;
+               in++;
+
+               if (i == inplen) {
+                       *out = base;
                        out++;
                        *out = 0;
-                       *outlen -= 2;
-                       return o_len - *outlen;
-               }
-               comb = *in;
+                       *outlen -= 2;
+                       return o_len - *outlen;
+               }
+
+               comb = *in;
                result = 0;
-               
+
                /* Non-Combination Character */
                if (comb < 0x300) ;
                
                /* Unicode Standard Annex #15 A10.3 Hangul Composition */
                /* Step 1 <L,V> */
-               else if ((HANGUL_VBASE <= comb) && (comb <= HANGUL_VBASE + HANGUL_VCOUNT)) {
-                       if ((HANGUL_LBASE <= base) && (base < HANGUL_LBASE + HANGUL_LCOUNT)) {
+               else if ((VBASE <= comb) && (comb <= VBASE + VCOUNT)) {
+                       if ((LBASE <= base) && (base < LBASE + LCOUNT)) {
                                result = 1;
-                               hangul_lindex = base - HANGUL_LBASE;
-                               hangul_vindex = comb - HANGUL_VBASE;
-                               base = HANGUL_SBASE + (hangul_lindex * HANGUL_VCOUNT + hangul_vindex) * HANGUL_TCOUNT;
+                               lindex = base - LBASE;
+                               vindex = comb - VBASE;
+                               base = SBASE + (lindex * VCOUNT + vindex) * TCOUNT;
                        }
-               }
+               }
                
                /* Step 2 <LV,T> */
-               else if ((HANGUL_TBASE < comb) && (comb < HANGUL_TBASE + HANGUL_TCOUNT)) {
-                       if ((HANGUL_SBASE <= base) && (base < HANGUL_SBASE +HANGUL_SCOUNT) && (((base - HANGUL_SBASE) % HANGUL_TCOUNT) == 0)) {
+               else if ((TBASE < comb) && (comb < TBASE + TCOUNT)) {
+                       if ((SBASE <= base) && (base < SBASE + SCOUNT) && (((base - SBASE) % TCOUNT) == 0)) {
                                result = 1;
-                               base += comb - HANGUL_TBASE;
+                               base += comb - TBASE;
                        }
                }
                
-               /* Combining Sequence */
-               else if ((result = do_precomposition(base, comb))) {
+               /* Binary Search for Surrogate Pair */
+               else if ((0xD800 <= base) && (base < 0xDC00)) {
+                       if ((0xDC00 <= comb) && (comb < 0xE000) && (i + 4 <= inplen)) {
+                               base_sp = ((u_int32_t)base << 16) | (u_int32_t)comb;
+                               do {
+                                       comb_sp = ((u_int32_t)in[1] << 16) | (u_int32_t)in[2];
+                                       if (result_sp = do_precomposition_sp(base_sp, comb_sp)) {
+                                               base_sp = result_sp;
+                                               i += 4;
+                                               in +=2;
+                                       }
+                               } while ((i + 4 <= inplen) && result_sp) ;
+
+                               *out = base_sp >> 16;
+                               out++;
+                               *outlen -= 2;
+
+                               if (*outlen <= 2) {
+                                       errno = E2BIG;
+                                       return (size_t)-1;
+                               }
+
+                               *out = base_sp & 0xFFFF;
+                               out++;
+                               *outlen -= 2;
+
+                               i += 2;
+                               in++;
+                               base = *in;
+
+                               result = 1;
+                       }
+               }
+
+               /* Binary Search for BMP */
+               else if (result = do_precomposition(base, comb)) {
                        base = result;
                }
                
                if (!result) {
-                       *out = base;
-                       out++;
-                       *outlen -= 2;
-                       base = comb;
-               }
-       }
-       
+                       *out = base;
+                       out++;
+                       *outlen -= 2;
+                       base = comb;
+               }
+       }
+
        errno = E2BIG;
        return (size_t)-1;
 }
 
 /* --------------- */
-
-/* Singleton Decomposition is unsupported.               */
-/* A new mapping table is needed for implementation.     */
-
 size_t decompose_w (ucs2_t *name, size_t inplen, ucs2_t *comp, size_t *outlen)
 {
        size_t i;
        size_t comblen;
-       ucs2_t base;
-       ucs2_t comb[MAXCOMBLEN];
-       ucs2_t hangul_sindex, tjamo;
+       ucs2_t base, comb[COMBBUFLEN];
+       u_int32_t base_sp;
+       ucs2_t sindex, tjamo;
        ucs2_t *in, *out;
        unsigned int result;
+       u_int64_t result_sp;
        size_t o_len = *outlen;
 
-       if (!inplen || (inplen & 1))
-               return (size_t)-1;
+       if (!inplen || (inplen & 1))
+               return (size_t)-1;
        i = 0;
        in  = name;
        out = comp;
-    
-       while (i < inplen) {
-               base = *in;
+
+       while (i < inplen) {
+               base = *in;
                comblen = 0;
                
                /* check ASCII first. this is frequent. */
                if (base <= 0x007f) ;
                
                /* Unicode Standard Annex #15 A10.2 Hangul Decomposition */
-               else if ((HANGUL_SBASE <= base) && (base < HANGUL_SBASE + HANGUL_SCOUNT)) {
-                       hangul_sindex = base - HANGUL_SBASE;
-                       base = HANGUL_LBASE + hangul_sindex / HANGUL_NCOUNT;
-                       comb[MAXCOMBLEN-2] = HANGUL_VBASE + (hangul_sindex % HANGUL_NCOUNT) / HANGUL_TCOUNT;
+               else if ((SBASE <= base) && (base < SBASE + SCOUNT)) {
+                       sindex = base - SBASE;
+                       base = LBASE + sindex / NCOUNT;
+                       comb[COMBBUFLEN-2] = VBASE + (sindex % NCOUNT) / TCOUNT;
                        
                        /* <L,V> */
-                       if ((tjamo = HANGUL_TBASE + hangul_sindex % HANGUL_TCOUNT) == HANGUL_TBASE) {
-                               comb[MAXCOMBLEN-1] = comb[MAXCOMBLEN-2];
+                       if ((tjamo = TBASE + sindex % TCOUNT) == TBASE) {
+                               comb[COMBBUFLEN-1] = comb[COMBBUFLEN-2];
                                comblen = 1;
                        }
                        
                        /* <L,V,T> */
                        else {
-                               comb[MAXCOMBLEN-1] = tjamo;
+                               comb[COMBBUFLEN-1] = tjamo;
                                comblen = 2;
                        }
                }
                
-               /* Combining Sequence */
-               /* exclude U2000-U2FFF and UFE30-UFE4F ranges in decompositions[]     */
-               /* from decomposition according to AFP 3.1 spec    */
+               /* Binary Search for Surrogate Pair */
+               else if ((0xD800 <= base) && (base < 0xDC00)) {
+                       if (i + 2 < inplen) {
+                               base_sp =  ((u_int32_t)base << 16) | (u_int32_t)in[1];
+                               do {
+                                       if ( !(result_sp = do_decomposition_sp(base_sp))) break;
+                                       comblen += 2;
+                                       base_sp = result_sp >> 32;
+                                       comb[COMBBUFLEN-comblen] = (result_sp >> 16) & 0xFFFF;  /* hi */
+                                       comb[COMBBUFLEN-comblen+1] = result_sp & 0xFFFF;        /* lo */
+                               } while (comblen < MAXCOMBSPLEN);
+
+                               if (*outlen < (comblen + 1) << 1) {
+                                       errno = E2BIG;
+                                       return (size_t)-1;
+                               }
+
+                               *out = base_sp >> 16;   /* hi */
+                               out++;
+                               *outlen -= 2;
+                               
+                               base = base_sp & 0xFFFF; /* lo */
+                               
+                               i += 2;
+                               in++;
+                       }
+               }
+                       
+               /* Binary Search for BMP */
                else {
                        do {
-                               if ((comblen >= MAXCOMBLEN) || !(result = do_decomposition(base))) break;
+                               if ( !(result = do_decomposition(base))) break;
                                comblen++;
                                base = result  >> 16;
-                               comb[MAXCOMBLEN-comblen] = result & 0xffff;
-                       } while (0x007f < base) ;
+                               comb[COMBBUFLEN-comblen] = result & 0xFFFF;
+                       } while ((0x007f < base) && (comblen < MAXCOMBLEN));
                }
                
                if (*outlen < (comblen + 1) << 1) {
-                               errno = E2BIG;
-                               return (size_t)-1;
-                       }
+                       errno = E2BIG;
+                       return (size_t)-1;
+               }
                
                *out = base;
-                       out++;
-                       *outlen -= 2;
+               out++;
+               *outlen -= 2;
                
                while ( comblen > 0 ) {
-                       *out = comb[MAXCOMBLEN-comblen];
-                       out++;
-                       *outlen -= 2;
+                       *out = comb[COMBBUFLEN-comblen];
+                       out++;
+                       *outlen -= 2;
                        comblen--;
-               }
+               }
                
-               i += 2;
-               in++;
-       }
-
-       /* Is Canonical Ordering necessary here? */
+               i += 2;
+               in++;
+       }
        
        *out = 0;
        return o_len-*outlen;
 }
 
+/*******************************************************************
+length of UTF-8 character and string
+********************************************************************/
+
 size_t utf8_charlen ( char* utf8 )
 {
-        unsigned char *p;
+       unsigned char *p;
 
-        p = (unsigned char*) utf8;
+       p = (unsigned char*) utf8;
        
        if ( *p < 0x80 )
-               return (1);
+               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)
@@ -575,43 +688,42 @@ size_t utf8_charlen ( char* utf8 )
 
 size_t utf8_strlen_validate ( char * utf8 )
 {
-        size_t len;
-        unsigned char *p;
+       size_t len;
+       unsigned char *p;
 
-        p = (unsigned char*) utf8;
-        len = 0;
+       p = (unsigned char*) utf8;
+       len = 0;
 
-        /* see http://www.unicode.org/unicode/reports/tr27/ for an explanation */
+       /* see http://www.unicode.org/unicode/reports/tr27/ for an explanation */
 
-        while ( *p != '\0')
-        {
-                if ( *p < 0x80 )
-                        p++;
+       while ( *p != '\0')
+       {
+               if ( *p < 0x80 )
+                       p++;
 
-                else if ( *p > 0xC1 && *p < 0xe0 && *(p+1) > 0x7f && *(p+1) < 0xC0)
-                        p += 2;
+               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+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 > 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+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 > 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 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);
+               else
+                       return ((size_t) -1);
 
-                len++;
-        }
+               len++;
+       }
 
-        return (len);
+       return (len);
 }
-
index f8eeb6b42c9c6e8506d8f6fcd95e713887c96368..b844dc5abbd3b87d1d153a99babeb2438e7cf756 100644 (file)
@@ -1,7 +1,5 @@
 # Makefile.am for libatalk/util/
 
-SUBDIRS = . test
-
 noinst_LTLIBRARIES = libutil.la
 
 AM_CFLAGS = -I$(top_srcdir)/sys
@@ -10,10 +8,12 @@ libutil_la_SOURCES = \
        atalk_addr.c    \
        bprint.c        \
        fault.c         \
+       ftw.c           \
        getiface.c      \
        locking.c   \
        logger.c        \
        module.c        \
+       queue.c     \
        server_child.c  \
        server_ipc.c    \
        server_lock.c   \
index 7ef4fb8a5143cac21ddc8c6bc604d60ca82822a2..2b9ef64455f403d34201c7936cc43ef6806e63cd 100644 (file)
@@ -22,8 +22,6 @@
 #include "config.h"
 #endif
 
-#ifdef DEBUG1
-
 #include <sys/types.h>
 #ifdef HAVE_UNISTD_H
 #include <unistd.h>
@@ -84,65 +82,28 @@ static void (*CatchSignal(int signum,void (*handler)(int )))(int)
  Something really nasty happened - panic !
 ********************************************************************/
 
-static void smb_panic(const char *why)
+void netatalk_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);
+       LOG(log_severe, logtype_default, "BACKTRACE: %d stack frames:", 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]);
+                       LOG(log_severe, logtype_default, " #%u %s", i, backtrace_strings[i]);
 
                SAFE_FREE(backtrace_strings);
        }
-
 #endif
-
 }
 
 
@@ -153,15 +114,16 @@ static void fault_report(int sig)
 {
        static int counter;
 
-       if (counter) _exit(1);
+       if (counter)
+        abort();
 
        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, "===============================================================");
+       LOG(log_severe, logtype_default, "===============================================================");
+       LOG(log_severe, logtype_default, "INTERNAL ERROR: Signal %d in pid %d (%s)",sig,(int)getpid(),VERSION);
+       LOG(log_severe, logtype_default, "===============================================================");
   
-       smb_panic("internal error");
+       netatalk_panic("internal error");
 
        if (cont_fn) {
                cont_fn(NULL);
@@ -173,7 +135,7 @@ static void fault_report(int sig)
 #endif
                return; /* this should cause a core dump */
        }
-       exit(1);
+    abort();
 }
 
 /****************************************************************************
@@ -199,4 +161,3 @@ void fault_setup(void (*fn)(void *))
 #endif
 }
 
-#endif
diff --git a/libatalk/util/ftw.c b/libatalk/util/ftw.c
new file mode 100644 (file)
index 0000000..3a32c12
--- /dev/null
@@ -0,0 +1,826 @@
+/* File tree walker functions.
+   Copyright (C) 1996-2004, 2006-2008, 2010 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#if __GNUC__
+# define alloca __builtin_alloca
+#else
+#  include <alloca.h>
+#endif
+
+#include <dirent.h>
+#define NAMLEN(dirent) strlen ((dirent)->d_name)
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <search.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+#if HAVE_SYS_PARAM_H
+# include <sys/param.h>
+#endif
+
+#include <atalk/ftw.h>
+
+#define mempcpy(D, S, N) ((void *) ((char *) memcpy (D, S, N) + (N)))
+
+#define NDEBUG 1
+#include <assert.h>
+
+#ifndef _LIBC
+# undef __chdir
+# define __chdir chdir
+# undef __closedir
+# define __closedir closedir
+# undef __fchdir
+# define __fchdir fchdir
+# undef __getcwd
+# define __getcwd(P, N) xgetcwd ()
+# undef __mempcpy
+# define __mempcpy mempcpy
+# undef __opendir
+# define __opendir opendir
+# undef __readdir64
+# define __readdir64 readdir
+# undef __tdestroy
+# define __tdestroy tdestroy
+# undef __tfind
+# define __tfind tfind
+# undef __tsearch
+# define __tsearch tsearch
+# undef internal_function
+# define internal_function /* empty */
+# undef dirent64
+# define dirent64 dirent
+# undef MAX
+# define MAX(a, b) ((a) > (b) ? (a) : (b))
+#endif
+
+#ifndef __set_errno
+# define __set_errno(Val) errno = (Val)
+#endif
+
+/* Support for the LFS API version.  */
+#ifndef FTW_NAME
+# define FTW_NAME ftw
+# define NFTW_NAME nftw
+# define NFTW_OLD_NAME __old_nftw
+# define NFTW_NEW_NAME __new_nftw
+# define INO_T ino_t
+# define STAT stat
+# define LXSTAT(V,f,sb) lstat (f,sb)
+# define XSTAT(V,f,sb) stat (f,sb)
+# define FXSTATAT(V,d,f,sb,m) fstatat (d, f, sb, m)
+
+#endif
+
+/* We define PATH_MAX if the system does not provide a definition.
+   This does not artificially limit any operation.  PATH_MAX is simply
+   used as a guesstimate for the expected maximal path length.
+   Buffers will be enlarged if necessary.  */
+#ifndef PATH_MAX
+# define PATH_MAX 1024
+#endif
+
+struct dir_data
+{
+    DIR *stream;
+    int streamfd;
+    char *content;
+};
+
+struct known_object
+{
+    dev_t dev;
+    INO_T ino;
+};
+
+struct ftw_data
+{
+    /* Array with pointers to open directory streams.  */
+    struct dir_data **dirstreams;
+    size_t actdir;
+    size_t maxdir;
+
+    /* Buffer containing name of currently processed object.  */
+    char *dirbuf;
+    size_t dirbufsize;
+
+    /* Passed as fourth argument to `nftw' callback.  The `base' member
+       tracks the content of the `dirbuf'.  */
+    struct FTW ftw;
+
+    /* Flags passed to `nftw' function.  0 for `ftw'.  */
+    int flags;
+
+    /* Conversion array for flag values.  It is the identity mapping for
+       `nftw' calls, otherwise it maps the values to those known by
+       `ftw'.  */
+    const int *cvt_arr;
+
+    /* Callback function.  We always use the `nftw' form.  */
+    NFTW_FUNC_T func;
+
+    /* Device of starting point.  Needed for FTW_MOUNT.  */
+    dev_t dev;
+
+    /* Data structure for keeping fingerprints of already processed
+       object.  This is needed when not using FTW_PHYS.  */
+    void *known_objects;
+};
+
+
+/* Internally we use the FTW_* constants used for `nftw'.  When invoked
+   as `ftw', map each flag to the subset of values used by `ftw'.  */
+static const int nftw_arr[] =
+{
+    FTW_F, FTW_D, FTW_DNR, FTW_NS, FTW_SL, FTW_DP, FTW_SLN
+};
+
+static const int ftw_arr[] =
+{
+    FTW_F, FTW_D, FTW_DNR, FTW_NS, FTW_F, FTW_D, FTW_NS
+};
+
+
+static dir_notification_func_t upfunc;
+
+/* Forward declarations of local functions.  */
+static int ftw_dir (struct ftw_data *data, struct STAT *st,
+                    struct dir_data *old_dir) internal_function;
+
+typedef void (*__free_fn_t) (void *__nodep);
+typedef struct node_t {
+    const void *key;
+    struct node_t *left;
+    struct node_t *right;
+    unsigned int red:1;
+} *node;
+
+static void tdestroy_recurse (node root, __free_fn_t freefct)
+{
+    if (root->left != NULL)
+        tdestroy_recurse (root->left, freefct);
+    if (root->right != NULL)
+        tdestroy_recurse (root->right, freefct);
+    (*freefct) ((void *) root->key);
+    /* Free the node itself.  */
+    free (root);
+}
+
+static void mytdestroy (void *vroot, __free_fn_t freefct)
+{
+    node root = (node) vroot;
+
+    if (root != NULL)
+        tdestroy_recurse (root, freefct);
+}
+
+static char *mystpcpy(char *a, const char *b)
+{
+    strcpy(a, b);
+    return (a + strlen(a));
+}
+
+static char *xgetcwd(void)
+{
+    char *cwd;
+    char *ret;
+    unsigned path_max;
+
+    errno = 0;
+    path_max = (unsigned) PATH_MAX;
+    path_max += 2;        /* The getcwd docs say to do this. */
+
+    cwd = malloc (path_max);
+    errno = 0;
+    while ((ret = getcwd (cwd, path_max)) == NULL && errno == ERANGE) {
+        path_max += 512;
+        cwd = realloc (cwd, path_max);
+        errno = 0;
+    }
+
+    if (ret == NULL) {
+        int save_errno = errno;
+        free (cwd);
+        errno = save_errno;
+        return NULL;
+    }
+    return cwd;
+}
+
+static int
+object_compare (const void *p1, const void *p2)
+{
+    /* We don't need a sophisticated and useful comparison.  We are only
+       interested in equality.  However, we must be careful not to
+       accidentally compare `holes' in the structure.  */
+    const struct known_object *kp1 = p1, *kp2 = p2;
+    int cmp1;
+    cmp1 = (kp1->ino > kp2->ino) - (kp1->ino < kp2->ino);
+    if (cmp1 != 0)
+        return cmp1;
+    return (kp1->dev > kp2->dev) - (kp1->dev < kp2->dev);
+}
+
+
+static int
+add_object (struct ftw_data *data, struct STAT *st)
+{
+    struct known_object *newp = malloc (sizeof (struct known_object));
+    if (newp == NULL)
+        return -1;
+    newp->dev = st->st_dev;
+    newp->ino = st->st_ino;
+    return __tsearch (newp, &data->known_objects, object_compare) ? 0 : -1;
+}
+
+
+static inline int
+find_object (struct ftw_data *data, struct STAT *st)
+{
+    struct known_object obj;
+    obj.dev = st->st_dev;
+    obj.ino = st->st_ino;
+    return __tfind (&obj, &data->known_objects, object_compare) != NULL;
+}
+
+
+static inline int
+open_dir_stream (int *dfdp, struct ftw_data *data, struct dir_data *dirp)
+{
+    int result = 0;
+
+    if (data->dirstreams[data->actdir] != NULL)
+    {
+        /* Oh, oh.  We must close this stream.  Get all remaining
+           entries and store them as a list in the `content' member of
+           the `struct dir_data' variable.  */
+        size_t bufsize = 1024;
+        char *buf = malloc (bufsize);
+
+        if (buf == NULL)
+            result = -1;
+        else
+        {
+            DIR *st = data->dirstreams[data->actdir]->stream;
+            struct dirent64 *d;
+            size_t actsize = 0;
+
+            while ((d = __readdir64 (st)) != NULL)
+            {
+                size_t this_len = NAMLEN (d);
+                if (actsize + this_len + 2 >= bufsize)
+                {
+                    char *newp;
+                    bufsize += MAX (1024, 2 * this_len);
+                    newp = (char *) realloc (buf, bufsize);
+                    if (newp == NULL)
+                    {
+                        /* No more memory.  */
+                        int save_err = errno;
+                        free (buf);
+                        __set_errno (save_err);
+                        return -1;
+                    }
+                    buf = newp;
+                }
+
+                *((char *) __mempcpy (buf + actsize, d->d_name, this_len))
+                    = '\0';
+                actsize += this_len + 1;
+            }
+
+            /* Terminate the list with an additional NUL byte.  */
+            buf[actsize++] = '\0';
+
+            /* Shrink the buffer to what we actually need.  */
+            data->dirstreams[data->actdir]->content = realloc (buf, actsize);
+            if (data->dirstreams[data->actdir]->content == NULL)
+            {
+                int save_err = errno;
+                free (buf);
+                __set_errno (save_err);
+                result = -1;
+            }
+            else
+            {
+                __closedir (st);
+                data->dirstreams[data->actdir]->stream = NULL;
+                data->dirstreams[data->actdir]->streamfd = -1;
+                data->dirstreams[data->actdir] = NULL;
+            }
+        }
+    }
+
+    /* Open the new stream.  */
+    if (result == 0)
+    {
+        assert (data->dirstreams[data->actdir] == NULL);
+
+        if (dfdp != NULL && *dfdp != -1)
+        {
+            int fd = openat(*dfdp, data->dirbuf + data->ftw.base, O_RDONLY);
+            dirp->stream = NULL;
+            if (fd != -1 && (dirp->stream = fdopendir (fd)) == NULL)
+                close(fd);
+        }
+        else
+        {
+            const char *name;
+
+            if (data->flags & FTW_CHDIR)
+            {
+                name = data->dirbuf + data->ftw.base;
+                if (name[0] == '\0')
+                    name = ".";
+            }
+            else
+                name = data->dirbuf;
+
+            dirp->stream = __opendir (name);
+        }
+
+        if (dirp->stream == NULL)
+            result = -1;
+        else
+        {
+            dirp->streamfd = dirfd (dirp->stream);
+            dirp->content = NULL;
+            data->dirstreams[data->actdir] = dirp;
+
+            if (++data->actdir == data->maxdir)
+                data->actdir = 0;
+        }
+    }
+
+    return result;
+}
+
+
+static int
+process_entry (struct ftw_data *data, struct dir_data *dir, const char *name, size_t namlen)
+{
+    struct STAT st;
+    int result = 0;
+    int flag = 0;
+    size_t new_buflen;
+
+    if (name[0] == '.' && (name[1] == '\0'
+                           || (name[1] == '.' && name[2] == '\0')))
+        /* Don't process the "." and ".." entries.  */
+        return 0;
+
+    new_buflen = data->ftw.base + namlen + 2;
+    if (data->dirbufsize < new_buflen)
+    {
+        /* Enlarge the buffer.  */
+        char *newp;
+
+        data->dirbufsize = 2 * new_buflen;
+        newp = (char *) realloc (data->dirbuf, data->dirbufsize);
+        if (newp == NULL)
+            return -1;
+        data->dirbuf = newp;
+    }
+
+    *((char *) __mempcpy (data->dirbuf + data->ftw.base, name, namlen)) = '\0';
+
+    int statres;
+    if (dir->streamfd != -1)
+        statres = FXSTATAT (_STAT_VER, dir->streamfd, name, &st,
+                            (data->flags & FTW_PHYS) ? AT_SYMLINK_NOFOLLOW : 0);
+    else
+    {
+        if ((data->flags & FTW_CHDIR) == 0)
+            name = data->dirbuf;
+
+        statres = ((data->flags & FTW_PHYS)
+                   ? LXSTAT (_STAT_VER, name, &st)
+                   : XSTAT (_STAT_VER, name, &st));
+    }
+
+    if (statres < 0)
+    {
+        if (errno != EACCES && errno != ENOENT)
+            result = -1;
+        else if (data->flags & FTW_PHYS)
+            flag = FTW_NS;
+        else
+        {
+            if (dir->streamfd != -1)
+                statres = FXSTATAT (_STAT_VER, dir->streamfd, name, &st,
+                                    AT_SYMLINK_NOFOLLOW);
+            else
+                statres = LXSTAT (_STAT_VER, name, &st);
+            if (statres == 0 && S_ISLNK (st.st_mode))
+                flag = FTW_SLN;
+            else
+                flag = FTW_NS;
+        }
+    }
+    else
+    {
+        if (S_ISDIR (st.st_mode))
+            flag = FTW_D;
+        else if (S_ISLNK (st.st_mode))
+            flag = FTW_SL;
+        else
+            flag = FTW_F;
+    }
+
+    if (result == 0
+        && (flag == FTW_NS
+            || !(data->flags & FTW_MOUNT) || st.st_dev == data->dev))
+    {
+        if (flag == FTW_D)
+        {
+            if ((data->flags & FTW_PHYS)
+                || (!find_object (data, &st)
+                    /* Remember the object.  */
+                    && (result = add_object (data, &st)) == 0))
+                result = ftw_dir (data, &st, dir);
+        }
+        else
+            result = (*data->func) (data->dirbuf, &st, data->cvt_arr[flag],
+                                    &data->ftw);
+    }
+
+    if ((data->flags & FTW_ACTIONRETVAL) && result == FTW_SKIP_SUBTREE)
+        result = 0;
+
+    return result;
+}
+
+
+static int
+ftw_dir (struct ftw_data *data, struct STAT *st, struct dir_data *old_dir)
+{
+    struct dir_data dir;
+    struct dirent64 *d;
+    int previous_base = data->ftw.base;
+    int result;
+    char *startp;
+
+    /* Open the stream for this directory.  This might require that
+       another stream has to be closed.  */
+    result = open_dir_stream (old_dir == NULL ? NULL : &old_dir->streamfd,
+                              data, &dir);
+    if (result != 0)
+    {
+        if (errno == EACCES)
+            /* We cannot read the directory.  Signal this with a special flag.  */
+            result = (*data->func) (data->dirbuf, st, FTW_DNR, &data->ftw);
+
+        return result;
+    }
+
+    /* First, report the directory (if not depth-first).  */
+    if (!(data->flags & FTW_DEPTH))
+    {
+        result = (*data->func) (data->dirbuf, st, FTW_D, &data->ftw);
+        if (result != 0)
+        {
+            int save_err;
+        fail:
+            save_err = errno;
+            __closedir (dir.stream);
+            dir.streamfd = -1;
+            __set_errno (save_err);
+
+            if (data->actdir-- == 0)
+                data->actdir = data->maxdir - 1;
+            data->dirstreams[data->actdir] = NULL;
+            return result;
+        }
+    }
+
+    /* If necessary, change to this directory.  */
+    if (data->flags & FTW_CHDIR)
+    {
+        if (__fchdir (dirfd (dir.stream)) < 0)
+        {
+            result = -1;
+            goto fail;
+        }
+    }
+
+    /* Next, update the `struct FTW' information.  */
+    ++data->ftw.level;
+    startp = data->dirbuf + strlen(data->dirbuf);
+    /* There always must be a directory name.  */
+    assert (startp != data->dirbuf);
+    if (startp[-1] != '/')
+        *startp++ = '/';
+    data->ftw.base = startp - data->dirbuf;
+
+    while (dir.stream != NULL && (d = __readdir64 (dir.stream)) != NULL)
+    {
+        result = process_entry (data, &dir, d->d_name, NAMLEN (d));
+        if (result != 0)
+            break;
+    }
+
+    if (dir.stream != NULL)
+    {
+        /* The stream is still open.  I.e., we did not need more
+           descriptors.  Simply close the stream now.  */
+        int save_err = errno;
+
+        assert (dir.content == NULL);
+
+        __closedir (dir.stream);
+        dir.streamfd = -1;
+        __set_errno (save_err);
+
+        if (data->actdir-- == 0)
+            data->actdir = data->maxdir - 1;
+        data->dirstreams[data->actdir] = NULL;
+    }
+    else
+    {
+        int save_err;
+        char *runp = dir.content;
+
+        while (result == 0 && *runp != '\0')
+        {
+            char *endp = strchr (runp, '\0');
+
+            // XXX Should store the d_type values as well?!
+            result = process_entry (data, &dir, runp, endp - runp);
+
+            runp = endp + 1;
+        }
+
+        save_err = errno;
+        free (dir.content);
+        __set_errno (save_err);
+    }
+
+    if ((data->flags & FTW_ACTIONRETVAL) && result == FTW_SKIP_SIBLINGS)
+        result = 0;
+
+    /* Prepare the return, revert the `struct FTW' information.  */
+    data->dirbuf[data->ftw.base - 1] = '\0';
+    --data->ftw.level;
+    if (upfunc)
+        (*upfunc)();
+    data->ftw.base = previous_base;
+
+    /* Finally, if we process depth-first report the directory.  */
+    if (result == 0 && (data->flags & FTW_DEPTH))
+        result = (*data->func) (data->dirbuf, st, FTW_DP, &data->ftw);
+
+    if (old_dir
+        && (data->flags & FTW_CHDIR)
+        && (result == 0
+            || ((data->flags & FTW_ACTIONRETVAL)
+                && (result != -1 && result != FTW_STOP))))
+    {
+        /* Change back to the parent directory.  */
+        int done = 0;
+        if (old_dir->stream != NULL)
+            if (__fchdir (dirfd (old_dir->stream)) == 0)
+                done = 1;
+
+        if (!done)
+        {
+            if (data->ftw.base == 1)
+            {
+                if (__chdir ("/") < 0)
+                    result = -1;
+            }
+            else
+                if (__chdir ("..") < 0)
+                    result = -1;
+        }
+    }
+
+    return result;
+}
+
+
+static int ftw_startup (const char *dir,
+                        int is_nftw,
+                        void *func,
+                        dir_notification_func_t up,
+                        int descriptors,
+                        int flags)
+{
+    struct ftw_data data;
+    struct STAT st;
+    int result = 0;
+    int save_err;
+    int cwdfd = -1;
+    char *cwd = NULL;
+    char *cp;
+
+    upfunc = up;
+
+    /* First make sure the parameters are reasonable.  */
+    if (dir[0] == '\0')
+    {
+        __set_errno (ENOENT);
+        return -1;
+    }
+
+    data.maxdir = descriptors < 1 ? 1 : descriptors;
+    data.actdir = 0;
+    data.dirstreams = (struct dir_data **) alloca (data.maxdir
+                                                   * sizeof (struct dir_data *));
+    memset (data.dirstreams, '\0', data.maxdir * sizeof (struct dir_data *));
+
+    /* PATH_MAX is always defined when we get here.  */
+    data.dirbufsize = MAX (2 * strlen (dir), PATH_MAX);
+    data.dirbuf = (char *) malloc (data.dirbufsize);
+    if (data.dirbuf == NULL)
+        return -1;
+    cp = mystpcpy (data.dirbuf, dir);
+    /* Strip trailing slashes.  */
+    while (cp > data.dirbuf + 1 && cp[-1] == '/')
+        --cp;
+    *cp = '\0';
+
+    data.ftw.level = 0;
+
+    /* Find basename.  */
+    while (cp > data.dirbuf && cp[-1] != '/')
+        --cp;
+    data.ftw.base = cp - data.dirbuf;
+
+    data.flags = flags;
+
+    /* This assignment might seem to be strange but it is what we want.
+       The trick is that the first three arguments to the `ftw' and
+       `nftw' callback functions are equal.  Therefore we can call in
+       every case the callback using the format of the `nftw' version
+       and get the correct result since the stack layout for a function
+       call in C allows this.  */
+    data.func = (NFTW_FUNC_T) func;
+
+    /* Since we internally use the complete set of FTW_* values we need
+       to reduce the value range before calling a `ftw' callback.  */
+    data.cvt_arr = is_nftw ? nftw_arr : ftw_arr;
+
+    /* No object known so far.  */
+    data.known_objects = NULL;
+
+    /* Now go to the directory containing the initial file/directory.  */
+    if (flags & FTW_CHDIR)
+    {
+        /* We have to be able to go back to the current working
+           directory.  The best way to do this is to use a file
+           descriptor.  */
+        cwdfd = open (".", O_RDONLY);
+        if (cwdfd == -1)
+        {
+            /* Try getting the directory name.  This can be needed if
+               the current directory is executable but not readable.  */
+            if (errno == EACCES)
+                /* GNU extension ahead.  */
+                cwd = __getcwd(NULL, 0);
+
+            if (cwd == NULL)
+                goto out_fail;
+        }
+        else if (data.maxdir > 1)
+            /* Account for the file descriptor we use here.  */
+            --data.maxdir;
+
+        if (data.ftw.base > 0)
+        {
+            /* Change to the directory the file is in.  In data.dirbuf
+               we have a writable copy of the file name.  Just NUL
+               terminate it for now and change the directory.  */
+            if (data.ftw.base == 1)
+                /* I.e., the file is in the root directory.  */
+                result = __chdir ("/");
+            else
+            {
+                char ch = data.dirbuf[data.ftw.base - 1];
+                data.dirbuf[data.ftw.base - 1] = '\0';
+                result = __chdir (data.dirbuf);
+                data.dirbuf[data.ftw.base - 1] = ch;
+            }
+        }
+    }
+
+    /* Get stat info for start directory.  */
+    if (result == 0)
+    {
+        const char *name;
+
+        if (data.flags & FTW_CHDIR)
+        {
+            name = data.dirbuf + data.ftw.base;
+            if (name[0] == '\0')
+                name = ".";
+        }
+        else
+            name = data.dirbuf;
+
+        if (((flags & FTW_PHYS)
+             ? LXSTAT (_STAT_VER, name, &st)
+             : XSTAT (_STAT_VER, name, &st)) < 0)
+        {
+            if (!(flags & FTW_PHYS)
+                && errno == ENOENT
+                && LXSTAT (_STAT_VER, name, &st) == 0
+                && S_ISLNK (st.st_mode))
+                result = (*data.func) (data.dirbuf, &st, data.cvt_arr[FTW_SLN],
+                                       &data.ftw);
+            else
+                /* No need to call the callback since we cannot say anything
+                   about the object.  */
+                result = -1;
+        }
+        else
+        {
+            if (S_ISDIR (st.st_mode))
+            {
+                /* Remember the device of the initial directory in case
+                   FTW_MOUNT is given.  */
+                data.dev = st.st_dev;
+
+                /* We know this directory now.  */
+                if (!(flags & FTW_PHYS))
+                    result = add_object (&data, &st);
+
+                if (result == 0)
+                    result = ftw_dir (&data, &st, NULL);
+            }
+            else
+            {
+                int flag = S_ISLNK (st.st_mode) ? FTW_SL : FTW_F;
+
+                result = (*data.func) (data.dirbuf, &st, data.cvt_arr[flag],
+                                       &data.ftw);
+            }
+        }
+
+        if ((flags & FTW_ACTIONRETVAL)
+            && (result == FTW_SKIP_SUBTREE || result == FTW_SKIP_SIBLINGS))
+            result = 0;
+    }
+
+    /* Return to the start directory (if necessary).  */
+    if (cwdfd != -1)
+    {
+        int save_err = errno;
+        __fchdir (cwdfd);
+        close(cwdfd);
+        __set_errno (save_err);
+    }
+    else if (cwd != NULL)
+    {
+        int save_err = errno;
+        __chdir (cwd);
+        free (cwd);
+        __set_errno (save_err);
+    }
+
+    /* Free all memory.  */
+out_fail:
+    save_err = errno;
+    mytdestroy (data.known_objects, free);
+    free (data.dirbuf);
+    __set_errno (save_err);
+
+    return result;
+}
+
+
+
+/* Entry points.  */
+int NFTW_NAME(const char *path,
+              NFTW_FUNC_T func,
+              dir_notification_func_t up,
+              int descriptors,
+              int flags)
+{
+    return ftw_startup (path, 1, func, up, descriptors, flags);
+}
+
diff --git a/libatalk/util/queue.c b/libatalk/util/queue.c
new file mode 100644 (file)
index 0000000..114e640
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+  Copyright (c) 2010 Frank Lahm <franklahm@gmail.com>
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+*/
+
+/*!
+ * @file
+ * Netatalk utility functions: queue
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include <stdlib.h>
+
+#include <atalk/queue.h>
+
+static qnode_t *alloc_init_node(void *data)
+{
+    qnode_t *node;
+    if ((node = malloc(sizeof(qnode_t))) == NULL)
+        return NULL;
+    node->data = data;
+
+    return node;
+}
+
+/********************************************************************************
+ * Interface
+ *******************************************************************************/
+
+q_t *queue_init(void)
+{
+    q_t *queue;
+
+    if ((queue = alloc_init_node(NULL)) == NULL)
+        return NULL;
+
+    queue->prev = queue->next = queue;
+    return queue;
+}
+
+/* Insert at tail */
+qnode_t *enqueue(q_t *q, void *data)
+{
+    qnode_t *node;
+
+    if ((node = alloc_init_node(data)) == NULL)
+        return NULL;
+
+    /* insert at tail */
+    node->next = q;
+    node->prev = q->prev;
+    q->prev->next = node;
+    q->prev = node;
+
+    return node;
+}
+
+/* Insert at head */
+qnode_t *prequeue(q_t *q, void *data)
+{
+    qnode_t *node;
+
+    if ((node = alloc_init_node(data)) == NULL)
+        return NULL;
+
+    /* insert at head */
+    q->next->prev = node;
+    node->next = q->next;
+    node->prev = q;
+    q->next = node;
+
+    return node;
+}
+
+/* Take from head */
+void *dequeue(q_t *q)
+{
+    qnode_t *node;
+    void *data;
+
+    if (q == NULL || q->next == q)
+        return NULL;
+
+    /* take first node from head */
+    node = q->next;
+    data = node->data;
+    q->next = node->next;
+    node->next->prev = node->prev;
+    free(node);
+
+    return data;    
+}
+
+void queue_destroy(q_t *q, void (*callback)(void *))
+{
+    void *p;
+
+    while ((p = dequeue(q)) != NULL)
+        callback(p);
+
+    free(q);
+    q = NULL;
+}
+
index 85c150c4c37cd9290f0aae8a53a99ab606d8660f..63f3683a54090e6caa27b5919bd5082e580188e0 100644 (file)
@@ -1,15 +1,13 @@
 /*
- * $Id: server_child.c,v 1.12 2010-01-21 14:14:49 didg Exp $
- *
  * Copyright (c) 1997 Adrian Sun (asun@zoology.washington.edu)
  * All rights reserved. See COPYRIGHT.
  *
  *
- * handle inserting, removing, and freeing of children. 
+ * handle inserting, removing, and freeing of children.
  * this does it via a hash table. it incurs some overhead over
  * a linear append/remove in total removal and kills, but it makes
  * single-entry removals a fast operation. as total removals occur during
- * child initialization and kills during server shutdown, this is 
+ * child initialization and kills during server shutdown, this is
  * probably a win for a lot of connections and unimportant for a small
  * number of connections.
  */
@@ -24,7 +22,7 @@
 #include <unistd.h>
 #endif /* HAVE_UNISTD_H */
 #include <signal.h>
-#include <atalk/logger.h>
+#include <errno.h>
 
 /* POSIX.1 sys/wait.h check */
 #include <sys/types.h>
 #endif /* HAVE_SYS_WAIT_H */
 #include <sys/time.h>
 
+#include <atalk/logger.h>
+#include <atalk/errchk.h>
+#include <atalk/util.h>
+#include <atalk/server_child.h>
+
 #ifndef WEXITSTATUS
 #define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
 #endif /* ! WEXITSTATUS */
 #define WIFSTOPPED(status) (((status) & 0xff) == 0x7f)
 #endif
 #ifndef WIFSIGNALED
-#define WIFSIGNALED(status) (!WIFSTOPPED(status) && !WIFEXITED(status)) 
+#define WIFSIGNALED(status) (!WIFSTOPPED(status) && !WIFEXITED(status))
 #endif
 #ifndef WTERMSIG
 #define WTERMSIG(status)      ((status) & 0x7f)
 #endif
 
-#include <atalk/server_child.h>
-
 /* hash/child functions: hash OR's pid */
 #define CHILD_HASHSIZE 32
 #define HASH(i) ((((i) >> 8) ^ (i)) & (CHILD_HASHSIZE - 1))
 
-struct server_child_data {
-  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;
-};
-
 typedef struct server_child_fork {
-  struct server_child_data *table[CHILD_HASHSIZE];
-  void (*cleanup)(const pid_t);
+    struct server_child_data *table[CHILD_HASHSIZE];
+    void (*cleanup)(const pid_t);
 } server_child_fork;
 
+int parent_or_child; /* 0: parent, 1: child */
+
 static inline void hash_child(struct server_child_data **htable,
-                                 struct server_child_data *child)
+                              struct server_child_data *child)
 {
-  struct server_child_data **table;
+    struct server_child_data **table;
 
-  table = &htable[HASH(child->pid)];
-  if ((child->next = *table) != NULL)
-    (*table)->prevp = &child->next;
-  *table = child;
-  child->prevp = table;
+    table = &htable[HASH(child->pid)];
+    if ((child->next = *table) != NULL)
+        (*table)->prevp = &child->next;
+    *table = child;
+    child->prevp = table;
 }
 
 static inline void unhash_child(struct server_child_data *child)
 {
-  if (child->prevp) {
-    if (child->next)
-      child->next->prevp = child->prevp;
-    *(child->prevp) = child->next;
-  }
+    if (child->prevp) {
+        if (child->next)
+            child->next->prevp = child->prevp;
+        *(child->prevp) = child->next;
+    }
 }
 
-static inline struct server_child_data 
-*resolve_child(struct server_child_data **table, const pid_t pid)
+static struct server_child_data *resolve_child(struct server_child_data **table, pid_t pid)
 {
-  struct server_child_data *child;
+    struct server_child_data *child;
 
-  for (child = table[HASH(pid)]; child; child = child->next) {
-    if (child->pid == pid)
-      break;
-  }
+    for (child = table[HASH(pid)]; child; child = child->next) {
+        if (child->pid == pid)
+            break;
+    }
 
-  return child;
+    return child;
 }
 
 /* initialize server_child structure */
 server_child *server_child_alloc(const int connections, const int nforks)
 {
-  server_child *children;
+    server_child *children;
 
-  children = (server_child *) calloc(1, sizeof(server_child));
-  if (!children)
-    return NULL;
+    children = (server_child *) calloc(1, sizeof(server_child));
+    if (!children)
+        return NULL;
 
-  children->nsessions = connections;
-  children->nforks = nforks;
-  children->fork = (void *) calloc(nforks, sizeof(server_child_fork));
-  
-  if (!children->fork) {
-    free(children);
-    return NULL;
-  } 
+    children->nsessions = connections;
+    children->nforks = nforks;
+    children->fork = (void *) calloc(nforks, sizeof(server_child_fork));
 
-  return children;
+    if (!children->fork) {
+        free(children);
+        return NULL;
+    }
+
+    return children;
 }
 
-/* add a child in. return 0 on success, -1 on serious error, and
- * > 0 for a non-serious error. */
-int server_child_add(server_child *children, const int forkid,
-                    const pid_t pid)
+/*!
+ * add a child
+ * @return pointer to struct server_child_data on success, NULL on error
+ */
+afp_child_t *server_child_add(server_child *children, int forkid, pid_t pid, uint ipc_fds[2])
 {
-  server_child_fork *fork;
-  struct server_child_data *child;
-  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, &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_SETMASK, &oldsig, NULL);
-    return 1;
-  }
-
-  fork = (server_child_fork *) children->fork + forkid;
-
-  /* if we already have an entry. just return. */
-  if (resolve_child(fork->table, pid)) {
-    sigprocmask(SIG_SETMASK, &oldsig, NULL);
-    return 0;
-  }
-
-  if ((child = (struct server_child_data *) 
-       calloc(1, sizeof(struct server_child_data))) == 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_SETMASK, &oldsig, NULL);
-
-  return 0;
+    server_child_fork *fork;
+    afp_child_t *child = NULL;
+    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);
+    pthread_sigmask(SIG_BLOCK, &sig, &oldsig);
+
+    /* it's possible that the child could have already died before the
+     * pthread_sigmask. we need to check for this. */
+    if (kill(pid, 0) < 0)
+        goto exit;
+
+    fork = (server_child_fork *) children->fork + forkid;
+
+    /* if we already have an entry. just return. */
+    if (child = resolve_child(fork->table, pid))
+        goto exit;
+
+    if ((child = calloc(1, sizeof(afp_child_t))) == NULL)
+        goto exit;
+
+    child->pid = pid;
+    child->valid = 0;
+    child->killed = 0;
+    child->ipc_fds[0] = ipc_fds[0];
+    child->ipc_fds[1] = ipc_fds[1];
+
+    hash_child(fork->table, child);
+    children->count++;
+
+exit:
+    pthread_sigmask(SIG_SETMASK, &oldsig, NULL);
+    return child;
 }
 
 /* remove a child and free it */
-int server_child_remove(server_child *children, const int forkid,
-                       const pid_t pid)
+int server_child_remove(server_child *children, const int forkid, pid_t pid)
 {
-  server_child_fork *fork;
-  struct server_child_data *child;
-
-  fork = (server_child_fork *) children->fork + forkid;
-  if (!(child = resolve_child(fork->table, pid)))
-    return 0;
-  
-  unhash_child(child);
-  if (child->clientid) {
-      free(child->clientid);
-  }
-  free(child);
-  children->count--;
-  return 1;
+    int fd;
+    server_child_fork *fork;
+    struct server_child_data *child;
+
+    fork = (server_child_fork *) children->fork + forkid;
+    if (!(child = resolve_child(fork->table, pid)))
+        return -1;
+
+    unhash_child(child);
+    if (child->clientid) {
+        free(child->clientid);
+        child->clientid = NULL;
+    }
+
+    /* In main:child_handler() we need the fd in order to remove it from the pollfd set */
+    fd = child->ipc_fds[0];
+    if (child->ipc_fds[0] != -1) {
+        close(child->ipc_fds[0]);
+        child->ipc_fds[0] = -1;
+    }
+    if (child->ipc_fds[1] != -1) {
+        close(child->ipc_fds[1]);
+        child->ipc_fds[1] = -1;
+    }
+
+    free(child);
+    children->count--;
+
+    if (fork->cleanup)
+        fork->cleanup(pid);
+
+    return fd;
 }
 
 /* free everything: by using a hash table, this increases the cost of
  * this part over a linked list by the size of the hash table */
 void server_child_free(server_child *children)
 {
-  server_child_fork *fork;
-  struct server_child_data *child, *tmp;
-  int i, j;
-
-  for (i = 0; i < children->nforks; i++) {
-    fork = (server_child_fork *) children->fork + i;
-    for (j = 0; j < CHILD_HASHSIZE; j++) {
-      child = fork->table[j]; /* start at the beginning */
-      while (child) {
-       tmp = child->next;
-        if (child->clientid) {
-            free(child->clientid);
+    server_child_fork *fork;
+    struct server_child_data *child, *tmp;
+    int i, j;
+
+    for (i = 0; i < children->nforks; i++) {
+        fork = (server_child_fork *) children->fork + i;
+        for (j = 0; j < CHILD_HASHSIZE; j++) {
+            child = fork->table[j]; /* start at the beginning */
+            while (child) {
+                tmp = child->next;
+                if (child->clientid) {
+                    free(child->clientid);
+                }
+                free(child);
+                child = tmp;
+            }
         }
-       free(child);
-       child = tmp;
-      }
     }
-  }
-  free(children->fork);
-  free(children);
+    free(children->fork);
+    free(children);
 }
 
-/* send kill to child processes: this also has an increased cost over
- * a plain-old linked list */
-void server_child_kill(server_child *children, const int forkid,
-                      const int sig)
+/* send signal to all child processes */
+void server_child_kill(server_child *children, int forkid, int sig)
 {
-  server_child_fork *fork;
-  struct server_child_data *child, *tmp;
-  int i;
-
-  fork = (server_child_fork *) children->fork + forkid;
-  for (i = 0; i < CHILD_HASHSIZE; i++) {
-    child = fork->table[i];
-    while (child) {
-      tmp = child->next;
-      kill(child->pid, sig);
-      child = tmp;
+    server_child_fork *fork;
+    struct server_child_data *child, *tmp;
+    int i;
+
+    fork = (server_child_fork *) children->fork + forkid;
+    for (i = 0; i < CHILD_HASHSIZE; i++) {
+        child = fork->table[i];
+        while (child) {
+            tmp = child->next;
+            kill(child->pid, sig);
+            child = tmp;
+        }
     }
-  }
 }
 
 /* send kill to a child processes.
- * a plain-old linked list 
+ * a plain-old linked list
  * FIXME use resolve_child ?
  */
 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;
+    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, "Unresponsive child[%d], sending SIGKILL", child->pid);
+        kill(child->pid, SIGKILL);
+    }
+    return 1;
 }
 
-/* -------------------- */
-void server_child_kill_one(server_child *children, const int forkid, const pid_t pid, const uid_t uid)
+/*!
+ * Try to find an old session and pass socket
+ * @returns -1 on error, 0 if no matching session was found, 1 if session was found and socket passed
+ */
+int server_child_transfer_session(server_child *children,
+                                  int forkid,
+                                  pid_t pid,
+                                  uid_t uid,
+                                  int afp_socket,
+                                  uint16_t DSI_requestID)
 {
-  server_child_fork *fork;
-  struct server_child_data *child, *tmp;
-  int i;
-
-  fork = (server_child_fork *) children->fork + forkid;
-  for (i = 0; i < CHILD_HASHSIZE; i++) {
-    child = fork->table[i];
-    while (child) {
-      tmp = child->next;
-      if (child->pid == pid) {
-          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;
+    EC_INIT;
+    server_child_fork *fork;
+    struct server_child_data *child;
+    int i;
+
+    fork = (server_child_fork *) children->fork + forkid;
+    if ((child = resolve_child(fork->table, pid)) == NULL) {
+        LOG(log_note, logtype_default, "Reconnect: no child[%u]", pid);
+        return 0;
+    }
+
+    if (!child->valid) {
+        /* hmm, client 'guess' the pid, rogue? */
+        LOG(log_error, logtype_default, "Reconnect: invalidated child[%u]", pid);
+        return 0;
+    } else if (child->uid != uid) {
+        LOG(log_error, logtype_default, "Reconnect: child[%u] not the same user", pid);
+        return 0;
     }
-  }
+
+    LOG(log_note, logtype_default, "Reconnect: transfering session to child[%u]", pid);
+    
+    if (writet(child->ipc_fds[0], &DSI_requestID, 2, 0, 2) != 2) {
+        LOG(log_error, logtype_default, "Reconnect: error sending DSI id to child[%u]", pid);
+        EC_STATUS(-1);
+        goto EC_CLEANUP;
+    }
+    EC_ZERO_LOG(send_fd(child->ipc_fds[0], afp_socket));
+    EC_ZERO_LOG(kill(pid, SIGURG));
+
+    EC_STATUS(1);
+
+EC_CLEANUP:
+    EC_EXIT;
 }
 
 
 /* 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,
-          const uid_t uid, 
-          const u_int32_t idlen, char *id, u_int32_t boottime)
+void server_child_kill_one_by_id(server_child *children, int forkid, pid_t pid,
+                                 uid_t uid, uint32_t idlen, char *id, uint32_t boottime)
 {
-  server_child_fork *fork;
-  struct server_child_data *child, *tmp;
-  int i;
-
-  fork = (server_child_fork *) children->fork + forkid;
-  for (i = 0; i < CHILD_HASHSIZE; i++) {
-    child = fork->table[i];
-    while (child) {
-      tmp = child->next;
-      if ( child->pid != pid) {
-          if ( child->idlen == idlen && !memcmp(child->clientid, id, idlen)) {
-            if ( child->time != boottime ) {
-                 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.",
-                      child->pid, pid);
-            } 
-               
-         }
-      }
-      else 
-      {
-         child->time = boottime;
-         /* free old token if any */
-         if (child->clientid) {
-             free(child->clientid);
-         }
-          child->uid = uid; 
-          child->valid = 1;
-         child->idlen = idlen;
-          child->clientid = id;
-         LOG(log_debug, logtype_default, "Setting clientid (len %d) for %d, boottime %X", idlen, child->pid, boottime);
-      }
-      child = tmp;
+    server_child_fork *fork;
+    struct server_child_data *child, *tmp;
+    int i;
+
+    fork = (server_child_fork *)children->fork + forkid;
+
+    for (i = 0; i < CHILD_HASHSIZE; i++) {
+        child = fork->table[i];
+        while (child) {
+            tmp = child->next;
+            if ( child->pid != pid) {
+                if (child->idlen == idlen && memcmp(child->clientid, id, idlen) == 0) {
+                    if ( child->time != boottime ) {
+                        /* Client rebooted */
+                        if (uid == child->uid) {
+                            kill_child(child);
+                            LOG(log_warning, logtype_default,
+                                "Terminated disconnected child[%u], client rebooted.",
+                                child->pid);
+                        } else {
+                            LOG(log_warning, logtype_default,
+                                "Session with different pid[%u]", child->pid);
+                        }
+                    } else {
+                        kill_child(child);
+                        LOG(log_note, logtype_default,
+                            "Terminated disconnected session[%u]", child->pid);
+                    }
+                }
+            } else {
+                /* update childs own slot */
+                child->time = boottime;
+                if (child->clientid)
+                    free(child->clientid);
+                LOG(log_debug, logtype_default, "Setting client ID for %d", child->pid);
+                child->uid = uid;
+                child->valid = 1;
+                child->idlen = idlen;
+                child->clientid = id;
+            }
+            child = tmp;
+        }
     }
-  }
 }
 
 /* for extra cleanup if necessary */
 void server_child_setup(server_child *children, const int forkid,
-                         void (*fcn)(const pid_t))
+                        void (*fcn)(const pid_t))
 {
-  server_child_fork *fork;
+    server_child_fork *fork;
 
-  fork = (server_child_fork *) children->fork + forkid;
-  fork->cleanup = fcn;
+    fork = (server_child_fork *) children->fork + forkid;
+    fork->cleanup = fcn;
 }
 
 
-/* keep track of children. */
-void server_child_handler(server_child *children)
-{
-  int status, i;
-  pid_t pid;
-  
-#ifndef WAIT_ANY
-#define WAIT_ANY (-1)
-#endif /* ! WAIT_ANY */
-
-  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, 
-              WEXITSTATUS(status));
-      } else {
-       LOG(log_info, logtype_default, "server_child[%d] %d done", i, pid);
-      }
-    } else {
-      if (WIFSIGNALED(status))
-      { 
-       LOG(log_info, logtype_default, "server_child[%d] %d killed by signal %d", i, pid,  
-              WTERMSIG (status));
-      }
-      else
-      {
-       LOG(log_info, logtype_default, "server_child[%d] %d died", i, pid);
-      }
-    }
-  }
-}
-
-/* --------------------------- 
+/* ---------------------------
  * reset children signals
-*/
+ */
 void server_reset_signal(void)
 {
     struct sigaction    sv;
@@ -415,18 +382,18 @@ void server_reset_signal(void)
     memset(&sv, 0, sizeof(sv));
     sv.sa_handler =  SIG_DFL;
     sigemptyset( &sv.sa_mask );
-    
+
     sigaction(SIGALRM, &sv, NULL );
     sigaction(SIGHUP,  &sv, NULL );
     sigaction(SIGTERM, &sv, NULL );
     sigaction(SIGUSR1, &sv, NULL );
     sigaction(SIGCHLD, &sv, NULL );
-    
+
     sigemptyset(&sigs);
     sigaddset(&sigs, SIGALRM);
     sigaddset(&sigs, SIGHUP);
     sigaddset(&sigs, SIGUSR1);
     sigaddset(&sigs, SIGCHLD);
-    sigprocmask(SIG_UNBLOCK, &sigs, NULL);
-        
+    pthread_sigmask(SIG_UNBLOCK, &sigs, NULL);
+
 }
index 289197fb7ac89a76c2da7e0cd91a3abfa2527e96..1115551ee4e10826f56aaa1d8fd2b807ecb25371 100644 (file)
@@ -1,10 +1,7 @@
 /*
- * $Id: server_ipc.c,v 1.4 2010-01-21 14:14:49 didg Exp $
- *
  * All rights reserved. See COPYRIGHT.
  *
- *
- * ipc between parent and children.
+ * IPC over socketpair between parent and children.
  */
 
 #ifdef HAVE_CONFIG_H
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <sys/socket.h>
+#include <errno.h>
+#include <signal.h>
 
 #include <atalk/server_child.h>
 #include <atalk/server_ipc.h>
 #include <atalk/logger.h>
+#include <atalk/util.h>
 
 typedef struct ipc_header {
-       u_int16_t command;
-        pid_t    child_pid;
-        uid_t     uid;
-        u_int32_t len;
-       char      *msg;
-} ipc_header;
-
-static int pipe_fd[2];
-   
-void *server_ipc_create(void)
-{
-    if (pipe(pipe_fd)) {
-        return NULL;
-    }
-    return &pipe_fd;
-}
-
-/* ----------------- */
-int server_ipc_child(void *obj _U_)
-{
-    /* close input */
-    close(pipe_fd[0]);
-    return pipe_fd[1];
-}
+       uint16_t command;
+    pid_t       child_pid;
+    uid_t    uid;
+    uint32_t len;
+       char     *msg;
+    int      afp_socket;
+    uint16_t DSI_requestID;
+} ipc_header_t;
+
+static char *ipc_cmd_str[] = { "IPC_DISCOLDSESSION",
+                               "IPC_GETSESSION"};
 
-/* ----------------- */
-int server_ipc_parent(void *obj _U_)
-{
-    return pipe_fd[0];
-}
-
-/* ----------------- */
-static int ipc_kill_token (struct ipc_header *ipc, server_child *children)
+/*
+ * Pass afp_socket to old disconnected session if one has a matching token (token = pid)
+ * @returns -1 on error, 0 if no matching session was found, 1 if session was found and socket passed
+ */
+static int ipc_kill_token(struct ipc_header *ipc, server_child *children)
 {
     pid_t pid;
 
@@ -66,22 +51,25 @@ static 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 user %d disconnected", pid, ipc->uid);
-    server_child_kill_one(children, CHILD_DSIFORK, pid, ipc->uid);
-    return 0;
+    return server_child_transfer_session(children,
+                                         CHILD_DSIFORK,
+                                         pid,
+                                         ipc->uid,
+                                         ipc->afp_socket,
+                                         ipc->DSI_requestID);
 }
 
 /* ----------------- */
-static int ipc_get_session (struct ipc_header *ipc, server_child *children)
+static int ipc_get_session(struct ipc_header *ipc, server_child *children)
 {
     u_int32_t boottime;
     u_int32_t idlen;
     char     *clientid, *p;
 
+    
+    if (ipc->len < (sizeof(idlen) + sizeof(boottime)) )
+        return -1;
 
-    if (ipc->len < (sizeof(idlen) + sizeof(boottime)) ) {
-       return -1;
-    }
     p = ipc->msg;
     memcpy (&idlen, p, sizeof(idlen));
     idlen = ntohl (idlen);
@@ -90,17 +78,24 @@ static int ipc_get_session (struct ipc_header *ipc, server_child *children)
     memcpy (&boottime, p, sizeof(boottime));
     p += sizeof(boottime);
     
-    if (ipc->len < idlen + sizeof(idlen) + sizeof(boottime)) {
-       return -1;
-    }
-    if (NULL == (clientid = (char*) malloc(idlen)) ) {
-       return -1;
-    }
+    if (ipc->len < idlen + sizeof(idlen) + sizeof(boottime))
+        return -1;
+
+    if (NULL == (clientid = (char*) malloc(idlen)) )
+        return -1;
     memcpy (clientid, p, idlen);
   
-    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_debug, logtype_afpd, "ipc_get_session: len: %u, idlen %d, time %x", ipc->len, idlen, boottime); 
+    LOG(log_debug, logtype_afpd, "ipc_get_session(pid: %u, uid: %u, time: 0x%08x)",
+        ipc->child_pid, ipc->uid, boottime); 
+
+    server_child_kill_one_by_id(children,
+                                CHILD_DSIFORK,
+                                ipc->child_pid,
+                                ipc->uid,
+                                idlen,
+                                clientid,
+                                boottime);
+
     return 0;
 }
 
@@ -114,16 +109,26 @@ static int ipc_get_session (struct ipc_header *ipc, server_child *children)
  * uid
  * 
 */
-int server_ipc_read(server_child *children)
+
+/*!
+ * Read a IPC message from a child
+ *
+ * @args children  (rw) pointer to our structure with all childs
+ * @args fd        (r)  IPC socket with child
+ *
+ * @returns number of bytes transfered, -1 on error, 0 on EOF
+ */
+int ipc_server_read(server_child *children, int fd)
 {
     int       ret = 0;
     struct ipc_header ipc;
     char      buf[IPC_MAXMSGSIZE], *p;
 
-    if ((ret = read(pipe_fd[0], buf, IPC_HEADERLEN)) != IPC_HEADERLEN) {
-       LOG (log_info, logtype_afpd, "Reading IPC header failed (%u of %u  bytes read)", ret, IPC_HEADERLEN);
-       return -1;
-    } 
+    if ((ret = read(fd, buf, IPC_HEADERLEN)) != IPC_HEADERLEN) {
+        LOG(log_error, logtype_afpd, "Reading IPC header failed (%i of %u bytes read): %s",
+            ret, IPC_HEADERLEN, strerror(errno));
+        return ret;
+    }
 
     p = buf;
 
@@ -139,40 +144,62 @@ int server_ipc_read(server_child *children)
     memcpy(&ipc.len, p, sizeof(ipc.len));
 
     /* This should never happen */
-    if (ipc.len > (IPC_MAXMSGSIZE - IPC_HEADERLEN))
-    {
-       LOG (log_info, logtype_afpd, "IPC message exceeds allowed size (%u)", ipc.len);
-       return -1;
+    if (ipc.len > (IPC_MAXMSGSIZE - IPC_HEADERLEN)) {
+        LOG (log_info, logtype_afpd, "IPC message exceeds allowed size (%u)", ipc.len);
+        return -1;
     }
 
     memset (buf, 0, IPC_MAXMSGSIZE);
     if ( ipc.len != 0) {
-           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;
+           if ((ret = read(fd, buf, ipc.len)) != (int) ipc.len) {
+            LOG(log_info, logtype_afpd, "Reading IPC message failed (%u of %u  bytes read): %s",
+                ret, ipc.len, strerror(errno));
+            return ret;
        }        
     }
     ipc.msg = buf;
-    
-    LOG (log_debug, logtype_afpd, "ipc_read: command: %u, pid: %u, len: %u", ipc.command, ipc.child_pid, ipc.len); 
 
-    switch (ipc.command)
-    {
-       case IPC_KILLTOKEN:
-               return (ipc_kill_token(&ipc, children));
-               break;
+    LOG(log_debug, logtype_afpd, "ipc_server_read(%s): pid: %u",
+        ipc_cmd_str[ipc.command], ipc.child_pid); 
+
+    int afp_socket;
+
+    switch (ipc.command) {
+
+       case IPC_DISCOLDSESSION:
+        if (readt(fd, &ipc.DSI_requestID, 2, 0, 2) != 2) {
+            LOG (log_error, logtype_afpd, "ipc_read(%s:child[%u]): couldnt read DSI id: %s",
+                 ipc_cmd_str[ipc.command], ipc.child_pid, strerror(errno));
+        }
+        if ((ipc.afp_socket = recv_fd(fd, 1)) == -1) {
+            LOG (log_error, logtype_afpd, "ipc_read(%s:child[%u]): recv_fd: %s",
+                 ipc_cmd_str[ipc.command], ipc.child_pid, strerror(errno));
+            return -1;
+        }
+               if (ipc_kill_token(&ipc, children) == 1) {
+            /* Transfered session (ie afp_socket) to old disconnected child, now kill the new one */
+            LOG(log_note, logtype_afpd, "Reconnect: killing new session child[%u] after transfer",
+                ipc.child_pid);
+            kill(ipc.child_pid, SIGTERM);
+        }        
+        close(ipc.afp_socket);
+        break;
+
        case IPC_GETSESSION:
-               return (ipc_get_session(&ipc, children));
-               break;
+               if (ipc_get_session(&ipc, children) != 0)
+            return -1;
+        break;
+
        default:
                LOG (log_info, logtype_afpd, "ipc_read: unknown command: %d", ipc.command);
                return -1;
     }
 
+    return ret;
 }
 
 /* ----------------- */
-int server_ipc_write( u_int16_t command, int len, void *msg)
+int ipc_child_write(int fd, uint16_t command, int len, void *msg)
 {
    char block[IPC_MAXMSGSIZE], *p;
    pid_t pid;
@@ -204,7 +231,8 @@ int server_ipc_write( u_int16_t command, int len, void *msg)
 
    memcpy(p, msg, len);
 
-   LOG (log_debug, logtype_afpd, "ipc_write: command: %u, pid: %u, msglen: %u", command, pid, len); 
-   return write(pipe_fd[1], block, len+IPC_HEADERLEN );
+   LOG(log_debug, logtype_afpd, "ipc_child_write(%s)", ipc_cmd_str[command]);
+
+   return write(fd, block, len+IPC_HEADERLEN );
 }
 
index f29f3837054f44ae0bf718b8ee25e0d745253795..9edeb6c55c0cf34f380c121b77826a43d7c71972 100644 (file)
@@ -1,5 +1,4 @@
 /*
-   $Id: socket.c,v 1.6 2010-01-05 19:05:52 franklahm Exp $
    Copyright (c) 2009 Frank Lahm <franklahm@gmail.com>
 
    This program is free software; you can redistribute it and/or modify
 #include "config.h"
 #endif /* HAVE_CONFIG_H */
 
+#ifndef _XOPEN_SOURCE
+# define _XOPEN_SOURCE 600
+#endif
+#ifndef __EXTENSIONS__
+# define __EXTENSIONS__
+#endif
+#ifndef _GNU_SOURCE
+# define _GNU_SOURCE
+#endif
 #include <unistd.h>
 #include <fcntl.h>
 #include <sys/types.h>
 #include <errno.h>
 #include <sys/time.h>
 #include <time.h>
+#include <sys/ioctl.h>
 
 #include <atalk/logger.h>
+#include <atalk/util.h>
 
 static char ipv4mapprefix[] = {0,0,0,0,0,0,0,0,0,0,0xff,0xff};
 
@@ -162,6 +172,101 @@ exit:
     return stored;
 }
 
+/*!
+ * non-blocking drop-in replacement for read with timeout using select
+ *
+ * @param socket          (r)  socket, if in blocking mode, pass "setnonblocking" arg as 1
+ * @param data            (rw) buffer for the read data
+ * @param lenght          (r)  how many bytes to read
+ * @param setnonblocking  (r)  when non-zero this func will enable and disable non blocking
+ *                             io mode for the socket
+ * @param timeout         (r)  number of seconds to try reading
+ *
+ * @returns number of bytes actually read or -1 on fatal error
+ */
+ssize_t writet(int socket, void *data, const size_t length, int setnonblocking, int timeout)
+{
+    size_t stored = 0;
+    ssize_t len = 0;
+    struct timeval now, end, tv;
+    fd_set rfds;
+    int ret;
+
+    if (setnonblocking) {
+        if (setnonblock(socket, 1) != 0)
+            return -1;
+    }
+
+    /* Calculate end time */
+    (void)gettimeofday(&now, NULL);
+    end = now;
+    end.tv_sec += timeout;
+
+    while (stored < length) {
+        len = write(socket, (char *) data + stored, length - stored);
+        if (len == -1) {
+            switch (errno) {
+            case EINTR:
+                continue;
+            case EAGAIN:
+                FD_ZERO(&rfds);
+                FD_SET(socket, &rfds);
+                tv.tv_usec = 0;
+                tv.tv_sec  = timeout;
+                        
+                while ((ret = select(socket + 1, &rfds, NULL, NULL, &tv)) < 1) {
+                    switch (ret) {
+                    case 0:
+                        LOG(log_warning, logtype_afpd, "select timeout %d s", timeout);
+                        goto exit;
+
+                    default: /* -1 */
+                        if (errno == EINTR) {
+                            (void)gettimeofday(&now, NULL);
+                            if (now.tv_sec >= end.tv_sec && now.tv_usec >= end.tv_usec) {
+                                LOG(log_warning, logtype_afpd, "select timeout %d s", timeout);
+                                goto exit;
+                            }
+                            if (now.tv_usec > end.tv_usec) {
+                                tv.tv_usec = 1000000 + end.tv_usec - now.tv_usec;
+                                tv.tv_sec  = end.tv_sec - now.tv_sec - 1;
+                            } else {
+                                tv.tv_usec = end.tv_usec - now.tv_usec;
+                                tv.tv_sec  = end.tv_sec - now.tv_sec;
+                            }
+                            FD_ZERO(&rfds);
+                            FD_SET(socket, &rfds);
+                            continue;
+                        }
+                        LOG(log_error, logtype_afpd, "select: %s", strerror(errno));
+                        stored = -1;
+                        goto exit;
+                    }
+                } /* while (select) */
+                continue;
+            } /* switch (errno) */
+            LOG(log_error, logtype_afpd, "read: %s", strerror(errno));
+            stored = -1;
+            goto exit;
+        } /* (len == -1) */
+        else if (len > 0)
+            stored += len;
+        else
+            break;
+    } /* while (stored < length) */
+
+exit:
+    if (setnonblocking) {
+        if (setnonblock(socket, 0) != 0)
+            return -1;
+    }
+
+    if (len == -1 && stored == 0)
+        /* last read or select got an error and we haven't got yet anything => return -1*/
+        return -1;
+    return stored;
+}
+
 /*!
  * @brief convert an IPv4 or IPv6 address to a static string using inet_ntop
  *
@@ -234,7 +339,7 @@ unsigned int getip_port(const struct sockaddr  *sa)
  * @param  ai        (rw) pointer to an struct sockaddr
  * @parma  mask      (r) number of maskbits
  */
-void apply_ip_mask(struct sockaddr *sa, uint32_t mask)
+void apply_ip_mask(struct sockaddr *sa, int mask)
 {
 
     switch (sa->sa_family) {
@@ -301,3 +406,239 @@ int compare_ip(const struct sockaddr *sa1, const struct sockaddr *sa2)
 
     return ret;
 }
+
+#define POLL_FD_SET_STARTSIZE 512
+#define POLL_FD_SET_INCREASE  128
+/*!
+ * Add a fd to a dynamic pollfd array that is allocated and grown as needed
+ *
+ * This uses an additional array of struct polldata which stores type information
+ * (enum fdtype) and a pointer to anciliary user data.
+ *
+ * 1. Allocate the arrays with an intial size of [POLL_FD_SET_STARTSIZE] if
+ *    *fdsetp is NULL.
+ * 2. Grow array as needed
+ * 3. Fill in both array elements and increase count of used elements
+ * 
+ * @param fdsetp      (rw) pointer to callers pointer to the pollfd array
+ * @param polldatap   (rw) pointer to callers pointer to the polldata array
+ * @param fdset_usedp (rw) pointer to an int with the number of used elements
+ * @param fdset_sizep (rw) pointer to an int which stores the array sizes
+ * @param fd          (r)  file descriptor to add to the arrays
+ * @param fdtype      (r)  type of fd, currently IPC_FD or LISTEN_FD
+ * @param data        (rw) pointer to data the caller want to associate with an fd
+ */
+void fdset_add_fd(struct pollfd **fdsetp,
+                  struct polldata **polldatap,
+                  int *fdset_usedp,
+                  int *fdset_sizep,
+                  int fd,
+                  enum fdtype fdtype,
+                  void *data)
+{
+    struct pollfd *fdset = *fdsetp;
+    struct polldata *polldata = *polldatap;
+    int fdset_size = *fdset_sizep;
+
+    LOG(log_debug, logtype_default, "fdset_add_fd: adding fd %i in slot %i", fd, *fdset_usedp);
+
+    if (fdset == NULL) { /* 1 */
+        /* Initialize with space for 512 fds */
+        fdset = calloc(POLL_FD_SET_STARTSIZE, sizeof(struct pollfd));
+        if (! fdset)
+            exit(EXITERR_SYS);
+
+        polldata = calloc(POLL_FD_SET_STARTSIZE, sizeof(struct polldata));
+        if (! polldata)
+            exit(EXITERR_SYS);
+
+        fdset_size = 512;
+        *fdset_sizep = fdset_size;
+        *fdsetp = fdset;
+        *polldatap = polldata;
+    }
+
+    if (*fdset_usedp >= fdset_size) { /* 2 */
+        fdset = realloc(fdset, sizeof(struct pollfd) * (fdset_size + POLL_FD_SET_INCREASE));
+        if (fdset == NULL)
+            exit(EXITERR_SYS);
+
+        polldata = realloc(polldata, sizeof(struct polldata) * (fdset_size + POLL_FD_SET_INCREASE));
+        if (polldata == NULL)
+            exit(EXITERR_SYS);
+
+        fdset_size += POLL_FD_SET_INCREASE;
+        *fdset_sizep = fdset_size;
+        *fdsetp = fdset;
+        *polldatap = polldata;
+    }
+
+    /* 3 */
+    fdset[*fdset_usedp].fd = fd;
+    fdset[*fdset_usedp].events = POLLIN;
+    polldata[*fdset_usedp].fdtype = fdtype;
+    polldata[*fdset_usedp].data = data;
+    (*fdset_usedp)++;
+}
+
+/*!
+ * Remove a fd from our pollfd array
+ *
+ * 1. Search fd
+ * 2. If we remove the last array elemnt, just decrease count
+ * 3. If found move all following elements down by one
+ * 4. Decrease count of used elements in array
+ *
+ * This currently doesn't shrink the allocated storage of the array.
+ *
+ * @param fdsetp      (rw) pointer to callers pointer to the pollfd array
+ * @param polldatap   (rw) pointer to callers pointer to the polldata array
+ * @param fdset_usedp (rw) pointer to an int with the number of used elements
+ * @param fdset_sizep (rw) pointer to an int which stores the array sizes
+ * @param fd          (r)  file descriptor to remove from the arrays
+ */
+void fdset_del_fd(struct pollfd **fdsetp,
+                  struct polldata **polldatap,
+                  int *fdset_usedp,
+                  int *fdset_sizep _U_,
+                  int fd)
+{
+    struct pollfd *fdset = *fdsetp;
+    struct polldata *polldata = *polldatap;
+
+    for (int i = 0; i < *fdset_usedp; i++) {
+        if (fdset[i].fd == fd) { /* 1 */
+            if (i < (*fdset_usedp - 1)) { /* 2 */
+                memmove(&fdset[i], &fdset[i+1], (*fdset_usedp - 1) * sizeof(struct pollfd)); /* 3 */
+                memmove(&polldata[i], &polldata[i+1], (*fdset_usedp - 1) * sizeof(struct polldata)); /* 3 */
+            }
+            (*fdset_usedp)--;
+            break;
+        }
+    }
+}
+
+/* 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
+
+/*
+ * Receive a fd on a suitable socket
+ * @args fd          (r) PF_UNIX socket to receive on
+ * @args nonblocking (r) 0: fd is in blocking mode - 1: fd is nonblocking, poll for 1 sec
+ * @returns fd on success, -1 on error
+ */
+int recv_fd(int fd, int nonblocking)
+{
+    int ret;
+    struct msghdr msgh;
+    struct iovec iov[1];
+    struct cmsghdr *cmsgp = NULL;
+    char buf[CMSG_SPACE(sizeof(int))];
+    char dbuf[80];
+    struct pollfd pollfds[1];
+
+    pollfds[0].fd = fd;
+    pollfds[0].events = POLLIN;
+
+    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);
+
+    if (nonblocking) {
+        do {
+            ret = poll(pollfds, 1, 2000); /* poll 2 seconds, evtl. multipe times (EINTR) */
+        } while ( ret == -1 && errno == EINTR );
+        if (ret != 1)
+            return -1;
+        ret = recvmsg(fd, &msgh, 0);
+    } else {
+        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;
+}
+
+/*
+ * Send a fd across a suitable socket
+ */
+int send_fd(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;
+}
diff --git a/libatalk/util/test/.gitignore b/libatalk/util/test/.gitignore
deleted file mode 100644 (file)
index 3dd6d8e..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-Makefile
-Makefile.in
-logger_test
-test.log
-.deps
-.libs
-
-.gitignore
-logger_test.o
diff --git a/libatalk/util/test/Makefile.am b/libatalk/util/test/Makefile.am
deleted file mode 100644 (file)
index 569936b..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-bin_PROGRAMS = logger_test
-
-logger_test_SOURCES = logger_test.c
-logger_test_LDADD =  $(top_builddir)/libatalk/util/libutil.la
diff --git a/libatalk/util/test/logger_test.c b/libatalk/util/test/logger_test.c
deleted file mode 100644 (file)
index a968cce..0000000
+++ /dev/null
@@ -1,94 +0,0 @@
-#include <stdio.h>
-
-#include <atalk/boolean.h>
-#include <atalk/logger.h>
-
-int main(int argc, char *argv[])
-{
-  set_processname("logger_Test");
-#if 0
-  LOG(log_severe, logtype_logger, "Logging Test starting: this should only log to syslog");
-
-  /* syslog testing */
-  LOG(log_severe, logtype_logger, "Disabling syslog logging.");
-  unsetuplog("Default");
-  LOG(log_error, logtype_default, "This shouldn't log to syslog: LOG(log_error, logtype_default).");
-  LOG(log_error, logtype_logger, "This shouldn't log to syslog: LOG(log_error, logtype_logger).");
-  setuplog("Default LOG_INFO");
-  LOG(log_info, logtype_logger, "Set syslog logging to 'log_info', so this should log again. LOG(log_info, logtype_logger).");
-  LOG(log_error, logtype_logger, "This should log to syslog: LOG(log_error, logtype_logger).");
-  LOG(log_error, logtype_default, "This should log to syslog. LOG(log_error, logtype_default).");
-  LOG(log_debug, logtype_logger, "This shouldn't log to syslog. LOG(log_debug, logtype_logger).");
-  LOG(log_debug, logtype_default, "This shouldn't log to syslog. LOG(log_debug, logtype_default).");
-  LOG(log_severe, logtype_logger, "Disabling syslog logging.");
-  unsetuplog("Default");
-#endif
-  /* filelog testing */
-
-  setuplog("DSI log_maxdebug test.log");
-  LOG(log_info, logtype_dsi, "This should log.");
-  LOG(log_error, logtype_default, "This should not log.");
-
-  setuplog("Default log_debug test.log");
-  LOG(log_debug, logtype_default, "This should log.");
-  LOG(log_maxdebug, logtype_default, "This should not log.");
-
-  LOG(log_maxdebug, logtype_dsi, "This should still log.");
-
-  /* flooding prevention check */
-  LOG(log_debug, logtype_default, "Flooding 3x");
-  for (int i = 0; i < 3; i++) {
-      LOG(log_debug, logtype_default, "Flooding...");
-  }
-  /* wipe the array */
-  LOG(log_debug, logtype_default, "1"); LOG(log_debug, logtype_default, "2"); LOG(log_debug, logtype_default, "3");
-
-  LOG(log_debug, logtype_default, "-============");
-  LOG(log_debug, logtype_default, "Flooding 5x");
-  for (int i = 0; i < 5; i++) {
-      LOG(log_debug, logtype_default, "Flooding...");
-  }
-  LOG(log_debug, logtype_default, "1"); LOG(log_debug, logtype_default, "2"); LOG(log_debug, logtype_default, "3");
-
-  LOG(log_debug, logtype_default, "o============");
-  LOG(log_debug, logtype_default, "Flooding 2005x");
-  for (int i = 0; i < 2005; i++) {
-      LOG(log_debug, logtype_default, "Flooding...");
-  }
-  LOG(log_debug, logtype_default, "1"); LOG(log_debug, logtype_default, "2"); LOG(log_debug, logtype_default, "3");
-
-  LOG(log_debug, logtype_default, "0============");
-  LOG(log_debug, logtype_default, "Flooding 11x1");
-  for (int i = 0; i < 11; i++) {
-      LOG(log_error, logtype_default, "flooding 11x1 1");
-  }
-
-  LOG(log_debug, logtype_default, "1============");
-  LOG(log_debug, logtype_default, "Flooding 11x2");
-  for (int i = 0; i < 11; i++) {
-      LOG(log_error, logtype_default, "flooding 11x2 1");
-      LOG(log_error, logtype_default, "flooding 11x2 2");
-  }
-
-  LOG(log_debug, logtype_default, "2============");
-  LOG(log_debug, logtype_default, "Flooding 11x3");
-  for (int i = 0; i < 11; i++) {
-      LOG(log_error, logtype_default, "flooding 11x3 1");
-      LOG(log_error, logtype_default, "flooding 11x3 2");
-      LOG(log_error, logtype_default, "flooding 11x3 3");
-  }
-
-  LOG(log_debug, logtype_default, "3============");
-  LOG(log_debug, logtype_default, "Flooding 11x4");
-  for (int i = 0; i < 11; i++) {
-      LOG(log_error, logtype_default, "flooding 11x4 1");
-      LOG(log_error, logtype_default, "flooding 11x4 2");
-      LOG(log_error, logtype_default, "flooding 11x4 3");
-      LOG(log_error, logtype_default, "flooding 11x4 4");
-  }
-
-
-  return 0;
-}
-
-
index 6231a03782c538809dd632593c0796bd9e57fc9a..9e71fcb4b71a3b7fd53479c4cebc2cef7cb3bb30 100644 (file)
@@ -1,5 +1,4 @@
 /*
-  $Id: unix.c,v 1.6 2010-02-28 22:29:16 didg Exp $
   Copyright (c) 2010 Frank Lahm <franklahm@gmail.com>
 
   This program is free software; you can redistribute it and/or modify
@@ -31,6 +30,8 @@
 #include <sys/stat.h>
 #include <fcntl.h>
 #include <dirent.h>
+#include <sys/time.h>
+#include <time.h>
 
 #include <atalk/adouble.h>
 #include <atalk/ea.h>
@@ -56,6 +57,26 @@ const char *getcwdpath(void)
         return strerror(errno);
 }
 
+/*!
+ * Takes a buffer with a path, strips slashs, returns basename
+ *
+ * @param p (rw) path
+ *        path may be
+ *          "[/][dir/[...]]file"
+ *        or
+ *          "[/][dir/[...]]dir/[/]"
+ *        Result is "file" or "dir" 
+ *
+ * @returns pointer to basename in path buffer, buffer is possibly modified
+ */
+char *stripped_slashes_basename(char *p)
+{
+    int i = strlen(p) - 1;
+    while (i > 0 && p[i] == '/')
+        p[i--] = 0;
+    return (strrchr(p, '/') ? strrchr(p, '/') + 1 : p);
+}
+
 /*!
  * @brief symlink safe chdir replacement
  *
@@ -129,3 +150,33 @@ int lchdir(const char *dir)
 
     return 0;
 }
+
+/*!
+ * Store n random bytes an buf
+ */
+void randombytes(void *buf, int n)
+{
+    char *p = (char *)buf;
+    int fd, i;
+    struct timeval tv;
+
+    if ((fd = open("/dev/urandom", O_RDONLY)) != -1) {
+        /* generate from /dev/urandom */
+        if (read(fd, buf, n) != n) {
+            close(fd);
+            fd = -1;
+        } else {
+            close(fd);
+            /* fd now != -1, so srandom wont be called below */
+        }
+    }
+
+    if (fd == -1) {
+        gettimeofday(&tv, NULL);
+        srandom((unsigned int)tv.tv_usec);
+        for (i=0 ; i < n ; i++)
+            p[i] = random() & 0xFF;
+    }
+
+    return;
+}
index ef438c5d278f5b103a968e8e41953c9cad4d5021..62afbc6559b490aa0d6c62a76380bc170aefe0c5 100644 (file)
@@ -139,16 +139,32 @@ static char * make_path_absolute(char *path, size_t bufsize)
     char       abspath[MAXPATHLEN];
     char       *p;
 
-    if (stat(path, &st) != 0) {
-        return NULL;
-    }
+    strlcpy(abspath, path, sizeof(abspath));
+
+    /* we might be called from `ad cp ...` with non existing target */
+    if (stat(abspath, &st) != 0) {
+        if (errno != ENOENT)
+            return NULL;
+
+        if (NULL == (p = strrchr(abspath, '/')) )
+            /* single component `ad cp SOURCEFILE TARGETFILE`, use "." instead */
+            strcpy(abspath, ".");
+        else
+            /* try without the last path element */
+            *p = '\0';
 
-    strlcpy (abspath, path, sizeof(abspath));
+        if (stat(abspath, &st) != 0) {
+            return NULL;
+        }
+    }
 
-    if (!S_ISDIR(st.st_mode)) {
-        if (NULL == (p=strrchr(abspath, '/')) )
+    if (S_ISREG(st.st_mode)) {
+        /* single file copy SOURCE */
+        if (NULL == (p = strrchr(abspath, '/')) )
+            /* no path, use "." instead */
             strcpy(abspath, ".");
         else
+            /* try without the last path element */
             *p = '\0';
     }
 
@@ -272,14 +288,16 @@ static int parseline ( char *buf, struct volinfo *vol)
         }
         break;
       case CNIDDBDPORT:
-        vol->v_dbd_port = atoi(value);
-        break;
-      case CNID_DBPATH:
-        if ((vol->v_dbpath = strdup(value)) == NULL) {
+        if ((vol->v_dbd_port = strdup(value)) == NULL) {
            fprintf (stderr, "strdup: %s", strerror(errno));
-            return -1;
+            return -1;            
         }
         break;
+      case CNID_DBPATH:
+          if ((vol->v_dbpath = malloc(MAXPATHLEN+1)) == NULL)
+              return -1;
+          strcpy(vol->v_dbpath, value);
+        break;
       case ADOUBLE_VER:
         if (strcasecmp(value, "v1") == 0) {
             vol->v_adouble = AD_VERSION1;
@@ -328,7 +346,7 @@ int loadvolinfo (char *path, struct volinfo *vol)
     char   volinfofile[MAXPATHLEN];
     char   buf[MAXPATHLEN];
     struct flock lock;
-    int    fd;
+    int    fd, len;
     FILE   *fp;
 
     if ( !path || !vol)
@@ -342,9 +360,16 @@ int loadvolinfo (char *path, struct volinfo *vol)
         return -1;
 
     if ((vol->v_path = strdup(volinfofile)) == NULL ) {
-       fprintf (stderr, "strdup: %s", strerror(errno));
+        fprintf (stderr, "strdup: %s", strerror(errno));
         return (-1);
     }
+    /* Remove trailing slashes */
+    len = strlen(vol->v_path);
+    while (len && (vol->v_path[len-1] == '/')) {
+        vol->v_path[len-1] = 0;
+        len--;
+    }
+
     strlcat(volinfofile, ".AppleDesktop/", sizeof(volinfofile));
     strlcat(volinfofile, VOLINFOFILE, sizeof(volinfofile));
 
@@ -387,10 +412,63 @@ int loadvolinfo (char *path, struct volinfo *vol)
     if ((vol->v_flags & AFPVOL_INV_DOTS))
         vol->v_ad_options |= ADVOL_INVDOTS;
 
+    vol->retaincount = 1;
+
     fclose(fp);
     return 0;
 }
 
+/*!
+ * Allocate a struct volinfo object for refcounting usage with retain and close, and
+ * call loadvolinfo with it
+ */
+struct volinfo *allocvolinfo(char *path)
+{
+    struct volinfo *p = malloc(sizeof(struct volinfo));
+    if (p == NULL)
+        return NULL;
+
+    if (loadvolinfo(path, p) == -1)
+        return NULL;
+
+    p->malloced = 1;
+
+    return p;
+}
+
+void retainvolinfo(struct volinfo *vol)
+{
+    vol->retaincount++;
+}
+
+/*!
+ * Decrement retain count, free resources when retaincount reaches 0
+ */
+int closevolinfo(struct volinfo *volinfo)
+{
+    if (volinfo->retaincount <= 0)
+        abort();
+
+    volinfo->retaincount--;
+
+    if (volinfo->retaincount == 0) {
+        free(volinfo->v_name); volinfo->v_name = NULL;
+        free(volinfo->v_path); volinfo->v_path = NULL;
+        free(volinfo->v_cnidscheme); volinfo->v_cnidscheme = NULL;
+        free(volinfo->v_dbpath); volinfo->v_dbpath = NULL;
+        free(volinfo->v_volcodepage); volinfo->v_volcodepage = NULL;
+        free(volinfo->v_maccodepage); volinfo->v_maccodepage = NULL;
+        free(volinfo->v_dbd_host); volinfo->v_dbd_host = NULL;
+        free(volinfo->v_dbd_port); volinfo->v_dbd_port = NULL;
+        if (volinfo->malloced) {
+            volinfo->malloced = 0;
+            free(volinfo);
+        }
+    }
+
+    return 0;
+}
+
 /*
  * 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.
index d48caa315961ace34097d50d2118518a848b3f23..9b8d14374c8e4fbb6aeaa86716ce7aff2af73c09 100644 (file)
@@ -1,10 +1,9 @@
-
-# Makefile.am for libatalk/adouble/
+# Makefile.am for libatalk/vfs/
 
 noinst_LTLIBRARIES = libvfs.la
 
 libvfs_la_SOURCES = vfs.c unix.c ea.c sys_ea.c ea_sys.c
 
-if USE_NFSv4_ACLS
+if HAVE_ACLS
 libvfs_la_SOURCES += acl.c
 endif
index d9c7d1f6e5132a09bdea970d886183ef39f5b0af..1396ce34c809d98e5083f1b96ba16fe49180f266 100644 (file)
@@ -1,5 +1,6 @@
 /*
   Copyright (c) 2009 Frank Lahm <franklahm@gmail.com>
+  Copyright (c) 2010 Frank Lahm <franklahm@gmail.com>
 
   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
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
-#include <sys/acl.h>
 
 #include <atalk/afp.h>
 #include <atalk/util.h>
 #include <atalk/logger.h>
+#include <atalk/errchk.h>
+#include <atalk/acl.h>
+
+#ifdef HAVE_SOLARIS_ACLS
 
 /* Removes all non-trivial ACLs from object. Returns full AFPERR code. */
-int remove_acl(const char *name)
+int remove_acl_vfs(const char *name)
 {
     int ret,i, ace_count, trivial_aces, new_aces_count;
     ace_t *old_aces = NULL;
@@ -81,3 +85,51 @@ exit:
     LOG(log_debug9, logtype_afpd, "remove_acl: END");
     return ret;
 }
+
+#endif  /* HAVE_SOLARIS_ACLS */
+
+#ifdef HAVE_POSIX_ACLS
+/*!
+ * Remove any ACL_USER, ACL_GROUP or ACL_TYPE_DEFAULT ACEs from an object
+ *
+ * @param name  (r) filesystem object name
+ *
+ * @returns AFP error code, AFP_OK (= 0) on success, AFPERR_MISC on error
+ */
+int remove_acl_vfs(const char *name)
+{
+    EC_INIT;
+
+    struct stat st;
+    acl_t acl = NULL;
+    acl_entry_t e;
+    acl_tag_t tag;
+    int entry_id = ACL_FIRST_ENTRY;
+
+
+    /* Remove default ACL if it's a dir */
+    EC_ZERO_LOG_ERR(stat(name, &st), AFPERR_MISC);
+    if (S_ISDIR(st.st_mode)) {
+        EC_NULL_LOG_ERR(acl = acl_init(0), AFPERR_MISC);
+        EC_ZERO_LOG_ERR(acl_set_file(name, ACL_TYPE_DEFAULT, acl), AFPERR_MISC);
+        EC_ZERO_LOG_ERR(acl_free(acl), AFPERR_MISC);
+        acl = NULL;
+    }
+
+    /* Now get ACL and remove ACL_USER or ACL_GROUP entries, then re-set the ACL again */
+    EC_NULL_LOG_ERR(acl = acl_get_file(name, ACL_TYPE_ACCESS), AFPERR_MISC);
+    for ( ; acl_get_entry(acl, entry_id, &e) == 1; entry_id = ACL_NEXT_ENTRY) {
+        EC_ZERO_LOG_ERR(acl_get_tag_type(e, &tag), AFPERR_MISC);
+        if (tag == ACL_USER || tag == ACL_GROUP)
+            EC_ZERO_LOG_ERR(acl_delete_entry(acl, e), AFPERR_MISC);
+    }
+    EC_ZERO_LOG_ERR(acl_calc_mask(&acl), AFPERR_MISC);
+    EC_ZERO_LOG_ERR(acl_valid(acl), AFPERR_MISC);
+    EC_ZERO_LOG_ERR(acl_set_file(name, ACL_TYPE_ACCESS, acl), AFPERR_MISC);
+
+EC_CLEANUP:
+    if (acl) acl_free(acl);
+
+    EC_EXIT;
+}
+#endif /* HAVE_POSIX_ACLS */
index a60b08a403ce1cbea5cb70e9b9cca5e6cb9ada3e..a43794e139550b0a6513602e3b7d82684eb78874 100644 (file)
@@ -1,9 +1,6 @@
 /*
- * $Id: unix.c,v 1.11 2010-04-18 16:14:51 hat001 Exp $
- *
  * Copyright (c) 1990,1993 Regents of The University of Michigan.
  * All Rights Reserved.  See COPYRIGHT.
- *
  */
 
 #ifdef HAVE_CONFIG_H
@@ -215,7 +212,7 @@ int copy_file(int dirfd, const char *src, const char *dst, mode_t mode)
         return -1;
     }
 
-    if ((dfd = open(dst, O_WRONLY | O_CREAT | O_EXCL, mode)) < 0) {
+    if ((dfd = open(dst, O_WRONLY | O_CREAT | O_TRUNC, mode)) < 0) {
         LOG(log_error, logtype_afpd, "copy_file('%s'/'%s'): open '%s' error: %s",
             src, dst, dst, strerror(errno));
         ret = -1;
index dadedc5bbee20c21ac384b0ee7d19f435656c069..3156afe33191433b0ac43cf7db77d1cb4d05e43e 100644 (file)
 #include "config.h"
 #endif /* HAVE_CONFIG_H */
 
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
 #include <string.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <libgen.h>
 
 #include <atalk/afp.h>    
 #include <atalk/adouble.h>
@@ -35,6 +39,9 @@
 #include <atalk/vfs.h>
 #include <atalk/directory.h>
 #include <atalk/unix.h>
+#include <atalk/errchk.h>
+#include <atalk/bstrlib.h>
+#include <atalk/bstradd.h>
 
 struct perm {
     uid_t uid;
@@ -320,7 +327,67 @@ static int RF_renamefile_adouble(VFS_FUNC_ARGS_RENAMEFILE)
        return 0;
 }
 
-#ifdef HAVE_NFSv4_ACLS
+static int RF_copyfile_adouble(VFS_FUNC_ARGS_COPYFILE)
+/* const struct vol *vol, int sfd, const char *src, const char *dst */
+{
+    EC_INIT;
+    bstring s = NULL, d = NULL;
+    char *dup1 = NULL;
+    char *dup2 = NULL;
+    char *dup3 = NULL;
+    char *dup4 = NULL;
+    const char *name = NULL;
+    const char *dir = NULL;
+
+    struct stat st;
+    EC_ZERO(stat(dst, &st));
+
+    if (S_ISDIR(st.st_mode)) {
+        /* build src path to AppleDouble file*/
+        EC_NULL(s = bfromcstr(src));
+        EC_ZERO(bcatcstr(s, "/.AppleDouble/.Parent"));
+
+        /* build dst path to AppleDouble file*/
+        EC_NULL(d = bfromcstr(dst));
+        EC_ZERO(bcatcstr(d, "/.AppleDouble/.Parent"));
+    } else {
+        /* get basename */
+
+        /* build src path to AppleDouble file*/
+        EC_NULL(dup1 = strdup(src));
+        EC_NULL(name = basename(strdup(dup1)));
+
+        EC_NULL(dup2 = strdup(src));
+        EC_NULL(dir = dirname(dup2));
+        EC_NULL(s = bfromcstr(dir));
+        EC_ZERO(bcatcstr(s, "/.AppleDouble/"));
+        EC_ZERO(bcatcstr(s, name));
+
+        /* build dst path to AppleDouble file*/
+        EC_NULL(dup4 = strdup(dst));
+        EC_NULL(name = basename(strdup(dup4)));
+
+        EC_NULL(dup3 = strdup(dst));
+        EC_NULL(dir = dirname(dup3));
+        EC_NULL(d = bfromcstr(dir));
+        EC_ZERO(bcatcstr(d, "/.AppleDouble/"));
+        EC_ZERO(bcatcstr(d, name));
+    }
+
+    EC_ZERO(copy_file(sfd, cfrombstr(s), cfrombstr(d), 0666));
+
+EC_CLEANUP:
+    bdestroy(s);
+    bdestroy(d);
+    if (dup1) free(dup1);
+    if (dup2) free(dup2);
+    if (dup3) free(dup3);
+    if (dup4) free(dup4);
+
+    EC_EXIT;
+}
+
+#ifdef HAVE_SOLARIS_ACLS
 static int RF_solaris_acl(VFS_FUNC_ARGS_ACL)
 {
     static char buf[ MAXPATHLEN + 1];
@@ -358,20 +425,74 @@ static int RF_solaris_remove_acl(VFS_FUNC_ARGS_REMOVE_ACL)
        if (len < 0 || len >=  MAXPATHLEN)
            return AFPERR_MISC;
        /* remove ACL from .AppleDouble/.Parent first */
-       if ((ret = remove_acl(vol->ad_path(path, ADFLAGS_DIR))) != AFP_OK)
+       if ((ret = remove_acl_vfs(vol->ad_path(path, ADFLAGS_DIR))) != AFP_OK)
            return ret;
        /* now remove from .AppleDouble dir */
-       if ((ret = remove_acl(buf)) != AFP_OK)
+       if ((ret = remove_acl_vfs(buf)) != AFP_OK)
            return ret;
     } else
        /* remove ACL from ressource fork */
-       if ((ret = remove_acl(vol->ad_path(path, ADFLAGS_HF))) != AFP_OK)
+       if ((ret = remove_acl_vfs(vol->ad_path(path, ADFLAGS_HF))) != AFP_OK)
            return ret;
 
     return AFP_OK;
 }
 #endif
 
+#ifdef HAVE_POSIX_ACLS
+static int RF_posix_acl(VFS_FUNC_ARGS_ACL)
+{
+    EC_INIT;
+    static char buf[ MAXPATHLEN + 1];
+    struct stat st;
+    int len;
+
+    if (S_ISDIR(st.st_mode)) {
+        len = snprintf(buf, MAXPATHLEN, "%s/.AppleDouble",path);
+        if (len < 0 || len >=  MAXPATHLEN)
+            EC_FAIL;
+        /* set acl on .AppleDouble dir first */
+        EC_ZERO_LOG(acl_set_file(buf, type, acl));
+
+        if (type == ACL_TYPE_ACCESS)
+            /* set ACL on ressource fork (".Parent") too */
+            EC_ZERO_LOG(acl_set_file(vol->ad_path(path, ADFLAGS_DIR), type, acl));
+    } else {
+        /* set ACL on ressource fork */
+        EC_ZERO_LOG(acl_set_file(vol->ad_path(path, ADFLAGS_HF), type, acl));
+    }
+    
+EC_CLEANUP:
+    if (ret != 0)
+        return AFPERR_MISC;
+    return AFP_OK;
+}
+
+static int RF_posix_remove_acl(VFS_FUNC_ARGS_REMOVE_ACL)
+{
+    EC_INIT;
+    static char buf[ MAXPATHLEN + 1];
+    int len;
+
+    if (dir) {
+        len = snprintf(buf, MAXPATHLEN, "%s/.AppleDouble",path);
+        if (len < 0 || len >=  MAXPATHLEN)
+            return AFPERR_MISC;
+        /* remove ACL from .AppleDouble/.Parent first */
+        EC_ZERO_LOG_ERR(remove_acl_vfs(vol->ad_path(path, ADFLAGS_DIR)), AFPERR_MISC);
+
+        /* now remove from .AppleDouble dir */
+        EC_ZERO_LOG_ERR(remove_acl_vfs(buf), AFPERR_MISC);
+    } else {
+        /* remove ACL from ressource fork */
+        EC_ZERO_LOG_ERR(remove_acl_vfs(vol->ad_path(path, ADFLAGS_HF)), AFPERR_MISC);
+    }
+
+EC_CLEANUP:
+    EC_EXIT;
+}
+#endif
+
 /*********************************************************************************
  * sfm adouble format
  *********************************************************************************/
@@ -839,8 +960,10 @@ VFS_MFUNC(setdirowner, VFS_FUNC_ARGS_SETDIROWNER, VFS_FUNC_VARS_SETDIROWNER)
 VFS_MFUNC(deletefile, VFS_FUNC_ARGS_DELETEFILE, VFS_FUNC_VARS_DELETEFILE)
 VFS_MFUNC(renamefile, VFS_FUNC_ARGS_RENAMEFILE, VFS_FUNC_VARS_RENAMEFILE)
 VFS_MFUNC(copyfile, VFS_FUNC_ARGS_COPYFILE, VFS_FUNC_VARS_COPYFILE)
+#ifdef HAVE_ACLS
 VFS_MFUNC(acl, VFS_FUNC_ARGS_ACL, VFS_FUNC_VARS_ACL)
 VFS_MFUNC(remove_acl, VFS_FUNC_ARGS_REMOVE_ACL, VFS_FUNC_VARS_REMOVE_ACL)
+#endif
 VFS_MFUNC(ea_getsize, VFS_FUNC_ARGS_EA_GETSIZE, VFS_FUNC_VARS_EA_GETSIZE)
 VFS_MFUNC(ea_getcontent, VFS_FUNC_ARGS_EA_GETCONTENT, VFS_FUNC_VARS_EA_GETCONTENT)
 VFS_MFUNC(ea_list, VFS_FUNC_ARGS_EA_LIST, VFS_FUNC_VARS_EA_LIST)
@@ -868,8 +991,10 @@ static struct vfs_ops vfs_master_funcs = {
     vfs_deletefile,
     vfs_renamefile,
     vfs_copyfile,
+#ifdef HAVE_ACLS
     vfs_acl,
     vfs_remove_acl,
+#endif
     vfs_ea_getsize,
     vfs_ea_getcontent,
     vfs_ea_list,
@@ -892,7 +1017,7 @@ static struct vfs_ops netatalk_adouble = {
     /* vfs_setdirowner:   */ RF_setdirowner_adouble,
     /* vfs_deletefile:    */ RF_deletefile_adouble,
     /* vfs_renamefile:    */ RF_renamefile_adouble,
-    /* vfs_copyfile:      */ NULL,
+    /* vfs_copyfile:      */ RF_copyfile_adouble,
     NULL
 };
 
@@ -943,8 +1068,10 @@ static struct vfs_ops netatalk_ea_adouble = {
     /* vfs_deletefile:    */ ea_deletefile,
     /* vfs_renamefile:    */ ea_renamefile,
     /* vfs_copyfile       */ ea_copyfile,
+#ifdef HAVE_ACLS
     /* vfs_acl:           */ NULL,
     /* vfs_remove_acl     */ NULL,
+#endif
     /* vfs_getsize        */ get_easize,
     /* vfs_getcontent     */ get_eacontent,
     /* vfs_list           */ list_eas,
@@ -964,8 +1091,10 @@ static struct vfs_ops netatalk_ea_sys = {
     /* rf_deletefile:     */ NULL,
     /* rf_renamefile:     */ NULL,
     /* vfs_copyfile:      */ sys_ea_copyfile,
+#ifdef HAVE_ACLS
     /* rf_acl:            */ NULL,
     /* rf_remove_acl      */ NULL,
+#endif
     /* ea_getsize         */ sys_get_easize,
     /* ea_getcontent      */ sys_get_eacontent,
     /* ea_list            */ sys_list_eas,
@@ -977,7 +1106,7 @@ static struct vfs_ops netatalk_ea_sys = {
  * Tertiary VFS modules for ACLs
  */
 
-#ifdef HAVE_NFSv4_ACLS
+#ifdef HAVE_SOLARIS_ACLS
 static struct vfs_ops netatalk_solaris_acl_adouble = {
     /* validupath:        */ NULL,
     /* rf_chown:          */ NULL,
@@ -996,6 +1125,25 @@ static struct vfs_ops netatalk_solaris_acl_adouble = {
 };
 #endif
 
+#ifdef HAVE_POSIX_ACLS
+static struct vfs_ops netatalk_posix_acl_adouble = {
+    /* validupath:        */ NULL,
+    /* rf_chown:          */ NULL,
+    /* rf_renamedir:      */ NULL,
+    /* rf_deletecurdir:   */ NULL,
+    /* rf_setfilmode:     */ NULL,
+    /* rf_setdirmode:     */ NULL,
+    /* rf_setdirunixmode: */ NULL,
+    /* rf_setdirowner:    */ NULL,
+    /* rf_deletefile:     */ NULL,
+    /* rf_renamefile:     */ NULL,
+    /* vfs_copyfile       */ NULL,
+    /* rf_acl:            */ RF_posix_acl,
+    /* rf_remove_acl      */ RF_posix_remove_acl,
+    NULL
+};
+#endif
+
 /* ---------------- */
 void initvol_vfs(struct vol *vol)
 {
@@ -1027,7 +1175,11 @@ void initvol_vfs(struct vol *vol)
     }
 
     /* ACLs */
-#ifdef HAVE_NFSv4_ACLS
+#ifdef HAVE_SOLARIS_ACLS
     vol->vfs_modules[2] = &netatalk_solaris_acl_adouble;
 #endif
+#ifdef HAVE_POSIX_ACLS
+    vol->vfs_modules[2] = &netatalk_posix_acl_adouble;
+#endif
+
 }
index 7b3c64edecdb1e62bf586399cc6e98de652231a8..081d27be75f28222122d1fb283ef21b24cdd4f44 100644 (file)
@@ -161,8 +161,10 @@ AC_DEFUN([AC_PATH_BDB],[
                             break;
                         fi
 
-                        dnl -- Search for 64bit lib in "lib" too
-                        if test x"$atalk_libname" = x"lib64" ; then
+                        dnl -- Search lib in "lib" too, as $atalk_libname might be set
+                        dnl -- to "lib64" or "lib/64" which would not be found above
+                        dnl -- if 64bit lib were installed in a dir named "lib"
+                        if test x"$atalk_libname" != x"lib" ; then
                            bdblibdir="${bdbdir}/lib"
                            bdbbindir="${bdbdir}/bin"
 
index 78ffb3eae7f3a7b12f052550c89e5065795a9a98..7673d4822589523e6eafb14e3d2050e02bf15b0c 100644 (file)
@@ -16,7 +16,6 @@ AC_DEFUN([AC_NETATALK_CONFIG_SUMMARY], [
                AC_MSG_RESULT([         Large file support (>2GB) for AFP3: $wx_largefile])
        fi
        AC_MSG_RESULT([         Extended Attributes: $neta_cv_eas])
-       AC_MSG_RESULT([         DDP enabled: $netatalk_cv_ddp_enabled])
        AC_MSG_RESULT([    CNID:])
        AC_MSG_RESULT([         backends: $compiled_backends])
        AC_MSG_RESULT([    UAMS:])
@@ -48,20 +47,22 @@ AC_DEFUN([AC_NETATALK_CONFIG_SUMMARY], [
        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])
+       AC_MSG_RESULT([         DDP (AppleTalk) support: $netatalk_cv_ddp_enabled])
+       AC_MSG_RESULT([         CUPS support:            $netatalk_cv_use_cups])
+       AC_MSG_RESULT([         SLP support:             $netatalk_cv_srvloc])
+       AC_MSG_RESULT([         Zeroconf support:        $netatalk_cv_zeroconf])
+       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            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])
-       AC_MSG_RESULT([         ACL support:            $neta_cv_nfsv4acl])
+       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])
+       AC_MSG_RESULT([         ACL support:             $with_acl_support])
        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])
diff --git a/macros/zeroconf.m4 b/macros/zeroconf.m4
new file mode 100644 (file)
index 0000000..788a193
--- /dev/null
@@ -0,0 +1,71 @@
+dnl Check for optional Zeroconf support
+
+AC_DEFUN([NETATALK_ZEROCONF], [
+       ZEROCONF_LIBS=""
+       ZEROCONF_CFLAGS=""
+       found_zeroconf=no
+       zeroconf_dir=""
+
+       AC_ARG_ENABLE(zeroconf,
+               [  --enable-zeroconf[[=DIR]]   enable Zeroconf support [[auto]]],
+               [zeroconf=$enableval],
+               [zeroconf=try]
+       )
+
+    dnl make sure atalk_libname is defined beforehand
+    [[ -n "$atalk_libname" ]] || AC_MSG_ERROR([internal error, atalk_libname undefined])
+
+       if test "x$zeroconf" != "xno"; then
+               savedcppflags="$CPPFLAGS"
+               savedldflags="$LDFLAGS"
+
+               if test "x$zeroconf" = "xyes" -o "x$zeroconf" = "xtry"; then
+                       zeroconf_dir="/usr"
+               else
+                       zeroconf_dir="$zeroconf"
+               fi
+
+    # mDNS support using Avahi
+    AC_CHECK_HEADER(
+        avahi-client/client.h,
+        AC_CHECK_LIB(
+           avahi-client,
+           avahi_client_new,
+           AC_DEFINE(USE_ZEROCONF, 1, [Use DNS-SD registration]))
+    )
+
+    case "$ac_cv_lib_avahi_client_avahi_client_new" in
+      yes)
+      PKG_CHECK_MODULES(AVAHI, [ avahi-client >= 0.6 ])
+      PKG_CHECK_MODULES(AVAHI_TPOLL, [ avahi-client >= 0.6.4 ],
+        [AC_DEFINE(HAVE_AVAHI_THREADED_POLL, 1, [Uses Avahis threaded poll implementation])],
+        [AC_MSG_WARN(This Avahi implementation is not supporting threaded poll objects. Maybe this is not what you want.)])
+      ZEROCONF_LIBS="$AVAHI_LIBS"
+      ZEROCONF_CFLAGS="$AVAHI_CFLAGS"
+      AC_DEFINE(HAVE_AVAHI, 1, [Use Avahi/DNS-SD registration])
+      found_zeroconf=yes
+      ;;
+    esac
+
+               CPPFLAGS="$savedcppflags"
+               LDFLAGS="$savedldflags"
+       fi
+       
+       netatalk_cv_zeroconf=no
+       AC_MSG_CHECKING([whether to enable Zerconf support])
+       if test "x$found_zeroconf" = "xyes"; then
+               AC_MSG_RESULT([yes])
+               AC_DEFINE(USE_ZEROCONF, 1, [Define to enable Zeroconf support])
+               netatalk_cv_zeroconf=yes
+       else
+               AC_MSG_RESULT([no])
+               if test "x$zeroconf" != "xno" -a "x$zeroconf" != "xtry"; then
+                       AC_MSG_ERROR([Zeroconf installation not found])
+               fi
+       fi
+
+       LIB_REMOVE_USR_LIB(ZEROCONF_LIBS)
+       CFLAGS_REMOVE_USR_INCLUDE(ZEROCONF_CFLAGS)
+       AC_SUBST(ZEROCONF_LIBS)
+       AC_SUBST(ZEROCONF_CFLAGS)
+])
index a9e39c1529d58bf570aeaad927bf3709c5631fe5..b3e6bdb54cab3b740bcb197136ba688cab1add3d 100644 (file)
@@ -12,35 +12,34 @@ SUFFIXES= .tmpl .
            -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  \
-                               ad.1 \
-                               aecho.1 \
-                               afile.1 \
+GENERATED_MANS = uniconv.1 asip-status.pl.1
+TEMPLATE_FILES = uniconv.1.tmpl asip-status.pl.1.tmpl
+NONGENERATED_MANS      =       ad.1 \
                                afppasswd.1 \
                                apple_dump.1 \
                                dbd.1 \
-                               getzones.1 \
                                hqx2bin.1 \
                                macbinary.1 \
                                megatron.1 \
+                               netatalk-config.1 \
+                               single2bin.1 \
+                               unbin.1 \
+                               unhex.1 \
+                               unsingle.1
+ATALK_MANS = aecho.1 \
+                               getzones.1 \
                                nbp.1 \
                                nbplkup.1 \
                                nbprgstr.1 \
                                nbpunrgstr.1 \
-                               netatalk-config.1 \
                                pap.1 \
                                papstatus.1 \
-                               psorder.1 \
-                               single2bin.1 \
-                               unbin.1 \
-                               unhex.1 \
-                               unsingle.1
+                               psorder.1
 
-man_MANS = $(GENERATED_MANS) $(NONGENERATED_MANS)
+if USE_APPLETALK
+NONGENERATED_MANS += $(ATALK_MANS)
+endif
 
+man_MANS = $(GENERATED_MANS) $(NONGENERATED_MANS)
 CLEANFILES = $(GENERATED_MANS)
-
-EXTRA_DIST = $(TEMPLATE_FILES) $(NONGENERATED_MANS)
-
+EXTRA_DIST = $(TEMPLATE_FILES) $(NONGENERATED_MANS) $(ATALK_MANS)
diff --git a/man/man1/achfile.1 b/man/man1/achfile.1
deleted file mode 100644 (file)
index 3acef04..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-'\" t
-.\"     Title: achfile
-.\"    Author: [FIXME: author] [see http://docbook.sf.net/el/author]
-.\" Generator: DocBook XSL Stylesheets v1.75.2 <http://docbook.sf.net/>
-.\"      Date: 26 Feb 1998
-.\"    Manual: Netatalk 2.1
-.\"    Source: Netatalk 2.1
-.\"  Language: English
-.\"
-.TH "ACHFILE" "1" "26 Feb 1998" "Netatalk 2.1" "Netatalk 2.1"
-.\" -----------------------------------------------------------------
-.\" * set default formatting
-.\" -----------------------------------------------------------------
-.\" disable hyphenation
-.nh
-.\" disable justification (adjust text to left margin only)
-.ad l
-.\" -----------------------------------------------------------------
-.\" * MAIN CONTENT STARTS HERE *
-.\" -----------------------------------------------------------------
-.SH "NAME"
-achfile \- change type and/or creator of Apple Macintosh files (netatalk format)
-.SH "SYNOPSIS"
-.HP \w'\fBachfile\fR\fB\fR\ 'u
-\fBachfile\fR\fB\fR [\-t\ \fItype\fR] [\-c\ \fIcreator\fR] \fIfile\fR...
-.SH "DESCRIPTION"
-.PP
-\fBachfile\fR
-changes the Macintosh type and/or creator of the
-\fIfile\fR
-arguments which have a corresponding \&.AppleDouble file\&.
-.SH "OPTIONS"
-.PP
-\fB\-t\fR
-\fItype\fR
-change the type\&.
-.PP
-\fB\-c\fR
-\fIcreator\fR
-change the creator\&.
-.SH "DIAGNOSTICS"
-.PP
-returns exit status 0 if all files changed successfully
-.SH "SEE ALSO"
-.PP
-\fBafile\fR(1),
-\fBafpd\fR(8)
index 597b4a4e5ef190f2859b7b402582c13cdebef5db..c0c3817a7d258e3278604fb6059e82aab5b1aaa5 100644 (file)
@@ -2,12 +2,12 @@
 .\"     Title: ad
 .\"    Author: [FIXME: author] [see http://docbook.sf.net/el/author]
 .\" Generator: DocBook XSL Stylesheets v1.75.2 <http://docbook.sf.net/>
-.\"      Date: 01 Sep 2009
-.\"    Manual: Netatalk 2.1
-.\"    Source: Netatalk 2.1
+.\"      Date: 12 Oct 2010
+.\"    Manual: Netatalk 2.2
+.\"    Source: Netatalk 2.2
 .\"  Language: English
 .\"
-.TH "AD" "1" "01 Sep 2009" "Netatalk 2.1" "Netatalk 2.1"
+.TH "AD" "1" "12 Oct 2010" "Netatalk 2.2" "Netatalk 2.2"
 .\" -----------------------------------------------------------------
 .\" * set default formatting
 .\" -----------------------------------------------------------------
@@ -22,7 +22,7 @@
 ad \- Netatalk compatible UNIX file utility suite\&.
 .SH "SYNOPSIS"
 .HP \w'\fBad\fR\ 'u
-\fBad\fR {ls} [\&.\&.\&.]
+\fBad\fR {ls\ |\ cp\ |\ mv\ |\ rm} [\&.\&.\&.]
 .SH "DESCRIPTION"
 .PP
 \fBad\fR
@@ -31,43 +31,204 @@ files in
 \&.AppleDouble
 directories and the CNID databases are updated as appropiate\&.
 .SH "AVAILABLE COMMANDS"
+.HP \w'\fBad\ ls\fR\ 'u
+\fBad ls\fR [\-dRl\ [u]] {file|dir\ [\&.\&.\&.]}
 .PP
-.HP \w'\fBad\ ls\fR\ 'u \fBad ls\fR [\-dRl\ [u]] {file|dir\ [\&.\&.\&.]}
+List files and directories\&.
+.HP \w'\fBad\ cp\fR\ 'u
+\fBad cp\fR [\-aipvf] {src_file} {dst_file}
+.HP \w'\fBad\ cp\ \-R\fR\ 'u
+\fBad cp \-R\fR [\-aipvf] {src_file|src_directory\ \&.\&.\&.} {dst_directory}
+.PP
+Copy files and directories\&.
+.HP \w'\fBad\ mv\fR\ 'u
+\fBad mv\fR [\-finv] {src_file} {dst_file}
+.HP \w'\fBad\ mv\fR\ 'u
+\fBad mv\fR [\-finv] {src_file|src_directory\ \&.\&.\&.} {dst_directory}
+.PP
+Move files and directories\&.
+.HP \w'\fBad\ rm\fR\ 'u
+\fBad rm\fR [\-Rv] {file|directory}
+.PP
+Remove files and directories\&.
+.SH "AD LS"
+.PP
+List files and directories\&. Options:
+.PP
+\-d
+.RS 4
+Directories are listed as plain files
+.RE
+.PP
+\-R
+.RS 4
+list subdirectories recursively
+.RE
+.PP
+\-l
+.RS 4
+Long output, list AFP info
+.RE
+.PP
+\-u
+.RS 4
+List UNIX info
+.RE
+.PP
+\fILong output description\fR
 .sp
 .if n \{\
 .RS 4
 .\}
 .nf
-\-l Long Output [\-u: unix info]:
+<unixinfo> <FinderFlags> <AFP Attributes> <Color> <Type> <Creator> <CNID from AppleDouble> <name>
+
+FinderFlags (valid for (f)iles and/or (d)irectories):
 
-   <unixinfo \&.\&.\&.> <FinderFlags> <AFPAttributes> <Color> <Type> <Creator> <CNID from AppleDouble> <name>
+  d = On Desktop                      (f/d)
+  e = Hidden extension                (f/d)
+  m = Shared (can run multiple times) (f)
+  n = No INIT resources               (f)
+  i = Inited                          (f/d)
+  c = Custom icon                     (f/d)
+  t = Stationery                      (f)
+  s = Name locked                     (f/d)
+  b = Bundle                          (f/d)
+  v = Invisible                       (f/d)
+  a = Alias file                      (f/d)
 
-   FinderFlags (valid for (f)ile and/or (d)irectory):
-     d = On Desktop (f/d)
-     e = Hidden extension (f/d)
-     m = Shared (can run multiple times) (f)
-     n = No INIT resources (f)
-     i = Inited (f/d)
-     c = Custom icon (f/d)
-     t = Stationery (f)
-     s = Name locked (f/d)
-     b = Bundle (f/d)
-     v = Invisible (f/d)
-     a = Alias file (f/d)
+AFP Attributes:
 
-   AFPAttributes:
-     y = System (f/d)
-     w = No write (f)
-     p = Needs backup (f/d)
-     r = No rename (f/d)
-     l = No delete (f/d)
-     o = No copy (f)
+  y = System                          (f/d)
+  w = No write                        (f)
+  p = Needs backup                    (f/d)
+  r = No rename                       (f/d)
+  l = No delete                       (f/d)
+  o = No copy                         (f)
 
-  Note: any letter appearing in uppercase means the flag is set but it\'s a directory for which the flag is not allowed\&.
+Note: any letter appearing in uppercase means the flag is set but it\'s a directory for which the flag is not allowed\&.
 .fi
 .if n \{\
 .RE
 .\}
+.SH "AD CP"
+.PP
+Copy files and directories\&.
+.PP
+In the first synopsis form, the cp utility copies the contents of the source_file to the target_file\&. In the second synopsis form, the contents of each named source_file is copied to the destination target_directory\&. The names of the files themselves are not changed\&. If cp detects an attempt to copy a file to itself, the copy will fail\&.
+.PP
+Netatalk AFP volumes are detected by means of their "\&.AppleDesktop" directory which is located in their volume root\&. When a copy targetting an AFP volume is detected, its CNID database daemon is connected and all copies will also go through the CNID database\&. AppleDouble files are also copied and created as needed when the target is an AFP volume\&.
+.PP
+Options:
+.PP
+\-a
+.RS 4
+Archive mode\&. Same as \-Rp\&.
+.RE
+.PP
+\-f
+.RS 4
+For each existing destination pathname, remove it and create a new file, without prompting for confirmation regardless of its permis\- sions\&. (The \-f option overrides any previous \-i or \-n options\&.)
+.RE
+.PP
+\-i
+.RS 4
+Cause cp to write a prompt to the standard error output before copying a file that would overwrite an existing file\&. If the response from the standard input begins with the character \'y\' or \'Y\', the file copy is attempted\&. (The \-i option overrides any pre\- vious \-f or \-n options\&.)
+.RE
+.PP
+\-n
+.RS 4
+Do not overwrite an existing file\&. (The \-n option overrides any previous \-f or \-i options\&.)
+.RE
+.PP
+\-p
+.RS 4
+Cause cp to preserve the following attributes of each source file in the copy: modification time, access time, file flags, file mode, user ID, and group ID, as allowed by permissions\&. If the user ID and group ID cannot be preserved, no error message is displayed and the exit value is not altered\&.
+.RE
+.PP
+\-R
+.RS 4
+If source_file designates a directory, cp copies the directory and the entire subtree connected at that point\&.If the source_file ends in a /, the contents of the directory are copied rather than the directory itself\&.
+.RE
+.PP
+\-v
+.RS 4
+Cause cp to be verbose, showing files as they are copied\&.
+.RE
+.PP
+\-x
+.RS 4
+File system mount points are not traversed\&.
+.RE
+.SH "AD MV"
+.PP
+Move files and directories\&.
+.PP
+Move files around within an AFP volume, updating the CNID database as needed\&. If either:
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+source or destination is not an AFP volume
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+source AFP volume != destination AFP volume
+.RE
+.sp
+.RE
+the files are copied and removed from the source\&.
+.PP
+Options:
+.PP
+\-f
+.RS 4
+Do not prompt for confirmation before overwriting the destination path\&. (The \-f option overrides any previous \-i or \-n options\&.)
+.RE
+.PP
+\-i
+.RS 4
+Cause mv to write a prompt to standard error before moving a file that would overwrite an existing file\&. If the response from the standard input begins with the character `y\' or `Y\', the move is attempted\&. (The \-i option overrides any previous \-f or \-n options\&.)
+.RE
+.PP
+\-n
+.RS 4
+Do not overwrite an existing file\&. (The \-n option overrides any previous \-f or \-i options\&.)
+.RE
+.PP
+\-v
+.RS 4
+Cause mv to be verbose, showing files after they are moved\&.
+.RE
+.SH "AD RM"
+.PP
+Remove files and directories\&.
+.PP
+The rm utility attempts to remove the non\-directory type files specified on the command line\&. If the files and directories reside on an AFP volume, the corresponding CNIDs are deleted from the volumes database\&.
+.PP
+The options are as follows:
+.PP
+\-R
+.RS 4
+Attempt to remove the file hierarchy rooted in each file argument\&.
+.RE
+.PP
+\-v
+.RS 4
+Be verbose when deleting files, showing them as they are removed\&.
+.RE
 .SH "REPORTING BUGS"
 .PP
 Report bugs to the Netatalk\-devel list <netatalk\-devel@lists\&.sourceforge\&.net>\&.
diff --git a/man/man1/apple_cp.1.tmpl b/man/man1/apple_cp.1.tmpl
deleted file mode 100644 (file)
index 59dd84b..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-'\" t
-.\"     Title: apple_cp
-.\"    Author: [FIXME: author] [see http://docbook.sf.net/el/author]
-.\" Generator: DocBook XSL Stylesheets v1.75.2 <http://docbook.sf.net/>
-.\"      Date: 22 Aug 2004
-.\"    Manual: Netatalk 2.1
-.\"    Source: Netatalk 2.1
-.\"  Language: English
-.\"
-.TH "APPLE_CP" "1" "22 Aug 2004" "Netatalk 2.1" "Netatalk 2.1"
-.\" -----------------------------------------------------------------
-.\" * set default formatting
-.\" -----------------------------------------------------------------
-.\" disable hyphenation
-.nh
-.\" disable justification (adjust text to left margin only)
-.ad l
-.\" -----------------------------------------------------------------
-.\" * MAIN CONTENT STARTS HERE *
-.\" -----------------------------------------------------------------
-.SH "NAME"
-apple_cp \- Do an apple copy, copying file metadata and the resource fork as well
-.SH "SYNOPSIS"
-.PP
-\fB:BINDIR:/apple_cp\fR\fB\fR
-\fISOURCE DEST\fR
-\fB:BINDIR:/apple_cp\fR
-\fISOURCE\fR\&.\&.\&.
-\fIDIRECTORY\fR
-.SH "DESCRIPTION"
-.PP
-\fBapple_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"
-.PP
-\fB:BINDIR:/apple_cp\fR
-test\&.text /target/directory/
-.PP
-\fB:BINDIR:/apple_cp\fR
-test\&.text /target/directory/test2\&.text
-.PP
-\fB:BINDIR:/apple_cp\fR
-test\&.text testing\&.text /target/directory/
-.SH "REPORTING BUGS"
-.PP
-Report bugs to the Netatalk\-devel list <netatalk\-devel@lists\&.sourceforge\&.net>\&.
-.SH "SEE ALSO"
-.PP
-\fBapple_mv\fR(1),
-\fBapple_rm\fR(1)\&.
diff --git a/man/man1/apple_mv.1.tmpl b/man/man1/apple_mv.1.tmpl
deleted file mode 100644 (file)
index e91d28c..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-'\" t
-.\"     Title: apple_mv
-.\"    Author: [FIXME: author] [see http://docbook.sf.net/el/author]
-.\" Generator: DocBook XSL Stylesheets v1.75.2 <http://docbook.sf.net/>
-.\"      Date: 22 Aug 2004
-.\"    Manual: Netatalk 2.1
-.\"    Source: Netatalk 2.1
-.\"  Language: English
-.\"
-.TH "APPLE_MV" "1" "22 Aug 2004" "Netatalk 2.1" "Netatalk 2.1"
-.\" -----------------------------------------------------------------
-.\" * set default formatting
-.\" -----------------------------------------------------------------
-.\" disable hyphenation
-.nh
-.\" disable justification (adjust text to left margin only)
-.ad l
-.\" -----------------------------------------------------------------
-.\" * MAIN CONTENT STARTS HERE *
-.\" -----------------------------------------------------------------
-.SH "NAME"
-apple_mv \- Do an apple move, moving metadata and the resource fork as well
-.SH "SYNOPSIS"
-.PP
-\fB:BINDIR:/apple_mv\fR\fB\fR
-\fISOURCE DEST\fR
-\fB:BINDIR:/apple_mv\fR
-\fISOURCE\fR\&.\&.\&.
-\fIDIRECTORY\fR
-.SH "DESCRIPTION"
-.PP
-\fBapple_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"
-.PP
-\fB:BINDIR:/apple_mv\fR
-test\&.text /target/directory/
-.PP
-\fB:BINDIR:/apple_mv\fR
-test\&.text /target/directory/test2\&.text
-.PP
-\fB:BINDIR:/apple_mv\fR
-test\&.text testing\&.text /target/directory/
-.SH "REPORTING BUGS"
-.PP
-Report bugs to the Netatalk\-devel list <netatalk\-devel@lists\&.sourceforge\&.net>\&.
-.SH "SEE ALSO"
-.PP
-\fBapple_cp\fR(1),
-\fBapple_rm\fR(1)\&.
diff --git a/man/man1/apple_rm.1.tmpl b/man/man1/apple_rm.1.tmpl
deleted file mode 100644 (file)
index 90dc0a9..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-'\" t
-.\"     Title: apple_rm
-.\"    Author: [FIXME: author] [see http://docbook.sf.net/el/author]
-.\" Generator: DocBook XSL Stylesheets v1.75.2 <http://docbook.sf.net/>
-.\"      Date: 22 Aug 2004
-.\"    Manual: Netatalk 2.1
-.\"    Source: Netatalk 2.1
-.\"  Language: English
-.\"
-.TH "APPLE_RM" "1" "22 Aug 2004" "Netatalk 2.1" "Netatalk 2.1"
-.\" -----------------------------------------------------------------
-.\" * set default formatting
-.\" -----------------------------------------------------------------
-.\" disable hyphenation
-.nh
-.\" disable justification (adjust text to left margin only)
-.ad l
-.\" -----------------------------------------------------------------
-.\" * MAIN CONTENT STARTS HERE *
-.\" -----------------------------------------------------------------
-.SH "NAME"
-apple_rm \- Do an apple remove, remove metadata and resource fork as well
-.SH "SYNOPSIS"
-.PP
-\fB:BINDIR:/apple_rm\fR\fB\fR
-\fIFILE\fR\&.\&.\&.
-.SH "DESCRIPTION"
-.PP
-\fBapple_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\&.
-\fBapple_rm\fR
-does not delete directories\&.
-.SH "EXAMPLES"
-.PP
-\fB:BINDIR:/apple_rm\fR
-test\&.text
-.PP
-\fB:BINDIR:/apple_rm\fR
-test\&.text testing\&.text
-.SH "REPORTING BUGS"
-.PP
-Report bugs to the Netatalk\-devel list <netatalk\-devel@lists\&.sourceforge\&.net>\&.
-.SH "SEE ALSO"
-.PP
-\fBapple_cp\fR(1),
-\fBapple_mv\fR(1)\&.
index 54d40ee6f2a20866c76936f10754f7354b9db869..caff254846f426d85fd1f3505ece5c5265afcd2c 100644 (file)
@@ -2,12 +2,12 @@
 .\"     Title: dbd
 .\"    Author: [FIXME: author] [see http://docbook.sf.net/el/author]
 .\" Generator: DocBook XSL Stylesheets v1.75.2 <http://docbook.sf.net/>
-.\"      Date: 23 Dec 2009
-.\"    Manual: Netatalk 2.1
-.\"    Source: Netatalk 2.1
+.\"      Date: 12 Oct 2010
+.\"    Manual: Netatalk 2.2
+.\"    Source: Netatalk 2.2
 .\"  Language: English
 .\"
-.TH "DBD" "1" "23 Dec 2009" "Netatalk 2.1" "Netatalk 2.1"
+.TH "DBD" "1" "12 Oct 2010" "Netatalk 2.2" "Netatalk 2.2"
 .\" -----------------------------------------------------------------
 .\" * set default formatting
 .\" -----------------------------------------------------------------
@@ -135,7 +135,6 @@ Options:
 .RS 4
 \fB\-c\fR
 Don\'t check \&.AppleDouble stuff, only check orphaned\&.
-
 \fB\-n\fR
 Don\'t open CNID database, skip CNID checks, only traverse filesystem
 .RE
index 1569cfd7296d6eb254f24544583996bdda7d86d4..198f977243df36fd0afc681afe6765816622ea65 100644 (file)
@@ -1,5 +1,9 @@
 # Makefile.am for man/man3
 
-man_MANS = atalk_aton.3 nbp_name.3
+ATALK_MANS = atalk_aton.3 nbp_name.3
 
-EXTRA_DIST = $(man_MANS)
+if USE_APPLETALK
+man_MANS = $(ATALK_MANS)
+endif
+
+EXTRA_DIST = $(ATALK_MANS)
index 944c3602ab2cfc1dad0e2b09bb738e9117da0e09..d0295d419af17c6cbdd335f6cadcfad0781ddb5b 100644 (file)
@@ -1,5 +1,9 @@
 # Makefile.am for man/man4/
 
-man_MANS = atalk.4
+ATALK_MANS = atalk.4
 
-EXTRA_DIST = $(man_MANS)
+if USE_APPLETALK
+man_MANS = $(ATALK_MANS)
+endif
+
+EXTRA_DIST = $(ATALK_MANS)
index 03bf91435a331e17482116ef3f0cb61d960e8b50..c754aeea017bcca0ebdc4564e69f9d9b4b7cae8b 100644 (file)
@@ -2,12 +2,12 @@
 .\"     Title: AppleVolumes.default
 .\"    Author: [FIXME: author] [see http://docbook.sf.net/el/author]
 .\" Generator: DocBook XSL Stylesheets v1.75.2 <http://docbook.sf.net/>
-.\"      Date: 22 Apr 2010
-.\"    Manual: Netatalk 2.1
-.\"    Source: Netatalk 2.1
+.\"      Date: 07 Dec 2010
+.\"    Manual: Netatalk 2.2
+.\"    Source: Netatalk 2.2
 .\"  Language: English
 .\"
-.TH "APPLEVOLUMES\&.DEFAU" "5" "22 Apr 2010" "Netatalk 2.1" "Netatalk 2.1"
+.TH "APPLEVOLUMES\&.DEFAU" "5" "07 Dec 2010" "Netatalk 2.2" "Netatalk 2.2"
 .\" -----------------------------------------------------------------
 .\" * set default formatting
 .\" -----------------------------------------------------------------
@@ -234,11 +234,9 @@ options:\fI[option]\fR
 .RS 4
 This allows multiple options to be specified in a comma delimited format\&. The available options are:
 .PP
-acls
+searchdb
 .RS 4
-Enable ACLs on this volume\&. Requires a
-\fINFSv4 ACLs\fR
-compatible filesystem (e\&.g\&. ZFS) and an ACL API compatible to *Solaris\&. In other words: this requires Solaris, Opensolaris or a derived distribution\&.
+Use fast CNID database namesearch instead of slow recursive filesystem search\&. Relies on a consistent CNID database, ie Samba or local filesystem access lead to inaccurate or wrong results\&. Works only for "dbd" CNID db volumes\&.
 .RE
 .PP
 tm
@@ -355,9 +353,11 @@ rwlist:\fI[users/groups]\fR
 Allows certain users and groups to have read/write access to a share\&. This follows the allow option format\&.
 .RE
 .PP
-veto:\fI[vetoed names]\fR
+veto:\fI[vetoed name]\fR
 .RS 4
-hide files and directories,where the path matches one of the \'/\' delimited vetoed names\&. The veto string must always be terminated with a \'/\', eg\&. "veto1/", "veto1/veto2/"\&.
+hide files and directories,where the path matches one of the \'/\' delimited vetoed names\&. Matches are partial, e\&.g\&. path is
+/abc/def/file
+and veto:/abc/ will hide the file\&.
 .RE
 .PP
 volcharset:\fI[charset]\fR
index a1e28886df45aa60cca4ce65529e79ca207da133..e3d258c74e04e3e75b877a3206096ba7b61e602b 100644 (file)
@@ -13,13 +13,24 @@ SUFFIXES = .tmpl .
            -e "s@:COMPILED_BACKENDS:@${compiled_backends}@g" \
            <$< >$@
 
-GENERATED_MANS = AppleVolumes.default.5 afpd.conf.5 \
-       atalkd.conf.5 netatalk.conf.5 papd.conf.5 \
-       afp_ldap.conf.5 afp_signature.conf.5
+GENERATED_MANS = AppleVolumes.default.5 \
+       afpd.conf.5 \
+       netatalk.conf.5 \
+       afp_ldap.conf.5 \
+       afp_signature.conf.5
 
-TEMPLATE_FILES = AppleVolumes.default.5.tmpl afpd.conf.5.tmpl \
-       atalkd.conf.5.tmpl netatalk.conf.5.tmpl papd.conf.5.tmpl \
-       afp_ldap.conf.5.tmpl afp_signature.conf.5.tmpl
+TEMPLATE_FILES = AppleVolumes.default.5.tmpl \
+       afpd.conf.5.tmpl \
+       netatalk.conf.5.tmpl \
+       afp_ldap.conf.5.tmpl \
+       afp_signature.conf.5.tmpl
+
+ATALK_MANS = atalkd.conf.5.tmpl papd.conf.5.tmpl
+
+if USE_APPLETALK
+GENERATED_MANS += atalkd.conf.5 papd.conf.5
+TEMPLATE_FILES += $(ATALK_MANS)
+endif
 
 NONGENERATED_MANS = AppleVolumes.5 AppleVolumes.system.5
 
@@ -27,4 +38,4 @@ man_MANS = $(GENERATED_MANS) $(NONGENERATED_MANS)
 
 CLEANFILES = $(GENERATED_MANS)
 
-EXTRA_DIST = $(TEMPLATE_FILES) $(NONGENERATED_MANS)
+EXTRA_DIST = $(TEMPLATE_FILES) $(NONGENERATED_MANS) $(ATALK_MANS)
index 0b440d05d7b8fb8aac28241c051713bd1478b31d..f06130409ecd0ce05e126c4851f7fe6cecae906e 100644 (file)
@@ -2,12 +2,12 @@
 .\"     Title: afpd.conf
 .\"    Author: [FIXME: author] [see http://docbook.sf.net/el/author]
 .\" Generator: DocBook XSL Stylesheets v1.75.2 <http://docbook.sf.net/>
-.\"      Date: 23 December 2009
-.\"    Manual: Netatalk 2.1
-.\"    Source: Netatalk 2.1
+.\"      Date: 1 November 2010
+.\"    Manual: Netatalk 2.2
+.\"    Source: Netatalk 2.2
 .\"  Language: English
 .\"
-.TH "AFPD\&.CONF" "5" "23 December 2009" "Netatalk 2.1" "Netatalk 2.1"
+.TH "AFPD\&.CONF" "5" "1 November 2010" "Netatalk 2.2" "Netatalk 2.2"
 .\" -----------------------------------------------------------------
 .\" * set default formatting
 .\" -----------------------------------------------------------------
@@ -354,7 +354,14 @@ Immediately unmount volumes removed from AppleVolumes files on SIGHUP sent to th
 .PP
 \-cnidserver \fI[ipaddress:port]\fR
 .RS 4
-Specifies the IP address and port of a cnid_metad server, required for CNID dbd backend\&. Defaults to localhost:4700\&. The network address may be specified either in dotted\-decimal format for IPv4 or in hexadecimal format for IPv6\&.
+Specifies the IP address and port of a cnid_metad server, required for CNID dbd backend\&. Defaults to localhost:4700\&. The network address may be specified either in dotted\-decimal format for IPv4 or in hexadecimal format for IPv6\&.\-
+.RE
+.PP
+\-dircachesize\fI entries\fR
+.RS 4
+Maximum possible entries in the directory cache\&. The cache stores directories and files\&. It is used to cache the full path to directories and CNIDs which considerably speeds up directory enumeration\&.
+.sp
+Default size is 8192, maximum size is 131072\&. Given value is rounded up to nearest power of 2\&. Each entry takes about 100 bytes, which is not much, but remember that every afpd child process for every connected user has its cache\&.
 .RE
 .PP
 \-guestname \fI[name]\fR
index 138fb62562937ae07a2db64b5410eef8e14a66e7..8adcb66c5484ea948f11d6b8bcf3073832b956a6 100644 (file)
@@ -2,12 +2,12 @@
 .\"     Title: netatalk.conf
 .\"    Author: [FIXME: author] [see http://docbook.sf.net/el/author]
 .\" Generator: DocBook XSL Stylesheets v1.75.2 <http://docbook.sf.net/>
-.\"      Date: 9 Jun 2009
-.\"    Manual: Netatalk 2.1
-.\"    Source: Netatalk 2.1
+.\"      Date: 26 Sep 2010
+.\"    Manual: Netatalk 2.2
+.\"    Source: Netatalk 2.2
 .\"  Language: English
 .\"
-.TH "NETATALK\&.CONF" "5" "9 Jun 2009" "Netatalk 2.1" "Netatalk 2.1"
+.TH "NETATALK\&.CONF" "5" "26 Sep 2010" "Netatalk 2.2" "Netatalk 2.2"
 .\" -----------------------------------------------------------------
 .\" * set default formatting
 .\" -----------------------------------------------------------------
 .\" -----------------------------------------------------------------
 .SH "NAME"
 netatalk.conf \- Configuration file used by netatalk(8) to determine its general configuration
+.SH "SYNOPSIS"
+.HP \w'\fB:ETCDIR:/netatalk\&.conf\fR\fB\fR\fB:DESTDIR:/etc/default/netatalk\fR\fB\fR\ 'u
+\fB:ETCDIR:/netatalk\&.conf\fR\fB\fR
+.br
+\fB:DESTDIR:/etc/default/netatalk\fR\fB\fR
 .SH "DESCRIPTION"
 .PP
 \fB:ETCDIR:/netatalk\&.conf\fR
 is the configuration file used by afpd to determine what portions of the file system will be shared via AFP, as well as their behaviors\&.
 .PP
+If netatalk has been configured with \-\-enable\-debian, it is not
+\fB:ETCDIR:/netatalk\&.conf\fR
+but
+\fB:DESTDIR:/etc/default/netatalk\fR\&.
+.PP
 Any line not prefixed with
 \fB#\fR
 is interpreted\&. The configuration lines are composed like:
index 99d41e391b953aa99736dd2a5640640c4da69031..26273d4378663bcbdaabe2e167fffd4a085cd202 100644 (file)
@@ -14,12 +14,17 @@ SUFFIXES = .tmpl .
            <$< >$@
 
 NONGENERATED_MANS = timelord.8
-GENERATED_MANS    = afp_acls.8 afpd.8 atalkd.8 cnid_dbd.8 cnid_metad.8 papd.8 papstatus.8 psf.8
-TEMPLATE_FILES    = afp_acls.8.tmpl afpd.8.tmpl atalkd.8.tmpl cnid_dbd.8.tmpl \
-       cnid_metad.8.tmpl papd.8.tmpl papstatus.8.tmpl psf.8.tmpl
+GENERATED_MANS    = afpd.8 cnid_dbd.8 cnid_metad.8
+TEMPLATE_FILES    = afpd.8.tmpl cnid_dbd.8.tmpl cnid_metad.8.tmpl
+ATALK_MANS        = atalkd.8.tmpl papd.8.tmpl papstatus.8.tmpl psf.8.tmpl
+
+if USE_APPLETALK
+GENERATED_MANS += atalkd.8 papd.8 papstatus.8 psf.8
+TEMPLATE_FILES += $(ATALK_MANS)
+endif
 
 man_MANS = $(GENERATED_MANS) $(NONGENERATED_MANS)
 
 CLEANFILES = $(GENERATED_MANS)
 
-EXTRA_DIST = $(TEMPLATE_FILES) $(NONGENERATED_MANS)
+EXTRA_DIST = $(TEMPLATE_FILES) $(NONGENERATED_MANS) $(ATALK_MANS)
diff --git a/man/man8/afp_acls.8.tmpl b/man/man8/afp_acls.8.tmpl
deleted file mode 100644 (file)
index c7c0c4e..0000000
+++ /dev/null
@@ -1,134 +0,0 @@
-'\" t
-.\"     Title: afp_acls
-.\"    Author: [FIXME: author] [see http://docbook.sf.net/el/author]
-.\" Generator: DocBook XSL Stylesheets v1.75.2 <http://docbook.sf.net/>
-.\"      Date: 20 Oct 2010
-.\"    Manual: Netatalk 2.1
-.\"    Source: Netatalk 2.1
-.\"  Language: English
-.\"
-.TH "AFP_ACLS" "8" "20 Oct 2010" "Netatalk 2.1" "Netatalk 2.1"
-.\" -----------------------------------------------------------------
-.\" * set default formatting
-.\" -----------------------------------------------------------------
-.\" disable hyphenation
-.nh
-.\" disable justification (adjust text to left margin only)
-.ad l
-.\" -----------------------------------------------------------------
-.\" * MAIN CONTENT STARTS HERE *
-.\" -----------------------------------------------------------------
-.SH "NAME"
-afp_acls \- Setup and Usage Howto for ACLs with Netatalk
-.SH "DESCRIPTION"
-.PP
-ACL support for AFP is implemented with NFSv4 ACLs\&. Few filesystems and fewer OSes support these\&. At the time of implementation its only provided with ZFS on Solaris, Opensolaris and derived distributions\&.
-.SH "CONFIGURATION"
-.PP
-In order to be able to support ACLs, the following things have to be configured:
-.sp
-.RS 4
-.ie n \{\
-\h'-04' 1.\h'+01'\c
-.\}
-.el \{\
-.sp -1
-.IP "  1." 4.2
-.\}
-ZFS Volumes
-.sp
-You MUST configure one ACL parameter for any volume you want to use with Netatalk:
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-aclinherit = passthrough
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-For an explanation of what this parameter means and how to apply it see, your hosts ZFS documentation (e\&.g\&. man zfs)\&.
-.RE
-.sp
-.RS 4
-.ie n \{\
-\h'-04' 2.\h'+01'\c
-.\}
-.el \{\
-.sp -1
-.IP "  2." 4.2
-.\}
-Authentication Domain
-.sp
-Your server and the clients must be part of a security association where identity data is coming from a common source\&. ACLs in Darwin are based on UUIDs and so is the ACL specification in AFP 3\&.2\&. Therefor your source of identity data has to provide an attribute for every user and group where a UUID is stored as a ASCII string\&.
-.sp
-In other words:
-.sp
-.RS 4
-.ie n \{\
-\h'-04'\(bu\h'+03'\c
-.\}
-.el \{\
-.sp -1
-.IP \(bu 2.3
-.\}
-you need an Open Directory Server or an LDAP server where you store UUIDs in some attribute
-.RE
-.sp
-.RS 4
-.ie n \{\
-\h'-04'\(bu\h'+03'\c
-.\}
-.el \{\
-.sp -1
-.IP \(bu 2.3
-.\}
-your clients must be configured to use this server
-.RE
-.sp
-.RS 4
-.ie n \{\
-\h'-04'\(bu\h'+03'\c
-.\}
-.el \{\
-.sp -1
-.IP \(bu 2.3
-.\}
-your server should be configured to use this server via nsswitch and PAM\&.
-.RE
-.sp
-.RS 4
-.ie n \{\
-\h'-04'\(bu\h'+03'\c
-.\}
-.el \{\
-.sp -1
-.IP \(bu 2.3
-.\}
-configure Netatalk via afp_ldap\&.conf so that Netatalk is able to retrieve the UUID for users and groups via LDAP search queries
-.RE
-.RE
-.sp
-.RS 4
-.ie n \{\
-\h'-04' 3.\h'+01'\c
-.\}
-.el \{\
-.sp -1
-.IP "  3." 4.2
-.\}
-Netatalk Volumes
-.sp
-Finally you can add
-\fBoptions:acls\fR
-to your volume defintion to add ACL support\&. In case your volume basedir doesn\'t grant read permissions via mode (like:
-\fB0700 root:adm\fR) but only via ACLs, you MUST add the
-\fBnostat\fR
-option to the volume defintion\&.
-.RE
-.SH "SEE ALSO"
-.PP
-\fBafp_ldap.conf\fR(5),
-\fBAppleVolumes.default\fR(5)
index 5fc967a55bd7f8f21a37ef63b90ae696ad3223b7..090ab7724413234efa19c5d661236318e0438854 100644 (file)
@@ -2,12 +2,12 @@
 .\"     Title: cnid_dbd
 .\"    Author: [FIXME: author] [see http://docbook.sf.net/el/author]
 .\" Generator: DocBook XSL Stylesheets v1.75.2 <http://docbook.sf.net/>
-.\"      Date: 21 Mar 2009
-.\"    Manual: Netatalk 2.1
-.\"    Source: Netatalk 2.1
+.\"      Date: 10 Dec 2010
+.\"    Manual: Netatalk 2.2
+.\"    Source: Netatalk 2.2
 .\"  Language: English
 .\"
-.TH "CNID_DBD" "8" "21 Mar 2009" "Netatalk 2.1" "Netatalk 2.1"
+.TH "CNID_DBD" "8" "10 Dec 2010" "Netatalk 2.2" "Netatalk 2.2"
 .\" -----------------------------------------------------------------
 .\" * set default formatting
 .\" -----------------------------------------------------------------
@@ -22,7 +22,7 @@
 cnid_dbd \- implement access to CNID databases through a dedicated daemon process
 .SH "SYNOPSIS"
 .HP \w'\fBcnid_dbd\fR\fB\fR\fB\fR\fB\fR\ 'u
-\fBcnid_dbd\fR\fB\fR\fB\fR\fB\fR \fIdbdir\fR \fIctrlfd\fR \fIclntfd\fR \fIlogconfig_string\fR
+\fBcnid_dbd\fR\fB\fR\fB\fR\fB\fR \fIvolpath\fR \fIctrlfd\fR \fIclntfd\fR \fIlogconfig_string\fR
 .SH "DESCRIPTION"
 .PP
 \fBcnid_dbd\fR
@@ -41,7 +41,7 @@ backend\&.
 \fBcnid_dbd\fR
 is never started via the command line or system startup scripts but only by the
 \fBcnid_metad\fR
-daemon\&. There is at most one instance of
+daemon\&. There is one instance of
 \fBcnid_dbd\fR
 per netatalk volume\&.
 .PP
@@ -53,11 +53,6 @@ database library and uses transactionally protected updates\&. The
 backend with transactions will avoid corruption of the CNID database even if the system crashes unexpectedly\&.
 .PP
 \fBcnid_dbd\fR
-uses the same on\-disk database format as the
-\fBcdb\fR
-backend\&. It is therefore possible to switch between the two backends as necessary\&.
-.PP
-\fBcnid_dbd\fR
 inherits the effective userid and groupid from
 \fBcnid_metad\fR
 on startup, which is normally caused by
@@ -105,7 +100,7 @@ database subsystem will create files named log\&.xxxxxxxxxx in the database home
 \fBlogfile_autoremove\fR
 option is specified in the
 \fIdb_param\fR
-configuration file (see below)\&.
+configuration file (see below) with a value of 0 (default 1)\&.
 .PP
 Do not use
 \fBcnid_dbd\fR
@@ -180,7 +175,11 @@ exits\&. Default: 600\&. Set this to 0 to disable the timeout\&.
 .RE
 .SH "UPDATING"
 .PP
-In order to update between Netatalk releases using different BerkeleyDB library versions, follow this steps:
+Note that the first version to appear
+\fIafter\fR
+Netatalk 2\&.1 ie Netatalk 2\&.1\&.1, will support BerkeleyDB updates on the fly without manual intervention\&. In other words Netatalk 2\&.1 does contain code to prepare the BerkeleyDB database for upgrades and to upgrade it in case it has been prepared before\&. That means it can\'t upgrade a 2\&.0\&.x version because that one didn\'t prepare the database\&.
+.PP
+In order to update between older Netatalk releases using different BerkeleyDB library versions, follow this steps:
 .sp
 .RS 4
 .ie n \{\
@@ -239,10 +238,6 @@ Again using the new BerkeleyDB utilities run
 .\}
 Start the the new version of Netatalk
 .RE
-.PP
-Note that the first version to appear
-\fIafter\fR
-Netatalk 2\&.1 ie Netatalk 2\&.1\&.1, will support BerkeleyDB updates on the fly without manual intervention\&. In other words Netatalk 2\&.1 does contain code to prepare the BerkeleyDB database for upgrades and to upgrade it in case it has been prepared before\&. That means it can\'t upgrade a 2\&.0\&.x version because that one didn\'t prepare the database\&.
 .SH "SEE ALSO"
 .PP
 \fBcnid_metad\fR(8),
diff --git a/test/.gitignore b/test/.gitignore
new file mode 100644 (file)
index 0000000..282522d
--- /dev/null
@@ -0,0 +1,2 @@
+Makefile
+Makefile.in
diff --git a/test/Makefile.am b/test/Makefile.am
new file mode 100644 (file)
index 0000000..bfd9288
--- /dev/null
@@ -0,0 +1 @@
+SUBDIRS = afpd
diff --git a/test/afpd/.gitignore b/test/afpd/.gitignore
new file mode 100644 (file)
index 0000000..4d6beea
--- /dev/null
@@ -0,0 +1,7 @@
+Makefile
+Makefile.in
+.deps
+.libs
+test
+test.conf
+test.default
\ No newline at end of file
diff --git a/test/afpd/Makefile.am b/test/afpd/Makefile.am
new file mode 100644 (file)
index 0000000..2bb6b3e
--- /dev/null
@@ -0,0 +1,65 @@
+# Makefile.am for test/afpd/
+
+pkgconfdir = @PKGCONFDIR@
+
+TESTS = test.sh test
+
+check_PROGRAMS = test
+noinst_HEADERS = test.h subtests.h afpfunc_helpers.h
+EXTRA_DIST = test.sh
+CLEANFILES = test.default test.conf
+
+test_SOURCES =  test.c subtests.c afpfunc_helpers.c \
+                               $(top_builddir)/etc/afpd/afp_avahi.c \
+                               $(top_builddir)/etc/afpd/afp_config.c \
+                               $(top_builddir)/etc/afpd/afp_dsi.c \
+                               $(top_builddir)/etc/afpd/afp_options.c \
+                               $(top_builddir)/etc/afpd/afp_util.c \
+                               $(top_builddir)/etc/afpd/afprun.c \
+                               $(top_builddir)/etc/afpd/appl.c \
+                               $(top_builddir)/etc/afpd/auth.c \
+                               $(top_builddir)/etc/afpd/afp_zeroconf.c \
+                               $(top_builddir)/etc/afpd/catsearch.c \
+                               $(top_builddir)/etc/afpd/desktop.c \
+                               $(top_builddir)/etc/afpd/dircache.c \
+                               $(top_builddir)/etc/afpd/directory.c \
+                               $(top_builddir)/etc/afpd/enumerate.c \
+                               $(top_builddir)/etc/afpd/extattrs.c \
+                               $(top_builddir)/etc/afpd/file.c \
+                               $(top_builddir)/etc/afpd/filedir.c \
+                               $(top_builddir)/etc/afpd/fork.c \
+                               $(top_builddir)/etc/afpd/gettok.c \
+                               $(top_builddir)/etc/afpd/hash.c \
+                               $(top_builddir)/etc/afpd/mangle.c \
+                               $(top_builddir)/etc/afpd/messages.c \
+                               $(top_builddir)/etc/afpd/nfsquota.c \
+                               $(top_builddir)/etc/afpd/ofork.c \
+                               $(top_builddir)/etc/afpd/quota.c \
+                               $(top_builddir)/etc/afpd/status.c \
+                               $(top_builddir)/etc/afpd/switch.c \
+                               $(top_builddir)/etc/afpd/uam.c \
+                               $(top_builddir)/etc/afpd/unix.c \
+                               $(top_builddir)/etc/afpd/volume.c
+
+if HAVE_ACLS
+test_SOURCES += $(top_builddir)/etc/afpd/acls.c
+endif
+
+test_CFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/etc/afpd \
+        @SLP_CFLAGS@ @ZEROCONF_CFLAGS@ \
+        -DAPPLCNAME \
+        -DSERVERTEXT=\"$(SERVERTEXT)/\" \
+        -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_ACL_LDAPCONF=\"$(pkgconfdir)/afp_ldap.conf\" \
+        -D_PATH_AFPDSIGCONF=\"$(pkgconfdir)/afp_signature.conf\" \
+        -D_PATH_AFPDUUIDCONF=\"$(pkgconfdir)/afp_voluuid.conf\"
+
+test_LDADD = $(top_builddir)/libatalk/cnid/libcnid.la \
+       $(top_builddir)/libatalk/libatalk.la \
+       @QUOTA_LIBS@ @SLP_LIBS@ @WRAP_LIBS@ @LIBADD_DL@ @ACL_LIBS@ @ZEROCONF_LIBS@ @PTHREAD_LIBS@
+
+test_LDFLAGS = -export-dynamic
diff --git a/test/afpd/afpfunc_helpers.c b/test/afpd/afpfunc_helpers.c
new file mode 100644 (file)
index 0000000..b5b8165
--- /dev/null
@@ -0,0 +1,237 @@
+/*
+  $Id: afpfunc_helpers.c,v 1.1.2.1 2010-02-01 10:56:08 franklahm Exp $
+  Copyright (c) 2010 Frank Lahm <franklahm@gmail.com>
+
+  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.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include <atalk/util.h>
+#include <atalk/cnid.h>
+#include <atalk/logger.h>
+#include <atalk/volume.h>
+#include <atalk/directory.h>
+#include <atalk/queue.h>
+#include <atalk/bstrlib.h>
+
+#include "file.h"
+#include "filedir.h"
+#include "directory.h"
+#include "dircache.h"
+#include "hash.h"
+#include "globals.h"
+#include "afp_config.h"
+#include "volume.h"
+
+#include "test.h"
+#include "subtests.h"
+
+
+#define rbufsize 128000
+static char rbuf[rbufsize];
+static size_t rbuflen;
+
+#define ADD(a, b, c) (a) += (c); \
+                         (b) += (c)
+
+#define PUSHBUF(p, val, size, len) \
+    memcpy((p), (val), (size));    \
+    (p) += (size);                 \
+    (len) += (size)
+
+#define PUSHVAL(p, type, val, len)         \
+    { \
+        type type = val;                          \
+        memcpy(p, &type, sizeof(type));           \
+        (p) += sizeof(type);                      \
+        (len) += sizeof(type);                    \
+    }
+
+static int push_path(char **bufp, const char *name)
+{
+    int len = 0;
+    int slen = strlen(name);
+    char *p = *bufp;
+
+    PUSHVAL(p, uint8_t, 3, len); /* path type */
+    PUSHVAL(p, uint32_t, kTextEncodingUTF8, len); /* text encoding hint */
+    PUSHVAL(p, uint16_t, htons(slen), len);
+    if (slen) {
+        for (int i = 0; i < slen; i++) {
+            if (name[i] == '/')
+                p[i] = 0;
+            else
+                p[i] = name[i];
+        }
+        len += slen;
+    }
+
+    *bufp += len;
+    return len;
+}
+
+/***********************************************************************************
+ * Interface
+ ***********************************************************************************/
+
+char **cnamewrap(const char *name)
+{
+    static char buf[256];
+    static char *p = buf;
+    int len = 0;
+
+    PUSHVAL(p, uint8_t, 3, len); /* path type */
+    PUSHVAL(p, uint32_t, kTextEncodingUTF8, len); /* text encoding hint */
+    PUSHVAL(p, uint16_t, ntohs(strlen(name)), len);
+    strcpy(p, name);
+
+    p = buf;
+    return &p;
+}
+
+int getfiledirparms(AFPObj *obj, uint16_t vid, cnid_t did, const char *name)
+{
+    const int bufsize = 256;
+    char buf[bufsize];
+    char *p = buf;
+    int len = 0;
+
+    ADD(p, len , 2);
+
+    PUSHVAL(p, uint16_t, vid, len);
+    PUSHVAL(p, cnid_t, did, len);
+    PUSHVAL(p, uint16_t, htons(FILPBIT_FNUM | FILPBIT_PDINFO), len);
+    PUSHVAL(p, uint16_t, htons(DIRPBIT_DID | DIRPBIT_PDINFO), len);
+
+    len += push_path(&p, name);
+
+    return afp_getfildirparams(obj, buf, len, rbuf, &rbuflen);
+}
+
+int createdir(AFPObj *obj, uint16_t vid, cnid_t did, const char *name)
+{
+    const int bufsize = 256;
+    char buf[bufsize];
+    char *p = buf;
+    int len = 0;
+
+    ADD(p, len , 2);
+
+    PUSHVAL(p, uint16_t, vid, len);
+    PUSHVAL(p, cnid_t, did, len);
+    len += push_path(&p, name);
+
+    return afp_createdir(obj, buf, len, rbuf, &rbuflen);
+}
+
+int createfile(AFPObj *obj, uint16_t vid, cnid_t did, const char *name)
+{
+    const int bufsize = 256;
+    char buf[bufsize];
+    char *p = buf;
+    int len = 0;
+
+    PUSHVAL(p, uint16_t, htons(128), len); /* hard create */
+    PUSHVAL(p, uint16_t, vid, len);
+    PUSHVAL(p, cnid_t, did, len);
+    len += push_path(&p, name);
+
+    return afp_createfile(obj, buf, len, rbuf, &rbuflen);
+}
+
+int delete(AFPObj *obj, uint16_t vid, cnid_t did, const char *name)
+{
+    const int bufsize = 256;
+    char buf[bufsize];
+    char *p = buf;
+    int len = 0;
+
+    PUSHVAL(p, uint16_t, htons(128), len); /* hard create */
+    PUSHVAL(p, uint16_t, vid, len);
+    PUSHVAL(p, cnid_t, did, len);
+    len += push_path(&p, name);
+
+    return afp_delete(obj, buf, len, rbuf, &rbuflen);
+}
+
+int enumerate(AFPObj *obj, uint16_t vid, cnid_t did)
+{
+    const int bufsize = 256;
+    char buf[bufsize];
+    char *p = buf;
+    int len = 0;
+
+    ADD(p, len , 2);
+
+    PUSHVAL(p, uint16_t, vid, len);
+    PUSHVAL(p, cnid_t, did, len);
+    PUSHVAL(p, uint16_t, htons(FILPBIT_PDID | FILPBIT_FNUM | FILPBIT_PDINFO), len);
+    PUSHVAL(p, uint16_t, htons(DIRPBIT_PDID | DIRPBIT_DID | DIRPBIT_PDINFO), len);
+    PUSHVAL(p, uint16_t, htons(20), len);       /* reqcount */
+    PUSHVAL(p, uint32_t, htonl(1), len);        /* startindex */
+    PUSHVAL(p, uint32_t, htonl(rbufsize), len); /* max replysize */
+
+    len += push_path(&p, "");
+
+    return afp_enumerate_ext2(obj, buf, len, rbuf, &rbuflen);
+}
+
+uint16_t openvol(AFPObj *obj, const char *name)
+{
+    int ret;
+    uint16_t bitmap;
+    uint16_t vid;
+    const int bufsize = 32;
+    char buf[bufsize];
+    char *p = buf;
+    char len = strlen(name);
+
+    memset(p, 0, bufsize);
+    p += 2;
+
+    /* bitmap */
+    bitmap = htons(1<<VOLPBIT_VID);
+    memcpy(p, &bitmap, 2);
+    p += 2;
+
+    /* name */
+    *p = len;
+    p++;
+    memcpy(p, name, len);
+    p += len;
+
+    len += 2 + 2 + 1; /* (command+pad) + bitmap + len */
+    if (len & 1)
+        len++;
+
+    rbuflen = 0;
+    if ((ret = afp_openvol(obj, buf, len, rbuf, &rbuflen)) != AFP_OK)
+        return 0;
+
+    p = rbuf;
+    memcpy(&bitmap, p, 2);
+    p += 2;
+    bitmap = ntohs(bitmap);
+    if ( ! (bitmap & 1<<VOLPBIT_VID))
+        return 0;
+
+    memcpy(&vid, p, 2);
+    return vid;
+}
+
diff --git a/test/afpd/afpfunc_helpers.h b/test/afpd/afpfunc_helpers.h
new file mode 100644 (file)
index 0000000..3fda7df
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+  $Id: afpfunc_helpers.h,v 1.1.2.1 2010-02-01 10:56:08 franklahm Exp $
+  Copyright (c) 2010 Frank Lahm <franklahm@gmail.com>
+
+  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.
+*/
+
+#ifndef AFPFUNC_HELPERS
+#define AFPFUNC_HELPERS
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include <atalk/util.h>
+#include <atalk/cnid.h>
+#include <atalk/logger.h>
+#include <atalk/volume.h>
+#include <atalk/directory.h>
+#include <atalk/queue.h>
+#include <atalk/bstrlib.h>
+
+#include "file.h"
+#include "filedir.h"
+#include "directory.h"
+#include "dircache.h"
+#include "hash.h"
+#include "globals.h"
+#include "afp_config.h"
+#include "volume.h"
+
+#include "test.h"
+#include "subtests.h"
+
+extern char **cnamewrap(const char *name);
+
+extern int getfiledirparms(AFPObj *obj, uint16_t vid, cnid_t did, const char *name);
+extern int createdir(AFPObj *obj, uint16_t vid, cnid_t did, const char *name);
+extern int createfile(AFPObj *obj, uint16_t vid, cnid_t did, const char *name);
+extern int delete(AFPObj *obj, uint16_t vid, cnid_t did, const char *name);
+extern int enumerate(AFPObj *obj, uint16_t vid, cnid_t did);
+extern uint16_t openvol(AFPObj *obj, const char *name);
+
+#endif  /* AFPFUNC_HELPERS */
diff --git a/test/afpd/subtests.c b/test/afpd/subtests.c
new file mode 100644 (file)
index 0000000..7049a7c
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+  $Id: subtests.c,v 1.1.2.1 2010-02-01 10:56:08 franklahm Exp $
+  Copyright (c) 2010 Frank Lahm <franklahm@gmail.com>
+
+  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.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include <atalk/util.h>
+#include <atalk/cnid.h>
+#include <atalk/logger.h>
+#include <atalk/volume.h>
+#include <atalk/directory.h>
+#include <atalk/queue.h>
+#include <atalk/bstrlib.h>
+
+#include "directory.h"
+#include "dircache.h"
+#include "hash.h"
+#include "globals.h"
+#include "afp_config.h"
+#include "volume.h"
+
+#include "test.h"
+#include "subtests.h"
+
+static int reti;                /* for the TEST_int macro */
+
+int test001_add_x_dirs(const struct vol *vol, cnid_t start, cnid_t end)
+{
+    struct dir *dir;
+    char dirname[20];
+    while (start++ < end) {
+        sprintf(dirname, "dir%04u", start);
+        dir = dir_new(dirname, dirname, vol, DIRDID_ROOT, htonl(start), bfromcstr(vol->v_path), 0);
+        if (dir == NULL)
+            return -1;
+        if (dircache_add(dir) != 0)
+            return -1;
+    }
+
+    return 0;
+}
+
+int test002_rem_x_dirs(const struct vol *vol, cnid_t start, cnid_t end)
+{
+    struct dir *dir;
+    while (start++ < end) {
+        if ((dir = dircache_search_by_did(vol, htonl(start))))
+            if (dir_remove(vol, dir) != 0)
+                return -1;
+    }
+
+    return 0;
+}
diff --git a/test/afpd/subtests.h b/test/afpd/subtests.h
new file mode 100644 (file)
index 0000000..1ce10a0
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+  $Id: subtests.h,v 1.1.2.1 2010-02-01 10:56:08 franklahm Exp $
+  Copyright (c) 2010 Frank Lahm <franklahm@gmail.com>
+
+  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.
+*/
+
+#ifndef SUBTESTS_H
+#define SUBTESTS_H
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include <atalk/util.h>
+#include <atalk/cnid.h>
+#include <atalk/logger.h>
+#include <atalk/volume.h>
+#include <atalk/directory.h>
+#include <atalk/queue.h>
+#include <atalk/bstrlib.h>
+
+#include "directory.h"
+#include "dircache.h"
+#include "hash.h"
+#include "globals.h"
+#include "afp_config.h"
+#include "volume.h"
+
+extern int test001_add_x_dirs(const struct vol *vol, cnid_t start, cnid_t end);
+extern int test002_rem_x_dirs(const struct vol *vol, cnid_t start, cnid_t end);
+#endif  /* SUBTESTS_H */
diff --git a/test/afpd/test.c b/test/afpd/test.c
new file mode 100644 (file)
index 0000000..c554260
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+  Copyright (c) 2010 Frank Lahm <franklahm@gmail.com>
+
+  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.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include <atalk/util.h>
+#include <atalk/cnid.h>
+#include <atalk/logger.h>
+#include <atalk/volume.h>
+#include <atalk/directory.h>
+#include <atalk/queue.h>
+#include <atalk/bstrlib.h>
+
+#include "file.h"
+#include "filedir.h"
+#include "directory.h"
+#include "dircache.h"
+#include "hash.h"
+#include "globals.h"
+#include "afp_config.h"
+#include "volume.h"
+
+#include "test.h"
+#include "subtests.h"
+#include "afpfunc_helpers.h"
+
+/* Stuff from main.c which of cource can't be added as source to testbin */
+unsigned char nologin = 0;
+struct afp_options default_options;
+static AFPConfig *configs;
+
+/* Static variables */
+
+int main(int argc, char **argv)
+{
+    #define ARGNUM 7
+    char *args[ARGNUM] = {"test", "-F", "test.conf", "-f", "test.default", "-s" ,"test.system"};
+    int reti;
+    uint16_t vid;
+    struct vol *vol;
+    struct dir *retdir;
+    struct path *path;
+
+    /* initialize */
+    afp_version = 32;
+    printf("Initializing\n============\n");
+    TEST(setuplog("default log_note /dev/tty"));
+    TEST(afp_options_init(&default_options));
+    TEST_int(afp_options_parse( ARGNUM, args, &default_options), 1);
+    TEST_expr(configs = configinit(&default_options), configs != NULL);
+    TEST(cnid_init());
+    TEST(load_volumes(&configs->obj));
+    TEST_int(dircache_init(8192), 0);
+    printf("\n");
+
+    /* now run tests */
+    printf("Running tests\n=============\n");
+
+    TEST_expr(vid = openvol(&configs->obj, "test"), vid != 0);
+    TEST_expr(vol = getvolbyvid(vid), vol != NULL);
+
+    /* test directory.c stuff */
+    TEST_expr(retdir = dirlookup(vol, DIRDID_ROOT_PARENT), retdir != NULL);
+    TEST_expr(retdir = dirlookup(vol, DIRDID_ROOT), retdir != NULL);
+    TEST_expr(path = cname(vol, retdir, cnamewrap("Network Trash Folder")), path != NULL);
+
+    TEST_expr(retdir = dirlookup(vol, DIRDID_ROOT), retdir != NULL);
+    TEST_int(getfiledirparms(&configs->obj, vid, DIRDID_ROOT_PARENT, "test"), 0);
+    TEST_int(getfiledirparms(&configs->obj, vid, DIRDID_ROOT, ""), 0);
+
+    TEST_expr(reti = createdir(&configs->obj, vid, DIRDID_ROOT, "dir1"),
+              reti == 0 || reti == AFPERR_EXIST);
+
+    TEST_int(getfiledirparms(&configs->obj, vid, DIRDID_ROOT, "dir1"), 0);
+/*
+  FIXME: this doesn't work although it should. "//" get translated to \000 \000 at means ".."
+  ie this should getfiledirparms for DIRDID_ROOT_PARENT -- at least afair!
+    TEST_int(getfiledirparms(&configs->obj, vid, DIRDID_ROOT, "//"), 0);
+*/
+    TEST_int(createfile(&configs->obj, vid, DIRDID_ROOT, "dir1/file1"), 0);
+    TEST_int(delete(&configs->obj, vid, DIRDID_ROOT, "dir1/file1"), 0);
+    TEST_int(delete(&configs->obj, vid, DIRDID_ROOT, "dir1"), 0);
+
+    TEST_int(createfile(&configs->obj, vid, DIRDID_ROOT, "file1"), 0);
+    TEST_int(getfiledirparms(&configs->obj, vid, DIRDID_ROOT, "file1"), 0);
+    TEST_int(delete(&configs->obj, vid, DIRDID_ROOT, "file1"), 0);
+
+
+    /* test enumerate.c stuff */
+    TEST_int(enumerate(&configs->obj, vid, DIRDID_ROOT), 0);
+}
diff --git a/test/afpd/test.h b/test/afpd/test.h
new file mode 100644 (file)
index 0000000..802120a
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+  $Id: test.h,v 1.1.2.1 2010-02-01 10:56:08 franklahm Exp $
+  Copyright (c) 2010 Frank Lahm <franklahm@gmail.com>
+
+  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.
+*/
+
+#ifndef TEST_H
+#define TEST_H
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include <atalk/util.h>
+#include <atalk/cnid.h>
+#include <atalk/logger.h>
+#include <atalk/volume.h>
+#include <atalk/directory.h>
+#include <atalk/queue.h>
+#include <atalk/bstrlib.h>
+
+#include "directory.h"
+#include "dircache.h"
+#include "hash.h"
+#include "globals.h"
+#include "afp_config.h"
+#include "volume.h"
+#include "subtests.h"
+
+static inline void alignok(int len)
+{
+    int i = 1;
+    if (len < 80)
+        i = 80 - len;
+    while (i--)
+        printf(" ");
+}
+
+#define TEST(a) \
+    printf("Testing: %s ... ", (#a) ); \
+    alignok(strlen(#a));               \
+    a;                                 \
+    printf("[ok]\n");
+
+#define TEST_int(a, b) \
+    printf("Testing: %s ... ", (#a) );            \
+    alignok(strlen(#a));                          \
+    if ((reti = (a)) != b) {                      \
+        printf("[error]\n");                      \
+        exit(1);                                  \
+    } else { printf("[ok]\n"); }
+
+#define TEST_expr(a, b)                              \
+    printf("Testing: %s ... ", (#a) );               \
+    alignok(strlen(#a));                             \
+    a;                                               \
+    if (b) {                                         \
+        printf("[ok]\n");                            \
+    } else {                                         \
+        printf("[error]\n");                         \
+        exit(1);                                     \
+    }
+#endif  /* TEST_H */
diff --git a/test/afpd/test.sh b/test/afpd/test.sh
new file mode 100755 (executable)
index 0000000..80066b6
--- /dev/null
@@ -0,0 +1,24 @@
+#!/bin/sh
+if [ ! -d /tmp/AFPtestvolume ] ; then
+    mkdir -p /tmp/AFPtestvolume
+    if [ $? -ne 0 ] ; then
+        echo Error creating AFP test volume /tmp/AFPtestvolume
+        exit 1
+    fi
+fi
+
+if [ ! -f test.conf ] ; then
+    echo -n "Creating configuration template ... "
+    cat > test.conf <<EOF
+test -noddp -port 10548
+EOF
+    echo [ok]
+fi
+
+if [ ! -f test.default ] ; then
+    echo -n "Creating volume config template ... "
+    cat > test.default <<EOF
+/tmp/AFPtestvolume "test" ea:none
+EOF
+    echo [ok]
+fi