+Changes in 2.2.2
+================
+
+* NEW: afpd: New option "adminauthuser". Specifying eg "-adminauthuser root"
+ whenever a normal user login fails, afpd tries to authenticate as
+ the specified adminauthuser. If this succeeds, a normal session is
+ created for the original connecting user. Said differently: if you
+ know the password of adminauthuser, you can authenticate as any other
+ user.
+* NEW: experimental systemd service files in distrib/systemd/
+* UPD: afpd: Enhanced POSIX ACL mapping semantics, from Laura Mueller
+* UPD: afpd: Reset options every time a :DEFAULT: line is found in a
+ AppleVolumes file
+* UPD: afpd: Convert passwords from legacy encoding (wire format) to host
+ encoding, NetAFP Bug ID #14
+* UPD: afpd: Don't set ATTRBIT_SHARED flag for directories
+* UPD: afpd: Use sendfile() on Solaris and FreeBSD for sending data
+* UPD: afpd: Faster volume used size calculation for "volsizelimit" option,
+ cf man AppleVolume.default for details
+* FIX: afpd: ACL access checking
+* FIX: afpd: Fix an error when duplicating files that lacked an AppleDouble
+ file which lead to a possible Finder crash
+* FIX: afpd: Read-only filesystems lead to afpd processes running as root
+* FIX: afpd: Fix for filesystem without NFSv4 ACL support on Solaris
+* FIX: afpd: Fix catsearch bug, NetAFP Bug ID #12
+* FIX: afpd: Fix dircache bug, NetAFP Bug ID #13
+* FIX: dbd: Better checking for duplicated or bogus CNIDs from AppleDouble
+ files
+* FIX: Fix compilation error when AppleTalk support is disabled
+* FIX: Portability fixes
+
Changes in 2.2.1
================
if DARWIN_ACE_ADD_SUBDIRECTORY is set
* FIX: afpd: afpd crashed when it failed to register with Avahi because eg
user service registration is disabled in the Avahi config
+* FIX: dbd: function checking and removing malformed ad:ea header files failed
+ to chdir back to the original working directory
* FIX: cnid_dbd: increase BerkeleyDB locks and lockobjs
* FIX: cnid_dbd: implement -d option, deletes CNID db
* FIX: dbd: better detection of local (or SMB/NFS) modifications on AFP volumes
static void usage_main(void)
{
printf("Usage: ad ls|cp|rm|mv|find [file|dir, ...]\n");
+ printf(" ad -v|--version\n");
+}
+
+static void show_version(void)
+{
+ printf("ad (Netatalk %s)\n", VERSION);
}
int main(int argc, char **argv)
return ad_mv(argc, argv);
else if (STRCMP(argv[1], ==, "find"))
return ad_find(argc, argv);
+ else if (STRCMP(argv[1], ==, "-v")) {
+ show_version();
+ return 1;
+ }
+ else if (STRCMP(argv[1], ==, "--version")) {
+ show_version();
+ return 1;
+ }
else {
usage_main();
return 1;
/*
- Copyright (c) 2009 Frank Lahm <franklahm@gmail.com>
+ Copyright (c) 2009,2011 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
#ifndef AD_H
#define AD_H
-#if !defined(__FreeBSD__)
-# define _XOPEN_SOURCE 600
-#endif
+#include <atalk/standards.h>
#include <sys/types.h>
#include <sys/stat.h>
/*
- * $Id: afppasswd.c,v 1.19 2005-04-28 20:49:19 bfernhomberg Exp $
- *
* Copyright 1999 (c) Adrian Sun (asun@u.washington.edu)
* All Rights Reserved. See COPYRIGHT.
*
flags = ((uid = getuid()) == 0) ? OPT_ISROOT : 0;
if (((flags & OPT_ISROOT) == 0) && (argc > 1)) {
+ fprintf(stderr, "afppasswd (Netatalk %s)\n", VERSION);
fprintf(stderr, "Usage: afppasswd [-acfn] [-u minuid] [-p path] [username]\n");
fprintf(stderr, " -a add a new user\n");
fprintf(stderr, " -c create and initialize password file or specific user\n");
-/*
- * $Id: megatron.c,v 1.14 2010-01-27 21:27:53 didg Exp $
- */
-
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif /* HAVE_CONFIG_H */
*newname = '\0';
for ( c = 1 ; c < argc ; ++c ) {
+ if ( strcmp( argv [ c ], "--version" ) == 0 ) {
+ printf("%s (Netatalk %s megatron)\n", argv[0], VERSION);
+ return( -1 );
+ }
+ if ( strcmp( argv [ c ], "-v" ) == 0 ) {
+ printf("%s (Netatalk %s megatron)\n", argv[0], VERSION);
+ return( -1 );
+ }
if ( strcmp( argv [ c ], "--header" ) == 0 ) {
flags |= OPTION_HEADERONLY;
continue;
}
return( rv );
}
-
#include <stdio.h>
+#include <stdbool.h>
-#include <atalk/boolean.h>
#include <atalk/logger.h>
int main(int argc, char *argv[])
# if you don't want the proxy server to act as
# a ddp server as well, set -uamlist to an empty
# string.
+# -dsireadbuf [number]
+# Scale factor that determines the size of the
+# DSI/TCP readahead buffer, default is 12. This is
+# multiplies with the DSI server quantum (default
+# ~300k) to give the size of the buffer. Increasing
+# this value might increase throughput in fast local
+# networks for volume to volume copies. Note: This
+# buffer is allocated per afpd child process, so
+# specifying large values will eat up large amount of
+# memory (buffer size * number of clients).
+# -tcprcvbuf [number]
+# Try to set TCP receive buffer using setsockpt().
+# Often OSes impose restrictions on the applications
+# ability to set this value.
+# -tcpsndbuf [number]
+# Try to set TCP send buffer using setsockpt().
+# Often OSes impose restrictions on the applications
+# ability to set this value.
# -slp Register this server with the Service Location
# Protocol (if SLP support was compiled in).
# -nozeroconf Don't register this server with the Multicats
# then tries to authenticate with the result
# through the availabel and active UAM authentication
# modules.
+# -dircachesize entries
+# 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.
+# 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.
+# -fcelistener host[:port]
+# Enables sending FCE events to the specified host,
+# default port is 12250 if not specified. Specifying
+# mutliple listeners is done by having this option
+# once for each of them.
+# -fceevents fmod,fdel,ddel,fcre,dcre,tmsz
+# Speficies which FCE events are active, default is
+# fmod,fdel,ddel,fcre,dcre.
+# -fcecoalesce all|delete|create
+# Coalesce FCE events.
+# -fceholdfmod seconds
+# This determines the time delay in seconds which is
+# always waited if another file modification for the
+# same file is done by a client before sending an FCE
+# file modification event (fmod). For example saving
+# a file in Photoshop would generate multiple events
+# by itself because the application is opening,
+# modifying and closing a file mutliple times for
+# every "save". Defautl: 60 seconds.
+# -keepsessions Enable "Continuous AFP Service". This means the
+# ability to stop the master afpd process with a
+# SIGQUIT signal, possibly install an afpd update and
+# start the afpd process. Existing AFP sessions afpd
+# processes will remain unaffected. Technically they
+# will be notified of the master afpd shutdown, sleep
+# 15-20 seconds and then try to reconnect their IPC
+# channel to the master afpd process. If this
+# reconnect fails, the sessions are in an undefined
+# state. Therefor it's absolutely critical to restart
+# the master process in time!
+# -noacl2maccess Don't map filesystem ACLs to effective permissions.
#
# Codepage Options:
# -unixcodepage <CODEPAGE> Specifies the servers unix codepage,
#### Control whether the daemons are started in the background.
#### If it is dissatisfied that legacy atalkd starts slowly, set "yes".
+#### In case using systemd/systemctl, this is not so significant.
#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
+#### it in atalkd.conf
#ATALK_ZONE=@zone
--- /dev/null
+dnl configure.in for netatalk
+
+AC_INIT(etc/afpd/main.c)
+
+NETATALK_VERSION=`cat $srcdir/VERSION`
+AC_SUBST(NETATALK_VERSION)
+
+AC_CANONICAL_SYSTEM
+AM_INIT_AUTOMAKE(netatalk, ${NETATALK_VERSION})
+AM_CONFIG_HEADER(config.h)
+AM_MAINTAINER_MODE([enable])
+
+dnl Checks for programs.
+AC_PROG_AWK
+AC_PROG_CC
+AC_PROG_CC_C99
+AC_PROG_INSTALL
+AC_PROG_LN_S
+AC_PROG_MAKE_SET
+AC_LIBTOOL_DLOPEN
+AC_PROG_LIBTOOL
+AC_PROG_PERL
+AC_PROG_GREP
+AC_PROG_PS
+AM_PROG_CC_C_O
+
+dnl Checks for typedefs, structures, and compiler characteristics.
+AC_C_INLINE
+
+dnl Request SUSv3 standard interfaces plus anything else the platform may have
+CFLAGS="$CFLAGS -D_XOPEN_SOURCE=600 -D__EXTENSIONS__ -D_GNU_SOURCE"
+
+dnl Check if we can use attribute unused (gcc only) from ethereal
+AC_MSG_CHECKING(to see if we can add '__attribute__((unused))' to CFLAGS)
+if test x$GCC != x ; then
+ CFLAGS="-D_U_=\"__attribute__((unused))\" $CFLAGS"
+ AC_MSG_RESULT(yes)
+else
+ CFLAGS="-D_U_=\"\" $CFLAGS"
+ AC_MSG_RESULT(no)
+fi
+
+dnl Configure libevent
+AC_CONFIG_SUBDIRS([libevent])
+
+dnl Checks for header files, some checks are obsolete, unfortunately the code
+dnl uses the resulting macros, so the code has to cleaned up too before
+dnl we can remove the checks here.
+AC_CHECK_HEADERS(mntent.h unistd.h termios.h ufs/quota.h)
+AC_CHECK_HEADERS(netdb.h sgtty.h statfs.h dlfcn.h langinfo.h locale.h)
+AC_CHECK_HEADERS(sys/param.h sys/fcntl.h sys/termios.h)
+AC_CHECK_HEADERS(sys/mnttab.h sys/statvfs.h sys/stat.h sys/vfs.h)
+dnl Checks for header files, confirmed to be required as of 2011
+AC_CHECK_HEADERS(sys/epoll.h)
+AC_CHECK_HEADERS([sys/mount.h], , ,
+[#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+])
+
+AC_SYS_LARGEFILE([], AC_MSG_ERROR([AFP 3.x support requires Large File Support.]))
+
+dnl --------------------------------------------------------------------------
+dnl check if dlsym needs to add an underscore, uses libtool macros
+dnl --------------------------------------------------------------------------
+AC_LTDL_DLLIB
+AC_CHECK_FUNCS(dlopen dlsym dlclose)
+AC_LTDL_DLSYM_USCORE
+if test x"$libltdl_cv_need_uscore" = xyes; then
+ AC_DEFINE(DLSYM_PREPEND_UNDERSCORE, 1, [BSD compatibility macro])
+fi
+
+dnl Special hecks
+ac_neta_haveatfuncs=yes
+AC_CHECK_FUNCS(openat renameat fstatat unlinkat, , ac_neta_haveatfuncs=no)
+if test x"$ac_neta_haveatfuncs" = x"yes" ; then
+ AC_DEFINE([_ATFILE_SOURCE], 1, AT file source)
+ AC_DEFINE([HAVE_ATFUNCS], 1, whether at funcs are available)
+fi
+AC_CHECK_MEMBERS(struct tm.tm_gmtoff,,, [#include <time.h>])
+
+dnl these tests have been comfirmed to be needed in 2011
+AC_CHECK_FUNC(epoll_create, AC_DEFINE([HAVE_EPOLL], 1, Whether Linux epoll is available))
+AC_CHECK_FUNCS(backtrace_symbols dirfd getusershell pread pwrite pselect)
+AC_CHECK_FUNCS(setlinebuf strlcat strlcpy strnlen)
+AC_CHECK_FUNCS(mmap utime getpagesize) dnl needed by tbd
+
+dnl search for necessary libraries
+AC_SEARCH_LIBS(gethostbyname, nsl)
+AC_SEARCH_LIBS(connect, socket)
+AC_SEARCH_LIBS(pthread_sigmask, pthread,,[AC_MSG_ERROR([missing pthread_sigmask])])
+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_DEFINE(OPEN_NOFOLLOW_ERRNO, ELOOP, errno returned by open with O_NOFOLLOW)
+
+AC_CACHE_SAVE
+
+dnl --------------------------------------------------------------------------
+dnl 64bit platform check
+dnl --------------------------------------------------------------------------
+
+AC_MSG_CHECKING([whether to check for 64bit libraries])
+# 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*
+
+case $host_cpu:$atalk_cv_cc_64bit_output in
+powerpc64:yes | s390x:yes | sparc*:yes | x86_64:yes | i386:yes)
+ case $target_os in
+ solaris2*)
+ AC_MSG_RESULT([yes])
+ atalk_libname="lib/64"
+ ;;
+ *bsd* | dragonfly*)
+ AC_MSG_RESULT([no])
+ atalk_libname="lib"
+ ;;
+ *)
+ AC_MSG_RESULT([yes])
+ atalk_libname="lib64"
+ ;;
+ esac
+ ;;
+*:*)
+ AC_MSG_RESULT([no])
+ atalk_libname="lib"
+ ;;
+esac
+
+dnl --------------------------------------------------------------------------
+dnl specific configuration comes in here:
+dnl --------------------------------------------------------------------------
+
+dnl Check for optional admin group support
+AC_NETATALK_ADMIN_GROUP
+
+dnl Check for optional AFS support
+AC_NETATALK_AFS_CHECK
+
+dnl --with-pkgconfdir check to change configuration directory location
+AC_NETATALK_CONFIG_DIRS
+
+dnl Check for optional cracklib support
+AC_NETATALK_CRACKLIB
+
+dnl Check whether to enable debug code
+AC_NETATALK_DEBUG
+
+dnl Check whethe to disable tickle SIGALARM stuff, which eases debugging
+AC_NETATALK_DEBUGGING
+
+dnl Check for libiconv support
+AC_NETATALK_CHECK_ICONV
+
+dnl Check for CNID database backends
+AC_NETATALK_CNID([bdb_required=yes],[bdb_required=no])
+
+dnl Check for quota support
+AC_NETATALK_CHECK_QUOTA
+
+dnl Check for optional server location protocol support (used by MacOS X)
+AC_NETATALK_SRVLOC
+
+dnl Check for optional Zeroconf support
+AC_NETATALK_ZEROCONF
+
+dnl Check for optional TCP-wrappers support
+AC_NETATALK_TCP_WRAPPERS
+
+dnl Check for PAM libs
+AC_NETATALK_PATH_PAM
+
+dnl Check for optional shadow password support
+AC_NETATALK_SHADOW
+
+dnl Check for optional valid-shell-check support
+AC_NETATALK_SHELL_CHECK
+
+dnl Check for optional Webmin
+AC_NETATALK_WEBMIN
+
+dnl Check for optional sysv initscript install
+AC_NETATALK_SYSV_STYLE
+
+dnl Path where UAM modules shall be installed
+AC_ARG_WITH(uams-path, [ --with-uams-path=PATH path to UAMs [[PKGCONF/uams]]], [uams_path="$withval"], [uams_path="${PKGCONFDIR}/uams"])
+
+dnl Check for libgcrypt, if found enables DHX2 UAM
+AC_NETATALK_PATH_LIBGCRYPT([1:1.2.3])
+
+dnl Check for openssl, if found enables DHX UAM and Randnum UAM
+AC_NETATALK_PATH_SSL
+
+dnl Check for Berkeley DB library
+AC_NETATALK_PATH_BDB
+
+dnl Check for crypt
+AC_NETATALK_CRYPT
+
+dnl Check for building PGP UAM module
+AC_NETATALK_PGP_UAM
+
+dnl Check for building Kerberos V UAM module
+AC_NETATALK_KRB5_UAM
+
+dnl Check for overwrite the config files or not
+AC_NETATALK_OVERWRITE_CONFIG
+
+dnl Check for LDAP support, for client-side ACL visibility
+AC_NETATALK_LDAP
+
+dnl Check for ACL support
+AC_NETATALK_ACL
+
+dnl Check for Extended Attributes support
+AC_NETATALK_EXTENDED_ATTRIBUTES
+
+dnl Check for libsmbsharemodes from Samba for Samba/Netatalk access/deny/share modes interop
+AC_NETATALK_SMB_SHAREMODES
+
+dnl Check if realpath() takes NULL
+AC_NETATALK_REALPATH
+
+dnl Check for sendfile()
+AC_NETATALK_SENDFILE
+
+dnl --------------------------------------------------------------------------
+dnl FHS stuff has to be done last because it overrides other defaults
+dnl --------------------------------------------------------------------------
+
+AC_MSG_CHECKING([whether to use Filesystem Hierarchy Standard (FHS) compatibility])
+AC_ARG_ENABLE(fhs,
+ [ --enable-fhs use Filesystem Hierarchy Standard (FHS) compatibility],[
+ if test "$enableval" = "yes"; then
+ uams_path="${libdir}/netatalk"
+ sysconfdir="/etc"
+ PKGCONFDIR=${sysconfdir}/netatalk
+ SERVERTEXT="${PKGCONFDIR}/msg"
+ use_pam_so=yes
+ mandir="/usr/share/man"
+ AC_DEFINE(FHS_COMPATIBILITY, 1, [Define if you want compatibily with the FHS])
+ AC_MSG_RESULT([yes])
+ else
+ AC_MSG_RESULT([no])
+ fi
+ ],[
+ AC_MSG_RESULT([no])
+ ]
+)
+
+dnl --------------------------------------------------------------------------
+dnl post-FHS substitutions, etc
+dnl --------------------------------------------------------------------------
+
+UAMS_PATH="${uams_path}"
+AC_SUBST(UAMS_PATH)
+
+
+dnl --------------------------------------------------------------------------
+dnl OS specific configuration comes in here:
+dnl --------------------------------------------------------------------------
+
+AC_NETATALK_OS_SPECIFIC
+
+
+dnl --------------------------------------------------------------------------
+dnl drop in includes for top level directory structures here...
+dnl --------------------------------------------------------------------------
+
+dnl Note: $(top_srcdir)/include should be added before all other includes
+dnl so that includes from that directory a preferred to includes from
+dnl /usr/include or similar places.
+LIBS="$LIBS -L\$(top_srcdir)/libatalk -L\$(top_srcdir)/libevent"
+CFLAGS="-I\$(top_srcdir)/include -I\$(top_srcdir)/sys -I\$(top_srcdir)/libevent/include $CFLAGS"
+
+
+dnl --------------------------------------------------------------------------
+dnl Last minute substitutions
+dnl --------------------------------------------------------------------------
+
+AC_SUBST(LIBS)
+AC_SUBST(CFLAGS)
+
+AM_CONDITIONAL(SOLARIS_MODULE, test x$solaris_module = 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(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)
+AM_CONDITIONAL(USE_PAM_SO, test x$use_pam_so = xyes)
+AM_CONDITIONAL(USE_PAM, test x$netatalk_cv_install_pam = xyes)
+AM_CONDITIONAL(BUILD_PAM, test x$compile_pam = xyes)
+AM_CONDITIONAL(USE_PGP, test x$compile_pgp = xyes)
+AM_CONDITIONAL(DEFAULT_HOOK, test x$neta_cv_have_libgcrypt != xyes && test x$neta_cv_have_openssl != xyes)
+AM_CONDITIONAL(USE_NETBSD, test x$sysv_style = xnetbsd)
+AM_CONDITIONAL(USE_REDHAT_SYSV, test x$sysv_style = xredhat-sysv)
+AM_CONDITIONAL(USE_REDHAT_SYSTEMD, test x$sysv_style = xredhat-systemd)
+AM_CONDITIONAL(USE_SUSE, test x$sysv_style = xsuse)
+AM_CONDITIONAL(USE_SHADOWPW, test x$shadowpw = xyes)
+AM_CONDITIONAL(USE_TRU64, test x$sysv_style = xtru64)
+AM_CONDITIONAL(USE_SOLARIS, test x$sysv_style = xsolaris)
+AM_CONDITIONAL(USE_GENTOO, test x$sysv_style = xgentoo)
+AM_CONDITIONAL(USE_DEBIAN, test x$sysv_style = xdebian)
+AM_CONDITIONAL(USE_UNDEF, test x$sysv_style = x)
+AM_CONDITIONAL(USE_BDB, test x$bdb_required = xyes)
+AM_CONDITIONAL(HAVE_ATFUNCS, test x"$ac_neta_haveatfuncs" = x"yes")
+
+dnl --------------------- generate files
+
+AC_OUTPUT([Makefile
+ bin/Makefile
+ bin/ad/Makefile
+ bin/afppasswd/Makefile
+ bin/cnid/Makefile
+ bin/cnid/cnid2_create
+ bin/megatron/Makefile
+ bin/misc/Makefile
+ bin/uniconv/Makefile
+ config/Makefile
+ config/pam/Makefile
+ contrib/Makefile
+ contrib/macusers/Makefile
+ contrib/macusers/macusers
+ contrib/shell_utils/Makefile
+ contrib/shell_utils/apple_dump
+ contrib/shell_utils/asip-status.pl
+ distrib/Makefile
+ distrib/config/Makefile
+ distrib/config/netatalk-config
+ distrib/initscripts/Makefile
+ distrib/m4/Makefile
+ distrib/systemd/Makefile
+ doc/Makefile
+ etc/Makefile
+ etc/afpd/Makefile
+ etc/cnid_dbd/Makefile
+ etc/netalockd/Makefile
+ etc/uams/Makefile
+ include/Makefile
+ include/atalk/Makefile
+ libatalk/Makefile
+ libatalk/acl/Makefile
+ libatalk/adouble/Makefile
+ libatalk/bstring/Makefile
+ libatalk/cnid/Makefile
+ libatalk/cnid/cdb/Makefile
+ libatalk/cnid/last/Makefile
+ libatalk/cnid/dbd/Makefile
+ libatalk/cnid/tdb/Makefile
+ libatalk/compat/Makefile
+ libatalk/dsi/Makefile
+ libatalk/locking/Makefile
+ libatalk/rpc/Makefile
+ libatalk/talloc/Makefile
+ libatalk/tevent/Makefile
+ libatalk/tsocket/Makefile
+ libatalk/tdb/Makefile
+ libatalk/unicode/Makefile
+ libatalk/unicode/charsets/Makefile
+ libatalk/util/Makefile
+ libatalk/vfs/Makefile
+ macros/Makefile
+ man/Makefile
+ man/man1/Makefile
+ man/man5/Makefile
+ man/man8/Makefile
+ test/Makefile
+ test/afpd/Makefile
+ test/netalockd/Makefile
+ ],
+ [chmod a+x distrib/config/netatalk-config contrib/shell_utils/apple_*]
+)
+
+AC_NETATALK_LIBS_SUMMARY
+AC_NETATALK_CONFIG_SUMMARY
+++ /dev/null
-dnl configure.in for netatalk
-
-AC_INIT(etc/afpd/main.c)
-
-NETATALK_VERSION=`cat $srcdir/VERSION`
-AC_SUBST(NETATALK_VERSION)
-
-AC_CANONICAL_SYSTEM
-AM_INIT_AUTOMAKE(netatalk, ${NETATALK_VERSION})
-AM_CONFIG_HEADER(config.h)
-AM_MAINTAINER_MODE([enable])
-
-dnl Checks for programs.
-AC_PROG_AWK
-AC_PROG_CC
-AC_PROG_CC_C99
-AC_PROG_INSTALL
-AC_PROG_LN_S
-AC_PROG_MAKE_SET
-AC_LIBTOOL_DLOPEN
-AC_PROG_LIBTOOL
-AC_PROG_PERL
-AC_PROG_GREP
-AC_PROG_PS
-AM_PROG_CC_C_O
-
-dnl Checks for typedefs, structures, and compiler characteristics.
-AC_C_INLINE
-
-dnl Request SUSv3 standard interfaces plus anything else the platform may have
-CFLAGS="$CFLAGS -D_XOPEN_SOURCE=600 -D__EXTENSIONS__ -D_GNU_SOURCE"
-
-dnl Check if we can use attribute unused (gcc only) from ethereal
-AC_MSG_CHECKING(to see if we can add '__attribute__((unused))' to CFLAGS)
-if test x$GCC != x ; then
- CFLAGS="-D_U_=\"__attribute__((unused))\" $CFLAGS"
- AC_MSG_RESULT(yes)
-else
- CFLAGS="-D_U_=\"\" $CFLAGS"
- AC_MSG_RESULT(no)
-fi
-
-dnl Configure libevent
-AC_CONFIG_SUBDIRS([libevent])
-
-dnl Checks for header files, some checks are obsolete, unfortunately the code
-dnl uses the resulting macros, so the code has to cleaned up too before
-dnl we can remove the checks here.
-AC_CHECK_HEADERS(mntent.h unistd.h termios.h ufs/quota.h)
-AC_CHECK_HEADERS(netdb.h sgtty.h statfs.h dlfcn.h langinfo.h locale.h)
-AC_CHECK_HEADERS(sys/param.h sys/fcntl.h sys/termios.h)
-AC_CHECK_HEADERS(sys/mnttab.h sys/statvfs.h sys/stat.h sys/vfs.h)
-dnl Checks for header files, confirmed to be required as of 2011
-AC_CHECK_HEADERS(sys/epoll.h)
-AC_CHECK_HEADERS([sys/mount.h], , ,
-[#ifdef HAVE_SYS_PARAM_H
-#include <sys/param.h>
-#endif
-])
-
-AC_SYS_LARGEFILE([], AC_MSG_ERROR([AFP 3.x support requires Large File Support.]))
-
-dnl --------------------------------------------------------------------------
-dnl check if dlsym needs to add an underscore, uses libtool macros
-dnl --------------------------------------------------------------------------
-AC_LTDL_DLLIB
-AC_CHECK_FUNCS(dlopen dlsym dlclose)
-AC_LTDL_DLSYM_USCORE
-if test x"$libltdl_cv_need_uscore" = xyes; then
- AC_DEFINE(DLSYM_PREPEND_UNDERSCORE, 1, [BSD compatibility macro])
-fi
-
-dnl Special hecks
-ac_neta_haveatfuncs=yes
-AC_CHECK_FUNCS(openat renameat fstatat unlinkat, , ac_neta_haveatfuncs=no)
-if test x"$ac_neta_haveatfuncs" = x"yes" ; then
- AC_DEFINE([_ATFILE_SOURCE], 1, AT file source)
- AC_DEFINE([HAVE_ATFUNCS], 1, whether at funcs are available)
-fi
-AC_CHECK_MEMBERS(struct tm.tm_gmtoff,,, [#include <time.h>])
-
-dnl these tests have been comfirmed to be needed in 2011
-AC_CHECK_FUNC(epoll_create, AC_DEFINE([HAVE_EPOLL], 1, Whether Linux epoll is available))
-AC_CHECK_FUNCS(backtrace_symbols dirfd getusershell pread pwrite pselect)
-AC_CHECK_FUNCS(setlinebuf strlcat strlcpy strnlen)
-AC_CHECK_FUNCS(mmap utime getpagesize) dnl needed by tbd
-
-dnl search for necessary libraries
-AC_SEARCH_LIBS(gethostbyname, nsl)
-AC_SEARCH_LIBS(connect, socket)
-AC_SEARCH_LIBS(pthread_sigmask, pthread,,[AC_MSG_ERROR([missing pthread_sigmask])])
-if test x"$ac_cv_search_pthread_sigmask" != x"none required" ; then
- PTHREAD_LIBS=$ac_cv_search_pthread_sigmask
-fi
-AC_SUBST(PTHREAD_LIBS)
-
-dnl --------------------- Check if realpath() takes NULL
-AC_CACHE_CHECK([if the realpath function allows a NULL argument],
- neta_cv_REALPATH_TAKES_NULL, [
- AC_TRY_RUN([
- #include <stdio.h>
- #include <limits.h>
- #include <signal.h>
-
- void exit_on_core(int ignored) {
- exit(1);
- }
-
- main() {
- char *newpath;
- signal(SIGSEGV, exit_on_core);
- newpath = realpath("/tmp", NULL);
- exit((newpath != NULL) ? 0 : 1);
- }],
- neta_cv_REALPATH_TAKES_NULL=yes,
- neta_cv_REALPATH_TAKES_NULL=no,
- neta_cv_REALPATH_TAKES_NULL=cross
- )
- ]
-)
-
-if test x"$neta_cv_REALPATH_TAKES_NULL" = x"yes"; then
- AC_DEFINE(REALPATH_TAKES_NULL,1,[Whether the realpath function allows NULL])
-fi
-
-AC_CACHE_SAVE
-
-dnl --------------------------------------------------------------------------
-dnl 64bit platform check
-dnl --------------------------------------------------------------------------
-
-AC_MSG_CHECKING([whether to check for 64bit libraries])
-# 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*
-
-case $host_cpu:$atalk_cv_cc_64bit_output in
-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
- ;;
-*:*)
- AC_MSG_RESULT([no])
- atalk_libname="lib"
- ;;
-esac
-
-dnl --------------------------------------------------------------------------
-dnl specific configuration comes in here:
-dnl --------------------------------------------------------------------------
-
-dnl Check for optional admin group support
-AC_NETATALK_ADMIN_GROUP
-
-dnl Check for optional AFS support
-AC_NETATALK_AFS_CHECK
-
-dnl --with-pkgconfdir check to change configuration directory location
-AC_NETATALK_CONFIG_DIRS
-
-dnl Check for optional cracklib support
-AC_NETATALK_CRACKLIB
-
-dnl Check whether to enable debug code
-AC_NETATALK_DEBUG
-
-dnl Check whethe to disable tickle SIGALARM stuff, which eases debugging
-AC_NETATALK_DEBUGGING
-
-dnl Check for libiconv support
-AC_NETATALK_CHECK_ICONV
-
-dnl Check for CNID database backends
-AC_NETATALK_CNID([bdb_required=yes],[bdb_required=no])
-
-dnl Check for quota support
-AC_NETATALK_CHECK_QUOTA
-
-dnl Check for optional server location protocol support (used by MacOS X)
-AC_NETATALK_SRVLOC
-
-dnl Check for optional Zeroconf support
-AC_NETATALK_ZEROCONF
-
-dnl Check for optional TCP-wrappers support
-AC_NETATALK_TCP_WRAPPERS
-
-dnl Check for PAM libs
-AC_NETATALK_PATH_PAM
-
-dnl Check for optional shadow password support
-AC_NETATALK_SHADOW
-
-dnl Check for optional valid-shell-check support
-AC_NETATALK_SHELL_CHECK
-
-dnl Check for optional Webmin
-AC_NETATALK_WEBMIN
-
-dnl Check for optional sysv initscript install
-AC_NETATALK_SYSV_STYLE
-
-dnl Path where UAM modules shall be installed
-AC_ARG_WITH(uams-path, [ --with-uams-path=PATH path to UAMs [[PKGCONF/uams]]], [uams_path="$withval"], [uams_path="${PKGCONFDIR}/uams"])
-
-dnl Check for libgcrypt, if found enables DHX2 UAM
-AC_NETATALK_PATH_LIBGCRYPT([1:1.2.3])
-
-dnl Check for openssl, if found enables DHX UAM and Randnum UAM
-AC_NETATALK_PATH_SSL
-
-dnl Check for Berkeley DB library
-AC_NETATALK_PATH_BDB
-
-dnl Check for crypt
-AC_NETATALK_CRYPT
-
-dnl Check for building PGP UAM module
-AC_NETATALK_PGP_UAM
-
-dnl Check for building Kerberos V UAM module
-AC_NETATALK_KRB5_UAM
-
-dnl Check for overwrite the config files or not
-AC_NETATALK_OVERWRITE_CONFIG
-
-dnl Check for LDAP support, for client-side ACL visibility
-AC_NETATALK_LDAP
-
-dnl Check for ACL support
-AC_NETATALK_ACL
-
-dnl Check for Extended Attributes support
-AC_NETATALK_EXTENDED_ATTRIBUTES
-
-dnl Check for libsmbsharemodes from Samba for Samba/Netatalk access/deny/share modes interop
-AC_NETATALK_SMB_SHAREMODES
-
-dnl --------------------------------------------------------------------------
-dnl FHS stuff has to be done last because it overrides other defaults
-dnl --------------------------------------------------------------------------
-
-AC_MSG_CHECKING([whether to use Filesystem Hierarchy Standard (FHS) compatibility])
-AC_ARG_ENABLE(fhs,
- [ --enable-fhs use Filesystem Hierarchy Standard (FHS) compatibility],[
- if test "$enableval" = "yes"; then
- uams_path="${libdir}/netatalk"
- sysconfdir="/etc"
- PKGCONFDIR=${sysconfdir}/netatalk
- SERVERTEXT="${PKGCONFDIR}/msg"
- use_pam_so=yes
- mandir="/usr/share/man"
- AC_DEFINE(FHS_COMPATIBILITY, 1, [Define if you want compatibily with the FHS])
- AC_MSG_RESULT([yes])
- else
- AC_MSG_RESULT([no])
- fi
- ],[
- AC_MSG_RESULT([no])
- ]
-)
-
-dnl --------------------------------------------------------------------------
-dnl post-FHS substitutions, etc
-dnl --------------------------------------------------------------------------
-
-UAMS_PATH="${uams_path}"
-AC_SUBST(UAMS_PATH)
-
-
-dnl --------------------------------------------------------------------------
-dnl OS specific configuration comes in here:
-dnl --------------------------------------------------------------------------
-
-AC_NETATALK_OS_SPECIFIC
-
-
-dnl --------------------------------------------------------------------------
-dnl drop in includes for top level directory structures here...
-dnl --------------------------------------------------------------------------
-
-dnl Note: $(top_srcdir)/include should be added before all other includes
-dnl so that includes from that directory a preferred to includes from
-dnl /usr/include or similar places.
-LIBS="$LIBS -L\$(top_srcdir)/libatalk -L\$(top_srcdir)/libevent"
-CFLAGS="-I\$(top_srcdir)/include -I\$(top_srcdir)/sys -I\$(top_srcdir)/libevent/include $CFLAGS"
-
-AC_DEFINE(OPEN_NOFOLLOW_ERRNO, ELOOP, errno returned by open with O_NOFOLLOW)
-
-
-dnl --------------------------------------------------------------------------
-dnl Last minute substitutions
-dnl --------------------------------------------------------------------------
-
-AC_SUBST(LIBS)
-AC_SUBST(CFLAGS)
-
-AM_CONDITIONAL(SOLARIS_MODULE, test x$solaris_module = 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(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)
-AM_CONDITIONAL(USE_PAM_SO, test x$use_pam_so = xyes)
-AM_CONDITIONAL(USE_PAM, test x$netatalk_cv_install_pam = xyes)
-AM_CONDITIONAL(BUILD_PAM, test x$compile_pam = xyes)
-AM_CONDITIONAL(USE_PGP, test x$compile_pgp = xyes)
-AM_CONDITIONAL(DEFAULT_HOOK, test x$neta_cv_have_libgcrypt != xyes && test x$neta_cv_have_openssl != xyes)
-AM_CONDITIONAL(USE_NETBSD, test x$sysv_style = xnetbsd)
-AM_CONDITIONAL(USE_REDHAT_SYSV, test x$sysv_style = xredhat-sysv)
-AM_CONDITIONAL(USE_REDHAT_SYSTEMD, test x$sysv_style = xredhat-systemd)
-AM_CONDITIONAL(USE_SUSE, test x$sysv_style = xsuse)
-AM_CONDITIONAL(USE_SHADOWPW, test x$shadowpw = xyes)
-AM_CONDITIONAL(USE_TRU64, test x$sysv_style = xtru64)
-AM_CONDITIONAL(USE_SOLARIS, test x$sysv_style = xsolaris)
-AM_CONDITIONAL(USE_GENTOO, test x$sysv_style = xgentoo)
-AM_CONDITIONAL(USE_DEBIAN, test x$sysv_style = xdebian)
-AM_CONDITIONAL(USE_UNDEF, test x$sysv_style = x)
-AM_CONDITIONAL(USE_BDB, test x$bdb_required = xyes)
-AM_CONDITIONAL(HAVE_ATFUNCS, test x"$ac_neta_haveatfuncs" = x"yes")
-
-dnl --------------------- generate files
-
-AC_OUTPUT([Makefile
- bin/Makefile
- bin/ad/Makefile
- bin/afppasswd/Makefile
- bin/cnid/Makefile
- bin/cnid/cnid2_create
- bin/megatron/Makefile
- bin/misc/Makefile
- bin/uniconv/Makefile
- config/Makefile
- config/pam/Makefile
- contrib/Makefile
- contrib/macusers/Makefile
- contrib/macusers/macusers
- contrib/shell_utils/Makefile
- contrib/shell_utils/afpd-mtab.pl
- contrib/shell_utils/apple_dump
- contrib/shell_utils/asip-status.pl
- distrib/Makefile
- distrib/config/Makefile
- distrib/config/netatalk-config
- distrib/initscripts/Makefile
- distrib/m4/Makefile
- doc/Makefile
- etc/Makefile
- etc/afpd/Makefile
- etc/cnid_dbd/Makefile
- etc/netalockd/Makefile
- etc/uams/Makefile
- include/Makefile
- include/atalk/Makefile
- libatalk/Makefile
- libatalk/acl/Makefile
- libatalk/adouble/Makefile
- libatalk/bstring/Makefile
- libatalk/cnid/Makefile
- libatalk/cnid/cdb/Makefile
- libatalk/cnid/last/Makefile
- libatalk/cnid/dbd/Makefile
- libatalk/cnid/tdb/Makefile
- libatalk/compat/Makefile
- libatalk/dsi/Makefile
- libatalk/locking/Makefile
- libatalk/rpc/Makefile
- libatalk/talloc/Makefile
- libatalk/tevent/Makefile
- libatalk/tsocket/Makefile
- libatalk/tdb/Makefile
- libatalk/unicode/Makefile
- libatalk/unicode/charsets/Makefile
- libatalk/util/Makefile
- libatalk/vfs/Makefile
- macros/Makefile
- man/Makefile
- man/man1/Makefile
- man/man5/Makefile
- man/man8/Makefile
- test/Makefile
- test/afpd/Makefile
- test/netalockd/Makefile
- ],
- [chmod a+x distrib/config/netatalk-config contrib/shell_utils/apple_*]
-)
-
-AC_NETATALK_LIBS_SUMMARY
-AC_NETATALK_CONFIG_SUMMARY
--- /dev/null
+# Makefile for contrib/misc/
+
+EXTRA_DIST = cnid.lua
--- /dev/null
+--
+-- Netatalk DBD protocol
+-- wireshark -X lua_script:cnid.lua
+-- don't forget to comment out the line disable_lua = true; do return end;
+-- in /etc/wireshark/init.lua
+
+-- global environment
+local b = _G
+
+-- declare our protocol
+local dbd_proto = Proto("dbd","Netatalk Dbd Wire Protocol")
+
+local cmd = ProtoField.uint32("dbd.cmd", "Request") -- , base.HEX
+local len = ProtoField.uint32("dbd.name.len", "Name Length")
+local filename = ProtoField.string("dbd.name", "Name")
+local error = ProtoField.uint32("dbd.error", "Error code")
+local cnid = ProtoField.uint32("dbd.cnid", "Cnid")
+local did = ProtoField.uint32("dbd.did", "Parent Directory Id")
+local dev = ProtoField.uint64("dbd.dev", "Device number")
+local ino = ProtoField.uint64("dbd.ino", "Inode number")
+local type = ProtoField.uint32("dbd.type", "File type")
+
+dbd_proto.fields = {cmd, error, cnid, did, dev, ino, type, filename, len}
+
+--- Request list
+local Cmd = { [3] = "add",
+ [4] = "get",
+ [5] = "resolve",
+ [6] = "lookup",
+ [7] = "update",
+ [8] = "delete",
+ [11] = "timestamp"
+ }
+
+--- display a filename
+local function fname(buffer, pinfo, tree, len, ofs)
+
+ pinfo.cols.info:append(" Name=" .. buffer(ofs +4, len):string())
+
+ local subtree = tree:add(buffer(ofs, len +4), buffer(ofs +4, len):string())
+ subtree:add(filename, buffer(ofs +4, len))
+
+ return subtree
+end
+
+-- create a function to dissect it
+function dbd_proto.dissector(buffer, pinfo, tree)
+
+
+ pinfo.cols.protocol = "DBD"
+
+ local subtree = tree:add(dbd_proto,buffer(),"Netatalk DBD Wire Protocol")
+
+ if pinfo.dst_port == 4700 then
+ pinfo.cols.info = "Query"
+ local val = buffer(0,4):uint()
+ local item = subtree:add(cmd, buffer(0,4))
+ if Cmd[val] then
+ item:append_text(" (" .. Cmd[val] .. ")")
+ pinfo.cols.info = Cmd[val]
+
+ local val = buffer(4,4):uint()
+ if val ~= 0 then
+ pinfo.cols.info:append(" Cnid=" .. val)
+ end
+ subtree:add(cnid, buffer(4, 4))
+ subtree:add(dev, buffer(8, 8))
+ subtree:add(ino, buffer(16, 8))
+ subtree:add(type, buffer(24, 4))
+
+ local val = buffer(28,4):uint()
+ if val ~= 0 then
+ pinfo.cols.info:append(" Did=" .. val)
+ end
+ subtree:add(did, buffer(28, 4))
+
+ local val = buffer(36,4):uint()
+ if val ~= 0 then
+ item = fname(buffer, pinfo, subtree, val, 36)
+ item:add(len, buffer(36, 4))
+
+ end
+ end
+ else
+ pinfo.cols.info = "Reply"
+
+ local rply = {}
+
+ local val = buffer(0,4):uint()
+ rply.error = val
+ subtree:add(error, buffer(0,4))
+ if val ~= 0 then
+ pinfo.cols.info:append(" Error=" .. val)
+ end
+
+ val = buffer(4,4):uint()
+ rply.cnid = val
+ subtree:add(cnid, buffer(4,4))
+ if val ~= 0 then
+ pinfo.cols.info:append(" Cnid=" .. val)
+ end
+
+ val = buffer(8,4):uint()
+ rply.did = val
+ subtree:add(did, buffer(8,4))
+ if val ~= 0 then
+ pinfo.cols.info:append(" Did=" .. val)
+ end
+
+ val = buffer(16,4):uint()
+ rply.len = val
+
+ if rply.error == 0 and rply.did ~= 0 then
+ subtree = fname(buffer, pinfo, subtree, val, 16)
+ subtree:add(len, buffer(16,4))
+ end
+ end
+end
+
+-- load the tcp.port table
+local tcp_table = DissectorTable.get("tcp.port")
+-- register our protocol
+tcp_table:add(4700, dbd_proto)
+++ /dev/null
-#!/usr/bin/perl
-#
-# usage: make-casetable.pl <infile> <outfile1> <outfile2>
-# make-casetable.pl UnicodeData.txt utf16_casetable.h utf16_case.c
-#
-# (c) 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/reports/tr44/
-# http://www.unicode.org/Public/UNIDATA/UnicodeData.txt
-
-# One block has 64 chars.
-#
-# BMP
-# block 0 = dummy
-# block 1 = U+0000 - U+003F
-# block 2 = U+0040 - U+007F
-# .....
-# block 1024 = U+FFC0 - U+FFFF
-# block 1025 = dummy
-#
-# Surrogate Pair
-# block 1024 = dummy
-# block 1025 = U+010000 - U+01003F
-# block 1026 = U+010040 - U+01007F
-# .....
-# block 17408 = U+10FFC0 - U+10FFFF
-# block 17409 = dummy
-#
-# Dummy block is for edge detection.
-# If block include upper/lower chars, block_enable[]=1.
-
-use strict;
-use warnings;
-
-our $code0;
-our $Name1;
-our $General_Category2;
-our $Canonical_Combining_Class3;
-our $Bidi_Class4;
-our $Decomposition_Mapping5;
-our $Numeric_Value6;
-our $Numeric_Value7;
-our $Numeric_Value8;
-our $Bidi_Mirrored9;
-our $Unicode_1_Name10;
-our $ISO_Comment11;
-our $Simple_Uppercase_Mapping12;
-our $Simple_Lowercase_Mapping13;
-our $Simple_Titlecase_Mapping14;
-
-our $hex_code0;
-our $Mapping;
-our $hex_Mapping;
-
-our $char;
-our $sp;
-our $block;
-
-our @table;
-our @table_sp;
-
-our @block_enable;
-our @block_enable_sp;
-
-our $table_no;
-our $block_start;
-our $block_end;
-our $char_start;
-our $char_end;
-
-open(CHEADER, ">$ARGV[1]");
-open(CSOURCE, ">$ARGV[2]");
-
-printf (CHEADER "\/\*\n");
-printf (CHEADER "DO NOT EDIT BY HAND\!\!\!\n");
-printf (CHEADER "\n");
-printf (CHEADER "This file is generated by\n");
-printf (CHEADER " contrib/misc/make-casetable.pl %s %s %s\n", $ARGV[0], $ARGV[1], $ARGV[2]);
-printf (CHEADER "\n");
-printf (CHEADER "%s is got from\n", $ARGV[0]);
-printf (CHEADER "http\:\/\/www.unicode.org\/Public\/UNIDATA\/UnicodeData.txt\n");
-printf (CHEADER "\*\/\n");
-printf (CHEADER "\n");
-
-printf (CSOURCE "\/\*\n");
-printf (CSOURCE "DO NOT EDIT BY HAND\!\!\!\n");
-printf (CSOURCE "\n");
-printf (CSOURCE "This file is generated by\n");
-printf (CSOURCE " contrib/misc/make-casetable.pl %s %s %s\n", $ARGV[0], $ARGV[1], $ARGV[2]);
-printf (CSOURCE "\n");
-printf (CSOURCE "%s is got from\n", $ARGV[0]);
-printf (CSOURCE "http\:\/\/www.unicode.org\/Public\/UNIDATA\/UnicodeData.txt\n");
-printf (CSOURCE "\*\/\n");
-printf (CSOURCE "\n");
-printf (CSOURCE "\#include \<stdint.h\>\n");
-printf (CSOURCE "\#include \<atalk\/unicode.h\>\n");
-printf (CSOURCE "\#include \"%s\"\n", $ARGV[1]);
-printf (CSOURCE "\n");
-
-&make_array("upper");
-&make_array("lower");
-
-printf (CHEADER "\/\* EOF \*\/\n");
-printf (CSOURCE "\/\* EOF \*\/\n");
-
-close(CHEADER);
-close(CSOURCE);
-
-
-###########################################################################
-sub make_array{
-
- # init table -----------------------------------------------------
-
- for ($char = 0 ; $char <= 0xFFFF ; $char++) {
- $table[$char][0] = $char; # mapped char
- $table[$char][1] = $char; # orig char
- $table[$char][2] = ""; # char name
- }
-
- for ($char = 0x10000 ; $char <= 0x10FFFF ; $char++) {
- $sp = ((0xD800 - (0x10000 >> 10) + ($char >> 10)) << 16)
- + (0xDC00 + ($char & 0x3FF));
- $table_sp[$char][0] = $sp; # mapped surrogate pair
- $table_sp[$char][1] = $sp; # orig surrogate pair
- $table_sp[$char][2] = $char; # mapped char
- $table_sp[$char][3] = $char; # orig char
- $table_sp[$char][4] = ""; # char name
- }
-
- for ($block = 0 ; $block <= 1025 ; $block++) {
- $block_enable[$block] = 0;
- }
-
- $block_enable[1] = 1; # ASCII block is forcibly included
- $block_enable[2] = 1; # in the array for Speed-Up.
-
- for ($block = 1024 ; $block <= 17409 ; $block++) {
- $block_enable_sp[$block] = 0;
- }
-
- # write data to table --------------------------------------------
-
- open(UNICODEDATA, "<$ARGV[0]");
-
- while (<UNICODEDATA>) {
- chop;
- (
- $code0,
- $Name1,
- $General_Category2,
- $Canonical_Combining_Class3,
- $Bidi_Class4,
- $Decomposition_Mapping5,
- $Numeric_Value6,
- $Numeric_Value7,
- $Numeric_Value8,
- $Bidi_Mirrored9,
- $Unicode_1_Name10,
- $ISO_Comment11,
- $Simple_Uppercase_Mapping12,
- $Simple_Lowercase_Mapping13,
- $Simple_Titlecase_Mapping14
- ) = split(/\;/);
-
- if ($_[0] eq "upper") {
- $Mapping = $Simple_Uppercase_Mapping12;
- } elsif ($_[0] eq "lower") {
- $Mapping = $Simple_Lowercase_Mapping13;
- } else {
- exit(1);
- }
-
- next if ($Mapping eq "");
-
- $hex_code0 = hex($code0);
- $hex_Mapping = hex($Mapping);
-
- if ($hex_code0 <= 0xFFFF) {
- $table[$hex_code0][0] = $hex_Mapping;
- #table[$hex_code0][1] already set
- $table[$hex_code0][2] = $Name1;
- $block_enable[($hex_code0 / 64) +1] = 1;
- } else {
- $sp = ((0xD800 - (0x10000 >> 10) + ($hex_Mapping >> 10)) << 16)
- + (0xDC00 + ($hex_Mapping & 0x3FF));
- $table_sp[$hex_code0][0] = $sp;
- #table_sp[$hex_code0][1] already set
- $table_sp[$hex_code0][2] = $hex_Mapping;
- #table_sp[$hex_code0][3] already set
- $table_sp[$hex_code0][4] = $Name1;
- $block_enable_sp[($hex_code0 / 64) +1] = 1;
- }
- }
-
- close(UNICODEDATA);
-
- # array for BMP --------------------------------------------------
-
- printf(CSOURCE "\/*******************************************************************\n");
- printf(CSOURCE " Convert a wide character to %s case.\n", $_[0]);
- printf(CSOURCE "*******************************************************************\/\n");
- printf(CSOURCE "ucs2\_t to%s\_w\(ucs2\_t val\)\n", $_[0]);
- printf(CSOURCE "{\n");
-
- $table_no = 1;
-
- for ($block = 1 ; $block <= 1024 ; $block++) {
-
- # rising edge detection
- if ($block_enable[$block - 1] == 0 && $block_enable[$block] == 1) {
- $block_start = $block;
- }
-
- # falling edge detection
- if ($block_enable[$block] == 1 && $block_enable[$block + 1] == 0) {
- $block_end = $block;
-
- $char_start = ($block_start -1)* 64;
- $char_end = ($block_end * 64) -1;
-
- printf(CHEADER "static const uint16\_t %s\_table\_%d\[%d\] \= \{\n",
- $_[0], $table_no, $char_end - $char_start +1);
-
- for ($char = $char_start ; $char <= $char_end ; $char++) {
- printf(CHEADER " 0x%04X, /*U\+%04X*/ /*%s*/\n",
- $table[$char][0],
- $table[$char][1],
- $table[$char][2]
- );
- }
- printf(CHEADER "\}\;\n");
- printf(CHEADER "\n");
-
- if ($char_start == 0x0000) {
- printf(CSOURCE " if \( val \<\= 0x%04X)\n",
- $char_end);
- printf(CSOURCE " return %s\_table\_%d\[val]\;\n",
- $_[0], $table_no);
- } else {
- printf(CSOURCE " if \( val \>\= 0x%04X \&\& val \<\= 0x%04X)\n",
- $char_start, $char_end);
- printf(CSOURCE " return %s\_table\_%d\[val-0x%04X\]\;\n",
- $_[0], $table_no, $char_start);
- }
- printf(CSOURCE "\n");
-
- $table_no++;
- }
- }
-
- printf(CSOURCE "\treturn \(val\)\;\n");
- printf(CSOURCE "\}\n");
- printf(CSOURCE "\n");
-
- # array for Surrogate Pair ---------------------------------------
-
- printf(CSOURCE "\/*******************************************************************\n");
- printf(CSOURCE " Convert a surrogate pair to %s case.\n", $_[0]);
- printf(CSOURCE "*******************************************************************\/\n");
- printf(CSOURCE "uint32\_t to%s\_sp\(uint32\_t val\)\n", $_[0]);
- printf(CSOURCE "{\n");
-
- $table_no = 1;
-
- for ($block = 1025 ; $block <= 17408 ; $block++) {
-
- # rising edge detection
- if ((($block_enable_sp[$block - 1] == 0) || ((($block - 1) & 0xF) == 0))
- && ($block_enable_sp[$block] == 1)) {
- $block_start = $block;
- }
-
- # falling edge detection
- if (($block_enable_sp[$block] == 1) &&
- ((($block - 1) & 0xF == 0xF) || ($block_enable_sp[$block + 1] == 0))) {
- $block_end = $block;
-
- $char_start = ($block_start -1)* 64;
- $char_end = ($block_end * 64) -1;
-
- printf(CHEADER "static const uint32\_t %s\_table\_sp\_%d\[%d\] \= \{\n",
- $_[0], $table_no, $char_end - $char_start +1);
-
- for ($char = $char_start ; $char <= $char_end ; $char++) {
- printf(CHEADER " 0x%08X, /*0x%08X*/ /*U\+%06X*/ /*U\+%06X*/ /*%s*/\n",
- $table_sp[$char][0],
- $table_sp[$char][1],
- $table_sp[$char][2],
- $table_sp[$char][3],
- $table_sp[$char][4]
- );
- }
- printf(CHEADER "\}\;\n");
- printf(CHEADER "\n");
-
- printf(CSOURCE " if \( val \>\= 0x%08X \&\& val \<\= 0x%08X)\n",
- $table_sp[$char_start][1], $table_sp[$char_end][1]);
- printf(CSOURCE " return %s\_table\_sp\_%d\[val-0x%08X\]\;\n",
- $_[0], $table_no, $table_sp[$char_start][1]);
- printf(CSOURCE "\n");
-
- $table_no++;
- }
- }
-
- printf(CSOURCE "\treturn \(val\)\;\n");
- printf(CSOURCE "\}\n");
- printf(CSOURCE "\n");
-}
-
-# EOF
+++ /dev/null
-#!/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/reports/tr15/
-# http://www.unicode.org/Public/*/ucd/UnicodeData*.txt
-# http://www.unicode.org/Public/UNIDATA/UnicodeData.txt
-
-
-# temp files for binary search (compose.TEMP, compose_sp.TEMP) -------------
-
-open(UNICODEDATA, "<$ARGV[0]");
-
-open(COMPOSE_TEMP, ">compose.TEMP");
-open(COMPOSE_SP_TEMP, ">compose_sp.TEMP");
-
-while (<UNICODEDATA>) {
- chop;
- (
- $code0,
- $Name1,
- $General_Category2,
- $Canonical_Combining_Class3,
- $Bidi_Class4,
- $Decomposition_Mapping5,
- $Numeric_Value6,
- $Numeric_Value7,
- $Numeric_Value8,
- $Bidi_Mirrored9,
- $Unicode_1_Name10,
- $ISO_Comment11,
- $Simple_Uppercase_Mapping12,
- $Simple_Lowercase_Mapping13,
- $Simple_Titlecase_Mapping14
- ) = split(/\;/);
-
- if (($Decomposition_Mapping5 ne "") && ($Decomposition_Mapping5 !~ /\</) && ($Decomposition_Mapping5 =~ / /)) {
- ($base, $comb) = split(/ /,$Decomposition_Mapping5);
-
- $leftbracket = " { ";
- $rightbracket =" }, ";
-
- # AFP 3.x Spec
- if ( ((0x2000 <= hex($code0)) && (hex($code0) <= 0x2FFF))
- || ((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(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 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 -------------------------------------------------------------------
-
-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");
-print (" unsigned int comb\;\n");
-print ("\} precompositions\[\] \= \{\n");
-
-system("cat precompose.SORT");
-
-print ("\}\;\n");
-print ("\n");
-
-print ("static const struct \{\n");
-print (" unsigned int replacement\;\n");
-print (" unsigned int base\;\n");
-print (" unsigned int comb\;\n");
-print ("\} decompositions\[\] \= \{\n");
-
-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
Makefile
Makefile.in
-afpd-mtab.pl
apple_cleanup
apple_cp
apple_mv
GENERATED_FILES = lp2pap.sh
TEMPLATE_FILES = lp2pap.sh.tmpl
PERLSCRIPTS = \
- afpd-mtab.pl \
asip-status.pl \
apple_dump
bin_SCRIPTS = $(PERLSCRIPTS) $(GENERATED_FILES)
-EXTRA_DIST = $(TEMPLATE_FILES)
+EXTRA_DIST = $(TEMPLATE_FILES) make-casetable.pl make-precompose.h.pl
+++ /dev/null
-#!@PERL@
-#
-# $Id: afpd-mtab.pl.in,v 1.1 2002-01-17 05:59:25 srittau Exp $
-#
-# Create an afpd.mtab on standard output from the mtab-format file on standard
-# input.
-#
-# afpd-mtab.pl < /etc/mtab > /etc/afpd.mtab
-#
-# Modification history:
-#
-# created. -- rgr, 9-Apr-01.
-#
-
-print("# afpd.mtab, generated by afpd-mtab.pl on ",
- `date`);
-while (<>) {
- ($device, $mount_point, $fstype) = split;
- next
- if $device eq 'none' || $mount_point eq '/boot';
- printf("%2d %-10s %s\n", ++$did_index, $device, $mount_point);
-}
--- /dev/null
+#!/usr/bin/perl
+#
+# usage: make-casetable.pl <infile> <outfile1> <outfile2>
+# make-casetable.pl UnicodeData.txt utf16_casetable.h utf16_case.c
+#
+# (c) 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/reports/tr44/
+# http://www.unicode.org/Public/UNIDATA/UnicodeData.txt
+
+# One block has 64 chars.
+#
+# BMP
+# block 0 = dummy
+# block 1 = U+0000 - U+003F
+# block 2 = U+0040 - U+007F
+# .....
+# block 1024 = U+FFC0 - U+FFFF
+# block 1025 = dummy
+#
+# Surrogate Pair
+# block 1024 = dummy
+# block 1025 = U+010000 - U+01003F
+# block 1026 = U+010040 - U+01007F
+# .....
+# block 17408 = U+10FFC0 - U+10FFFF
+# block 17409 = dummy
+#
+# Dummy block is for edge detection.
+# If block include upper/lower chars, block_enable[]=1.
+
+use strict;
+use warnings;
+
+our $code0;
+our $Name1;
+our $General_Category2;
+our $Canonical_Combining_Class3;
+our $Bidi_Class4;
+our $Decomposition_Mapping5;
+our $Numeric_Value6;
+our $Numeric_Value7;
+our $Numeric_Value8;
+our $Bidi_Mirrored9;
+our $Unicode_1_Name10;
+our $ISO_Comment11;
+our $Simple_Uppercase_Mapping12;
+our $Simple_Lowercase_Mapping13;
+our $Simple_Titlecase_Mapping14;
+
+our $hex_code0;
+our $Mapping;
+our $hex_Mapping;
+
+our $char;
+our $sp;
+our $block;
+
+our @table;
+our @table_sp;
+
+our @block_enable;
+our @block_enable_sp;
+
+our $table_no;
+our $block_start;
+our $block_end;
+our $char_start;
+our $char_end;
+
+open(CHEADER, ">$ARGV[1]");
+open(CSOURCE, ">$ARGV[2]");
+
+printf (CHEADER "\/\*\n");
+printf (CHEADER "DO NOT EDIT BY HAND\!\!\!\n");
+printf (CHEADER "\n");
+printf (CHEADER "This file is generated by\n");
+printf (CHEADER " contrib/shell_utils/make-casetable.pl %s %s %s\n", $ARGV[0], $ARGV[1], $ARGV[2]);
+printf (CHEADER "\n");
+printf (CHEADER "%s is got from\n", $ARGV[0]);
+printf (CHEADER "http\:\/\/www.unicode.org\/Public\/UNIDATA\/UnicodeData.txt\n");
+printf (CHEADER "\*\/\n");
+printf (CHEADER "\n");
+
+printf (CSOURCE "\/\*\n");
+printf (CSOURCE "DO NOT EDIT BY HAND\!\!\!\n");
+printf (CSOURCE "\n");
+printf (CSOURCE "This file is generated by\n");
+printf (CSOURCE " contrib/shell_utils/make-casetable.pl %s %s %s\n", $ARGV[0], $ARGV[1], $ARGV[2]);
+printf (CSOURCE "\n");
+printf (CSOURCE "%s is got from\n", $ARGV[0]);
+printf (CSOURCE "http\:\/\/www.unicode.org\/Public\/UNIDATA\/UnicodeData.txt\n");
+printf (CSOURCE "\*\/\n");
+printf (CSOURCE "\n");
+printf (CSOURCE "\#include \<stdint.h\>\n");
+printf (CSOURCE "\#include \<atalk\/unicode.h\>\n");
+printf (CSOURCE "\#include \"%s\"\n", $ARGV[1]);
+printf (CSOURCE "\n");
+
+&make_array("upper");
+&make_array("lower");
+
+printf (CHEADER "\/\* EOF \*\/\n");
+printf (CSOURCE "\/\* EOF \*\/\n");
+
+close(CHEADER);
+close(CSOURCE);
+
+
+###########################################################################
+sub make_array{
+
+ # init table -----------------------------------------------------
+
+ for ($char = 0 ; $char <= 0xFFFF ; $char++) {
+ $table[$char][0] = $char; # mapped char
+ $table[$char][1] = $char; # orig char
+ $table[$char][2] = ""; # char name
+ }
+
+ for ($char = 0x10000 ; $char <= 0x10FFFF ; $char++) {
+ $sp = ((0xD800 - (0x10000 >> 10) + ($char >> 10)) << 16)
+ + (0xDC00 + ($char & 0x3FF));
+ $table_sp[$char][0] = $sp; # mapped surrogate pair
+ $table_sp[$char][1] = $sp; # orig surrogate pair
+ $table_sp[$char][2] = $char; # mapped char
+ $table_sp[$char][3] = $char; # orig char
+ $table_sp[$char][4] = ""; # char name
+ }
+
+ for ($block = 0 ; $block <= 1025 ; $block++) {
+ $block_enable[$block] = 0;
+ }
+
+ $block_enable[1] = 1; # ASCII block is forcibly included
+ $block_enable[2] = 1; # in the array for Speed-Up.
+
+ for ($block = 1024 ; $block <= 17409 ; $block++) {
+ $block_enable_sp[$block] = 0;
+ }
+
+ # write data to table --------------------------------------------
+
+ open(UNICODEDATA, "<$ARGV[0]");
+
+ while (<UNICODEDATA>) {
+ chop;
+ (
+ $code0,
+ $Name1,
+ $General_Category2,
+ $Canonical_Combining_Class3,
+ $Bidi_Class4,
+ $Decomposition_Mapping5,
+ $Numeric_Value6,
+ $Numeric_Value7,
+ $Numeric_Value8,
+ $Bidi_Mirrored9,
+ $Unicode_1_Name10,
+ $ISO_Comment11,
+ $Simple_Uppercase_Mapping12,
+ $Simple_Lowercase_Mapping13,
+ $Simple_Titlecase_Mapping14
+ ) = split(/\;/);
+
+ if ($_[0] eq "upper") {
+ $Mapping = $Simple_Uppercase_Mapping12;
+ } elsif ($_[0] eq "lower") {
+ $Mapping = $Simple_Lowercase_Mapping13;
+ } else {
+ exit(1);
+ }
+
+ next if ($Mapping eq "");
+
+ $hex_code0 = hex($code0);
+ $hex_Mapping = hex($Mapping);
+
+ if ($hex_code0 <= 0xFFFF) {
+ $table[$hex_code0][0] = $hex_Mapping;
+ #table[$hex_code0][1] already set
+ $table[$hex_code0][2] = $Name1;
+ $block_enable[($hex_code0 / 64) +1] = 1;
+ } else {
+ $sp = ((0xD800 - (0x10000 >> 10) + ($hex_Mapping >> 10)) << 16)
+ + (0xDC00 + ($hex_Mapping & 0x3FF));
+ $table_sp[$hex_code0][0] = $sp;
+ #table_sp[$hex_code0][1] already set
+ $table_sp[$hex_code0][2] = $hex_Mapping;
+ #table_sp[$hex_code0][3] already set
+ $table_sp[$hex_code0][4] = $Name1;
+ $block_enable_sp[($hex_code0 / 64) +1] = 1;
+ }
+ }
+
+ close(UNICODEDATA);
+
+ # array for BMP --------------------------------------------------
+
+ printf(CSOURCE "\/*******************************************************************\n");
+ printf(CSOURCE " Convert a wide character to %s case.\n", $_[0]);
+ printf(CSOURCE "*******************************************************************\/\n");
+ printf(CSOURCE "ucs2\_t to%s\_w\(ucs2\_t val\)\n", $_[0]);
+ printf(CSOURCE "{\n");
+
+ $table_no = 1;
+
+ for ($block = 1 ; $block <= 1024 ; $block++) {
+
+ # rising edge detection
+ if ($block_enable[$block - 1] == 0 && $block_enable[$block] == 1) {
+ $block_start = $block;
+ }
+
+ # falling edge detection
+ if ($block_enable[$block] == 1 && $block_enable[$block + 1] == 0) {
+ $block_end = $block;
+
+ $char_start = ($block_start -1)* 64;
+ $char_end = ($block_end * 64) -1;
+
+ printf(CHEADER "static const u\_int16\_t %s\_table\_%d\[%d\] \= \{\n",
+ $_[0], $table_no, $char_end - $char_start +1);
+
+ for ($char = $char_start ; $char <= $char_end ; $char++) {
+ printf(CHEADER " 0x%04X, /*U\+%04X*/ /*%s*/\n",
+ $table[$char][0],
+ $table[$char][1],
+ $table[$char][2]
+ );
+ }
+ printf(CHEADER "\}\;\n");
+ printf(CHEADER "\n");
+
+ if ($char_start == 0x0000) {
+ printf(CSOURCE " if \( val \<\= 0x%04X)\n",
+ $char_end);
+ printf(CSOURCE " return %s\_table\_%d\[val]\;\n",
+ $_[0], $table_no);
+ } else {
+ printf(CSOURCE " if \( val \>\= 0x%04X \&\& val \<\= 0x%04X)\n",
+ $char_start, $char_end);
+ printf(CSOURCE " return %s\_table\_%d\[val-0x%04X\]\;\n",
+ $_[0], $table_no, $char_start);
+ }
+ printf(CSOURCE "\n");
+
+ $table_no++;
+ }
+ }
+
+ printf(CSOURCE "\treturn \(val\)\;\n");
+ printf(CSOURCE "\}\n");
+ printf(CSOURCE "\n");
+
+ # array for Surrogate Pair ---------------------------------------
+
+ printf(CSOURCE "\/*******************************************************************\n");
+ printf(CSOURCE " Convert a surrogate pair to %s case.\n", $_[0]);
+ printf(CSOURCE "*******************************************************************\/\n");
+ printf(CSOURCE "uint32\_t to%s\_sp\(uint32\_t val\)\n", $_[0]);
+ printf(CSOURCE "{\n");
+
+ $table_no = 1;
+
+ for ($block = 1025 ; $block <= 17408 ; $block++) {
+
+ # rising edge detection
+ if ((($block_enable_sp[$block - 1] == 0) || ((($block - 1) & 0xF) == 0))
+ && ($block_enable_sp[$block] == 1)) {
+ $block_start = $block;
+ }
+
+ # falling edge detection
+ if (($block_enable_sp[$block] == 1) &&
+ ((($block - 1) & 0xF == 0xF) || ($block_enable_sp[$block + 1] == 0))) {
+ $block_end = $block;
+
+ $char_start = ($block_start -1)* 64;
+ $char_end = ($block_end * 64) -1;
+
+ printf(CHEADER "static const u\_int32\_t %s\_table\_sp\_%d\[%d\] \= \{\n",
+ $_[0], $table_no, $char_end - $char_start +1);
+
+ for ($char = $char_start ; $char <= $char_end ; $char++) {
+ printf(CHEADER " 0x%08X, /*0x%08X*/ /*U\+%06X*/ /*U\+%06X*/ /*%s*/\n",
+ $table_sp[$char][0],
+ $table_sp[$char][1],
+ $table_sp[$char][2],
+ $table_sp[$char][3],
+ $table_sp[$char][4]
+ );
+ }
+ printf(CHEADER "\}\;\n");
+ printf(CHEADER "\n");
+
+ printf(CSOURCE " if \( val \>\= 0x%08X \&\& val \<\= 0x%08X)\n",
+ $table_sp[$char_start][1], $table_sp[$char_end][1]);
+ printf(CSOURCE " return %s\_table\_sp\_%d\[val-0x%08X\]\;\n",
+ $_[0], $table_no, $table_sp[$char_start][1]);
+ printf(CSOURCE "\n");
+
+ $table_no++;
+ }
+ }
+
+ printf(CSOURCE "\treturn \(val\)\;\n");
+ printf(CSOURCE "\}\n");
+ printf(CSOURCE "\n");
+}
+
+# EOF
--- /dev/null
+#!/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/reports/tr15/
+# http://www.unicode.org/Public/*/ucd/UnicodeData*.txt
+# http://www.unicode.org/Public/UNIDATA/UnicodeData.txt
+
+
+# temp files for binary search (compose.TEMP, compose_sp.TEMP) -------------
+
+open(UNICODEDATA, "<$ARGV[0]");
+
+open(COMPOSE_TEMP, ">compose.TEMP");
+open(COMPOSE_SP_TEMP, ">compose_sp.TEMP");
+
+while (<UNICODEDATA>) {
+ chop;
+ (
+ $code0,
+ $Name1,
+ $General_Category2,
+ $Canonical_Combining_Class3,
+ $Bidi_Class4,
+ $Decomposition_Mapping5,
+ $Numeric_Value6,
+ $Numeric_Value7,
+ $Numeric_Value8,
+ $Bidi_Mirrored9,
+ $Unicode_1_Name10,
+ $ISO_Comment11,
+ $Simple_Uppercase_Mapping12,
+ $Simple_Lowercase_Mapping13,
+ $Simple_Titlecase_Mapping14
+ ) = split(/\;/);
+
+ if (($Decomposition_Mapping5 ne "") && ($Decomposition_Mapping5 !~ /\</) && ($Decomposition_Mapping5 =~ / /)) {
+ ($base, $comb) = split(/ /,$Decomposition_Mapping5);
+
+ $leftbracket = " { ";
+ $rightbracket =" }, ";
+
+ # AFP 3.x Spec
+ if ( ((0x2000 <= hex($code0)) && (hex($code0) <= 0x2FFF))
+ || ((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(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 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 -------------------------------------------------------------------
+
+print ("\/\* DO NOT EDIT BY HAND\!\!\! \*\/\n");
+print ("\/\* This file is generated by \*\/\n");
+printf ("\/\* contrib/shell_utils/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");
+print (" unsigned int comb\;\n");
+print ("\} precompositions\[\] \= \{\n");
+
+system("cat precompose.SORT");
+
+print ("\}\;\n");
+print ("\n");
+
+print ("static const struct \{\n");
+print (" unsigned int replacement\;\n");
+print (" unsigned int base\;\n");
+print (" unsigned int comb\;\n");
+print ("\} decompositions\[\] \= \{\n");
+
+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
+++ /dev/null
---
--- Netatalk DBD protocol
--- wireshark -X lua_script:cnid.lua
--- don't forget to comment out the line disable_lua = true; do return end;
--- in /etc/wireshark/init.lua
-
--- global environment
-local b = _G
-
--- declare our protocol
-local dbd_proto = Proto("dbd","Netatalk Dbd Wire Protocol")
-
-local cmd = ProtoField.uint32("dbd.cmd", "Request") -- , base.HEX
-local len = ProtoField.uint32("dbd.name.len", "Name Length")
-local filename = ProtoField.string("dbd.name", "Name")
-local error = ProtoField.uint32("dbd.error", "Error code")
-local cnid = ProtoField.uint32("dbd.cnid", "Cnid")
-local did = ProtoField.uint32("dbd.did", "Parent Directory Id")
-local dev = ProtoField.uint64("dbd.dev", "Device number")
-local ino = ProtoField.uint64("dbd.ino", "Inode number")
-local type = ProtoField.uint32("dbd.type", "File type")
-
-dbd_proto.fields = {cmd, error, cnid, did, dev, ino, type, filename, len}
-
---- Request list
-local Cmd = { [3] = "add",
- [4] = "get",
- [5] = "resolve",
- [6] = "lookup",
- [7] = "update",
- [8] = "delete",
- [11] = "timestamp"
- }
-
---- display a filename
-local function fname(buffer, pinfo, tree, len, ofs)
-
- pinfo.cols.info:append(" Name=" .. buffer(ofs +4, len):string())
-
- local subtree = tree:add(buffer(ofs, len +4), buffer(ofs +4, len):string())
- subtree:add(filename, buffer(ofs +4, len))
-
- return subtree
-end
-
--- create a function to dissect it
-function dbd_proto.dissector(buffer, pinfo, tree)
-
-
- pinfo.cols.protocol = "DBD"
-
- local subtree = tree:add(dbd_proto,buffer(),"Netatalk DBD Wire Protocol")
-
- if pinfo.dst_port == 4700 then
- pinfo.cols.info = "Query"
- local val = buffer(0,4):uint()
- local item = subtree:add(cmd, buffer(0,4))
- if Cmd[val] then
- item:append_text(" (" .. Cmd[val] .. ")")
- pinfo.cols.info = Cmd[val]
-
- local val = buffer(4,4):uint()
- if val ~= 0 then
- pinfo.cols.info:append(" Cnid=" .. val)
- end
- subtree:add(cnid, buffer(4, 4))
- subtree:add(dev, buffer(8, 8))
- subtree:add(ino, buffer(16, 8))
- subtree:add(type, buffer(24, 4))
-
- local val = buffer(28,4):uint()
- if val ~= 0 then
- pinfo.cols.info:append(" Did=" .. val)
- end
- subtree:add(did, buffer(28, 4))
-
- local val = buffer(36,4):uint()
- if val ~= 0 then
- item = fname(buffer, pinfo, subtree, val, 36)
- item:add(len, buffer(36, 4))
-
- end
- end
- else
- pinfo.cols.info = "Reply"
-
- local rply = {}
-
- local val = buffer(0,4):uint()
- rply.error = val
- subtree:add(error, buffer(0,4))
- if val ~= 0 then
- pinfo.cols.info:append(" Error=" .. val)
- end
-
- val = buffer(4,4):uint()
- rply.cnid = val
- subtree:add(cnid, buffer(4,4))
- if val ~= 0 then
- pinfo.cols.info:append(" Cnid=" .. val)
- end
-
- val = buffer(8,4):uint()
- rply.did = val
- subtree:add(did, buffer(8,4))
- if val ~= 0 then
- pinfo.cols.info:append(" Did=" .. val)
- end
-
- val = buffer(16,4):uint()
- rply.len = val
-
- if rply.error == 0 and rply.did ~= 0 then
- subtree = fname(buffer, pinfo, subtree, val, 16)
- subtree:add(len, buffer(16,4))
- end
- end
-end
-
--- load the tcp.port table
-local tcp_table = DissectorTable.get("tcp.port")
--- register our protocol
-tcp_table:add(4700, dbd_proto)
# Makefile.am for distrib/
-SUBDIRS = config initscripts m4
+SUBDIRS = config initscripts m4 systemd
service.atalk.redhat-systemd
netatalk
atalk
+netatalk.service
+netatalk.sh
.gitignore
*.o
# Required-Start: $remote_fs $syslog
# Required-Stop: $remote_fs $syslog
# Default-Start: 2 3 4 5
-# Default-Stop: 1
+# Default-Stop: 0 1 6
### END INIT INFO
#
# netatalk Netatalk :NETATALK_VERSION: initscript
# Netatalk :NETATALK_VERSION: startup script for systemd.
+# The method of using this script is not suitable.
+# This script will be deleted in the future.
+
ATALK_BIN=:BINDIR:
ATALK_CONF_DIR=:ETCDIR:
ATALK_SBIN=:SBINDIR:
# This file is part of netatalk :NETATALK_VERSION:.
+# The method of using shell-script "netatalk.sh" is not suitable.
+# The future service files are due to start daemons directly.
+# See netatalk-xxx/distrib/systemd/ directory in tarball.
+
[Unit]
Description=File and Printer sharing for Macintosh clients
After=syslog.target network.target
--- /dev/null
+# Makefile for distrib/systemd/
+
+EXTRA_DIST = README netatalk-afpd.service netatalk-cnid_metad.service
--- /dev/null
+The service file of the current Netatalk is not appropriate because it use
+a shell-script "netatalk.sh".
+Two experimental files are for future netatalk.
+
+These files start daemons directly and do not read "netatalk.conf".
+Therefore, you need to edit files for setting options.
+
+ATALK_NAME: set in afpd.conf instead
+AFPD_MAX_CLIENTS: set in netatalk-afpd.service by using -c
+AFPD_UAMLIST: set in afpd.conf instead
+AFPD_GUEST: set in afpd.conf instead
+CNID_CONFIG: set in netatalk-cnid_metad.service by using -l and -f options
+
+There are no service files for atalkd, papd, timelord and a2boot
+because AppleTalk feature is due to be abolished in the future.
--- /dev/null
+# This is experimental service file.
+# See distrib/systemd/README
+
+[Unit]
+Description=Netatalk AFP fileserver for Macintosh clients
+After=syslog.target network.target slpd.service avahi-daemon.service netatalk-cnid_metad.service
+
+[Service]
+Type=forking
+GuessMainPID=no
+ExecStart=/usr/sbin/afpd -c 20
+Restart=always
+RestartSec=1
+
+[Install]
+WantedBy=multi-user.target
--- /dev/null
+# This is experimental service file.
+# See distrib/systemd/README
+
+[Unit]
+Description=Netatalk CNID database daemon for afpd
+After=syslog.target network.target
+
+[Service]
+Type=forking
+GuessMainPID=no
+ExecStart=/usr/sbin/cnid_metad -l log_note
+Restart=always
+RestartSec=1
+
+[Install]
+WantedBy=multi-user.target
/*
Copyright (c) 2008, 2009, 2010 Frank Lahm <franklahm@gmail.com>
+ Copyright (c) 2011 Laura Mueller <laura-mueller@uni-duesseldorf.de>
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
#define MAP_MASK 31
#define IS_DIR 32
+/* bit flags for set_acl() and map_aces_darwin_to_posix() */
+#define HAS_DEFAULT_ACL 0x01
+#define HAS_EXT_DEFAULT_ACL 0x02
+
/********************************************************
* Solaris funcs
********************************************************/
uint32_t *result)
{
EC_INIT;
- int havemask = 0;
int entry_id = ACL_FIRST_ENTRY;
- uint32_t rights = 0, maskrights = 0;
+ uint32_t rights = 0; /* rights which do not depend on ACL_MASK */
+ uint32_t acl_rights = 0; /* rights which are subject to limitations imposed by ACL_MASK */
+ uint32_t mask_rights = 0xffffffff;
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;
- }
- }
+ EC_NULL_LOGSTR(acl = acl_get_file(path, ACL_TYPE_ACCESS),
+ "acl_get_file(\"%s\"): %s", fullpathname(path), strerror(errno));
- /* itereate through all ACEs */
- entry_id = ACL_FIRST_ENTRY;
+ /* Iterate through all ACEs. If we apply mask_rights later there is no need to iterate twice. */
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 (!(sb->st_uid == uuid) && 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:
- if (!(sb->st_uid == uuid) && !gmem(sb->st_gid)) {
- LOG(log_maxdebug, logtype_afpd, "ACL_OTHER");
- rights |= posix_permset_to_darwin_rights(e, S_ISDIR(sb->st_mode));
- }
- break;
- default:
- continue;
+ 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_USER:
+ EC_NULL_LOG(uid = (uid_t *)acl_get_qualifier(e));
+
+ if (*uid == uuid) {
+ LOG(log_maxdebug, logtype_afpd, "ACL_USER: %u", *uid);
+ acl_rights |= posix_permset_to_darwin_rights(e, S_ISDIR(sb->st_mode));
+ }
+ acl_free(uid);
+ uid = NULL;
+ break;
+
+ case ACL_GROUP_OBJ:
+ if (!(sb->st_uid == uuid) && gmem(sb->st_gid)) {
+ LOG(log_maxdebug, logtype_afpd, "ACL_GROUP_OBJ: %u", sb->st_gid);
+ acl_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);
+ acl_rights |= posix_permset_to_darwin_rights(e, S_ISDIR(sb->st_mode));
+ }
+ acl_free(gid);
+ gid = NULL;
+ break;
+
+ case ACL_MASK:
+ mask_rights = posix_permset_to_darwin_rights(e, S_ISDIR(sb->st_mode));
+ LOG(log_maxdebug, logtype_afpd, "maskrights: 0x%08x", mask_rights);
+ break;
+
+ case ACL_OTHER:
+ if (!(sb->st_uid == uuid) && !gmem(sb->st_gid)) {
+ LOG(log_maxdebug, logtype_afpd, "ACL_OTHER");
+ rights |= posix_permset_to_darwin_rights(e, S_ISDIR(sb->st_mode));
+ }
+ break;
+
+ default:
+ continue;
}
} /* while */
+ /* apply the mask and collect the rights */
+ rights |= (acl_rights & mask_rights);
+
*result |= rights;
EC_CLEANUP:
EC_EXIT;
}
+/*!
+ * Helper function for posix_acls_to_uaperms() to convert Posix ACL permissions
+ * into access rights needed to fill ua_permissions of a FPUnixPrivs structure.
+ *
+ * @param entry (r) Posix ACL entry
+ *
+ * @returns access rights
+ */
+static u_char acl_permset_to_uarights(acl_entry_t entry) {
+ acl_permset_t permset;
+ u_char rights = 0;
+
+ if (acl_get_permset(entry, &permset) == -1)
+ return rights;
+
+#ifdef HAVE_ACL_GET_PERM_NP
+ if (acl_get_perm_np(permset, ACL_READ))
+#else
+ if (acl_get_perm(permset, ACL_READ))
+#endif
+ rights |= AR_UREAD;
+
+#ifdef HAVE_ACL_GET_PERM_NP
+ if (acl_get_perm_np(permset, ACL_WRITE))
+#else
+ if (acl_get_perm(permset, ACL_WRITE))
+#endif
+ rights |= AR_UWRITE;
+
+#ifdef HAVE_ACL_GET_PERM_NP
+ if (acl_get_perm_np(permset, ACL_EXECUTE))
+#else
+ if (acl_get_perm(permset, ACL_EXECUTE))
+#endif
+ rights |= AR_USEARCH;
+
+ return rights;
+}
+
+/*!
+ * Update FPUnixPrivs for a file-system object on a volume supporting ACLs
+ *
+ * Checks permissions granted by ACLS for a user to one fs-object and
+ * updates user and group permissions in given struct maccess. As OS X
+ * doesn't conform to Posix 1003.1e Draft 17 it expects proper group
+ * permissions in st_mode of struct stat even if the fs-object has an
+ * ACL_MASK entry, st_mode gets modified to properly reflect group
+ * permissions.
+ *
+ * @param path (r) path to filesystem object
+ * @param sb (rw) struct stat of path
+ * @param maccess (rw) struct maccess of path
+ *
+ * @returns 0 or -1 on error
+ */
+static int posix_acls_to_uaperms(const char *path, struct stat *sb, struct maccess *ma) {
+ EC_INIT;
+
+ int entry_id = ACL_FIRST_ENTRY;
+ acl_entry_t entry;
+ acl_tag_t tag;
+ acl_t acl = NULL;
+ uid_t *uid;
+ gid_t *gid;
+ uid_t whoami = geteuid();
+
+ u_char group_rights = 0x00;
+ u_char acl_rights = 0x00;
+ u_char mask = 0xff;
+
+ EC_NULL_LOG(acl = acl_get_file(path, ACL_TYPE_ACCESS));
+
+ /* iterate through all ACEs */
+ while (acl_get_entry(acl, entry_id, &entry) == 1) {
+ entry_id = ACL_NEXT_ENTRY;
+ EC_ZERO_LOG(acl_get_tag_type(entry, &tag));
+
+ switch (tag) {
+ case ACL_USER:
+ EC_NULL_LOG(uid = (uid_t *)acl_get_qualifier(entry));
+
+ if (*uid == uuid && !(whoami == sb->st_uid)) {
+ LOG(log_maxdebug, logtype_afpd, "ACL_USER: %u", *uid);
+ acl_rights |= acl_permset_to_uarights(entry);
+ }
+ acl_free(uid);
+ break;
+
+ case ACL_GROUP_OBJ:
+ group_rights = acl_permset_to_uarights(entry);
+ LOG(log_maxdebug, logtype_afpd, "ACL_GROUP_OBJ: %u", sb->st_gid);
+
+ if (gmem(sb->st_gid) && !(whoami == sb->st_uid))
+ acl_rights |= group_rights;
+ break;
+
+ case ACL_GROUP:
+ EC_NULL_LOG(gid = (gid_t *)acl_get_qualifier(entry));
+
+ if (gmem(*gid) && !(whoami == sb->st_uid)) {
+ LOG(log_maxdebug, logtype_afpd, "ACL_GROUP: %u", *gid);
+ acl_rights |= acl_permset_to_uarights(entry);
+ }
+ acl_free(gid);
+ break;
+
+ case ACL_MASK:
+ mask = acl_permset_to_uarights(entry);
+ LOG(log_maxdebug, logtype_afpd, "ACL_MASK: 0x%02x", mask);
+ break;
+
+ default:
+ break;
+ }
+ }
+ /* apply the mask and adjust user and group permissions */
+ ma->ma_user |= (acl_rights & mask);
+ ma->ma_group = (group_rights & mask);
+
+ /* update st_mode to properly reflect group permissions */
+ sb->st_mode &= ~S_IRWXG;
+
+ if (ma->ma_group & AR_USEARCH)
+ sb->st_mode |= S_IXGRP;
+
+ if (ma->ma_group & AR_UWRITE)
+ sb->st_mode |= S_IWGRP;
+
+ if (ma->ma_group & AR_UREAD)
+ sb->st_mode |= S_IRGRP;
+
+EC_CLEANUP:
+ if (acl) acl_free(acl);
+
+ EC_EXIT;
+}
+
/*!
* Add entries of one acl to another acl
*
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)))
+ if (darwin_ace_rights & (DARWIN_ACE_WRITE_DATA | (is_dir ? DARWIN_ACE_DELETE_CHILD : 0)))
perm |= ACL_WRITE;
if (darwin_ace_rights & DARWIN_ACE_EXECUTE)
EC_ZERO_LOG(acl_add_perm(permset, perm));
EC_ZERO_LOG(acl_set_permset(e, permset));
}
-
+
EC_CLEANUP:
if (eid) acl_free(eid);
* - 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
+ * @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
+ * @param default_acl_flags (rw) flags to indicate if the object has a basic default
+ * acl or an extended default acl.
*
- * @returns 0 on success storing the result in aclp, -1 on error.
+ * @returns 0 on success storing the result in aclp, -1 on error. default_acl_flags
+ * is set to HAS_DEFAULT_ACL|HAS_EXT_DEFAULT_ACL in case there is at least one
+ * extended default ace. Otherwise default_acl_flags is left unchanged.
*/
static int map_aces_darwin_to_posix(const darwin_ace_t *darwin_aces,
acl_t *def_aclp,
acl_t *acc_aclp,
- int ace_count)
+ int ace_count,
+ uint32_t *default_acl_flags)
{
EC_INIT;
char *name = NULL;
}
/* add it as default ace */
EC_ZERO_LOG(posix_acl_add_perm(def_aclp, tag, id, perm));
-
+ *default_acl_flags = (HAS_DEFAULT_ACL|HAS_EXT_DEFAULT_ACL);
if (! (darwin_ace_flags & DARWIN_ACE_FLAGS_ONLY_INHERIT))
/* if it not a "inherit only" ace, it must be added as access aces too */
uint32_t ace_count)
{
EC_INIT;
- acl_t def_acl = NULL;
- acl_t acc_acl = NULL;
+ struct stat st;
+ acl_t default_acl = NULL;
+ acl_t access_acl = NULL;
+ acl_entry_t entry;
+ acl_tag_t tag;
+ int entry_id = ACL_FIRST_ENTRY;
+ int has_def_acl = 0;
+ /* flags to indicate if the object has a minimal default acl and/or an extended
+ * default acl.
+ */
+ uint32_t default_acl_flags = 0;
LOG(log_maxdebug, logtype_afpd, "set_acl: BEGIN");
- struct stat st;
- EC_ZERO_LOG_ERR(lstat(name, &st), AFPERR_NOOBJ);
+ EC_NULL_LOG_ERR(access_acl = acl_get_file(name, ACL_TYPE_ACCESS), AFPERR_MISC);
+
+ /* Iterate through acl and remove all extended acl entries. */
+ while (acl_get_entry(access_acl, entry_id, &entry) == 1) {
+ entry_id = ACL_NEXT_ENTRY;
+ EC_ZERO_LOG(acl_get_tag_type(entry, &tag));
+
+ if ((tag == ACL_USER) || (tag == ACL_GROUP) || (tag == ACL_MASK)) {
+ EC_ZERO_LOG_ERR(acl_delete_entry(access_acl, entry), AFPERR_MISC);
+ }
+ } /* while */
- /* 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);
+ /* In case we are acting on a directory prepare a default acl. For files default_acl will be NULL.
+ * If the directory already has a default acl it will be preserved.
+ */
+ EC_ZERO_LOG_ERR(lstat(name, &st), AFPERR_NOOBJ);
- /* for files def_acl will be NULL */
+ if (S_ISDIR(st.st_mode)) {
+ default_acl = acl_get_file(name, ACL_TYPE_DEFAULT);
- /* create access acl from mode */
- EC_NULL_LOG_ERR(acc_acl = acl_from_mode(st.st_mode), AFPERR_MISC);
+ if (default_acl) {
+ /* If default_acl is not empty then the dir has a default acl. */
+ if (acl_get_entry(default_acl, ACL_FIRST_ENTRY, &entry) == 1)
+ default_acl_flags = HAS_DEFAULT_ACL;
+ acl_free(default_acl);
+ }
+ default_acl = acl_dup(access_acl);
+ }
/* adds the clients aces */
- EC_ZERO_ERR(map_aces_darwin_to_posix(daces, &def_acl, &acc_acl, ace_count), AFPERR_MISC);
+ EC_ZERO_ERR(map_aces_darwin_to_posix(daces, &default_acl, &access_acl, ace_count, &default_acl_flags), AFPERR_MISC);
/* calcuate ACL mask */
- EC_ZERO_LOG_ERR(acl_calc_mask(&acc_acl), AFPERR_MISC);
+ EC_ZERO_LOG_ERR(acl_calc_mask(&access_acl), AFPERR_MISC);
/* is it ok? */
- EC_ZERO_LOG_ERR(acl_valid(acc_acl), AFPERR_MISC);
+ EC_ZERO_LOG_ERR(acl_valid(access_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);
+ EC_ZERO_LOG_ERR(acl_set_file(name, ACL_TYPE_ACCESS, access_acl), AFPERR_MISC);
+ EC_ZERO_LOG_ERR(vol->vfs->vfs_acl(vol, name, ACL_TYPE_ACCESS, 0, access_acl), AFPERR_MISC);
+
+ if (default_acl) {
+ /* If the dir has an extended default acl it's ACL_MASK must be updated.*/
+ if (default_acl_flags & HAS_EXT_DEFAULT_ACL)
+ EC_ZERO_LOG_ERR(acl_calc_mask(&default_acl), AFPERR_MISC);
+
+ if (default_acl_flags) {
+ EC_ZERO_LOG_ERR(acl_valid(default_acl), AFPERR_MISC);
+ EC_ZERO_LOG_ERR(acl_set_file(name, ACL_TYPE_DEFAULT, default_acl), AFPERR_MISC);
+ EC_ZERO_LOG_ERR(vol->vfs->vfs_acl(vol, name, ACL_TYPE_DEFAULT, 0, default_acl), AFPERR_MISC);
+ }
}
EC_CLEANUP:
- acl_free(acc_acl);
- acl_free(def_acl);
+ if (access_acl) acl_free(access_acl);
+ if (default_acl) acl_free(default_acl);
LOG(log_maxdebug, logtype_afpd, "set_acl: END");
EC_EXIT;
LOG(log_maxdebug, logtype_afpd, "check_acl_access(dir: \"%s\", path: \"%s\", curdir: \"%s\", 0x%08x)",
cfrombstr(dir->d_fullpath), path, getcwdpath(), requested_rights);
+ /* This check is not used anymore, as OS X Server seems to be ignoring too */
+#if 0
/* Get uid or gid from UUID */
EC_ZERO_ERR(getnamefromuuid(uuid, &username, &uuidtype), AFPERR_PARAM);
- EC_ZERO_LOG_ERR(lstat(path, &st), AFPERR_PARAM);
-
switch (uuidtype) {
case UUID_USER:
break;
EC_STATUS(AFPERR_MISC);
goto EC_CLEANUP;
}
+#endif
+
+ EC_ZERO_LOG_ERR(lstat(path, &st), AFPERR_PARAM);
is_dir = !strcmp(path, ".");
if (allowed_rights & DARWIN_ACE_ADD_SUBDIRECTORY)
allowed_rights |= DARWIN_ACE_DELETE;
- dir->d_rights_cache = allowed_rights;
+ curdir->d_rights_cache = allowed_rights;
}
LOG(log_debug, logtype_afpd, "allowed rights: 0x%08x", allowed_rights);
}
* 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)
+int acltoownermode(const struct vol *vol, char *path, struct stat *st, struct maccess *ma)
{
EC_INIT;
uint32_t rights = 0;
if ( ! (AFPobj->options.flags & OPTION_ACL2MACCESS)
- || (current_vol == NULL)
- || ! (current_vol->v_flags & AFPVOL_ACLS))
+ || ! (vol->v_flags & AFPVOL_ACLS))
return 0;
LOG(log_maxdebug, logtype_afpd, "acltoownermode(\"%s/%s\", 0x%02x)",
#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
LOG(log_maxdebug, logtype_afpd, "rights: 0x%08x", rights);
ma->ma_user |= AR_UWRITE;
if (rights & (DARWIN_ACE_EXECUTE | DARWIN_ACE_SEARCH))
ma->ma_user |= AR_USEARCH;
+#endif
+
+#ifdef HAVE_POSIX_ACLS
+ EC_ZERO_LOG(posix_acls_to_uaperms(path, st, ma));
+#endif
- LOG(log_maxdebug, logtype_afpd, "resulting user maccess: 0x%02x", ma->ma_user);
+ LOG(log_maxdebug, logtype_afpd, "resulting user maccess: 0x%02x group maccess: 0x%02x", ma->ma_user, ma->ma_group);
EC_CLEANUP:
EC_EXIT;
extern int acl_ldap_readconfig(char *name);
/* Misc funcs */
-extern int acltoownermode(char *path, struct stat *st, struct maccess *ma);
+extern int acltoownermode(const struct vol *vol, char *path, struct stat *st, struct maccess *ma);
extern int check_vol_acl_support(const struct vol *vol);
#endif
continue;
/* Blocking read on the network socket */
- cmd = dsi_receive(dsi);
+ cmd = dsi_stream_receive(dsi);
if (cmd == 0) {
/* cmd == 0 is the error condition */
/* AFP replay cache */
rc_idx = dsi->clientID % REPLAYCACHE_SIZE;
- LOG(log_debug, logtype_afpd, "DSI request ID: %u", dsi->clientID);
+ LOG(log_debug, logtype_dsi, "DSI request ID: %u", dsi->clientID);
if (replaycache[rc_idx].DSIreqID == dsi->clientID
&& replaycache[rc_idx].AFPcommand == function) {
if (dsi->flags & DSI_NOREPLY) {
dsi->flags &= ~DSI_NOREPLY;
break;
- }
-
- if (!dsi_cmdreply(dsi, err)) {
+ } else if (!dsi_cmdreply(dsi, err)) {
LOG(log_error, logtype_afpd, "dsi_cmdreply(%d): %s", dsi->socket, strerror(errno) );
if (dsi_disconnect(dsi) != 0)
afp_dsi_die(EXITERR_CLNT);
free(opt->logconfig);
if (opt->mimicmodel && (opt->mimicmodel != save->mimicmodel))
free(opt->mimicmodel);
+ if (opt->adminauthuser && (opt->adminauthuser != save->adminauthuser))
+ free(opt->adminauthuser);
}
/* initialize options */
options->dsireadbuf = 12;
options->mimicmodel = NULL;
options->fce_fmodwait = 60; /* put fmod events 60 seconds on hold */
+ options->adminauthuser = NULL;
}
/* parse an afpd.conf line. i'm doing it this way because it's
if ((c = getoption(buf, "-mimicmodel")) && (opt = strdup(c)))
options->mimicmodel = opt;
+ if ((c = getoption(buf, "-adminauthuser")) && (opt = strdup(c)))
+ options->adminauthuser = opt;
+
return 1;
}
#undef accessmode
#endif
-void afsmode( path, ma, dir, st )
+void afsmode( vol, path, ma, dir, st )
+const struct volume *vol;
char *path;
struct maccess *ma;
struct dir *dir;
return;
}
- accessmode( path, ma, dir, st );
+ accessmode(vol, path, ma, dir, st );
return;
}
{
static uint32_t cur_pos; /* Saved position index (ID) - used to remember "position" across FPCatSearch calls */
static DIR *dirpos; /* UNIX structure describing currently opened directory. */
- struct dir *curdir; /* struct dir of current directory */
+ struct dir *currentdir; /* struct dir of current directory */
int cidx, r;
struct dirent *entry;
int result = AFP_OK;
start_time = time(NULL);
while ((cidx = reducestack()) != -1) {
+ LOG(log_debug, logtype_afpd, "catsearch: dir: \"%s\"", dstack[cidx].path);
+
error = lchdir(dstack[cidx].path);
if (!error && dirpos == NULL)
goto catsearch_end;
}
- if ((curdir = dirlookup_bypath(vol, dstack[cidx].path)) == NULL) {
+ if ((currentdir = dirlookup_bypath(vol, dstack[cidx].path)) == NULL) {
result = AFPERR_MISC;
goto catsearch_end;
}
+ LOG(log_debug, logtype_afpd, "catsearch: current struct dir: \"%s\"", cfrombstr(currentdir->d_fullpath));
while ((entry = readdir(dirpos)) != NULL) {
(*pos)++;
if (!check_dirent(vol, entry->d_name))
continue;
+ LOG(log_debug, logtype_afpd, "catsearch(\"%s\"): dirent: \"%s\"",
+ cfrombstr(currentdir->d_fullpath), entry->d_name);
+
memset(&path, 0, sizeof(path));
path.u_name = entry->d_name;
if (of_stat(&path) != 0) {
*/
int unlen = strlen(path.u_name);
path.d_dir = dircache_search_by_name(vol,
- curdir,
+ currentdir,
path.u_name,
unlen);
if (path.d_dir == NULL) {
/* path.m_name is set by adddir */
if ((path.d_dir = dir_add(vol,
- curdir,
+ currentdir,
&path,
unlen)) == NULL) {
result = AFPERR_MISC;
goto catsearch_end;
}
} else {
- path.d_dir = curdir;
+ path.d_dir = currentdir;
}
ccr = crit_check(vol, &path);
dircache_stat.expunged++;
}
key.d_vid = vol->v_vid;
- key.d_pdid = dir->d_did;
+ key.d_pdid = dir->d_pdid;
key.d_u_name = dir->d_u_name;
if ((hn = hash_lookup(index_didname, &key))) {
/* Found an entry with the same DID/name, delete it */
cnid = htonl(2);
dir = vol->v_root;
+ LOG(log_debug, logtype_afpd, "dirlookup_bypath(\"%s\")", path);
+
+ if (strcmp(vol->v_path, path) == 0)
+ return dir;
+
EC_NULL(rpath = rel_path_in_vol(path, vol->v_path)); /* 1. */
+
+ LOG(log_debug, logtype_afpd, "dirlookup_bypath: rpath: \"%s\"", cfrombstr(rpath));
+
EC_NULL(statpath = bfromcstr(vol->v_path)); /* 2. */
l = bsplit(rpath, '/');
did = cnid;
EC_ZERO(bcatcstr(statpath, "/"));
EC_ZERO(bconcat(statpath, l->entry[i]));
+
+ LOG(log_debug, logtype_afpd, "dirlookup_bypath: statpath: \"%s\"", cfrombstr(statpath));
+
EC_ZERO_LOGSTR(lstat(cfrombstr(statpath), &st),
"lstat(rpath: %s, elem: %s): %s: %s",
cfrombstr(rpath), cfrombstr(l->entry[i]),
dir,
cfrombstr(l->entry[i]),
blength(l->entry[i]))) == NULL) {
+
if ((cnid = cnid_add(vol->v_cdb, /* 6. */
&st,
did,
cfrombstr(l->entry[i]),
blength(l->entry[i]),
- 0)) == CNID_INVALID) {
+ 0)) == CNID_INVALID)
EC_FAIL;
- }
if ((dir = dirlookup(vol, cnid)) == NULL) /* 7. */
EC_FAIL;
if (ret != 0)
return NULL;
+ LOG(log_debug, logtype_afpd, "dirlookup_bypath: result: \"%s\"",
+ cfrombstr(dir->d_fullpath));
+
return dir;
}
if (!p)
return -1;
- accessmode(p, &ma, curdir, NULL);
+ accessmode(current_vol, p, &ma, curdir, NULL);
if ((mode & OPENACC_WR) && !(ma.ma_user & AR_UWRITE))
return -1;
if ((mode & OPENACC_RD) && !(ma.ma_user & AR_UREAD))
{
struct maccess ma;
- accessmode(path->u_name, &ma, curdir, &path->st);
+ accessmode(current_vol, path->u_name, &ma, curdir, &path->st);
LOG(log_debug, logtype_afpd, "file_access(\"%s\"): mapped user mode: 0x%02x",
path->u_name, ma.ma_user);
ashort = htons(ATTRBIT_INVISIBLE);
} else
ashort = 0;
- ashort |= htons(ATTRBIT_SHARED);
memcpy( data, &ashort, sizeof( ashort ));
data += sizeof( ashort );
break;
break;
case DIRPBIT_ACCESS :
- accessmode( upath, &ma, dir , st);
+ accessmode(vol, upath, &ma, dir , st);
*data++ = ma.ma_user;
*data++ = ma.ma_world;
break;
case DIRPBIT_UNIXPR :
+ /* accessmode may change st_mode with ACLs */
+ accessmode(vol, upath, &ma, dir, st);
+
aint = htonl(st->st_uid);
memcpy( data, &aint, sizeof( aint ));
data += sizeof( aint );
memcpy( data, &aint, sizeof( aint ));
data += sizeof( aint );
- accessmode( upath, &ma, dir , st);
-
*data++ = ma.ma_user;
*data++ = ma.ma_world;
*data++ = ma.ma_group;
dir_remove( vol, fdir );
} else {
LOG(log_error, logtype_afpd, "deletecurdir(\"%s\"): netatalk_rmdir_all_errors error",
- curdir->d_fullpath);
+ cfrombstr(curdir->d_fullpath));
}
delete_done:
udp_initialized = FCE_FALSE;
}
-
/*
* Construct a UDP packet for our listeners and return packet size
* */
static ssize_t build_fce_packet( struct fce_packet *packet, char *path, int mode, uint32_t event_id )
{
- size_t pathlen;
+ size_t pathlen = 0;
ssize_t data_len = 0;
+ uint64_t *t;
- strncpy(packet->magic, FCE_PACKET_MAGIC, sizeof(packet->magic) );
+ /* Set content of packet */
+ memcpy(packet->magic, FCE_PACKET_MAGIC, sizeof(packet->magic) );
packet->version = FCE_PACKET_VERSION;
packet->mode = mode;
- packet->event_id = event_id;
-
- pathlen = strlen(path) + 1; /* include string terminator */
+
+ packet->event_id = event_id;
+ pathlen = strlen(path); /* exclude string terminator */
+
/* This should never happen, but before we bust this server, we send nonsense, fce listener has to cope */
if (pathlen >= MAXPATHLEN)
pathlen = MAXPATHLEN - 1;
- /* This is the payload len. Means: the stream has len bytes more until packet is finished */
- /* A server should read the first 16 byte, decode them and then fetch the rest */
- data_len = FCE_PACKET_HEADER_SIZE + pathlen;
packet->datalen = pathlen;
+ /* This is the payload len. Means: the packet has len bytes more until packet is finished */
+ data_len = FCE_PACKET_HEADER_SIZE + pathlen;
+
switch (mode) {
case FCE_TM_SIZE:
- tm_used = hton64(tm_used);
- memcpy(packet->data, &tm_used, sizeof(tm_used));
- strncpy(packet->data + sizeof(tm_used), path, pathlen);
-
- packet->datalen += sizeof(tm_used);
+ t = (uint64_t *)packet->data;
+ *t = hton64(tm_used);
+ memcpy(packet->data + sizeof(tm_used), path, pathlen);
+
+ packet->datalen = pathlen + sizeof(tm_used);
data_len += sizeof(tm_used);
break;
default:
- strncpy(packet->data, path, pathlen);
+ memcpy(packet->data, path, pathlen);
break;
}
return data_len;
}
-static int pack_fce_packet(struct fce_packet *packet, unsigned char *buf)
+/*
+ * Handle Endianess and write into buffer w/o padding
+ **/
+static void pack_fce_packet(struct fce_packet *packet, unsigned char *buf, int maxlen)
{
unsigned char *p = buf;
*p = packet->mode;
p++;
- uint32_t id = htonl(packet->event_id);
- memcpy(p, &id, sizeof(id));
+ uint32_t *id = (uint32_t*)p;
+ *id = htonl(packet->event_id);
p += sizeof(packet->event_id);
- uint16_t l = htons(packet->datalen);
- memcpy(p, &l, sizeof(l));
- p += sizeof(l);
+ uint16_t *l = ( uint16_t *)p;
+ *l = htons(packet->datalen);
+ p += sizeof(packet->datalen);
- memcpy(p, &packet->data[0], packet->datalen);
- p += packet->datalen;
-
- return 0;
+ if (((p - buf) + packet->datalen) < maxlen) {
+ memcpy(p, &packet->data[0], packet->datalen);
+ }
}
/*
/* build our data packet */
ssize_t data_len = build_fce_packet( &packet, path, mode, ++event_id );
- pack_fce_packet(&packet, iobuf);
+ pack_fce_packet(&packet, iobuf, MAXIOBUF);
for (int i = 0; i < udp_sockets; i++)
{
/* Okay, we have a running socket again, send server that we had a problem on our side*/
data_len = build_fce_packet( &packet, "", FCE_CONN_BROKEN, 0 );
- pack_fce_packet(&packet, iobuf);
+ pack_fce_packet(&packet, iobuf, MAXIOBUF);
sendto(udp_entry->sock,
iobuf,
/* Rebuild our original data packet */
data_len = build_fce_packet( &packet, path, mode, event_id );
- pack_fce_packet(&packet, iobuf);
+ pack_fce_packet(&packet, iobuf, MAXIOBUF);
}
sent_data = sendto(udp_entry->sock,
if (!(fce_ev_enabled & (1 << FCE_FILE_DELETE)))
return ret;
- ret = register_fce( path->u_name, FALSE, FCE_FILE_DELETE );
+ ret = register_fce( path->u_name, false, FCE_FILE_DELETE );
return ret;
}
if (!(fce_ev_enabled & (1 << FCE_DIR_DELETE)))
return ret;
- ret = register_fce( name, TRUE, FCE_DIR_DELETE);
+ ret = register_fce( name, true, FCE_DIR_DELETE);
return ret;
}
if (!(fce_ev_enabled & (1 << FCE_DIR_CREATE)))
return ret;
- ret = register_fce( path->u_name, TRUE, FCE_DIR_CREATE );
+ ret = register_fce( path->u_name, true, FCE_DIR_CREATE );
return ret;
}
if (!(fce_ev_enabled & (1 << FCE_FILE_CREATE)))
return ret;
- ret = register_fce( path->u_name, FALSE, FCE_FILE_CREATE );
+ ret = register_fce( path->u_name, false, FCE_FILE_CREATE );
return ret;
}
return AFPERR_MISC;
}
- ret = register_fce( u_name, FALSE, FCE_FILE_MODIFY );
+ ret = register_fce( u_name, false, FCE_FILE_MODIFY );
return ret;
}
return ret;
tm_used = used; /* oh what a hack */
- ret = register_fce(vol, FALSE, FCE_TM_SIZE);
+ ret = register_fce(vol, false, FCE_TM_SIZE);
return ret;
}
#ifndef _FCE_API_INTERNAL_H
#define _FCE_API_INTERNAL_H
+#include <stdbool.h>
+
#define FCE_MAX_UDP_SOCKS 5 /* Allow a maximum of udp listeners for file change events */
#define FCE_SOCKET_RETRY_DELAY_S 600 /* Pause this time in s after socket was broken */
#define FCE_PACKET_VERSION 1
#define PACKET_HDR_LEN (sizeof(struct fce_packet) - FCE_MAX_PATH_LEN)
-int fce_handle_coalescation( char *path, int is_dir, int mode );
+bool fce_handle_coalescation( char *path, int is_dir, int mode );
void fce_initialize_history();
#endif /* HAVE_CONFIG_H */
#include <stdio.h>
-
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <time.h>
-
-
+#include <stdbool.h>
#include <sys/param.h>
#include <sys/socket.h>
#include <netinet/in.h>
}
}
-int fce_handle_coalescation( char *path, int is_dir, int mode )
+bool fce_handle_coalescation( char *path, int is_dir, int mode )
{
/* These two are used to eval our next index in history */
/* the history is unsorted, speed should not be a problem, length is 10 */
struct timeval tv;
if (coalesce == 0)
- return FALSE;
+ return false;
/* After a file creation *ALWAYS* a file modification is produced */
if ((mode == FCE_FILE_CREATE) && (coalesce & FCE_COALESCE_CREATE))
- return TRUE;
+ return true;
/* get timestamp */
gettimeofday(&tv, 0);
if ((coalesce & FCE_COALESCE_CREATE) && (fh->mode == FCE_DIR_CREATE)) {
/* Parent dir ? */
if (!strncmp(fh->path, path, strlen(fh->path)))
- return TRUE;
+ return true;
}
/* If we find a parent dir we should be DELETED we are done */
&& (mode == FCE_FILE_DELETE || mode == FCE_DIR_DELETE)) {
/* Parent dir ? */
if (!strncmp(fh->path, path, strlen(fh->path)))
- return TRUE;
+ return true;
}
/* Detect oldest entry for next new entry */
strncpy( fce_history_list[oldest_entry_idx].path, path, MAXPATHLEN);
/* we have to handle this event */
- return FALSE;
+ return false;
}
/*
/* FIXME do we want a visual clue if the file is read only
*/
struct maccess ma;
- accessmode( ".", &ma, dir , NULL);
+ accessmode(vol, ".", &ma, dir , NULL);
if ((ma.ma_user & AR_UWRITE)) {
- accessmode( upath, &ma, dir , st);
+ accessmode(vol, upath, &ma, dir , st);
if (!(ma.ma_user & AR_UWRITE)) {
ashort |= htons(ATTRBIT_NOWRITE);
}
break;
case FILPBIT_UNIXPR :
/* accessmode may change st_mode with ACLs */
- accessmode( upath, &ma, dir , st);
+ accessmode(vol, upath, &ma, dir , st);
aint = htonl(st->st_uid);
memcpy( data, &aint, sizeof( aint ));
if (ad_reso_fileno(adp) == -1 || 0 == (err = copy_fork(ADEID_RFORK, &add, adp))){
/* copy the data fork */
if ((err = copy_fork(ADEID_DFORK, &add, adp)) == 0) {
- err = d_vol->vfs->vfs_copyfile(d_vol, sfd, src, dst);
+ if (ad_meta_fileno(adp) != -1)
+ err = d_vol->vfs->vfs_copyfile(d_vol, sfd, src, dst);
}
}
goto afp_read_err;
}
+ LOG(log_debug, logtype_afpd, "afp_read(name: \"%s\", offset: %jd, reqcount: %jd)",
+ of_name(ofork), (intmax_t)offset, (intmax_t)reqcount);
+
savereqcount = reqcount;
saveoff = offset;
if (ad_tmplock(ofork->of_ad, eid, ADLOCK_RD, saveoff, savereqcount,ofork->of_refnum) < 0) {
goto afp_read_err;
}
+<<<<<<< HEAD
#define min(a,b) ((a)<(b)?(a):(b))
*rbuflen = min( reqcount, *rbuflen );
+=======
+ *rbuflen = MIN(reqcount, *rbuflen);
+ LOG(log_debug, logtype_afpd, "afp_read(name: \"%s\", offset: %jd, reqcount: %jd): reading %jd bytes from file",
+ of_name(ofork), (intmax_t)offset, (intmax_t)reqcount, (intmax_t)*rbuflen);
+>>>>>>> netafp/master
err = read_file(ofork, eid, offset, nlmask, nlchar, rbuf, rbuflen, xlate);
if (err < 0)
goto afp_read_done;
+ LOG(log_debug, logtype_afpd, "afp_read(name: \"%s\", offset: %jd, reqcount: %jd): got %jd bytes from file",
+ of_name(ofork), (intmax_t)offset, (intmax_t)reqcount, (intmax_t)*rbuflen);
/* dsi can stream requests. we can only do this if we're not checking
* for an end-of-line character. oh well. */
int fd;
fd = ad_readfile_init(ofork->of_ad, eid, &offset, 0);
+
if (dsi_stream_read_file(dsi, fd, offset, dsi->datasize) < 0) {
if (errno == EINVAL || errno == ENOSYS)
goto afp_read_loop;
* in reqcount et al. */
static int write_fork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen, int is64)
{
+<<<<<<< HEAD
struct ofork *ofork;
off_t offset, saveoff, reqcount;
int endflag, eid, xlate = 0, err = AFP_OK;
uint16_t ofrefnum;
+=======
+ struct ofork *ofork;
+ off_t offset, saveoff, reqcount, oldsize, newsize;
+ int endflag, eid, xlate = 0, err = AFP_OK;
+ u_int16_t ofrefnum;
+>>>>>>> netafp/master
ssize_t cc;
/* figure out parameters */
goto afp_write_err;
}
+ oldsize = ad_size(ofork->of_ad, eid);
if (endflag)
- offset += ad_size(ofork->of_ad, eid);
+ offset += oldsize;
/* handle bogus parameters */
if (reqcount < 0 || offset < 0) {
goto afp_write_err;
}
+ newsize = ((offset + reqcount) > oldsize) ? (offset + reqcount) : oldsize;
+
/* offset can overflow on 64-bit capable filesystems.
* report disk full if that's going to happen. */
if (sum_neg(is64, offset, reqcount)) {
ofork->of_flags |= AFPFORK_MODIFIED;
/* update write count */
- ofork->of_vol->v_written += reqcount;
+ ofork->of_vol->v_appended += (newsize > oldsize) ? (newsize - oldsize) : 0;
*rbuflen = set_off_t (offset, rbuf, is64);
return( AFP_OK );
struct rlimit rlim;
if (getrlimit(RLIMIT_NOFILE, &rlim) != 0) {
- LOG(log_error, logtype_afpd, "setlimits: %s", strerror(errno));
- exit(1);
+ LOG(log_warning, logtype_afpd, "setlimits: reading current limits failed: %s", strerror(errno));
+ return -1;
}
if (rlim.rlim_cur != RLIM_INFINITY && rlim.rlim_cur < 65535) {
rlim.rlim_cur = 65535;
if (rlim.rlim_max != RLIM_INFINITY && rlim.rlim_max < 65535)
rlim.rlim_max = 65535;
if (setrlimit(RLIMIT_NOFILE, &rlim) != 0) {
- LOG(log_error, logtype_afpd, "setlimits: %s", strerror(errno));
- exit(1);
+ LOG(log_warning, logtype_afpd, "setlimits: increasing limits failed: %s", strerror(errno));
+ return -1;
}
}
return 0;
#include <stdio.h>
#include <stdlib.h>
+#include <inttypes.h>
#include <string.h>
#include <errno.h>
#include <limits.h>
*/
int ustatfs_getvolspace(const struct vol *vol, VolSpace *bfree, VolSpace *btotal, uint32_t *bsize)
{
- VolSpace maxVolSpace = (~(VolSpace)0);
+ VolSpace maxVolSpace = UINT64_MAX;
#ifdef ultrix
struct fs_data sfs;
struct statfs sfs;
#endif /*ultrix*/
-
if ( statfs( vol->v_path, &sfs ) < 0 ) {
LOG(log_error, logtype_afpd, "ustatfs_getvolspace unable to stat %s", vol->v_path);
return( AFPERR_PARAM );
*
* dir parameter is used by AFS
*/
-void accessmode(char *path, struct maccess *ma, struct dir *dir _U_, struct stat *st)
+void accessmode(const struct vol *vol, char *path, struct maccess *ma, struct dir *dir _U_, struct stat *st)
{
struct stat sb;
}
utommode( st, ma );
#ifdef HAVE_ACLS
- acltoownermode(path, st, ma);
+ acltoownermode(vol, path, st, ma);
#endif
}
}
if (S_ISDIR(st.st_mode)) {
- if ( chmod( modbuf, (DIRBITS | mode) & ~default_options.umask ) < 0 && errno != EPERM ) {
+ if ( chmod_acl( modbuf, (DIRBITS | mode) & ~default_options.umask ) < 0 && errno != EPERM ) {
LOG(log_error, logtype_afpd, "setdeskmode: chmod %s: %s",fullpathname(modbuf), strerror(errno) );
}
- } else if ( chmod( modbuf, mode & ~(default_options.umask | EXEC_MODE) ) < 0 && errno != EPERM ) {
+ } else if ( chmod_acl( modbuf, mode & ~(default_options.umask | EXEC_MODE) ) < 0 && errno != EPERM ) {
LOG(log_error, logtype_afpd, "setdeskmode: chmod %s: %s",fullpathname(modbuf), strerror(errno) );
}
}
closedir( sub );
/* XXX: need to preserve special modes */
- if ( chmod( deskp->d_name, (DIRBITS | mode) & ~default_options.umask ) < 0 && errno != EPERM ) {
+ if ( chmod_acl( deskp->d_name, (DIRBITS | mode) & ~default_options.umask ) < 0 && errno != EPERM ) {
LOG(log_error, logtype_afpd, "setdeskmode: chmod %s: %s",fullpathname(deskp->d_name), strerror(errno) );
}
}
return -1;
}
/* XXX: need to preserve special modes */
- if ( chmod( ".AppleDesktop", (DIRBITS | mode) & ~default_options.umask ) < 0 && errno != EPERM ) {
+ if ( chmod_acl( ".AppleDesktop", (DIRBITS | mode) & ~default_options.umask ) < 0 && errno != EPERM ) {
LOG(log_error, logtype_afpd, "setdeskmode: chmod %s: %s", fullpathname(".AppleDesktop"),strerror(errno) );
}
return( 0 );
extern int setdirowner (const struct vol *, const char *, const uid_t, const gid_t);
extern int setfilunixmode (const struct vol *, struct path*, const mode_t);
extern int setfilowner (const struct vol *, const uid_t, const gid_t, struct path*);
-extern void accessmode (char *, struct maccess *, struct dir *, struct stat *);
+extern void accessmode (const struct vol *, char *, struct maccess *, struct dir *, struct stat *);
#ifdef AFS
#define accessmode afsmode
#include <atalk/ftw.h>
#include <atalk/globals.h>
#include <atalk/fce_api.h>
+#include <atalk/errchk.h>
#ifdef CNID_DB
#include <atalk/cnid.h>
int i;
struct passwd *pw;
struct vol_option save_options[VOLOPT_NUM];
+ struct vol_option default_options[VOLOPT_NUM];
struct vol_option options[VOLOPT_NUM];
struct stat st;
break;
}
- memset(save_options, 0, sizeof(save_options));
+ memset(default_options, 0, sizeof(default_options));
/* Enable some default options for all volumes */
- save_options[VOLOPT_FLAGS].i_value |= AFPVOL_CACHE;
+ default_options[VOLOPT_FLAGS].i_value |= AFPVOL_CACHE;
#ifdef HAVE_ACLS
- save_options[VOLOPT_FLAGS].i_value |= AFPVOL_ACLS;
+ default_options[VOLOPT_FLAGS].i_value |= AFPVOL_ACLS;
#endif
- save_options[VOLOPT_EA_VFS].i_value = AFPVOL_EA_AUTO;
+ default_options[VOLOPT_EA_VFS].i_value = AFPVOL_EA_AUTO;
LOG(log_maxdebug, logtype_afpd, "readvolfile: seeding default umask: %04o",
obj->options.umask);
- save_options[VOLOPT_UMASK].i_value = obj->options.umask;
+ default_options[VOLOPT_UMASK].i_value = obj->options.umask;
+ memcpy(save_options, default_options, sizeof(options));
LOG(log_debug, logtype_afpd, "readvolfile: \"%s\"", path);
case ':':
/* change the default options for this file */
if (strncmp(path, VOLOPT_DEFAULT, VOLOPT_DEFAULT_LEN) == 0) {
+ volfree(default_options, save_options);
+ memcpy(default_options, save_options, sizeof(options));
*tmp = '\0';
for (i = 0; i < VOLOPT_NUM; i++) {
if (parseline( sizeof( path ) - VOLOPT_DEFAULT_LEN - 1,
path + VOLOPT_DEFAULT_LEN) < 0)
break;
- volset(save_options, NULL, tmp, sizeof(tmp) - 1,
+ volset(default_options, NULL, tmp, sizeof(tmp) - 1,
path + VOLOPT_DEFAULT_LEN);
}
}
* able to specify things in any order, but i don't want to
* re-write everything. */
- memcpy(options, save_options, sizeof(options));
+ memcpy(options, default_options, sizeof(options));
*volname = '\0';
/* read in up to VOLOP_NUM possible options */
if (parseline( sizeof( tmp ) - 1, tmp ) < 0)
break;
- volset(options, save_options, volname, sizeof(volname) - 1, tmp);
+ volset(options, default_options, volname, sizeof(volname) - 1, tmp);
}
/* check allow/deny lists (if not afpd master loading volumes for Zeroconf reg.):
creatvol(obj, pwent, path, tmp, options, p2 != NULL);
}
- volfree(options, save_options);
+ volfree(options, default_options);
break;
case '.' :
}
}
}
-
-static off_t getused_size; /* result of getused() */
-
/*!
- nftw callback for getused()
+ * Read band-size info from Info.plist XML file of an TM sparsebundle
+ *
+ * @param path (r) path to Info.plist file
+ * @return band-size in bytes, -1 on error
*/
-static int getused_stat(const char *path,
- const struct stat *statp,
- int tflag,
- struct FTW *ftw)
+static long long int get_tm_bandsize(const char *path)
{
- off_t low, high;
+ EC_INIT;
+ FILE *file = NULL;
+ char buf[512];
+ long long int bandsize = -1;
+
+ EC_NULL_LOGSTR( file = fopen(path, "r"),
+ "get_tm_bandsize(\"%s\"): %s",
+ path, strerror(errno) );
+
+ while (fgets(buf, sizeof(buf), file) != NULL) {
+ if (strstr(buf, "band-size") == NULL)
+ continue;
- if (tflag == FTW_F || tflag == FTW_D) {
- getused_size += statp->st_blocks * 512;
+ if (fscanf(file, " <integer>%lld</integer>", &bandsize) != 1) {
+ LOG(log_error, logtype_afpd, "get_tm_bandsize(\"%s\"): can't parse band-size", path);
+ EC_FAIL;
+ }
+ break;
}
- return 0;
+EC_CLEANUP:
+ if (file)
+ fclose(file);
+ LOG(log_debug, logtype_afpd, "get_tm_bandsize(\"%s\"): bandsize: %lld", path, bandsize);
+ return bandsize;
}
-#define GETUSED_CACHETIME 5
/*!
- * Calculate used size of a volume with nftw
+ * Return number on entries in a directory
*
- * The result is cached, we're try to avoid frequently calling nftw()
+ * @param path (r) path to dir
+ * @return number of entries, -1 on error
+ */
+static long long int get_tm_bands(const char *path)
+{
+ EC_INIT;
+ long long int count = 0;
+ DIR *dir = NULL;
+ const struct dirent *entry;
+
+ EC_NULL( dir = opendir(path) );
+
+ while ((entry = readdir(dir)) != NULL)
+ count++;
+ count -= 2; /* All OSens I'm aware of return "." and "..", so just substract them, avoiding string comparison in loop */
+
+EC_CLEANUP:
+ if (dir)
+ closedir(dir);
+ if (ret != 0)
+ return -1;
+ return count;
+}
+
+/*!
+ * Calculate used size of a TimeMachine volume
*
- * 1) Call nftw an refresh if:
- * 1a) - we're called the first time
- * 1b) - volume modification date is not yet set and the last time we've been called is
- * longer then 30 sec ago
- * 1c) - the last volume modification is less then 30 sec old
+ * This assumes that the volume is used only for TimeMachine.
+ *
+ * 1) readdir(path of volume)
+ * 2) for every element that matches regex "\(.*\)\.sparsebundle$" :
+ * 3) parse "\1.sparsebundle/Info.plist" and read the band-size XML key integer value
+ * 4) readdir "\1.sparsebundle/bands/" counting files
+ * 5) calculate used size as: (file_count - 1) * band-size
+ *
+ * The result of the calculation is returned in "volume->v_tm_used".
+ * "volume->v_appended" gets reset to 0.
+ * "volume->v_tm_cachetime" is updated with the current time from time(NULL).
+ *
+ * "volume->v_tm_used" is cached for TM_USED_CACHETIME seconds and updated by
+ * "volume->v_appended". The latter is increased by X every time the client
+ * appends X bytes to a file (in fork.c).
*
* @param vol (rw) volume to calculate
+ * @return 0 on success, -1 on error
*/
-static int getused(struct vol *vol)
+#define TM_USED_CACHETIME 60 /* cache for 60 seconds */
+static int get_tm_used(struct vol * restrict vol)
{
- static time_t vol_mtime = 0;
- int ret = 0;
+ EC_INIT;
+ long long int bandsize;
+ VolSpace used = 0;
+ bstring infoplist = NULL;
+ bstring bandsdir = NULL;
+ DIR *dir = NULL;
+ const struct dirent *entry;
+ const char *p;
+ struct stat st;
+ long int links;
time_t now = time(NULL);
- if (!vol_mtime
- || (!vol->v_mtime && ((vol_mtime + GETUSED_CACHETIME) < now))
- || (vol->v_mtime && ((vol_mtime + GETUSED_CACHETIME) < vol->v_mtime))
- ) {
- vol_mtime = now;
- getused_size = 0;
- vol->v_written = 0;
- ret = nftw(vol->v_path, getused_stat, NULL, 20, FTW_PHYS); /* 2 */
- LOG(log_debug, logtype_afpd, "volparams: from nftw: %" PRIu64 " bytes",
- getused_size);
- } else {
- getused_size += vol->v_written;
- vol->v_written = 0;
- LOG(log_debug, logtype_afpd, "volparams: cached used: %" PRIu64 " bytes",
- getused_size);
+ if (vol->v_tm_cachetime
+ && ((vol->v_tm_cachetime + TM_USED_CACHETIME) >= now)) {
+ if (vol->v_tm_used == -1)
+ EC_FAIL;
+ vol->v_tm_used += vol->v_appended;
+ vol->v_appended = 0;
+ LOG(log_debug, logtype_afpd, "getused(\"%s\"): cached: %" PRIu64 " bytes",
+ vol->v_path, vol->v_tm_used);
+ return 0;
}
- return ret;
+ vol->v_tm_cachetime = now;
+
+ EC_NULL( dir = opendir(vol->v_path) );
+
+ while ((entry = readdir(dir)) != NULL) {
+ if (((p = strstr(entry->d_name, "sparsebundle")) != NULL)
+ && (strlen(entry->d_name) == (p + strlen("sparsebundle") - entry->d_name))) {
+
+ EC_NULL_LOG( infoplist = bformat("%s/%s/%s", vol->v_path, entry->d_name, "Info.plist") );
+
+ if ((bandsize = get_tm_bandsize(cfrombstr(infoplist))) == -1)
+ continue;
+
+ EC_NULL_LOG( bandsdir = bformat("%s/%s/%s/", vol->v_path, entry->d_name, "bands") );
+
+ if ((links = get_tm_bands(cfrombstr(bandsdir))) == -1)
+ continue;
+
+ used += (links - 1) * bandsize;
+ LOG(log_debug, logtype_afpd, "getused(\"%s\"): bands: %" PRIu64 " bytes",
+ cfrombstr(bandsdir), used);
+ }
+ }
+
+ vol->v_tm_used = used;
+
+EC_CLEANUP:
+ if (infoplist)
+ bdestroy(infoplist);
+ if (bandsdir)
+ bdestroy(bandsdir);
+ if (dir)
+ closedir(dir);
+
+ LOG(log_debug, logtype_afpd, "getused(\"%s\"): %" PRIu64 " bytes", vol->v_path, vol->v_tm_used);
+
+ EC_EXIT;
}
static int getvolspace(struct vol *vol,
return( rc );
}
-#define min(a,b) ((a)<(b)?(a):(b))
#ifndef NO_QUOTA_SUPPORT
if ( spaceflag == AFPVOL_NONE || spaceflag == AFPVOL_UQUOTA ) {
if ( uquota_getvolspace( vol, &qfree, &qtotal, *bsize ) == AFP_OK ) {
vol->v_flags = ( ~AFPVOL_GVSMASK & vol->v_flags ) | AFPVOL_UQUOTA;
- *xbfree = min(*xbfree, qfree);
- *xbtotal = min( *xbtotal, qtotal);
+ *xbfree = MIN(*xbfree, qfree);
+ *xbtotal = MIN(*xbtotal, qtotal);
goto getvolspace_done;
}
}
getvolspace_done:
if (vol->v_limitsize) {
- if (getused(vol) != 0)
+ if (get_tm_used(vol) != 0)
return AFPERR_MISC;
- LOG(log_debug, logtype_afpd, "volparams: used on volume: %" PRIu64 " bytes",
- getused_size);
- vol->v_tm_used = getused_size;
- *xbtotal = min(*xbtotal, (vol->v_limitsize * 1024 * 1024));
- *xbfree = min(*xbfree, *xbtotal < getused_size ? 0 : *xbtotal - getused_size);
+ *xbtotal = MIN(*xbtotal, (vol->v_limitsize * 1024 * 1024));
+ *xbfree = MIN(*xbfree, *xbtotal < vol->v_tm_used ? 0 : *xbtotal - vol->v_tm_used);
+
+ LOG(log_debug, logtype_afpd,
+ "volparams: total: %" PRIu64 ", used: %" PRIu64 ", free: %" PRIu64 " bytes",
+ *xbtotal, vol->v_tm_used, *xbfree);
}
- *bfree = min( *xbfree, maxsize);
- *btotal = min( *xbtotal, maxsize);
+ *bfree = MIN(*xbfree, maxsize);
+ *btotal = MIN(*xbtotal, maxsize);
return( AFP_OK );
}
last = now;
for ( ; vol; vol = vol->v_next ) {
if (vol->v_flags & AFPVOL_TM)
- (void)fce_register_tm_size(vol->v_path, vol->v_tm_used + vol->v_written);
+ (void)fce_register_tm_size(vol->v_path, vol->v_tm_used + vol->v_appended);
}
}
}
if (!S_ISDIR(st.st_mode)) {
continue; /* not a dir */
}
- accessmode(volume->v_path, &ma, NULL, &st);
+ accessmode(volume, volume->v_path, &ma, NULL, &st);
if ((ma.ma_user & (AR_UREAD | AR_USEARCH)) != (AR_UREAD | AR_USEARCH)) {
continue; /* no r-x access */
}
if ((dp = opendir(".")) == NULL) {
dbd_log(LOGSTD, "Couldn't open the directory '%s/%s': %s",
cwdbuf, ADv2_DIRNAME, strerror(errno));
- return;
+ goto exit;
}
while ((ep = readdir(dp))) {
} /* if */
} /* while */
+exit:
if (dp)
closedir(dp);
-
+ if ((chdir("..")) != 0) {
+ dbd_log(LOGSTD, "Couldn't chdir to '%s': %s", cwdbuf, strerror(errno));
+ /* we can't proceed */
+ longjmp(jmp, 1); /* this jumps back to cmd_dbd_scanvol() */
+ }
}
/*
/* Everything is fine */
return db_cnid;
} else if (ad_cnid && db_cnid && (ad_cnid != db_cnid)) {
- /* Mismatch ? Delete both from db and re-add data from file */
+ /* Mismatch, overwrite ad file with value from db */
dbd_log( LOGSTD, "CNID mismatch for '%s/%s', db: %u, ad-file: %u", cwdbuf, name, ntohl(db_cnid), ntohl(ad_cnid));
if ( ! (dbd_flags & DBD_FLAGS_SCAN)) {
- rqst.cnid = db_cnid;
- ret = dbd_delete(dbd, &rqst, &rply, DBIF_CNID);
- if (dbif_txn_close(dbd, ret) != 0)
- return CNID_INVALID;
-
- rqst.cnid = ad_cnid;
- ret = dbd_delete(dbd, &rqst, &rply, DBIF_CNID);
- if (dbif_txn_close(dbd, ret) != 0)
- return CNID_INVALID;
-
- ret = dbd_rebuild_add(dbd, &rqst, &rply);
- if (dbif_txn_close(dbd, ret) != 0)
+ dbd_log(LOGSTD, "Updating AppleDouble file for '%s/%s' with CNID: %u from database",
+ cwdbuf, name, ntohl(db_cnid));
+ 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));
return CNID_INVALID;
+ }
+ ad_setid( &ad, st->st_dev, st->st_ino, db_cnid, did, stamp);
+ ad_flush(&ad);
+ ad_close_metadata(&ad);
}
- return ad_cnid;
+ return db_cnid;
} else if (ad_cnid && (db_cnid == 0)) {
/* in ad-file but not in db */
if ( ! (dbd_flags & DBD_FLAGS_SCAN)) {
rqst.cnid = ad_cnid;
ret = dbd_resolve(dbd, &rqst, &rply);
- if (ret == CNID_DBD_RES_OK) {
+ if (rply.result == CNID_DBD_RES_OK) {
/* Occupied! Choose another, update ad-file */
ret = dbd_add(dbd, &rqst, &rply, 1);
if (dbif_txn_close(dbd, ret) != 0)
#include "config.h"
#endif
-#if !defined(__FreeBSD__) && !defined(__NetBSD__)
-#ifndef _XOPEN_SOURCE
-# define _XOPEN_SOURCE 600
-#endif
-#ifndef __EXTENSIONS__
-# define __EXTENSIONS__
-#endif
-#ifndef _GNU_SOURCE
-# define _GNU_SOURCE
-#endif
-#endif
+#include <atalk/standards.h>
#include <stdio.h>
#include <stdlib.h>
return -1;
}
+ LOG(log_debug, logtype_cnid,
+ "dbd_rebuild_add(CNID: %u, did: %u, name: \"%s\", dev/ino:0x%llx/0x%llx): success",
+ ntohl(rqst->cnid), ntohl(rqst->did), rqst->name,
+ (unsigned long long)rqst->dev, (unsigned long long)rqst->ino);
+
key.data = ROOTINFO_KEY;
key.size = ROOTINFO_KEYLEN;
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);
+ LOG(log_debug, logtype_cnid, "dbd_resolve(CNID: %u): did: %u, name: \"%s\"",
+ ntohl(rqst->cnid), ntohl(rply->did), rply->name + CNID_NAME_OFS);
rply->result = CNID_DBD_RES_OK;
return 1;
return ret;
}
-static int logincont2(void *obj, struct passwd **uam_pwd,
+/**
+ * Try to authenticate via PAM as "adminauthuser"
+ **/
+static int loginasroot(const char *adminauthuser, const char **hostname, int status)
+{
+ int PAM_error;
+
+ if ((PAM_error = pam_end(pamh, status)) != PAM_SUCCESS)
+ goto exit;
+ pamh = NULL;
+
+ if ((PAM_error = pam_start("netatalk", adminauthuser, &PAM_conversation, &pamh)) != PAM_SUCCESS) {
+ LOG(log_info, logtype_uams, "DHX2: PAM_Error: %s", pam_strerror(pamh,PAM_error));
+ goto exit;
+ }
+
+ /* solaris craps out if PAM_TTY and PAM_RHOST aren't set. */
+ pam_set_item(pamh, PAM_TTY, "afpd");
+ pam_set_item(pamh, PAM_RHOST, *hostname);
+ if ((PAM_error = pam_authenticate(pamh, 0)) != PAM_SUCCESS)
+ goto exit;
+
+ LOG(log_warning, logtype_uams, "DHX2: Authenticated as \"%s\"", adminauthuser);
+
+exit:
+ return PAM_error;
+}
+
+static int logincont2(void *obj_in, struct passwd **uam_pwd,
char *ibuf, size_t ibuflen,
char *rbuf _U_, size_t *rbuflen)
{
- int ret;
+ AFPObj *obj = obj_in;
+ int ret = AFPERR_MISC;
int PAM_error;
const char *hostname = NULL;
gcry_mpi_t retServerNonce;
gcry_cipher_hd_t ctx;
gcry_error_t ctxerror;
+ char *utfpass = NULL;
*rbuflen = 0;
/* ---- Start authentication with PAM --- */
+ /* The password is in legacy Mac encoding, convert it to host encoding */
+ if (convert_string_allocate(CH_MAC, CH_UNIX, ibuf, -1, &utfpass) == (size_t)-1) {
+ LOG(log_error, logtype_uams, "DHX2: conversion error");
+ goto error_ctx;
+ }
+ PAM_password = utfpass;
+
+#ifdef DEBUG
+ LOG(log_maxdebug, logtype_default, "DHX2: password: %s", PAM_password);
+#endif
+
/* Set these things up for the conv function */
- PAM_password = ibuf;
ret = AFPERR_NOTAUTH;
PAM_error = pam_start("netatalk", PAM_username, &PAM_conversation, &pamh);
if (PAM_error != PAM_SUCCESS) {
- LOG(log_info, logtype_uams, "DHX2: PAM_Error: %s",
- pam_strerror(pamh,PAM_error));
+ LOG(log_info, logtype_uams, "DHX2: PAM_Error: %s", pam_strerror(pamh,PAM_error));
goto error_ctx;
}
/* solaris craps out if PAM_TTY and PAM_RHOST aren't set. */
pam_set_item(pamh, PAM_TTY, "afpd");
pam_set_item(pamh, PAM_RHOST, hostname);
+
PAM_error = pam_authenticate(pamh, 0);
if (PAM_error != PAM_SUCCESS) {
if (PAM_error == PAM_MAXTRIES)
ret = AFPERR_PWDEXPR;
- LOG(log_info, logtype_uams, "DHX2: PAM_Error: %s",
- pam_strerror(pamh, PAM_error));
- goto error_ctx;
+ LOG(log_info, logtype_uams, "DHX2: PAM_Error: %s", pam_strerror(pamh, PAM_error));
+
+ if (!obj->options.adminauthuser)
+ goto error_ctx;
+ if (loginasroot(obj->options.adminauthuser, &hostname, PAM_error) != PAM_SUCCESS) {
+ goto error_ctx;
+ }
}
PAM_error = pam_acct_mgmt(pamh, 0);
else if (PAM_error == PAM_AUTHTOKEN_REQD)
ret = AFPERR_PWDCHNG;
#endif
- else
- goto error_ctx;
+ goto error_ctx;
}
#ifndef PAM_CRED_ESTABLISH
}
memset(ibuf, 0, 256); /* zero out the password */
+ if (utfpass)
+ memset(utfpass, 0, strlen(utfpass));
*uam_pwd = dhxpwd;
LOG(log_info, logtype_uams, "DHX2: PAM Auth OK!");
- if ( ret == AFPERR_PWDEXPR)
- return ret;
+
ret = AFP_OK;
error_ctx:
gcry_cipher_close(ctx);
error_noctx:
+ if (utfpass) free(utfpass);
free(K_MD5hash);
K_MD5hash=NULL;
gcry_mpi_release(serverNonce);
#ifdef UAM_DHX2
+#include <atalk/standards.h>
+
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "config.h"
#endif /* HAVE_CONFIG_H */
-#ifdef NETBSD
-#define _XOPEN_SOURCE 500 /* for crypt() */
-#endif
-#ifdef FREEBSD
-#define _XOPEN_SOURCE /* for crypt() */
-#endif
+#include <atalk/standards.h>
#include <stdio.h>
#include <stdlib.h>
#include <config.h>
#endif /* HAVE_CONFIG_H */
-#include <sys/types.h>
-/* crypt needs _XOPEN_SOURCE (500) at least on BSD, but that breaks Solaris compile */
-#ifdef NETBSD
-#define _XOPEN_SOURCE 500 /* for crypt() */
-#endif
-#ifdef FREEBSD
-#define _XOPEN_SOURCE /* for crypt() */
-#endif
+#include <atalk/standards.h>
+#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef UAM_PGP
-/* for crypt() */
-#define _XOPEN_SOURCE
+#include <atalk/standards.h>
+
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
ldapconfig.h \
list.h \
globals.h \
- fce_api.h
+ fce_api.h \
+ standards.h
BUILT_SOURCES = lockrpc.gen.h
EXTRADIST = lockrpc.gen.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 */
+#define chmod_acl nfsv4_chmod
-#ifdef HAVE_SOLARIS_ACLS
-#define chmod nfsv4_chmod
extern int get_nfsv4_acl(const char *name, ace_t **retAces);
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_SOLARIS_ACLS */
+
+#endif /* HAVE_SOLARIS_ACLS */
+
+#ifdef HAVE_POSIX_ACLS
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/acl.h>
+
+#define chmod_acl posix_chmod
+#define fchmod_acl posix_fchmod
+
+extern int posix_chmod(const char *name, mode_t mode);
+extern int posix_fchmod(int fd, mode_t mode);
+
+#endif /* HAVE_POSIX_ACLS */
extern int remove_acl_vfs(const char *name);
+#else /* HAVE_ACLS=no */
+
+#define chmod_acl chmod
+
#endif /* HAVE_ACLS */
#endif /* ATALK_ACL_H */
#include <config.h>
#endif
+#include <atalk/standards.h>
+
#include <inttypes.h>
#include <sys/types.h>
#include <sys/stat.h>
+++ /dev/null
-#ifndef _ATALK_BOOLEAN_H
-#define _ATALK_BOOLEAN_H 1
-
-/*
- * bool is a standard type in c++. In theory its one bit in size.
- * In reality just use the quickest standard type.
- */
-
-# ifndef __cplusplus
-# ifndef bool
-typedef char bool;
-
-/*
- * bool, true and false
- *
- */
-
-# endif /* ndef bool */
-# endif /* not C++ */
-# ifndef true
-# define true ((bool) 1)
-# endif
-# ifndef false
-# define false ((bool) 0)
-# endif
-typedef bool *BoolPtr;
-
-# ifndef TRUE
-# define TRUE 1
-# endif /* TRUE */
-
-# ifndef FALSE
-# define FALSE 0
-# endif /* FALSE */
-
-#endif
extern ssize_t dsi_stream_write (DSI *, void *, const size_t, const int mode);
extern size_t dsi_stream_read (DSI *, void *, const size_t);
extern int dsi_stream_send (DSI *, void *, size_t);
-extern int dsi_stream_receive (DSI *, void *, const size_t, size_t *);
+extern int dsi_stream_receive (DSI *);
extern int dsi_disconnect(DSI *dsi);
#ifdef WITH_SENDFILE
(x)->header.dsi_len = htonl((x)->cmdlen); \
dsi_stream_send((x), (x)->commands, (x)->cmdlen); \
} while (0)
-#define dsi_receive(x) (dsi_stream_receive((x), (x)->commands, \
- DSI_CMDSIZ, &(x)->cmdlen))
+
#endif /* atalk/dsi.h */
#define EC_INIT int ret = 0
#define EC_STATUS(a) ret = (a)
-#define EC_FAIL ret = -1; goto cleanup
+#define EC_FAIL do { ret = -1; goto cleanup; } while (0)
#define EC_CLEANUP cleanup
#define EC_EXIT return ret
char *logconfig;
char *mimicmodel;
+ char *adminauthuser;
};
#define AFPOBJ_TMPSIZ (MAXPATHLEN)
-#ifdef HAVE_ACLS
+#ifdef HAVE_LDAP
#ifndef LDAPCONFIG_H
#define LDAPCONFIG_H
#endif /* LDAPCONFIG_H */
-#endif /* HAVE_ACLS */
+#endif /* HAVE_LDAP */
#include <limits.h>
#include <stdio.h>
-
-#include <atalk/boolean.h>
+#include <stdbool.h>
#ifdef HAVE_CONFIG_H
#include "config.h"
/* lock file path. this should be re-organized a bit. */
#if ! defined (_PATH_LOCKDIR)
-# if defined (FHS_COMPATIBILITY) || defined (__NetBSD__)
+# if defined (FHS_COMPATIBILITY) || defined (__NetBSD__) || defined (__OpenBSD__)
# define _PATH_LOCKDIR "/var/run/"
# elif defined (BSD4_4)
# ifdef MACOSX_SERVER
*/
#define _PATH_ATALKDEBUG "/tmp/atalkd.debug"
#define _PATH_ATALKDTMP "atalkd.tmp"
-#if defined (FHS_COMPATIBILITY) || defined (__NetBSD__)
+#if defined (FHS_COMPATIBILITY) || defined (__NetBSD__) || defined (__OpenBSD__)
# define _PATH_ATALKDLOCK ATALKPATHCAT(_PATH_LOCKDIR,"atalkd.pid")
#else
# define _PATH_ATALKDLOCK ATALKPATHCAT(_PATH_LOCKDIR,"atalkd")
* psorder paths
*/
#define _PATH_TMPPAGEORDER "/tmp/psorderXXXXXX"
-#if defined (FHS_COMPATIBILITY) || defined (__NetBSD__)
+#if defined (FHS_COMPATIBILITY) || defined (__NetBSD__) || defined (__OpenBSD__)
# define _PATH_PAPDLOCK ATALKPATHCAT(_PATH_LOCKDIR,"papd.pid")
#else
# define _PATH_PAPDLOCK ATALKPATHCAT(_PATH_LOCKDIR,"papd")
*/
#define _PATH_AFPTKT "/tmp/AFPtktXXXXXX"
#define _PATH_AFP_IPC ATALKPATHCAT(_PATH_LOCKDIR,"afpd_ipc")
-#if defined (FHS_COMPATIBILITY) || defined (__NetBSD__)
+#if defined (FHS_COMPATIBILITY) || defined (__NetBSD__) || defined (__OpenBSD__)
# define _PATH_AFPDLOCK ATALKPATHCAT(_PATH_LOCKDIR,"afpd.pid")
#else
# define _PATH_AFPDLOCK ATALKPATHCAT(_PATH_LOCKDIR,"afpd")
/*
* cnid_metad paths
*/
-#if defined (FHS_COMPATIBILITY) || defined (__NetBSD__)
+#if defined (FHS_COMPATIBILITY) || defined (__NetBSD__) || defined (__OpenBSD__)
# define _PATH_CNID_METAD_LOCK ATALKPATHCAT(_PATH_LOCKDIR,"cnid_metad.pid")
#else
# define _PATH_CNID_METAD_LOCK ATALKPATHCAT(_PATH_LOCKDIR,"cnid_metad")
--- /dev/null
+/*
+ Copyright (c) 2011, 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.
+*/
+
+#ifndef ATALK_STANDARDS_H
+#define ATALK_STANDARDS_H 1
+
+#if !defined(__FreeBSD__) && !defined(__NetBSD__) && !defined(__OpenBSD__)
+# ifndef _XOPEN_SOURCE
+# define _XOPEN_SOURCE 600
+# endif
+# ifndef __EXTENSIONS__
+# define __EXTENSIONS__
+# endif
+# ifndef _GNU_SOURCE
+# define _GNU_SOURCE
+# endif
+#endif
+
+#endif /* ATALK_STANDARDS_H */
/* vfs/unix.c */
extern int netatalk_unlink(const char *name);
extern int netatalk_unlinkat(int dirfd, const char *name);
-extern char *fullpathname(const char *);
extern int statat(int dirfd, const char *path, struct stat *st);
extern int lstatat(int dirfd, const char *path, struct stat *st);
extern DIR *opendirat(int dirfd, const char *path);
#define STRCMP(a,b,c) (strcmp(a,c) b 0)
#define ZERO_STRUCT(a) memset(&(a), 0, sizeof(a))
#define ZERO_STRUCTP(a) memset((a), 0, sizeof(a))
+#ifndef MAX
+#define MAX(a,b) ((a) > (b) ? a : b)
+#endif
+#ifndef MIN
+#define MIN(a,b) ((a) < (b) ? a : b)
+#endif
#if BYTE_ORDER == BIG_ENDIAN
#define hton64(x) (x)
extern const char *abspath(const char *name);
extern const char *getcwdpath(void);
+extern const char *fullpathname(const char *);
extern char *stripped_slashes_basename(char *p);
extern int lchdir(const char *dir);
extern void randombytes(void *buf, int n);
#ifndef ATALK_VOLUME_H
#define ATALK_VOLUME_H 1
+#include <stdint.h>
+#include <sys/cdefs.h>
#include <sys/types.h>
#include <atalk/unicode.h>
char *v_gvs;
void *v_nfsclient;
int v_nfs;
- uintmax_t v_tm_used; /* used bytes on a TM volume */
- uintmax_t v_written; /* amount of data written in afp_write, reset every time a FCE_TM_SIZE event is sent */
+ VolSpace v_tm_used; /* used bytes on a TM volume */
+ time_t v_tm_cachetime; /* time at which v_tm_used was calculated last */
+ VolSpace v_appended; /* amount of data appended to files */
/* only when opening/closing volumes or in error */
int v_casefold;
#ifndef _ATALK_ZIP_H
#define _ATALK_ZIP_H 1
+#ifndef NO_DDP
+
#include <netatalk/endian.h>
struct ziphdr {
#define ZIPGNI_INVALID 0x80
#define ZIPGNI_ONEZONE 0x20
+#endif /* NO_DDP */
#endif
/*
Copyright (c) 2010 Frank Lahm <franklahm@gmail.com>
+ Copyright (c) 2011 Laura Mueller <laura-mueller@uni-duesseldorf.de>
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 "config.h"
#endif /* HAVE_CONFIG_H */
-#ifdef HAVE_SOLARIS_ACLS
+#ifdef HAVE_ACLS
#include <unistd.h>
#include <sys/types.h>
#include <atalk/util.h>
#include <atalk/acl.h>
+#ifdef HAVE_SOLARIS_ACLS
+
/* Get ACL. Allocates storage as needed. Caller must free.
* Returns no of ACEs or -1 on error. */
int get_nfsv4_acl(const char *name, ace_t **retAces)
/* sorry, no ACLs for symlinks */
return 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);
+ if ( ! (S_ISREG(st.st_mode) || S_ISDIR(st.st_mode))) {
+ LOG(log_debug, 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);
+ LOG(log_debug, 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",
+ LOG(log_debug, logtype_afpd, "get_nfsv4_acl: acl('%s/%s', ACE_GETACLCNT): ace_count %i, error: %s",
getcwdpath(), name, ace_count, strerror(errno));
return -1;
}
* Change mode of file preserving existing explicit ACEs
*
* nfsv4_chmod
- * (1) reads objects ACL (acl1)
+ * (1) reads objects ACL (acl1), may return 0 or -1 NFSv4 ACEs on eg UFS fs
* (2) removes all trivial ACEs from the ACL by calling strip_trivial_aces(), possibly
* leaving 0 ACEs in the ACL if there were only trivial ACEs as mapped from the mode
- * (3) calls chmod() with mode
+ * (3) calls chmod() with mode, we're done if step (1) returned 0 for noaces
* (4) reads the changed ACL (acl2) which
* a) might still contain explicit ACEs (up to onnv132)
* b) will have any explicit ACE removed (starting with onnv145/Openindiana)
LOG(log_debug, logtype_afpd, "nfsv4_chmod(\"%s/%s\", %04o)",
getcwdpath(), name, mode);
- if ((noaces = get_nfsv4_acl(name, &oacl)) == -1) /* (1) */
- goto exit;
+ if ((noaces = get_nfsv4_acl(name, &oacl)) < 1) /* (1) */
+ return chmod(name, mode);
+
if ((noaces = strip_trivial_aces(&oacl, noaces)) == -1) /* (2) */
goto exit;
-#ifdef chmod
-#undef chmod
-#endif
if (chmod(name, mode) != 0) /* (3) */
goto exit;
}
#endif /* HAVE_SOLARIS_ACLS */
+
+#ifdef HAVE_POSIX_ACLS
+
+/* This is a workaround for chmod() on filestystems supporting Posix 1003.1e draft 17
+ * compliant ACLs. For objects with extented ACLs, eg objects with an ACL_MASK entry,
+ * chmod() manipulates ACL_MASK instead of ACL_GROUP_OBJ. As OS X isn't aware of
+ * this behavior calling FPSetFileDirParms may lead to unpredictable results. For
+ * more information see section 23.1.2 of Posix 1003.1e draft 17.
+ *
+ * posix_chmod() accepts the same arguments as chmod() and returns 0 in case of
+ * success or -1 in case something went wrong.
+ */
+
+#define SEARCH_GROUP_OBJ 0x01
+#define SEARCH_MASK 0x02
+
+int posix_chmod(const char *name, mode_t mode) {
+ int ret = 0;
+ int entry_id = ACL_FIRST_ENTRY;
+ acl_entry_t entry;
+ acl_entry_t group_entry;
+ acl_tag_t tag;
+ acl_t acl;
+ u_char not_found = (SEARCH_GROUP_OBJ|SEARCH_MASK); /* used as flags */
+
+ LOG(log_maxdebug, logtype_afpd, "posix_chmod: %s mode: 0x%08x", name, mode);
+
+ /* Call chmod() first because there might be some special bits to be set which
+ * aren't related to access control.
+ */
+ ret = chmod(name, mode);
+
+ if (ret)
+ goto done;
+
+ /* Check if the underlying filesystem supports ACLs. */
+ acl = acl_get_file(name, ACL_TYPE_ACCESS);
+
+ if (acl) {
+ /* There is no need to keep iterating once we have found ACL_GROUP_OBJ and ACL_MASK. */
+ while ((acl_get_entry(acl, entry_id, &entry) == 1) && not_found) {
+ entry_id = ACL_NEXT_ENTRY;
+
+ ret = acl_get_tag_type(entry, &tag);
+
+ if (ret) {
+ LOG(log_error, logtype_afpd, "posix_chmod: Failed to get tag type.");
+ goto cleanup;
+ }
+
+ switch (tag) {
+ case ACL_GROUP_OBJ:
+ group_entry = entry;
+ not_found &= ~SEARCH_GROUP_OBJ;
+ break;
+
+ case ACL_MASK:
+ not_found &= ~SEARCH_MASK;
+ break;
+
+ default:
+ break;
+ }
+ }
+ if (!not_found) {
+ /* The filesystem object has extented ACLs. We have to update ACL_GROUP_OBJ
+ * with the group permissions.
+ */
+ acl_permset_t permset;
+ acl_perm_t perm = 0;
+
+ ret = acl_get_permset(group_entry, &permset);
+
+ if (ret) {
+ LOG(log_error, logtype_afpd, "posix_chmod: Can't get permset.");
+ goto cleanup;
+ }
+ ret = acl_clear_perms(permset);
+
+ if (ret)
+ goto cleanup;
+
+ if (mode & S_IXGRP)
+ perm |= ACL_EXECUTE;
+
+ if (mode & S_IWGRP)
+ perm |= ACL_WRITE;
+
+ if (mode & S_IRGRP)
+ perm |= ACL_READ;
+
+ ret = acl_add_perm(permset, perm);
+
+ if (ret)
+ goto cleanup;
+
+ ret = acl_set_permset(group_entry, permset);
+
+ if (ret) {
+ LOG(log_error, logtype_afpd, "posix_chmod: Can't set permset.");
+ goto cleanup;
+ }
+ /* also update ACL_MASK */
+ ret = acl_calc_mask(&acl);
+
+ if (ret) {
+ LOG(log_error, logtype_afpd, "posix_chmod: acl_calc_mask failed.");
+ goto cleanup;
+ }
+ ret = acl_set_file(name, ACL_TYPE_ACCESS, acl);
+ }
+cleanup:
+ acl_free(acl);
+ }
+done:
+ LOG(log_maxdebug, logtype_afpd, "posix_chmod: %d", ret);
+ return ret;
+}
+
+/*
+ * posix_fchmod() accepts the same arguments as fchmod() and returns 0 in case of
+ * success or -1 in case something went wrong.
+ */
+int posix_fchmod(int fd, mode_t mode) {
+ int ret = 0;
+ int entry_id = ACL_FIRST_ENTRY;
+ acl_entry_t entry;
+ acl_entry_t group_entry;
+ acl_tag_t tag;
+ acl_t acl;
+ u_char not_found = (SEARCH_GROUP_OBJ|SEARCH_MASK); /* used as flags */
+
+ /* Call chmod() first because there might be some special bits to be set which
+ * aren't related to access control.
+ */
+ ret = fchmod(fd, mode);
+
+ if (ret)
+ goto done;
+
+ /* Check if the underlying filesystem supports ACLs. */
+ acl = acl_get_fd(fd);
+
+ if (acl) {
+ /* There is no need to keep iterating once we have found ACL_GROUP_OBJ and ACL_MASK. */
+ while ((acl_get_entry(acl, entry_id, &entry) == 1) && not_found) {
+ entry_id = ACL_NEXT_ENTRY;
+
+ ret = acl_get_tag_type(entry, &tag);
+
+ if (ret) {
+ LOG(log_error, logtype_afpd, "posix_fchmod: Failed to get tag type.");
+ goto cleanup;
+ }
+
+ switch (tag) {
+ case ACL_GROUP_OBJ:
+ group_entry = entry;
+ not_found &= ~SEARCH_GROUP_OBJ;
+ break;
+
+ case ACL_MASK:
+ not_found &= ~SEARCH_MASK;
+ break;
+
+ default:
+ break;
+ }
+ }
+ if (!not_found) {
+ /* The filesystem object has extented ACLs. We have to update ACL_GROUP_OBJ
+ * with the group permissions.
+ */
+ acl_permset_t permset;
+ acl_perm_t perm = 0;
+
+ ret = acl_get_permset(group_entry, &permset);
+
+ if (ret) {
+ LOG(log_error, logtype_afpd, "posix_fchmod: Can't get permset.");
+ goto cleanup;
+ }
+ ret = acl_clear_perms(permset);
+
+ if (ret)
+ goto cleanup;
+
+ if (mode & S_IXGRP)
+ perm |= ACL_EXECUTE;
+
+ if (mode & S_IWGRP)
+ perm |= ACL_WRITE;
+
+ if (mode & S_IRGRP)
+ perm |= ACL_READ;
+
+ ret = acl_add_perm(permset, perm);
+
+ if (ret)
+ goto cleanup;
+
+ ret = acl_set_permset(group_entry, permset);
+
+ if (ret) {
+ LOG(log_error, logtype_afpd, "posix_fchmod: Can't set permset.");
+ goto cleanup;
+ }
+ /* also update ACL_MASK */
+ ret = acl_calc_mask(&acl);
+
+ if (ret) {
+ LOG(log_error, logtype_afpd, "posix_fchmod: acl_calc_mask failed.");
+ goto cleanup;
+ }
+ ret = acl_set_fd(fd, acl);
+ }
+cleanup:
+ acl_free(acl);
+ }
+done:
+ return ret;
+}
+
+#endif /* HAVE_POSIX_ACLS */
+
+#endif /* HAVE_ACLS */
#include "ad_lock.h"
-#if defined(LINUX_BROKEN_SENDFILE_API)
-
-extern int32_t sendfile (int fdout, int fdin, int32_t *offset, u_int32_t count);
+#if defined(SENDFILE_FLAVOR_LINUX)
+#include <sys/sendfile.h>
ssize_t sys_sendfile(int tofd, int fromfd, off_t *offset, size_t count)
{
-u_int32_t small_total;
-int32_t small_offset;
-int32_t nwritten;
-
- /*
- * Fix for broken Linux 2.4 systems with no working sendfile64().
- * If the offset+count > 2 GB then pretend we don't have the
- * system call sendfile at all. The upper layer catches this
- * and uses a normal read. JRA.
- */
-
- if ((sizeof(off_t) >= 8) && (*offset + count > (off_t)0x7FFFFFFF)) {
- errno = ENOSYS;
- return -1;
- }
- small_offset = (int32_t)*offset;
- small_total = (u_int32_t)count;
- nwritten = sendfile(tofd, fromfd, &small_offset, small_total);
- if (nwritten > = 0)
- *offset += nwritten;
-
- return nwritten;
+ return sendfile(tofd, fromfd, offset, count);
}
-#elif defined(SENDFILE_FLAVOR_LINUX)
+#elif defined(SENDFILE_FLAVOR_SOLARIS)
#include <sys/sendfile.h>
ssize_t sys_sendfile(int tofd, int fromfd, off_t *offset, size_t count)
}
#elif defined(SENDFILE_FLAVOR_BSD )
-/* FIXME untested */
-#error sendfile semantic broken
#include <sys/sendfile.h>
ssize_t sys_sendfile(int tofd, int fromfd, off_t *offset, size_t count)
{
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)
{
-cnid_t ret;
+ cnid_t ret;
+
+ if (len == 0)
+ return CNID_INVALID;
block_signal(cdb->flags);
ret = valide(cdb->cnid_add(cdb, st, did, name, len, hint));
/*
- * $Id: dsi_cmdreply.c,v 1.5 2009-10-25 06:13:11 didg Exp $
- *
* Copyright (c) 1997 Adrian Sun (asun@zoology.washington.edu)
* All rights reserved. See COPYRIGHT.
*/
#include <arpa/inet.h>
#include <atalk/dsi.h>
+#include <atalk/logger.h>
+#include <netatalk/endian.h>
/* this assumes that the reply follows right after the command, saving
* on a couple assignments. specifically, command, requestID, and
* reserved field are assumed to already be set. */
int dsi_cmdreply(DSI *dsi, const int err)
{
-int ret;
- dsi->header.dsi_flags = DSIFL_REPLY;
- /*dsi->header.dsi_command = DSIFUNC_CMD;*/
- dsi->header.dsi_len = htonl(dsi->datalen);
- dsi->header.dsi_code = htonl(err);
-
- ret = dsi_stream_send(dsi, dsi->data, dsi->datalen);
- return ret;
+ int ret;
+
+ LOG(log_debug, logtype_dsi, "dsi_cmdreply(DSI ID: %u, len: %jd): START",
+ dsi->clientID, (intmax_t)dsi->datalen);
+
+ dsi->header.dsi_flags = DSIFL_REPLY;
+ dsi->header.dsi_len = htonl(dsi->datalen);
+ dsi->header.dsi_code = htonl(err);
+
+ ret = dsi_stream_send(dsi, dsi->data, dsi->datalen);
+
+ LOG(log_debug, logtype_dsi, "dsi_cmdreply(DSI ID: %u, len: %jd): END",
+ dsi->clientID, (intmax_t)dsi->datalen);
+
+ return ret;
}
#include <sys/time.h>
#include <atalk/dsi.h>
-
-#ifndef min
-#define min(a,b) ((a) < (b) ? (a) : (b))
-#endif /* ! min */
+#include <atalk/util.h>
+#include <atalk/logger.h>
/* streaming i/o for afp_read. this is all from the perspective of the
* client. it basically does the reverse of dsi_write. on first entry,
* buffer. it returns the amount of stuff still to be read
* (constrained by the buffer size). */
ssize_t dsi_readinit(DSI *dsi, void *buf, const size_t buflen,
- const size_t size, const int err)
+ const size_t size, const int err)
{
+ LOG(log_maxdebug, logtype_dsi, "dsi_readinit: sending %zd bytes from buffer, total size: %zd",
+ buflen, size);
- 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);
- dsi->header.dsi_code = htonl(err);
+ dsi->flags |= DSI_NOREPLY; /* we will handle our own replies */
+ dsi->header.dsi_flags = DSIFL_REPLY;
+ dsi->header.dsi_len = htonl(size);
+ dsi->header.dsi_code = htonl(err);
- dsi->in_write++;
- if (dsi_stream_send(dsi, buf, buflen)) {
- dsi->datasize = size - buflen;
- return min(dsi->datasize, buflen);
- }
+ dsi->in_write++;
+ if (dsi_stream_send(dsi, buf, buflen)) {
+ dsi->datasize = size - buflen;
+ LOG(log_maxdebug, logtype_dsi, "dsi_readinit: remaining data for sendfile: %zd", dsi->datasize);
+ return MIN(dsi->datasize, buflen);
+ }
- return -1; /* error */
+ return -1; /* error */
}
void dsi_readdone(DSI *dsi)
{
- dsi->in_write--;
+ dsi->in_write--;
}
/* send off the data */
ssize_t dsi_read(DSI *dsi, void *buf, const size_t buflen)
{
- size_t len;
-
- len = dsi_stream_write(dsi, buf, buflen, 0);
+ size_t len;
+
+ len = dsi_stream_write(dsi, buf, buflen, 0);
- if (len == buflen) {
- dsi->datasize -= len;
- return min(dsi->datasize, buflen);
- }
+ if (len == buflen) {
+ dsi->datasize -= len;
+ return MIN(dsi->datasize, buflen);
+ }
- return -1;
+ return -1;
}
dsi->in_write++;
written = 0;
- LOG(log_maxdebug, logtype_dsi, "dsi_stream_write: sending %u bytes", length);
+ LOG(log_maxdebug, logtype_dsi, "dsi_stream_write(send: %zd bytes): START", length);
if (dsi->flags & DSI_DISCONNECTED)
return -1;
}
dsi->write_count += written;
+ LOG(log_maxdebug, logtype_dsi, "dsi_stream_write(send: %zd bytes): END", length);
exit:
dsi->in_write--;
#ifdef WITH_SENDFILE
ssize_t dsi_stream_read_file(DSI *dsi, int fromfd, off_t offset, const size_t length)
{
+ int ret = 0;
size_t written;
ssize_t len;
+ off_t pos = offset;
- LOG(log_maxdebug, logtype_dsi, "dsi_stream_read_file: sending %u bytes", length);
+ LOG(log_maxdebug, logtype_dsi, "dsi_stream_read_file(send %zd bytes): START", length);
if (dsi->flags & DSI_DISCONNECTED)
return -1;
written = 0;
while (written < length) {
- len = sys_sendfile(dsi->socket, fromfd, &offset, length - written);
+ len = sys_sendfile(dsi->socket, fromfd, &pos, length - written);
if (len < 0) {
if (errno == EINTR)
continue;
- if (errno == EINVAL || errno == ENOSYS)
- return -1;
-
+ if (errno == EINVAL || errno == ENOSYS) {
+ ret = -1;
+ goto exit;
+ }
if (errno == EAGAIN || errno == EWOULDBLOCK) {
+#ifdef SOLARIS
+ if (pos > offset) {
+ /* we actually have sent sth., adjust counters and keep trying */
+ len = pos - offset;
+ written += len;
+ offset = pos;
+ }
+#endif
if (dsi_peek(dsi)) {
/* can't go back to blocking mode, exit, the next read
will return with an error and afpd will die.
}
else if (!len) {
/* afpd is going to exit */
- errno = EIO;
- return -1; /* I think we're at EOF here... */
+ ret = -1;
+ goto exit;
}
else
written += len;
}
dsi->write_count += written;
+
+exit:
dsi->in_write--;
+ LOG(log_maxdebug, logtype_dsi, "dsi_stream_read_file: sent: %zd", written);
+ if (ret != 0)
+ return -1;
return written;
}
#endif
size_t towrite;
ssize_t len;
- LOG(log_maxdebug, logtype_dsi, "dsi_stream_send: %u bytes",
- length ? length : sizeof(block));
+ LOG(log_maxdebug, logtype_dsi, "dsi_stream_send(%u bytes): START", length);
if (dsi->flags & DSI_DISCONNECTED)
return 0;
sizeof(dsi->header.dsi_reserved));
if (!length) { /* just write the header */
+ LOG(log_maxdebug, logtype_dsi, "dsi_stream_send(%u bytes): DSI header, no data", sizeof(block));
length = (dsi_stream_write(dsi, block, sizeof(block), 0) == sizeof(block));
return length; /* really 0 on failure, 1 on success */
}
iov[1].iov_len -= len;
}
}
+
+ LOG(log_maxdebug, logtype_dsi, "dsi_stream_send(%u bytes): END", length);
unblock_sig(dsi);
return 1;
}
-/* ---------------------------------------
- * read data. function on success. 0 on failure. data length gets
- * stored in length variable. this should really use size_t's, but
- * that would require changes elsewhere. */
-int dsi_stream_receive(DSI *dsi, void *buf, const size_t ilength,
- size_t *rlength)
+/*!
+ * Read DSI command and data
+ *
+ * @param dsi (rw) DSI handle
+ *
+ * @return DSI function on success, 0 on failure
+ */
+int dsi_stream_receive(DSI *dsi)
{
char block[DSI_BLOCKSIZ];
- LOG(log_maxdebug, logtype_dsi, "dsi_stream_receive: %u bytes", ilength);
+ LOG(log_maxdebug, logtype_dsi, "dsi_stream_receive: START");
if (dsi->flags & DSI_DISCONNECTED)
return 0;
dsi->header.dsi_flags = block[0];
dsi->header.dsi_command = block[1];
- /* FIXME, not the right place,
- but we get a server disconnect without reason in the log
- */
- if (!block[1]) {
- LOG(log_error, logtype_dsi, "dsi_stream_receive: invalid packet, fatal");
+
+ if (dsi->header.dsi_command == 0)
return 0;
- }
- memcpy(&dsi->header.dsi_requestID, block + 2,
- sizeof(dsi->header.dsi_requestID));
+ memcpy(&dsi->header.dsi_requestID, block + 2, sizeof(dsi->header.dsi_requestID));
memcpy(&dsi->header.dsi_code, block + 4, sizeof(dsi->header.dsi_code));
memcpy(&dsi->header.dsi_len, block + 8, sizeof(dsi->header.dsi_len));
- memcpy(&dsi->header.dsi_reserved, block + 12,
- sizeof(dsi->header.dsi_reserved));
+ memcpy(&dsi->header.dsi_reserved, block + 12, sizeof(dsi->header.dsi_reserved));
dsi->clientID = ntohs(dsi->header.dsi_requestID);
/* make sure we don't over-write our buffers. */
- *rlength = min(ntohl(dsi->header.dsi_len), ilength);
- if (dsi_stream_read(dsi, buf, *rlength) != *rlength)
+ dsi->cmdlen = min(ntohl(dsi->header.dsi_len), DSI_CMDSIZ);
+ if (dsi_stream_read(dsi, dsi->commands, dsi->cmdlen) != dsi->cmdlen)
return 0;
+ LOG(log_debug, logtype_dsi, "dsi_stream_receive: DSI cmdlen: %zd", dsi->cmdlen);
+
return block[1];
}
/* DO NOT EDIT BY HAND!!! */
/* This file is generated by */
-/* contrib/misc/make-precompose.h.pl UnicodeData.txt */
+/* contrib/shell_utils/make-precompose.h.pl UnicodeData.txt */
/* UnicodeData.txt is got from */
/* http://www.unicode.org/Public/UNIDATA/UnicodeData.txt */
DO NOT EDIT BY HAND!!!
This file is generated by
- contrib/misc/make-casetable.pl UnicodeData.txt utf16_casetable.h utf16_case.c
+ contrib/shell_utils/make-casetable.pl UnicodeData.txt utf16_casetable.h utf16_case.c
UnicodeData.txt is got from
http://www.unicode.org/Public/UNIDATA/UnicodeData.txt
DO NOT EDIT BY HAND!!!
This file is generated by
- contrib/misc/make-casetable.pl UnicodeData.txt utf16_casetable.h utf16_case.c
+ contrib/shell_utils/make-casetable.pl UnicodeData.txt utf16_casetable.h utf16_case.c
UnicodeData.txt is got from
http://www.unicode.org/Public/UNIDATA/UnicodeData.txt
#include <time.h>
#include <ctype.h>
#include <errno.h>
+#include <stdbool.h>
-#include <atalk/boolean.h>
#include <atalk/util.h>
-
#include <atalk/logger.h>
#define OPEN_LOGS_AS_UID 0
#include "config.h"
#endif /* HAVE_CONFIG_H */
-#if !defined(__FreeBSD__) && !defined(__NetBSD__)
-# ifndef _XOPEN_SOURCE
-# define _XOPEN_SOURCE 600
-# endif
-# ifndef __EXTENSIONS__
-# define __EXTENSIONS__
-# endif
-# ifndef _GNU_SOURCE
-# define _GNU_SOURCE
-# endif
-#endif
+#include <atalk/standards.h>
+
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/socket.h>
-#include <arpa/inet.h>
+#include <sys/uio.h>
#include <netinet/in.h>
+#include <arpa/inet.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
}
/*!
- * Make argument path absoulte
+ * @brief Request absolute path
*
- * @returns pointer to path or pointer to error messages on error
+ * @returns Absolute filesystem path to object
*/
-const char *abspath(const char *name)
+const char *fullpathname(const char *name)
{
- static char buf[MAXPATHLEN + 1];
- char *p;
- int n;
+ static char wd[MAXPATHLEN + 1];
if (name[0] == '/')
return name;
- if ((p = getcwd(buf, MAXPATHLEN)) == NULL)
- return strerror(errno);
+ if (getcwd(wd , MAXPATHLEN)) {
+ strlcat(wd, "/", MAXPATHLEN);
+ strlcat(wd, name, MAXPATHLEN);
+ } else {
+ strlcpy(wd, name, MAXPATHLEN);
+ }
- n = strlen(buf);
- if (buf[n-1] != '/')
- buf[n++] = '/';
-
- strlcpy(buf + n, name, MAXPATHLEN - n);
- return buf;
+ return wd;
}
/*!
}
if ((fd = open(item, O_RDWR | O_CREAT , 0666)) <0 ) {
- LOG(log_error, logtype_afpd,"Error opening %s: %s", item, strerror(errno));
+ LOG(log_debug, logtype_default,"Error opening %s: %s", item, strerror(errno));
+ if (process_uid) {
+ if (seteuid(process_uid) == -1) {
+ LOG(log_error, logtype_default, "can't seteuid back %s", strerror(errno));
+ exit(EXITERR_SYS);
+ }
+ }
return (-1);
}
if (process_uid) {
if (seteuid(process_uid) == -1) {
- LOG(log_error, logtype_logger, "can't seteuid back %s", strerror(errno));
+ LOG(log_error, logtype_default, "can't seteuid back %s", strerror(errno));
exit(EXITERR_SYS);
}
}
/* ignore, other process already writing the file */
return 0;
} else {
- LOG(log_error, logtype_cnid, "savevoloptions: cannot get lock: %s", strerror(errno));
+ LOG(log_error, logtype_default, "savevoloptions: cannot get lock: %s", strerror(errno));
return (-1);
}
}
strlcat(buf, item, sizeof(buf));
if (strlen(buf) >= sizeof(buf)-1)
- LOG(log_debug, logtype_afpd,"Error writing .volinfo file: buffer too small, %s", buf);
+ LOG(log_debug, logtype_default, "Error writing .volinfo file: buffer too small, %s", buf);
if (write( fd, buf, strlen(buf)) < 0 || ftruncate(fd, strlen(buf)) < 0 ) {
- LOG(log_debug, logtype_afpd,"Error writing .volinfo file: %s", strerror(errno));
+ LOG(log_debug, logtype_default, "Error writing .volinfo file: %s", strerror(errno));
}
lock.l_type = F_UNLCK;
#ifdef HAVE_POSIX_ACLS
/*!
- * Remove any ACL_USER, ACL_GROUP or ACL_TYPE_DEFAULT ACEs from an object
+ * Remove any ACL_USER, ACL_GROUP, ACL_MASK or ACL_TYPE_DEFAULT ACEs from an object
*
* @param name (r) filesystem object name
*
acl = NULL;
}
- /* Now get ACL and remove ACL_USER or ACL_GROUP entries, then re-set the ACL again */
+ /* Now get ACL and remove ACL_MASK, ACL_USER or ACL_GROUP entries, then re-set
+ * the ACL again. acl_calc_mask() must not be called because there is no need
+ * for an ACL_MASK entry in a basic ACL. */
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)
+ if (tag == ACL_USER || tag == ACL_GROUP || tag == ACL_MASK)
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);
unsigned int count = 0;
if (ea->ea_count == 0) {
- LOG(log_error, logtype_afpd, "ea_delentry('%s'): illegal ea_count of 0 on deletion");
+ LOG(log_error, logtype_afpd, "ea_delentry('%s'): illegal ea_count of 0 on deletion",
+ attruname);
return -1;
}
while (count < ea->ea_count) {
/* search matching EA */
- if (strcmp(attruname, (*ea->ea_entries)[count].ea_name) == 0) {
+ if ((*ea->ea_entries)[count].ea_name &&
+ strcmp(attruname, (*ea->ea_entries)[count].ea_name) == 0) {
free((*ea->ea_entries)[count].ea_name);
(*ea->ea_entries)[count].ea_name = NULL;
* Ignore EPERM errors: We may be dealing with a directory that is
* group writable, in which case chmod will fail.
*/
- if ( (chmod( name, (DIRBITS | mode) & ~v_umask ) < 0) && errno != EPERM &&
+ if ( (chmod_acl( name, (DIRBITS | mode) & ~v_umask ) < 0) && errno != EPERM &&
!(errno == ENOENT && (dropbox & AFPVOL_NOADOUBLE)) )
{
LOG(log_error, logtype_afpd, "stickydirmode: chmod \"%s\": %s", fullpathname(name), strerror(errno) );
mode |= st->st_mode & ~mask; /* keep other bits from previous mode */
- if ( chmod( name, mode & ~v_umask ) < 0 && errno != EPERM ) {
+ if ( chmod_acl( name, mode & ~v_umask ) < 0 && errno != EPERM ) {
return -1;
}
return 0;
return AFP_OK;
}
-char *fullpathname(const char *name)
-{
- static char wd[ MAXPATHLEN + 1];
-
- if ( getcwd( wd , MAXPATHLEN) ) {
- strlcat(wd, "/", MAXPATHLEN);
- strlcat(wd, name, MAXPATHLEN);
- }
- else {
- strlcpy(wd, name, MAXPATHLEN);
- }
- return wd;
-}
-
-
/**************************************************************************
* *at semnatics support functions (like openat, renameat standard funcs)
**************************************************************************/
sfd = open(src, O_RDONLY);
#endif
if (sfd < 0) {
- LOG(log_error, logtype_afpd, "copy_file('%s'/'%s'): open '%s' error: %s",
+ LOG(log_info, logtype_afpd, "copy_file('%s'/'%s'): open '%s' error: %s",
src, dst, src, strerror(errno));
return -1;
}
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",
+ LOG(log_info, logtype_afpd, "copy_file('%s'/'%s'): open '%s' error: %s",
src, dst, dst, strerror(errno));
ret = -1;
goto exit;
/* ----------------- */
static int RF_chown_ea(VFS_FUNC_ARGS_CHOWN)
{
+ mode_t file_mode = ad_hf_mode(mode);
+ mode_t dir_mode = file_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_acl( name, dir_mode ) < 0)
+ return -1;
+ }
+ param.st = st;
+ param.mode = file_mode;
+ if (for_each_adouble("setfilmode_ads", name, ads_setfilmode_loop, ¶m, 0, v_umask) < 0)
+ return -1;
+
+ if (!dir_rx_set(dir_mode)) {
+ if (chmod_acl( name, dir_mode ) < 0)
+ return -1;
+ }
+
return 0;
}
CFLAGS="$CFLAGS $GSSAPI_CFLAGS"
CPPFLAGS="$CPPFLAGS $GSSAPI_CPPFLAGS"
LDFLAGS="$LDFLAGS $GSSAPI_LDFLAGS"
- LIBS="$GSSAPI_LIBS"
+ LIBS="$LIBS $GSSAPI_LIBS"
# check for gssapi headers
dnl #################################################
dnl # check for libiconv support
+ saved_CPPFLAGS="$CPPFLAGS"
savedcflags="$CFLAGS"
savedldflags="$LDFLAGS"
ICONV_CFLAGS=""
powerpc|ppc) this_cpu=ppc ;;
esac
+dnl --------------------- GNU source
+case "$this_os" in
+ linux) AC_DEFINE(_GNU_SOURCE, 1, [Whether to use GNU libc extensions])
+ ;;
+ kfreebsd-gnu) AC_DEFINE(_GNU_SOURCE, 1, [Whether to use GNU libc extensions])
+ ;;
+esac
+
dnl --------------------- operating system specific flags (port from sys/*)
dnl ----- FreeBSD specific -----
AC_MSG_RESULT([ * FreeBSD specific configuration])
AC_DEFINE(BSD4_4, 1, [BSD compatiblity macro])
AC_DEFINE(FREEBSD, 1, [Define if OS is FreeBSD])
- AC_DEFINE(SENDFILE_FLAVOR_BSD, 1, [Define if the sendfile() function uses BSD semantics])
+ AC_DEFINE(OPEN_NOFOLLOW_ERRNO, EMLINK, errno returned by open with O_NOFOLLOW)
+fi
+
+dnl ----- GNU/kFreeBSD specific -----
+if test x"$this_os" = "xkfreebsd-gnu"; then
+ AC_MSG_RESULT([ * GNU/kFreeBSD specific configuration])
+ AC_DEFINE(BSD4_4, 1, [BSD compatiblity macro])
+ AC_DEFINE(FREEBSD, 1, [Define if OS is FreeBSD])
AC_DEFINE(OPEN_NOFOLLOW_ERRNO, EMLINK, errno returned by open with O_NOFOLLOW)
fi
dnl ----- see etc/afpd/quota.c
AC_DEFINE(HAVE_BROKEN_DBTOB, 1, [Define if dbtob is broken])
- netatalk_cv_linux_sendfile=yes
- AC_MSG_CHECKING([use sendfile syscall])
- AC_ARG_ENABLE(sendfile,
- [ --disable-sendfile disable linux sendfile syscall],[
- if test x"$enableval" = x"no"; then
- netatalk_cv_linux_sendfile=no
- AC_MSG_RESULT([no])
- else
- AC_MSG_RESULT([yes])
-
- fi
- ],[
- AC_MSG_RESULT([yes])
- ]
-
- )
-
- if test x"$netatalk_cv_linux_sendfile" = "xyes"; then
- AC_CACHE_CHECK([for linux sendfile support],netatalk_cv_HAVE_SENDFILE,[
- AC_TRY_LINK([#include <sys/sendfile.h>],
-[\
-int tofd, fromfd;
-off_t offset;
-size_t total;
-ssize_t nwritten = sendfile(tofd, fromfd, &offset, total);
-],
-netatalk_cv_HAVE_SENDFILE=yes,netatalk_cv_HAVE_SENDFILE=no)])
-
-# Try and cope with broken Linux sendfile....
- AC_CACHE_CHECK([for broken linux sendfile support],netatalk_cv_HAVE_BROKEN_LINUX_SENDFILE,[
- AC_TRY_LINK([\
-#if defined(_FILE_OFFSET_BITS) && (_FILE_OFFSET_BITS == 64)
-#undef _FILE_OFFSET_BITS
-#endif
-#include <sys/sendfile.h>],
-[\
-int tofd, fromfd;
-off_t offset;
-size_t total;
-ssize_t nwritten = sendfile(tofd, fromfd, &offset, total);
-],
-netatalk_cv_HAVE_BROKEN_LINUX_SENDFILE=yes,netatalk_cv_HAVE_BROKEN_LINUX_SENDFILE=no,netatalk_cv_HAVE_BROKEN_SENDFILE=cross)])
-
- if test x"$netatalk_cv_HAVE_SENDFILE" = x"yes"; then
- AC_DEFINE(HAVE_SENDFILE,1,[Whether sendfile() is available])
- AC_DEFINE(SENDFILE_FLAVOR_LINUX,1,[Whether linux sendfile() API is available])
- AC_DEFINE(WITH_SENDFILE,1,[Whether sendfile() should be used])
- elif test x"$netatalk_cv_HAVE_BROKEN_LINUX_SENDFILE" = x"yes"; then
- AC_DEFINE(SENDFILE_FLAVOR_LINUX,1,[Whether linux sendfile() API is available])
- AC_DEFINE(LINUX_BROKEN_SENDFILE_API,1,[Whether (linux) sendfile() is broken])
- AC_DEFINE(WITH_SENDFILE,1,[Whether sendfile should be used])
- else
- netatalk_cv_linux_sendfile=no
- AC_MSG_RESULT(no);
- fi
- fi
-
need_dash_r=no
fi
-dnl ----- Mac OSX specific -----
-if test x"$this_os" = "xmacosx"; then
- AC_MSG_RESULT([ * Mac OSX specific configuration])
- AC_DEFINE(BSD4_4, 1, [BSD compatiblity macro])
- AC_DEFINE(HAVE_2ARG_DBTOB, 1, [Define if dbtob takes two arguments])
- dnl AC_DEFINE(NO_DLFCN_H)
- AC_DEFINE(NO_QUOTA_SUPPORT, 1, [Define if Quota support should be disabled])
- AC_DEFINE(MACOSX_SERVER, 1, [Define if compiling for MacOS X Server])
- AC_DEFINE(NO_DDP, 1, [Define if DDP should be disabled])
-fi
-
dnl ----- NetBSD specific -----
if test x"$this_os" = "xnetbsd"; then
AC_MSG_RESULT([ * NetBSD specific configuration])
dnl ----- OpenBSD specific -----
if test x"$this_os" = "xopenbsd"; then
AC_MSG_RESULT([ * OpenBSD specific configuration])
+ AC_DEFINE(BSD4_4, 1, [BSD compatiblity macro])
dnl ----- OpenBSD does not have crypt.h, uses unistd.h -----
AC_DEFINE(UAM_DHX, 1, [Define if the DHX UAM modules should be compiled])
fi
AM_CONDITIONAL(USE_SMB_SHAREMODES, test x"$neta_cv_have_smbshmd" = x"yes")
])
+
+dnl ------ Check for sendfile() --------
+AC_DEFUN([AC_NETATALK_SENDFILE], [
+netatalk_cv_search_sendfile=yes
+AC_ARG_ENABLE(sendfile,
+ [ --disable-sendfile disable sendfile syscall],
+ [if test x"$enableval" = x"no"; then
+ netatalk_cv_search_sendfile=no
+ fi]
+)
+
+if test x"$netatalk_cv_search_sendfile" = x"yes"; then
+ case "$host_os" in
+ *linux*)
+ AC_DEFINE(SENDFILE_FLAVOR_LINUX,1,[Whether linux sendfile() API is available])
+ AC_CHECK_FUNC([sendfile], [netatalk_cv_HAVE_SENDFILE=yes])
+ ;;
+
+ *solaris*)
+ AC_DEFINE(SENDFILE_FLAVOR_SOLARIS, 1, [Solaris sendfile()])
+ AC_SEARCH_LIBS(sendfile, sendfile)
+ AC_CHECK_FUNC([sendfile], [netatalk_cv_HAVE_SENDFILE=yes])
+ ;;
+
+ *freebsd*)
+ AC_DEFINE(SENDFILE_FLAVOR_BSD, 1, [Define if the sendfile() function uses BSD semantics])
+ AC_CHECK_FUNC([sendfile], [netatalk_cv_HAVE_SENDFILE=yes])
+ ;;
+
+ *)
+ ;;
+
+ esac
+
+ if test x"$netatalk_cv_HAVE_SENDFILE" = x"yes"; then
+ AC_DEFINE(WITH_SENDFILE,1,[Whether sendfile() should be used])
+ fi
+fi
+])
+
+dnl --------------------- Check if realpath() takes NULL
+AC_DEFUN([AC_NETATALK_REALPATH], [
+AC_CACHE_CHECK([if the realpath function allows a NULL argument],
+ neta_cv_REALPATH_TAKES_NULL, [
+ AC_TRY_RUN([
+ #include <stdio.h>
+ #include <limits.h>
+ #include <signal.h>
+
+ void exit_on_core(int ignored) {
+ exit(1);
+ }
+
+ main() {
+ char *newpath;
+ signal(SIGSEGV, exit_on_core);
+ newpath = realpath("/tmp", NULL);
+ exit((newpath != NULL) ? 0 : 1);
+ }],
+ neta_cv_REALPATH_TAKES_NULL=yes,
+ neta_cv_REALPATH_TAKES_NULL=no,
+ neta_cv_REALPATH_TAKES_NULL=cross
+ )
+ ]
+)
+
+if test x"$neta_cv_REALPATH_TAKES_NULL" = x"yes"; then
+ AC_DEFINE(REALPATH_TAKES_NULL,1,[Whether the realpath function allows NULL])
+fi
+])
\ No newline at end of file
AC_MSG_RESULT([ DHX2 ($uams_using_options)])
fi
if test "x$neta_cv_have_openssl" = "xyes"; then
- AC_MSG_RESULT([ RANDNUM ($uams_using_options)])
+ AC_MSG_RESULT([ RANDNUM])
fi
if test x"$netatalk_cv_build_krb5_uam" = x"yes"; then
AC_MSG_RESULT([ Kerberos V])
if test x"$compile_pgp" = x"yes"; then
AC_MSG_RESULT([ PGP])
fi
- AC_MSG_RESULT([ passwd ($uams_using_options)])
+ AC_MSG_RESULT([ clrtxt ($uams_using_options)])
AC_MSG_RESULT([ guest])
AC_MSG_RESULT([ Options:])
AC_MSG_RESULT([ SLP support: $netatalk_cv_srvloc])
.\" Title: ad
.\" Author: [FIXME: author] [see http://docbook.sf.net/el/author]
.\" Generator: DocBook XSL Stylesheets v1.75.2 <http://docbook.sf.net/>
-.\" Date: 30 Mar 2011
+.\" Date: 02 Sep 2011
.\" Manual: Netatalk 2.2
.\" Source: Netatalk 2.2
.\" Language: English
.\"
-.TH "AD" "1" "30 Mar 2011" "Netatalk 2.2" "Netatalk 2.2"
+.TH "AD" "1" "02 Sep 2011" "Netatalk 2.2" "Netatalk 2.2"
.\" -----------------------------------------------------------------
.\" * set default formatting
.\" -----------------------------------------------------------------
.SH "SYNOPSIS"
.HP \w'\fBad\fR\ 'u
\fBad\fR {ls\ |\ cp\ |\ mv\ |\ rm} [\&.\&.\&.]
+.HP \w'\fBad\fR\ 'u
+\fBad\fR {\-v\ |\ \-\-version}
.SH "DESCRIPTION"
.PP
\fBad\fR
Move files and directories\&.
.HP \w'\fBad\ rm\fR\ 'u
\fBad rm\fR [\-Rv] {file|directory}
+.HP \w'\fBad\ \-v|\-\-version\fR\ 'u
+\fBad \-v|\-\-version\fR
.PP
-Remove files and directories\&.
+Show version\&.
.SH "AD LS"
.PP
List files and directories\&. Options:
.\" Title: apple_dump
.\" Author: [FIXME: author] [see http://docbook.sf.net/el/author]
.\" Generator: DocBook XSL Stylesheets v1.75.2 <http://docbook.sf.net/>
-.\" Date: 30 Mar 2011
+.\" Date: 02 Sep 2011
.\" Manual: Netatalk 2.2
.\" Source: Netatalk 2.2
.\" Language: English
.\"
-.TH "APPLE_DUMP" "1" "30 Mar 2011" "Netatalk 2.2" "Netatalk 2.2"
+.TH "APPLE_DUMP" "1" "02 Sep 2011" "Netatalk 2.2" "Netatalk 2.2"
.\" -----------------------------------------------------------------
.\" * set default formatting
.\" -----------------------------------------------------------------
.SH "NAME"
apple_dump \- Dump AppleSingle/AppleDouble format file
.SH "SYNOPSIS"
-.HP \w'\fBapple_dump\fR\fB\fR\fBapple_dump\fR\fB\fR\fBapple_dump\fR\fB\fR\fBapple_dump\fR\fB\fR\ 'u
+.HP \w'\fBapple_dump\fR\fB\fR\fBapple_dump\fR\fB\fR\fBapple_dump\fR\fB\fR\fBapple_dump\fR\fB\fR\fBapple_dump\fR\fB\fR\ 'u
\fBapple_dump\fR\fB\fR [\-a] \fIFILE\fR | \fIDIR\fR
.br
\fBapple_dump\fR\fB\fR \-f \fIFILE\fR
\fBapple_dump\fR\fB\fR \-d \fIFILE\fR
.br
\fBapple_dump\fR\fB\fR \-h | \-help | \-\-help
+.br
+\fBapple_dump\fR\fB\fR \-v | \-version | \-\-version
.SH "DESCRIPTION"
.PP
\fBapple_dump\fR
.RS 4
Display the help and exit
.RE
+.PP
+\fB\-v, \-version, \-\-version\fR
+.RS 4
+Show version and exit
+.RE
.SH "NOTE"
.PP
There is no way to detect whether FinderInfo is FileInfo or DirInfo\&. By default, apple_dump examins whether file or directory, a parent directory is \&.AppleDouble, filename is \&._*, filename is \&.Parent, and so on\&.
.\" Title: asip-status.pl
.\" Author: [FIXME: author] [see http://docbook.sf.net/el/author]
.\" Generator: DocBook XSL Stylesheets v1.75.2 <http://docbook.sf.net/>
-.\" Date: 10 Mar 2011
+.\" Date: 02 Sep 2011
.\" Manual: Netatalk 2.2
.\" Source: Netatalk 2.2
.\" Language: English
.\"
-.TH "ASIP\-STATUS\&.PL" "1" "10 Mar 2011" "Netatalk 2.2" "Netatalk 2.2"
+.TH "ASIP\-STATUS\&.PL" "1" "02 Sep 2011" "Netatalk 2.2" "Netatalk 2.2"
.\" -----------------------------------------------------------------
.\" * set default formatting
.\" -----------------------------------------------------------------
.SH "SYNOPSIS"
.HP \w'\fBasip\-status\&.pl\fR\fB\fR\ 'u
\fBasip\-status\&.pl\fR\fB\fR [\-d] [\-i] [\-x] HOSTNAME[:PORT]
+
+.br
+.HP \w'\fBasip\-status\&.pl\fR\fB\fR\ 'u
+\fBasip\-status\&.pl\fR\fB\fR \-v | \-version | \-\-version
.SH "DESCRIPTION"
.PP
\fBasip\-status\&.pl\fR
.RS 4
Enable hex dump output\&.
.RE
+.PP
+\fB\-v, \-version, \-\-version\fR
+.RS 4
+Show version\&.
+.RE
.SH "EXAMPLES"
.PP
.if n \{\
--- /dev/null
+'\" t
+.\" Title: macusers
+.\" Author: [FIXME: author] [see http://docbook.sf.net/el/author]
+.\" Generator: DocBook XSL Stylesheets v1.75.2 <http://docbook.sf.net/>
+.\" Date: 13 Oct 2011
+.\" Manual: Netatalk 2.2
+.\" Source: Netatalk 2.2
+.\" Language: English
+.\"
+.TH "MACUSERS" "1" "13 Oct 2011" "Netatalk 2.2" "Netatalk 2.2"
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+macusers \- List the users connecting via AFP
+.SH "SYNOPSIS"
+.HP \w'\fBmacusers\fR\fB\fR\ 'u
+\fBmacusers\fR\fB\fR
+.HP \w'\fBmacusers\fR\fB\fR\ 'u
+\fBmacusers\fR\fB\fR \-v | \-version | \-\-version | \-h | \-help | \-\-help
+.SH "DESCRIPTION"
+.PP
+\fBmacusers\fR
+list the users connecting via AFP\&.
+.SH "OPTIONS"
+.PP
+\fB\-v, \-version, \-\-version\fR
+.RS 4
+Show version and exit
+.RE
+.PP
+\fB\-h, \-help, \-\-help\fR
+.RS 4
+Display the help and exit
+.RE
+.SH "SEE ALSO"
+.PP
+\fBafpd\fR(8)
.\" Title: megatron
.\" Author: [FIXME: author] [see http://docbook.sf.net/el/author]
.\" Generator: DocBook XSL Stylesheets v1.75.2 <http://docbook.sf.net/>
-.\" Date: 8 Jan 1992
+.\" Date: 02 Sep 2011
.\" Manual: Netatalk 2.2
.\" Source: Netatalk 2.2
.\" Language: English
.\"
-.TH "MEGATRON" "1" "8 Jan 1992" "Netatalk 2.2" "Netatalk 2.2"
+.TH "MEGATRON" "1" "02 Sep 2011" "Netatalk 2.2" "Netatalk 2.2"
.\" -----------------------------------------------------------------
.\" * set default formatting
.\" -----------------------------------------------------------------
will read from standard input\&.
.PP
The filename used to store any output file is the filename that is encoded in the source file\&. MacBinary files are created with a "\&.bin" extension\&. In the case of conflicts, the old file is overwritten!
+.SH "OPTIONS"
+.PP
+\fB\-v, \-\-version\fR
+.RS 4
+Show version\&.
+.RE
.SH "SEE ALSO"
.PP
\fBafpd\fR(8)
.\" 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: 30 Mar 2011
+.\" Date: 13 Oct 2011
.\" Manual: Netatalk 2.2
.\" Source: Netatalk 2.2
.\" Language: English
.\"
-.TH "APPLEVOLUMES\&.DEFAU" "5" "30 Mar 2011" "Netatalk 2.2" "Netatalk 2.2"
+.TH "APPLEVOLUMES\&.DEFAU" "5" "13 Oct 2011" "Netatalk 2.2" "Netatalk 2.2"
.\" -----------------------------------------------------------------
.\" * set default formatting
.\" -----------------------------------------------------------------
volsizelimit:\fIsize in MiB\fR
.RS 4
Useful for TimeMachine: limits the reported volume size, thus preventing TM from using the whole real disk space for backup\&. Example: "volsizelimit:1000" would limit the reported disk space to 1 GB\&.
+\fBIMPORTANT: \fR
+This is an approximated calculation taking into accout the contents of TM sparsebundle images\&. Therefor you MUST NOT use this volume to store other content when using this option, because it would NOT be accounted\&. The calculation works by reading the band size from the Info\&.plist XML file of the sparsebundle, reading the bands/ directory counting the number of band files, and then multiplying one with the other\&.
.RE
.PP
allow:\fI[users/groups]\fR
needs a way to preserve extended macintosh characters, or characters illegal in unix filenames, when saving files on a unix filesystem\&. Earlier versions used the the so called CAP encoding\&. An extended character (>0x7F) would be converted to a :xx sequence, e\&.g\&. the Apple Logo (MacRoman: 0XF0) was saved as
:f0\&. Some special characters will be converted as to :xx notation as well\&. \'/\' will be encoded to
:2f, if
-\fB\-usedots\fR
+\fBusedots\fR
is not specified, a leading dot \'\&.\' will be encoded as
:2e\&.
.PP
.RS 4
Use for eg\&. winbind authentication, prepends both strings before the username from login and then tries to authenticate with the result through the availabel and active UAM authentication modules\&.
.RE
+.PP
+\-adminauthuser
+.RS 4
+Specifying eg
+\fB\-adminauthuser root\fR
+whenever a normal user login fails, afpd will try to authenticate as the specified
+\fBadminauthuser\fR\&. If this succeeds, a normal session is created for the original connecting user\&. Said differently: if you know the password of
+\fBadminauthuser\fR, you can authenticate as any other user\&.
+.RE
.SH "CODEPAGE OPTIONS"
.PP
With OS X Apple introduced the AFP3 protocol\&. One of the big changes was, that AFP3 uses Unicode names encoded as Decomposed UTF\-8 (UTF8\-MAC)\&. Previous AFP/OS versions used codepages like MacRoman, MacCentralEurope, etc\&.