]> arthur.barton.de Git - netatalk.git/commitdiff
Merge master
authorFrank Lahm <franklahm@googlemail.com>
Wed, 1 Jun 2011 14:03:25 +0000 (16:03 +0200)
committerFrank Lahm <franklahm@googlemail.com>
Wed, 1 Jun 2011 14:03:25 +0000 (16:03 +0200)
82 files changed:
NEWS
bin/ad/ad.h
bin/ad/ad_cp.c
bin/misc/.gitignore
bin/misc/Makefile.am
bin/misc/fce.c [new file with mode: 0644]
bin/misc/uuidtest.c
config/afpd.conf.tmpl
etc/afpd/.gitignore
etc/afpd/Makefile.am
etc/afpd/acls.c
etc/afpd/afp_avahi.c
etc/afpd/afp_avahi.h
etc/afpd/afp_config.c
etc/afpd/afp_config.h
etc/afpd/afp_dsi.c
etc/afpd/afp_options.c
etc/afpd/afp_util.c
etc/afpd/appl.c
etc/afpd/auth.c
etc/afpd/auth.h
etc/afpd/catsearch.c
etc/afpd/desktop.c
etc/afpd/desktop.h
etc/afpd/dircache.c
etc/afpd/directory.c
etc/afpd/directory.h
etc/afpd/enumerate.c
etc/afpd/extattrs.c
etc/afpd/fce_api.c [new file with mode: 0755]
etc/afpd/fce_api_internal.h [new file with mode: 0755]
etc/afpd/fce_util.c [new file with mode: 0755]
etc/afpd/file.c
etc/afpd/file.h
etc/afpd/filedir.c
etc/afpd/filedir.h
etc/afpd/fork.c
etc/afpd/fork.h
etc/afpd/gettok.c
etc/afpd/globals.h [deleted file]
etc/afpd/icon.h
etc/afpd/main.c
etc/afpd/mangle.h
etc/afpd/messages.c
etc/afpd/misc.h
etc/afpd/ofork.c
etc/afpd/status.c
etc/afpd/status.h
etc/afpd/switch.c
etc/afpd/uam.c
etc/afpd/uam_auth.h
etc/afpd/volume.c
etc/afpd/volume.h
etc/cnid_dbd/cnid_metad.c
etc/uams/uams_dhx2_pam.c
include/atalk/Makefile.am
include/atalk/directory.h
include/atalk/dsi.h
include/atalk/fce_api.h [new file with mode: 0755]
include/atalk/globals.h [new file with mode: 0644]
include/atalk/paths.h
include/atalk/server_child.h
include/atalk/server_ipc.h
include/atalk/uam.h
include/atalk/util.h
include/atalk/uuid.h
include/atalk/volume.h
libatalk/acl/cache.c
libatalk/acl/cache.h
libatalk/acl/uuid.c
libatalk/cnid/dbd/cnid_dbd.c
libatalk/dsi/dsi_getsess.c
libatalk/dsi/dsi_stream.c
libatalk/util/logger.c
libatalk/util/server_child.c
libatalk/util/server_ipc.c
libatalk/util/socket.c
macros/netatalk.m4
man/man1/afppasswd.1
man/man5/AppleVolumes.default.5.tmpl
man/man5/afpd.conf.5.tmpl
man/man8/afpd.8.tmpl

diff --git a/NEWS b/NEWS
index f8d92829c0ce4883ec62ef59eda9e7211471fdfd..2a54c2b9dad44dd8d957bd9093cf1c64142abda1 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,10 +1,17 @@
 Changes in 2.2
 ==============
 
+* NEW: afpd: new volume option "nonetids"
+* NEW: afpd: ACL access check caching
+* NEW: afpd: FCE event notifications
+* NEW: afpd: new option "-mimicmodel" for specifying Bonjour model registration
 * UPD: Support for Berkeley DB 5.1
 * UPD: case-conversion is based on Unicode 6.0.0
 * UPD: cnid_metad: allow up to 4096 volumes
 * UPD: afpd: only forward SIGTERM and SIGUSR1 from parent to childs
+* UPD: afpd: use internal function instead of popening du -sh in order to
+       calculate the used size of a volume for option "volsizelimit"
+* UPD: afpd: Add negative UUID caching, enhance local UUID handling
 * FIX: afpd: configuration reload with SIGHUP
 * FIX: afpd: crashes in the dircache
 * FIX: afpd: Correct afp logout vs dsi eof behaviour
index ee4f57721e6319b5d04294cbe787037628a18649..360ac17369a0a4b8f7eadd79baa6850508038837 100644 (file)
@@ -15,7 +15,9 @@
 #ifndef AD_H
 #define AD_H
 
-#define _XOPEN_SOURCE 600
+#if !defined(__FreeBSD__)
+# define _XOPEN_SOURCE 600
+#endif
 
 #include <sys/types.h>
 #include <sys/stat.h>
index b0723b021976d69f4a778fdbeef3006d4c3489ea..1020d7d6c022fcb998baab55edbcc05d0dbda6fe 100644 (file)
@@ -841,8 +841,14 @@ static int setfile(const struct stat *fs, int fd)
     islink = !fdval && S_ISLNK(fs->st_mode);
     mode = fs->st_mode & (S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO);
 
+#if defined(__FreeBSD__)
+    TIMESPEC_TO_TIMEVAL(&tv[0], &fs->st_atimespec);
+    TIMESPEC_TO_TIMEVAL(&tv[1], &fs->st_mtimespec);
+#else
     TIMESPEC_TO_TIMEVAL(&tv[0], &fs->st_atim);
     TIMESPEC_TO_TIMEVAL(&tv[1], &fs->st_mtim);
+#endif
+
     if (utimes(to.p_path, tv)) {
         SLOG("utimes: %s", to.p_path);
         rval = 1;
index 2bff10ed3a1d944593ad9ff8cea65d8cbecbe84d..84dddb390fcef45d5bc5b67288146b947a67fcce 100644 (file)
@@ -2,6 +2,7 @@ Makefile
 Makefile.in
 netacnv
 afpldaptest
+fce
 logger_test
 .deps
 .libs
index 04a53e23e8b72fa1c59ff0af9944890f9a6188af..426dc3179f25ad99371bdff4e0e341e0a3cc6386 100644 (file)
@@ -3,7 +3,7 @@
 pkgconfdir = @PKGCONFDIR@
 bin_PROGRAMS =
 
-noinst_PROGRAMS = netacnv logger_test
+noinst_PROGRAMS = netacnv logger_test fce
 
 netacnv_SOURCES = netacnv.c
 netacnv_LDADD = $(top_builddir)/libatalk/libatalk.la
@@ -11,6 +11,10 @@ netacnv_LDADD = $(top_builddir)/libatalk/libatalk.la
 logger_test_SOURCES = logger_test.c
 logger_test_LDADD = $(top_builddir)/libatalk/libatalk.la
 
+fce_SOOURCE = fce.c
+fce_LDADD = $(top_builddir)/libatalk/libatalk.la
+fce_CFLAGS = -I$(top_srcdir)/include
+
 bin_PROGRAMS += afpldaptest
 afpldaptest_SOURCES = uuidtest.c
 afpldaptest_CFLAGS = -D_PATH_ACL_LDAPCONF=\"$(pkgconfdir)/afp_ldap.conf\"
diff --git a/bin/misc/fce.c b/bin/misc/fce.c
new file mode 100644 (file)
index 0000000..76ca0a8
--- /dev/null
@@ -0,0 +1,164 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <inttypes.h>
+#include <sys/types.h>
+
+#include <sys/param.h>
+#include <sys/cdefs.h>
+
+#include <atalk/fce_api.h>
+#include <atalk/util.h>
+
+#define MAXBUFLEN 1024
+
+static char *fce_ev_names[] = {
+    "",
+    "FCE_FILE_MODIFY",
+    "FCE_FILE_DELETE",
+    "FCE_DIR_DELETE",
+    "FCE_FILE_CREATE",
+    "FCE_DIR_CREATE",
+    "FCE_TM_SIZE"
+};
+
+// get sockaddr, IPv4 or IPv6:
+static void *get_in_addr(struct sockaddr *sa)
+{
+    if (sa->sa_family == AF_INET) {
+        return &(((struct sockaddr_in*)sa)->sin_addr);
+    }
+
+    return &(((struct sockaddr_in6*)sa)->sin6_addr);
+}
+
+static int unpack_fce_packet(unsigned char *buf, struct fce_packet *packet)
+{
+    unsigned char *p = buf;
+
+    memcpy(&packet->magic[0], p, sizeof(packet->magic));
+    p += sizeof(packet->magic);
+
+    packet->version = *p;
+    p++;
+
+    packet->mode = *p;
+    p++;
+
+    memcpy(&packet->event_id, p, sizeof(packet->event_id));
+    p += sizeof(packet->event_id);
+    packet->event_id = ntohl(packet->event_id);
+
+    memcpy(&packet->datalen, p, sizeof(packet->datalen));
+    p += sizeof(packet->datalen);
+    packet->datalen = ntohs(packet->datalen);
+
+    memcpy(&packet->data[0], p, packet->datalen);
+    p += packet->datalen;
+
+    return 0;
+}
+
+int main(void)
+{
+    int sockfd;
+    struct addrinfo hints, *servinfo, *p;
+    int rv;
+    int numbytes;
+    struct sockaddr_storage their_addr;
+    char buf[MAXBUFLEN];
+    socklen_t addr_len;
+    char s[INET6_ADDRSTRLEN];
+    uint64_t tmsize;
+
+    memset(&hints, 0, sizeof hints);
+    hints.ai_family = AF_UNSPEC; // set to AF_INET to force IPv4
+    hints.ai_socktype = SOCK_DGRAM;
+
+    if ((rv = getaddrinfo(NULL, FCE_DEFAULT_PORT_STRING, &hints, &servinfo)) != 0) {
+        fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
+        return 1;
+    }
+
+    // loop through all the results and bind to the first we can
+    for(p = servinfo; p != NULL; p = p->ai_next) {
+        if ((sockfd = socket(p->ai_family, p->ai_socktype,
+                             p->ai_protocol)) == -1) {
+            perror("listener: socket");
+            continue;
+        }
+
+        if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
+            close(sockfd);
+            perror("listener: bind");
+            continue;
+        }
+
+        break;
+    }
+
+    if (p == NULL) {
+        fprintf(stderr, "listener: failed to bind socket\n");
+        return 2;
+    }
+
+    freeaddrinfo(servinfo);
+
+    printf("listener: waiting to recvfrom...\n");
+
+    addr_len = sizeof their_addr;
+
+    struct fce_packet packet;
+    while (1) {
+        if ((numbytes = recvfrom(sockfd,
+                                 buf,
+                                 MAXBUFLEN - 1,
+                                 0,
+                                 (struct sockaddr *)&their_addr,
+                                 &addr_len)) == -1) {
+            perror("recvfrom");
+            exit(1);
+        }
+
+        unpack_fce_packet(buf, &packet);
+
+        if (memcmp(packet.magic, FCE_PACKET_MAGIC, sizeof(packet.magic)) == 0) {
+
+            switch (packet.mode) {
+            case FCE_TM_SIZE:
+                memcpy(&tmsize, packet.data, sizeof(uint64_t));
+                tmsize = ntoh64(tmsize);
+                printf("ID: %" PRIu32 ", Event: %s, Volume: %s, TM used size: %" PRIu64 " \n",
+                       packet.event_id, fce_ev_names[packet.mode], packet.data + sizeof(uint64_t), tmsize);
+                break;
+
+            case FCE_CONN_START:
+                printf("FCE Start\n");
+                break;
+
+            case FCE_CONN_BROKEN:
+                printf("Broken FCE connection\n");
+                break;
+
+            default:
+                printf("ID: %" PRIu32 ", Event: %s, Path: %s\n",
+                       packet.event_id, fce_ev_names[packet.mode], packet.data);
+                break;
+            }
+        }
+    }
+
+    close(sockfd);
+    return 0;
+}
index b12585ee9b7e57a2a7e57fdff81330d7e3de218f..0efc3318c6a45d0fe25c85b3cdf5016b9c548789 100644 (file)
@@ -123,15 +123,15 @@ int main( int argc, char **argv)
             ret = getnamefromuuid( uuid, &name, &type);
             if (ret == 0) {
                 switch (type) {
-                case UUID_LOCAL:
-                    printf("local UUID: %s\n", optarg);
-                    break;
                 case UUID_USER:
                     printf("UUID: %s ==> User: %s\n", optarg, name);
                     break;
                 case UUID_GROUP:
                     printf("UUID: %s ==> Group: %s\n", optarg, name);
                     break;
+                default:
+                    printf("???: %s\n", optarg);
+                    break;
                 }
                 free(name);
             } else {
index 0994a116d4821f1f2475fac5ccd889e1451e20db..04ba0ca6b71290a25bb27482e536c647637541e5 100644 (file)
 #                               in dotted-decimal format for IPv4 or in
 #                               hexadecimal format for IPv6.
 #
+#   Avahi (Bonjour) related options:
+#     -mimicmodel <model>
+#                               Specifies the icon model that appears on
+#                               clients. Defaults to off. Examples: RackMac
+#                               (same as Xserve), PowerBook, PowerMac, Macmini,
+#                               iMac, MacBook, MacBookPro, MacBookAir, MacPro,
+#                               AppleTV1,1, AirPort
+#
 
 
 #
index add16d71cb657ed407fe0f06f7fdbbe8c83ba9eb..5d0c03fa85cb4a199ed3beead2cdc679b820512b 100644 (file)
@@ -1,6 +1,7 @@
 Makefile
 Makefile.in
 afpd
+fce
 hash
 test_parse_mtab
 .deps
index 9b3fcae6063c5ecd7379a5e90642d841dc860a21..34edab51f9c439a68b8f8656715ea19c4ebe27ae 100644 (file)
@@ -3,7 +3,7 @@
 pkgconfdir = @PKGCONFDIR@
 
 sbin_PROGRAMS = afpd
-noinst_PROGRAMS = hash
+noinst_PROGRAMS = hash fce
 
 afpd_SOURCES = \
        afp_avahi.c \
@@ -22,6 +22,8 @@ afpd_SOURCES = \
        directory.c \
        enumerate.c \
        extattrs.c \
+       fce_api.c \
+       fce_util.c \
        file.c \
        filedir.c \
        fork.c \
@@ -69,9 +71,13 @@ endif
 
 
 noinst_HEADERS = auth.h afp_config.h desktop.h directory.h file.h \
-        filedir.h fork.h globals.h icon.h mangle.h misc.h status.h switch.h \
+        filedir.h fork.h icon.h mangle.h misc.h status.h switch.h \
         uam_auth.h uid.h unix.h volume.h hash.h acls.h acl_mappings.h extattrs.h \
         dircache.h afp_zeroconf.h afp_avahi.h
 
 hash_SOURCES = hash.c
 hash_CFLAGS = -DKAZLIB_TEST_MAIN -I$(top_srcdir)/include
+
+fce_SOURCES = fce_api.c fce_util.c
+fce_CFLAGS = -DFCE_TEST_MAIN -I$(top_srcdir)/include
+fce_LDADD = $(top_builddir)/libatalk/libatalk.la
index 43e91042f10e0ee3850a2d3cc312b7b51ee7a038..c87ef9a0079cb95f44f1be366d9aad8340e1397e 100644 (file)
@@ -28,6 +28,8 @@
 #endif
 #ifdef HAVE_POSIX_ACLS
 #include <sys/acl.h>
+#endif
+#ifdef HAVE_ACL_LIBACL_H
 #include <acl/libacl.h>
 #endif
 
@@ -268,11 +270,6 @@ static int map_aces_darwin_to_solaris(darwin_ace_t *darwin_aces,
         /* uid/gid first */
         EC_ZERO(getnamefromuuid(darwin_aces->darwin_ace_uuid, &name, &uuidtype));
         switch (uuidtype) {
-        case UUID_LOCAL:
-            free(name);
-            name = NULL;
-            darwin_aces++;
-            continue;
         case UUID_USER:
             EC_NULL_LOG(pwd = getpwnam(name));
             nfsv4_aces->a_who = pwd->pw_uid;
@@ -282,6 +279,9 @@ static int map_aces_darwin_to_solaris(darwin_ace_t *darwin_aces,
             nfsv4_aces->a_who = (uid_t)(grp->gr_gid);
             nfsv4_ace_flags |= ACE_IDENTIFIER_GROUP;
             break;
+        default:
+            LOG(log_error, logtype_afpd, "map_aces_darwin_to_solaris: unkown uuidtype");
+            EC_FAIL;
         }
         free(name);
         name = NULL;
@@ -309,8 +309,12 @@ static int map_aces_darwin_to_solaris(darwin_ace_t *darwin_aces,
                 nfsv4_ace_rights |= darwin_to_nfsv4_rights[i].to;
         }
 
-        LOG(log_debug9, logtype_afpd, "map_aces_darwin_to_solaris: ACE flags: Darwin:%08x -> NFSv4:%04x", darwin_ace_flags, nfsv4_ace_flags);
-        LOG(log_debug9, logtype_afpd, "map_aces_darwin_to_solaris: ACE rights: Darwin:%08x -> NFSv4:%08x", darwin_ace_rights, nfsv4_ace_rights);
+        LOG(log_debug9, logtype_afpd,
+            "map_aces_darwin_to_solaris: ACE flags: Darwin:%08x -> NFSv4:%04x",
+            darwin_ace_flags, nfsv4_ace_flags);
+        LOG(log_debug9, logtype_afpd,
+            "map_aces_darwin_to_solaris: ACE rights: Darwin:%08x -> NFSv4:%08x",
+            darwin_ace_rights, nfsv4_ace_rights);
 
         nfsv4_aces->a_flags = nfsv4_ace_flags;
         nfsv4_aces->a_access_mask = nfsv4_ace_rights;
@@ -342,12 +346,20 @@ static uint32_t posix_permset_to_darwin_rights(acl_entry_t e, int is_dir)
 
     EC_ZERO_LOG(acl_get_permset(e, &permset));
 
+#ifdef HAVE_ACL_GET_PERM_NP
+    if (acl_get_perm_np(permset, ACL_READ))
+#else
     if (acl_get_perm(permset, ACL_READ))
+#endif
         rights = DARWIN_ACE_READ_DATA
             | DARWIN_ACE_READ_EXTATTRIBUTES
             | DARWIN_ACE_READ_ATTRIBUTES
             | DARWIN_ACE_READ_SECURITY;
+#ifdef HAVE_ACL_GET_PERM_NP
+    if (acl_get_perm_np(permset, ACL_WRITE)) {
+#else
     if (acl_get_perm(permset, ACL_WRITE)) {
+#endif
         rights |= DARWIN_ACE_WRITE_DATA
             | DARWIN_ACE_APPEND_DATA
             | DARWIN_ACE_WRITE_EXTATTRIBUTES
@@ -355,7 +367,11 @@ static uint32_t posix_permset_to_darwin_rights(acl_entry_t e, int is_dir)
         if (is_dir)
             rights |= DARWIN_ACE_DELETE_CHILD;
     }
+#ifdef HAVE_ACL_GET_PERM_NP
+    if (acl_get_perm_np(permset, ACL_EXECUTE))
+#else
     if (acl_get_perm(permset, ACL_EXECUTE))
+#endif
         rights |= DARWIN_ACE_EXECUTE;
 
 EC_CLEANUP:
@@ -624,10 +640,6 @@ static int map_aces_darwin_to_posix(const darwin_ace_t *darwin_aces,
          /* uid/gid */
         EC_ZERO_LOG(getnamefromuuid(darwin_aces->darwin_ace_uuid, &name, &uuidtype));
         switch (uuidtype) {
-        case UUID_LOCAL:
-            free(name);
-            name = NULL;
-            continue;
         case UUID_USER:
             EC_NULL_LOG(pwd = getpwnam(name));
             tag = ACL_USER;
@@ -640,6 +652,8 @@ static int map_aces_darwin_to_posix(const darwin_ace_t *darwin_aces,
             id = (uid_t)(grp->gr_gid);
             LOG(log_debug, logtype_afpd, "map_ace: name: %s, gid: %u", name, id);
             break;
+        default:
+            continue;
         }
         free(name);
         name = NULL;
@@ -1043,8 +1057,11 @@ static int set_acl(const struct vol *vol,
     /* for files def_acl will be NULL */
 
     /* create access acl from mode */
+#ifdef HAVE_ACL_FROM_MODE
     EC_NULL_LOG_ERR(acc_acl = acl_from_mode(st.st_mode), AFPERR_MISC);
-
+#else
+#error "Missing acl_from_mode() replacement"
+#endif
     /* adds the clients aces */
     EC_ZERO_ERR(map_aces_darwin_to_posix(daces, &def_acl, &acc_acl, ace_count), AFPERR_MISC);
 
@@ -1078,7 +1095,7 @@ EC_CLEANUP:
  * Note: this gets called frequently and is a good place for optimizations !
  *
  * @param vol              (r) volume
- * @param dir              (r) directory
+ * @param dir              (rw) directory
  * @param path             (r) path to filesystem object
  * @param uuid             (r) UUID of user
  * @param requested_rights (r) requested Darwin ACE
@@ -1086,7 +1103,7 @@ EC_CLEANUP:
  * @returns                    AFP result code
 */
 static int check_acl_access(const struct vol *vol,
-                            const struct dir *dir,
+                            struct dir *dir,
                             const char *path,
                             const uuidp_t uuid,
                             uint32_t requested_rights)
@@ -1111,57 +1128,60 @@ static int check_acl_access(const struct vol *vol,
         LOG(log_warning, logtype_afpd, "check_access: afp_access not supported for groups");
         EC_STATUS(AFPERR_MISC);
         goto EC_CLEANUP;
-
-    case UUID_LOCAL:
-        LOG(log_warning, logtype_afpd, "check_access: local UUID");
+    default:
         EC_STATUS(AFPERR_MISC);
         goto EC_CLEANUP;
     }
 
+    if ((strcmp(path, ".") == 0) && (dir->d_rights_cache != 0xffffffff)) {
+        /* its a dir and the cache value is valid */
+        allowed_rights = dir->d_rights_cache;
+        LOG(log_debug, logtype_afpd, "allowed rights from dircache: 0x%08x", allowed_rights);
+    } else {
 #ifdef HAVE_SOLARIS_ACLS
-    EC_ZERO_LOG(solaris_acl_rights(path, &st, &allowed_rights));
+        EC_ZERO_LOG(solaris_acl_rights(path, &st, &allowed_rights));
 #endif
 #ifdef HAVE_POSIX_ACLS
-    EC_ZERO_LOG(posix_acl_rights(path, &st, &allowed_rights));
+        EC_ZERO_LOG(posix_acl_rights(path, &st, &allowed_rights));
 #endif
+        /*
+         * The DARWIN_ACE_DELETE right might implicitly result from write acces to the parent
+         * directory. As it seems the 10.6 AFP client is puzzled when this right is not
+         * allowed where a delete would succeed because the parent dir gives write perms.
+         * So we check the parent dir for write access and set the right accordingly.
+         * Currentyl acl2ownermode calls us with dir = NULL, because it doesn't make sense
+         * there to do this extra check -- afaict.
+         */
+        if (vol && dir && (requested_rights & DARWIN_ACE_DELETE)) {
+            int i;
+            uint32_t parent_rights = 0;
+
+            if (dir->d_did == DIRDID_ROOT_PARENT) {
+                /* use volume path */
+                EC_NULL_LOG_ERR(parent = bfromcstr(vol->v_path), AFPERR_MISC);
+            } else {
+                /* build path for parent */
+                EC_NULL_LOG_ERR(parent = bstrcpy(dir->d_fullpath), AFPERR_MISC);
+                EC_ZERO_LOG_ERR(bconchar(parent, '/'), AFPERR_MISC);
+                EC_ZERO_LOG_ERR(bcatcstr(parent, path), AFPERR_MISC);
+                EC_NEG1_LOG_ERR(i = bstrrchr(parent, '/'), AFPERR_MISC);
+                EC_ZERO_LOG_ERR(binsertch(parent, i, 1, 0), AFPERR_MISC);
+            }
 
-    LOG(log_debug, logtype_afpd, "allowed rights: 0x%08x", allowed_rights);
-
-    /*
-     * The DARWIN_ACE_DELETE right might implicitly result from write acces to the parent
-     * directory. As it seems the 10.6 AFP client is puzzled when this right is not
-     * allowed where a delete would succeed because the parent dir gives write perms.
-     * So we check the parent dir for write access and set the right accordingly.
-     * Currentyl acl2ownermode calls us with dir = NULL, because it doesn't make sense
-     * there to do this extra check -- afaict.
-     */
-    if (vol && dir && (requested_rights & DARWIN_ACE_DELETE)) {
-        int i;
-        uint32_t parent_rights = 0;
-
-        if (dir->d_did == DIRDID_ROOT_PARENT) {
-            /* use volume path */
-            EC_NULL_LOG_ERR(parent = bfromcstr(vol->v_path), AFPERR_MISC);
-        } else {
-            /* build path for parent */
-            EC_NULL_LOG_ERR(parent = bstrcpy(dir->d_fullpath), AFPERR_MISC);
-            EC_ZERO_LOG_ERR(bconchar(parent, '/'), AFPERR_MISC);
-            EC_ZERO_LOG_ERR(bcatcstr(parent, path), AFPERR_MISC);
-            EC_NEG1_LOG_ERR(i = bstrrchr(parent, '/'), AFPERR_MISC);
-            EC_ZERO_LOG_ERR(binsertch(parent, i, 1, 0), AFPERR_MISC);
-        }
-
-        LOG(log_debug, logtype_afpd,"parent: %s", cfrombstr(parent));
-        EC_ZERO_LOG_ERR(lstat(cfrombstr(parent), &st), AFPERR_MISC);
+            LOG(log_debug, logtype_afpd,"parent: %s", cfrombstr(parent));
+            EC_ZERO_LOG_ERR(lstat(cfrombstr(parent), &st), AFPERR_MISC);
 
 #ifdef HAVE_SOLARIS_ACLS
-        EC_ZERO_LOG(solaris_acl_rights(cfrombstr(parent), &st, &parent_rights));
+            EC_ZERO_LOG(solaris_acl_rights(cfrombstr(parent), &st, &parent_rights));
 #endif
 #ifdef HAVE_POSIX_ACLS
-    EC_ZERO_LOG(posix_acl_rights(path, &st, &allowed_rights));
+            EC_ZERO_LOG(posix_acl_rights(path, &st, &allowed_rights));
 #endif
-        if (parent_rights & (DARWIN_ACE_WRITE_DATA | DARWIN_ACE_DELETE_CHILD))
-            allowed_rights |= DARWIN_ACE_DELETE; /* man, that was a lot of work! */
+            if (parent_rights & (DARWIN_ACE_WRITE_DATA | DARWIN_ACE_DELETE_CHILD))
+                allowed_rights |= DARWIN_ACE_DELETE; /* man, that was a lot of work! */
+        }
+        LOG(log_debug, logtype_afpd, "allowed rights: 0x%08x", allowed_rights);
+        dir->d_rights_cache = allowed_rights;
     }
 
     if ((requested_rights & allowed_rights) != requested_rights) {
index a06c7be4237209e35faa9a4bee6f16da6ff01d00..dbd0cf2e75fd266f8e328b6df485ad4986a7ff29 100644 (file)
@@ -48,6 +48,7 @@ static void register_stuff(void) {
     DSI *dsi;
     char name[MAXINSTANCENAMELEN+1];
     AvahiStringList *strlist = NULL;
+    AvahiStringList *strlist2 = NULL;
     char tmpname[256];
 
     assert(ctx->client);
@@ -143,6 +144,25 @@ static void register_stuff(void) {
                     avahi_strerror(avahi_client_errno(ctx->client)));
                 goto fail;
             }  /* if */
+
+            if (config->obj.options.mimicmodel) {
+                strlist2 = avahi_string_list_add_printf(strlist2, "model=%s", config->obj.options.mimicmodel);
+                if (avahi_entry_group_add_service_strlst(ctx->group,
+                                                         AVAHI_IF_UNSPEC,
+                                                         AVAHI_PROTO_UNSPEC,
+                                                         0,
+                                                         dsi->bonjourname,
+                                                         DEV_INFO_SERVICE_TYPE,
+                                                         NULL,
+                                                         NULL,
+                                                         0,
+                                                         strlist2) < 0) {
+                    LOG(log_error, logtype_afpd, "Failed to add service: %s",
+                        avahi_strerror(avahi_client_errno(ctx->client)));
+                    goto fail;
+                }
+            } /* if (config->obj.options.mimicmodel) */
+
         }      /* for config*/
 
         if (avahi_entry_group_commit(ctx->group) < 0) {
index 2c6ca706d0e5176e1bf8d82eb12b2154d02d9480..c0216fef4723f7d0b722c2a1d7b89bc7634105fb 100644 (file)
@@ -26,6 +26,7 @@
 
 #define AFP_DNS_SERVICE_TYPE "_afpovertcp._tcp"
 #define ADISK_SERVICE_TYPE "_adisk._tcp"
+#define DEV_INFO_SERVICE_TYPE "_device-info._tcp"
 
 #define MAXINSTANCENAMELEN 63
 
index 8c997ebe94f7999e0e51b248a304e95fd38997da..4b451527c87230584a783d5713c361498d36ab6c 100644 (file)
@@ -33,7 +33,7 @@
 #include <atalk/ldapconfig.h>
 #endif
 
-#include "globals.h"
+#include <atalk/globals.h>
 #include "afp_config.h"
 #include "uam_auth.h"
 #include "status.h"
index 7a603512af2c8538896a3a05a429bded201a0ae8..022a6e65d41e1c979fb7597408b41fb1dd47c139 100644 (file)
@@ -2,8 +2,7 @@
 #define AFPD_CONFIG_H 1
 
 #include <atalk/server_child.h>
-
-#include "globals.h"
+#include <atalk/globals.h>
 
 typedef struct AFPConfig {
     AFPObj obj;
index dfebaca0fb8f20e1781d46388afc469635a9bd07..bde1818bd7a1598ceedb48626671b45de674e9e6 100644 (file)
 #endif /* HAVE_SYS_STAT_H */
 #include <netinet/in.h>
 #include <arpa/inet.h>
-#include <atalk/logger.h>
 #include <setjmp.h>
+#include <time.h>
 
+#include <atalk/logger.h>
 #include <atalk/dsi.h>
 #include <atalk/compat.h>
 #include <atalk/util.h>
 #include <atalk/locking.h>
+#include <atalk/uuid.h>
+#include <atalk/paths.h>
+#include <atalk/server_ipc.h>
+#include <atalk/fce_api.h>
+#include <atalk/globals.h>
 
-#include "globals.h"
 #include "switch.h"
 #include "auth.h"
 #include "fork.h"
@@ -125,6 +130,25 @@ static void afp_dsi_die(int sig)
     }
 }
 
+/* SIGQUIT handler */
+static void ipc_reconnect_handler(int sig _U_)
+{
+    DSI *dsi = (DSI *)AFPobj->handle;
+
+    if (reconnect_ipc(AFPobj) != 0) {
+        LOG(log_error, logtype_afpd, "ipc_reconnect_handler: failed IPC reconnect");
+        afp_dsi_close(AFPobj);
+        exit(EXITERR_SYS);        
+    }
+
+    if (ipc_child_write(AFPobj->ipc_fd, IPC_GETSESSION, AFPobj->sinfo.clientid_len, AFPobj->sinfo.clientid) != 0) {
+        LOG(log_error, logtype_afpd, "ipc_reconnect_handler: failed IPC ID resend");
+        afp_dsi_close(AFPobj);
+        exit(EXITERR_SYS);        
+    }
+    LOG(log_note, logtype_afpd, "ipc_reconnect_handler: IPC reconnect done");
+}
+
 /* SIGURG handler (primary reconnect) */
 static void afp_dsi_transfer_session(int sig _U_)
 {
@@ -287,6 +311,10 @@ static void alarm_handler(int sig _U_)
     } 
 
     if (dsi->flags & DSI_DISCONNECTED) {
+        if (geteuid() == 0) {
+            LOG(log_note, logtype_afpd, "afp_alarm: unauthenticated user, connection problem");
+            afp_dsi_die(EXITERR_CLNT);
+        }
         if (dsi->tickle > AFPobj->options.disconnected) {
             LOG(log_error, logtype_afpd, "afp_alarm: reconnect timer expired, goodbye");
             afp_dsi_die(EXITERR_CLNT);
@@ -297,8 +325,8 @@ static void alarm_handler(int sig _U_)
     /* if we're in the midst of processing something, don't die. */        
     if ( !(dsi->flags & DSI_RUNNING) && (dsi->tickle >= AFPobj->options.timeout)) {
         LOG(log_error, logtype_afpd, "afp_alarm: child timed out, entering disconnected state");
-        dsi->proto_close(dsi);
-        dsi->flags |= DSI_DISCONNECTED;
+        if (dsi_disconnect(dsi) != 0)
+            afp_dsi_die(EXITERR_CLNT);
         return;
     }
 
@@ -306,9 +334,13 @@ static void alarm_handler(int sig _U_)
         LOG(log_debug, logtype_afpd, "afp_alarm: sending DSI tickle");
         err = dsi_tickle(AFPobj->handle);
     if (err <= 0) {
+        if (geteuid() == 0) {
+            LOG(log_note, logtype_afpd, "afp_alarm: unauthenticated user, connection problem");
+            afp_dsi_die(EXITERR_CLNT);
+        }
         LOG(log_error, logtype_afpd, "afp_alarm: connection problem, entering disconnected state");
-        dsi->proto_close(dsi);
-        dsi->flags |= DSI_DISCONNECTED;
+        if (dsi_disconnect(dsi) != 0)
+            afp_dsi_die(EXITERR_CLNT);
     }
 }
 
@@ -348,22 +380,18 @@ void afp_over_dsi(AFPObj *obj)
     struct sigaction action;
 
     AFPobj = obj;
+    dsi->AFPobj = obj;
     obj->exit = afp_dsi_die;
     obj->reply = (int (*)()) dsi_cmdreply;
     obj->attention = (int (*)(void *, AFPUserBytes)) dsi_attention;
     dsi->tickle = 0;
 
     memset(&action, 0, sizeof(action));
+    sigfillset(&action.sa_mask);
+    action.sa_flags = SA_RESTART;
 
     /* install SIGHUP */
     action.sa_handler = afp_dsi_reload;
-    sigemptyset( &action.sa_mask );
-    sigaddset(&action.sa_mask, SIGALRM);
-    sigaddset(&action.sa_mask, SIGTERM);
-    sigaddset(&action.sa_mask, SIGUSR1);
-    sigaddset(&action.sa_mask, SIGINT);
-    sigaddset(&action.sa_mask, SIGUSR2);
-    action.sa_flags = SA_RESTART;
     if ( sigaction( SIGHUP, &action, NULL ) < 0 ) {
         LOG(log_error, logtype_afpd, "afp_over_dsi: sigaction: %s", strerror(errno) );
         afp_dsi_die(EXITERR_SYS);
@@ -371,13 +399,6 @@ void afp_over_dsi(AFPObj *obj)
 
     /* install SIGURG */
     action.sa_handler = afp_dsi_transfer_session;
-    sigemptyset( &action.sa_mask );
-    sigaddset(&action.sa_mask, SIGALRM);
-    sigaddset(&action.sa_mask, SIGTERM);
-    sigaddset(&action.sa_mask, SIGUSR1);
-    sigaddset(&action.sa_mask, SIGINT);
-    sigaddset(&action.sa_mask, SIGUSR2);
-    action.sa_flags = SA_RESTART;
     if ( sigaction( SIGURG, &action, NULL ) < 0 ) {
         LOG(log_error, logtype_afpd, "afp_over_dsi: sigaction: %s", strerror(errno) );
         afp_dsi_die(EXITERR_SYS);
@@ -385,27 +406,20 @@ void afp_over_dsi(AFPObj *obj)
 
     /* install SIGTERM */
     action.sa_handler = afp_dsi_die;
-    sigemptyset( &action.sa_mask );
-    sigaddset(&action.sa_mask, SIGALRM);
-    sigaddset(&action.sa_mask, SIGHUP);
-    sigaddset(&action.sa_mask, SIGUSR1);
-    sigaddset(&action.sa_mask, SIGINT);
-    sigaddset(&action.sa_mask, SIGUSR2);
-    action.sa_flags = SA_RESTART;
     if ( sigaction( SIGTERM, &action, NULL ) < 0 ) {
         LOG(log_error, logtype_afpd, "afp_over_dsi: sigaction: %s", strerror(errno) );
         afp_dsi_die(EXITERR_SYS);
     }
 
-    /* Added for server message support */
+    /* install SIGQUIT */
+    action.sa_handler = ipc_reconnect_handler;
+    if ( sigaction(SIGQUIT, &action, NULL ) < 0 ) {
+        LOG(log_error, logtype_afpd, "afp_over_dsi: sigaction: %s", strerror(errno) );
+        afp_dsi_die(EXITERR_SYS);
+    }
+
+    /* SIGUSR2 - server message support */
     action.sa_handler = afp_dsi_getmesg;
-    sigemptyset( &action.sa_mask );
-    sigaddset(&action.sa_mask, SIGALRM);
-    sigaddset(&action.sa_mask, SIGTERM);
-    sigaddset(&action.sa_mask, SIGUSR1);
-    sigaddset(&action.sa_mask, SIGHUP);
-    sigaddset(&action.sa_mask, SIGINT);
-    action.sa_flags = SA_RESTART;
     if ( sigaction( SIGUSR2, &action, NULL) < 0 ) {
         LOG(log_error, logtype_afpd, "afp_over_dsi: sigaction: %s", strerror(errno) );
         afp_dsi_die(EXITERR_SYS);
@@ -413,12 +427,6 @@ void afp_over_dsi(AFPObj *obj)
 
     /*  SIGUSR1 - set down in 5 minutes  */
     action.sa_handler = afp_dsi_timedown;
-    sigemptyset( &action.sa_mask );
-    sigaddset(&action.sa_mask, SIGALRM);
-    sigaddset(&action.sa_mask, SIGHUP);
-    sigaddset(&action.sa_mask, SIGTERM);
-    sigaddset(&action.sa_mask, SIGINT);
-    sigaddset(&action.sa_mask, SIGUSR2);
     action.sa_flags = SA_RESTART;
     if ( sigaction( SIGUSR1, &action, NULL) < 0 ) {
         LOG(log_error, logtype_afpd, "afp_over_dsi: sigaction: %s", strerror(errno) );
@@ -427,23 +435,14 @@ void afp_over_dsi(AFPObj *obj)
 
     /*  SIGINT - enable max_debug LOGging to /tmp/afpd.PID.XXXXXX */
     action.sa_handler = afp_dsi_debug;
-    sigfillset( &action.sa_mask );
-    action.sa_flags = SA_RESTART;
     if ( sigaction( SIGINT, &action, NULL) < 0 ) {
         LOG(log_error, logtype_afpd, "afp_over_dsi: sigaction: %s", strerror(errno) );
         afp_dsi_die(EXITERR_SYS);
     }
 
 #ifndef DEBUGGING
-    /* tickle handler */
+    /* SIGALRM - tickle handler */
     action.sa_handler = alarm_handler;
-    sigemptyset(&action.sa_mask);
-    sigaddset(&action.sa_mask, SIGHUP);
-    sigaddset(&action.sa_mask, SIGTERM);
-    sigaddset(&action.sa_mask, SIGUSR1);
-    sigaddset(&action.sa_mask, SIGINT);
-    sigaddset(&action.sa_mask, SIGUSR2);
-    action.sa_flags = SA_RESTART;
     if ((sigaction(SIGALRM, &action, NULL) < 0) ||
             (setitimer(ITIMER_REAL, &dsi->timer, NULL) < 0)) {
         afp_dsi_die(EXITERR_SYS);
@@ -489,15 +488,25 @@ void afp_over_dsi(AFPObj *obj)
                 dsi->flags &= ~DSI_RECONSOCKET;
                 continue;
             }
-            /* Some error on the client connection, enter disconnected state */
-            dsi->flags |= DSI_DISCONNECTED;
 
             /* the client sometimes logs out (afp_logout) but doesn't close the DSI session */
             if (dsi->flags & DSI_AFP_LOGGED_OUT) {
+                LOG(log_note, logtype_afpd, "afp_over_dsi: client logged out, terminating DSI session");
                 afp_dsi_close(obj);
                 exit(0);
             }
 
+            /*  got ECONNRESET in read from client => exit*/
+            if (dsi->flags & DSI_GOT_ECONNRESET) {
+                LOG(log_note, logtype_afpd, "afp_over_dsi: client connection reset");
+                afp_dsi_close(obj);
+                exit(0);
+            }
+
+            /* Some error on the client connection, enter disconnected state */
+            if (dsi_disconnect(dsi) != 0)
+                afp_dsi_die(EXITERR_CLNT);
+
             pause(); /* gets interrupted by SIGALARM or SIGURG tickle */
             continue; /* continue receiving until disconnect timer expires
                        * or a primary reconnect succeeds  */
@@ -520,6 +529,7 @@ void afp_over_dsi(AFPObj *obj)
             debug_request = 0;
 
             dircache_dump();
+            uuidcache_dump();
 
             if (debugging) {
                 if (obj->options.logconfig)
@@ -616,7 +626,8 @@ void afp_over_dsi(AFPObj *obj)
 
             if (!dsi_cmdreply(dsi, err)) {
                 LOG(log_error, logtype_afpd, "dsi_cmdreply(%d): %s", dsi->socket, strerror(errno) );
-                dsi->flags |= DSI_DISCONNECTED;
+                if (dsi_disconnect(dsi) != 0)
+                    afp_dsi_die(EXITERR_CLNT);
             }
             break;
 
@@ -644,7 +655,8 @@ void afp_over_dsi(AFPObj *obj)
 
             if (!dsi_wrtreply(dsi, err)) {
                 LOG(log_error, logtype_afpd, "dsi_wrtreply: %s", strerror(errno) );
-                dsi->flags |= DSI_DISCONNECTED;
+                if (dsi_disconnect(dsi) != 0)
+                    afp_dsi_die(EXITERR_CLNT);
             }
             break;
 
@@ -661,6 +673,8 @@ void afp_over_dsi(AFPObj *obj)
             break;
         }
         pending_request(dsi);
+
+        vol_fce_tm_event();
     }
 
     /* error */
index ffe28590289fd1f1c4ec01b67620b4087ebf536b..16863eb547ae3c12b7ea635562aff80074511d87 100644 (file)
@@ -34,8 +34,9 @@
 #include <atalk/paths.h>
 #include <atalk/util.h>
 #include <atalk/compat.h>
+#include <atalk/globals.h>
+#include <atalk/fce_api.h>
 
-#include "globals.h"
 #include "status.h"
 #include "auth.h"
 #include "dircache.h"
@@ -139,6 +140,8 @@ void afp_options_free(struct afp_options *opt,
        free(opt->ntseparator);
     if (opt->logconfig && (opt->logconfig != save->logconfig))
        free(opt->logconfig);
+       if (opt->mimicmodel && (opt->mimicmodel != save->mimicmodel))
+       free(opt->mimicmodel);
 }
 
 /* initialize options */
@@ -189,6 +192,7 @@ void afp_options_init(struct afp_options *options)
     options->tcp_sndbuf = 0;    /* 0 means don't change OS default */
     options->tcp_rcvbuf = 0;    /* 0 means don't change OS default */
     options->dsireadbuf = 12;
+       options->mimicmodel = NULL;
 }
 
 /* parse an afpd.conf line. i'm doing it this way because it's
@@ -479,6 +483,22 @@ int afp_options_parseline(char *buf, struct afp_options *options)
     if ((c = getoption(buf, "-tcprcvbuf")))
         options->tcp_rcvbuf = atoi(c);
 
+       if ((c = getoption(buf, "-fcelistener"))) {
+               LOG(log_note, logtype_afpd, "Adding fce listener \"%s\"", c);
+               fce_add_udp_socket(c);
+       }
+       if ((c = getoption(buf, "-fcecoalesce"))) {
+               LOG(log_note, logtype_afpd, "Fce coalesce: %s", c);
+               fce_set_coalesce(c);
+       }
+       if ((c = getoption(buf, "-fceevents"))) {
+               LOG(log_note, logtype_afpd, "Fce events: %s", c);
+               fce_set_events(c);
+       }
+
+    if ((c = getoption(buf, "-mimicmodel")) && (opt = strdup(c)))
+       options->mimicmodel = opt;
+
     return 1;
 }
 
index 7cf78ed211c3b7342e410f972507ab214d474a27..a8282c22b3fb38e57a4ddb94af1e529004a7022f 100644 (file)
@@ -15,7 +15,7 @@
 #endif /* HAVE_CONFIG_H */
 
 #include <atalk/afp.h>
-#include "globals.h"
+#include <atalk/globals.h>
 
 const char *AfpNum2name(int num)
 {
index fe9ff250336214d410a32bee946578865d490fd2..51b64ef283b97d48e3ef826fd25d20a6c3b7a7ed 100644 (file)
@@ -22,9 +22,9 @@
 #include <atalk/afp.h>
 #include <atalk/bstrlib.h>
 #include <atalk/bstradd.h>
+#include <atalk/globals.h>
 
 #include "volume.h"
-#include "globals.h"
 #include "directory.h"
 #include "file.h"
 #include "desktop.h"
index 0768d22d1d6cacc122b8293798dabe5e79a48ebf..fef13eb8fc46ac79dad45003e09013b84fa78e74 100644 (file)
@@ -38,8 +38,8 @@ extern void afp_get_cmdline( int *ac, char ***av );
 #include <atalk/logger.h>
 #include <atalk/server_ipc.h>
 #include <atalk/uuid.h>
+#include <atalk/globals.h>
 
-#include "globals.h"
 #include "auth.h"
 #include "uam_auth.h"
 #include "switch.h"
@@ -538,7 +538,13 @@ int afp_getsession(
             if (ibuflen < idlen || idlen > (90-10)) {
                 return AFPERR_PARAM;
             }
-            ipc_child_write(obj->ipc_fd, IPC_GETSESSION, idlen+8, p);
+            if (!obj->sinfo.clientid) {
+                obj->sinfo.clientid = malloc(idlen + 8);
+                memcpy(obj->sinfo.clientid, p, idlen + 8);
+                obj->sinfo.clientid_len = idlen + 8;
+            }
+            if (ipc_child_write(obj->ipc_fd, IPC_GETSESSION, idlen+8, p) != 0)
+                return AFPERR_MISC;
             tklen = obj->sinfo.sessiontoken_len;
             token = obj->sinfo.sessiontoken;
         }
@@ -620,7 +626,7 @@ int afp_disconnect(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_,
     setitimer(ITIMER_REAL, &none, NULL);
 
     /* check for old session, possibly transfering session from here to there */
-    if (ipc_child_write(obj->ipc_fd, IPC_DISCOLDSESSION, tklen, &token) == -1)
+    if (ipc_child_write(obj->ipc_fd, IPC_DISCOLDSESSION, tklen, &token) != 0)
         goto exit;
     /* write uint16_t DSI request ID */
     if (writet(obj->ipc_fd, &dsi->header.dsi_requestID, 2, 0, 2) != 2) {
index e7f141ba0f426f07bf7685bebc07fbac90498252..1d4792454204c36ac28311d1f6c698d78b31a793 100644 (file)
@@ -8,7 +8,7 @@
 
 #include <limits.h>
 
-#include "globals.h"
+#include <atalk/globals.h>
 
 struct afp_versions {
     char       *av_name;
index d0e89f39fdad3527dddd1a4862e8e5ca042610ad..a488501e6b67e3c101660b844aa218bb460a1da5 100644 (file)
 #include <atalk/util.h>
 #include <atalk/bstradd.h>
 #include <atalk/unicode.h>
+#include <atalk/globals.h>
 
 #include "desktop.h"
 #include "directory.h"
 #include "dircache.h"
 #include "file.h"
 #include "volume.h"
-#include "globals.h"
 #include "filedir.h"
 #include "fork.h"
 
index 043c4737b90ffcc60882c138d6f5395ad51dfe89..eda917b10f69e853c504ab5496fe86222dc06fd8 100644 (file)
 #include <atalk/afp.h>
 #include <atalk/util.h>
 #include <atalk/logger.h>
+#include <atalk/globals.h>
 #include "volume.h"
 #include "directory.h"
 #include "fork.h"
-#include "globals.h"
 #include "desktop.h"
 #include "mangle.h"
 
index c9d0e99e3f22b39c98725d0bd98afa2125d0f476..ccaa1654ab3b9c63a8f1c57b9c5ed3a679cee469 100644 (file)
@@ -26,7 +26,8 @@
 #ifndef AFPD_DESKTOP_H
 #define AFPD_DESKTOP_H 1
 
-#include "globals.h"
+#include <atalk/globals.h>
+
 #include "volume.h"
 
 struct savedt {
index 44b74ada4286696d3148525f285e5206ac83c5db..5a702fa55bfd125f943c4ce37bf12ff4ba8524d5 100644 (file)
 #include <atalk/queue.h>
 #include <atalk/bstrlib.h>
 #include <atalk/bstradd.h>
+#include <atalk/globals.h>
 
 #include "dircache.h"
 #include "directory.h"
 #include "hash.h"
-#include "globals.h"
+
 
 /*
  * Directory Cache
index df01ccc4b63e5a93fe345dfe3d0003ef9cab58b0..b139cbcd661952e1ebe5aef0ecdf6a7c605706ed 100644 (file)
@@ -29,6 +29,8 @@
 #include <atalk/bstrlib.h>
 #include <atalk/bstradd.h>
 #include <atalk/errchk.h>
+#include <atalk/globals.h>
+#include <atalk/fce_api.h>
 
 #include "directory.h"
 #include "dircache.h"
@@ -37,7 +39,6 @@
 #include "fork.h"
 #include "file.h"
 #include "filedir.h"
-#include "globals.h"
 #include "unix.h"
 #include "mangle.h"
 #include "hash.h"
@@ -831,6 +832,7 @@ struct dir *dir_new(const char *m_name,
     dir->dcache_ino = st->st_ino;
     if (!S_ISDIR(st->st_mode))
         dir->d_flags = DIRF_ISFILE;
+    dir->d_rights_cache = 0xffffffff;
     return dir;
 }
 
@@ -1487,6 +1489,29 @@ int getdirparams(const struct vol *vol,
         ad_init(&ad, vol->v_adouble, vol->v_ad_options);
         if ( !ad_metadata( upath, ADFLAGS_DIR, &ad) )
             isad = 1;
+            if (ad.ad_md->adf_flags & O_CREAT) {
+                /* We just created it */
+                if (s_path->m_name == NULL) {
+                    if ((s_path->m_name = utompath(vol,
+                                                   upath,
+                                                   dir->d_did,
+                                                   utf8_encoding())) == NULL) {
+                        LOG(log_error, logtype_afpd,
+                            "getdirparams(\"%s\"): can't assign macname",
+                            cfrombstr(dir->d_fullpath));
+                        return AFPERR_MISC;
+                    }
+                }
+                ad_setname(&ad, s_path->m_name);
+                ad_setid( &ad,
+                          s_path->st.st_dev,
+                          s_path->st.st_ino,
+                          dir->d_did,
+                          dir->d_pdid,
+                          vol->v_stamp);
+                ad_flush( &ad);
+            }
+        }
     }
 
     pdid = dir->d_pdid;
@@ -2251,6 +2276,8 @@ int afp_createdir(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_
     ad_setname(&ad, s_path->m_name);
     ad_setid( &ad, s_path->st.st_dev, s_path->st.st_ino, dir->d_did, did, vol->v_stamp);
 
+    fce_register_new_dir(s_path);
+
     ad_flush( &ad);
     ad_close_metadata( &ad);
 
@@ -2488,9 +2515,6 @@ int afp_mapid(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *r
             rbuf += sizeof( id );
             *rbuflen = 2 * sizeof( id );
             break;
-        case UUID_LOCAL:
-            free(name);
-            return (AFPERR_NOITEM);
         default:
             return AFPERR_MISC;
         }
index b438b370251148fe22745d425b48ca2a1db0ad47..82daa86c5b5bf5f7bc11e3afdc88baf3851ed593 100644 (file)
@@ -35,8 +35,8 @@
 #endif
 
 #include <atalk/directory.h>
+#include <atalk/globals.h>
 
-#include "globals.h"
 #include "volume.h"
 
 /* directory bits */
index 0bc24cec4dbed2ff62836e1ff244d8cf4feebf77..fe5a66d993746610ce45747d347abc1e409036e4 100644 (file)
 #include <atalk/util.h>
 #include <atalk/bstrlib.h>
 #include <atalk/bstradd.h>
+#include <atalk/globals.h>
 
 #include "desktop.h"
 #include "directory.h"
 #include "dircache.h"
 #include "volume.h"
-#include "globals.h"
 #include "file.h"
 #include "fork.h"
 #include "filedir.h"
index 060011f1681badeeb52fab32e32ebfd472b418a8..3be452ed962c4c0eb1d9b34433ccc2510a5116cd 100644 (file)
@@ -27,8 +27,8 @@
 #include <atalk/afp.h>
 #include <atalk/logger.h>
 #include <atalk/ea.h>
+#include <atalk/globals.h>
 
-#include "globals.h"
 #include "volume.h"
 #include "desktop.h"
 #include "directory.h"
diff --git a/etc/afpd/fce_api.c b/etc/afpd/fce_api.c
new file mode 100755 (executable)
index 0000000..b2dead2
--- /dev/null
@@ -0,0 +1,646 @@
+/*\r
+ * Copyright (c) 2010 Mark Williams\r
+ *\r
+ * File change event API for netatalk\r
+ *\r
+ * for every detected filesystem change a UDP packet is sent to an arbitrary list\r
+ * of listeners. Each packet contains unix path of modified filesystem element,\r
+ * event reason, and a consecutive event id (32 bit). Technically we are UDP client and are sending\r
+ * out packets synchronuosly as they are created by the afp functions. This should not affect\r
+ * performance measurably. The only delaying calls occur during initialization, if we have to\r
+ * resolve non-IP hostnames to IP. All numeric data inside the packet is network byte order, so use\r
+ * ntohs / ntohl to resolve length and event id. Ideally a listener receives every packet with\r
+ * no gaps in event ids, starting with event id 1 and mode FCE_CONN_START followed by\r
+ * data events from id 2 up to 0xFFFFFFFF, followed by 0 to 0xFFFFFFFF and so on.\r
+ *\r
+ * A gap or not starting with 1 mode FCE_CONN_START or receiving mode FCE_CONN_BROKEN means that\r
+ * the listener has lost at least one filesystem event\r
+ * \r
+ * All Rights Reserved.  See COPYRIGHT.\r
+ */\r
+\r
+#ifdef HAVE_CONFIG_H\r
+#include "config.h"\r
+#endif /* HAVE_CONFIG_H */\r
+\r
+#include <stdio.h>\r
+\r
+#include <string.h>\r
+#include <stdlib.h>\r
+#include <errno.h>\r
+#include <time.h>\r
+\r
+\r
+#include <sys/param.h>\r
+#include <sys/socket.h>\r
+#include <netinet/in.h>\r
+#include <arpa/inet.h>\r
+#include <netdb.h>\r
+\r
+#include <netatalk/at.h>\r
+\r
+#include <atalk/adouble.h>\r
+#include <atalk/vfs.h>\r
+#include <atalk/logger.h>\r
+#include <atalk/afp.h>\r
+#include <atalk/util.h>\r
+#include <atalk/cnid.h>\r
+#include <atalk/unix.h>\r
+#include <atalk/fce_api.h>\r
+#include <atalk/globals.h>\r
+\r
+#include "fork.h"\r
+#include "file.h"\r
+#include "directory.h"\r
+#include "desktop.h"\r
+#include "volume.h"\r
+\r
+// ONLY USED IN THIS FILE\r
+#include "fce_api_internal.h"\r
+\r
+#define FCE_TRUE 1\r
+#define FCE_FALSE 0\r
+\r
+/* We store our connection data here */\r
+static struct udp_entry udp_socket_list[FCE_MAX_UDP_SOCKS];\r
+static int udp_sockets = 0;\r
+static int udp_initialized = FCE_FALSE;\r
+static unsigned long fce_ev_enabled =\r
+    (1 << FCE_FILE_MODIFY) |\r
+    (1 << FCE_FILE_DELETE) |\r
+    (1 << FCE_DIR_DELETE) |\r
+    (1 << FCE_FILE_CREATE) |\r
+    (1 << FCE_DIR_CREATE);\r
+\r
+static uint64_t tm_used;          /* used for passing to event handler */\r
+#define MAXIOBUF 1024\r
+static char iobuf[MAXIOBUF];\r
+static const char *skip_files[] = \r
+{\r
+       ".DS_Store",\r
+       NULL\r
+};\r
+\r
+/*\r
+ *\r
+ * Initialize network structs for any listeners\r
+ * We dont give return code because all errors are handled internally (I hope..)\r
+ *\r
+ * */\r
+void fce_init_udp()\r
+{\r
+    int rv;\r
+    struct addrinfo hints, *servinfo, *p;\r
+\r
+    if (udp_initialized == FCE_TRUE)\r
+        return;\r
+\r
+    memset(&hints, 0, sizeof hints);\r
+    hints.ai_family = AF_UNSPEC;\r
+    hints.ai_socktype = SOCK_DGRAM;\r
+\r
+    for (int i = 0; i < udp_sockets; i++) {\r
+        struct udp_entry *udp_entry = udp_socket_list + i;\r
+\r
+        /* Close any pending sockets */\r
+        if (udp_entry->sock != -1)\r
+            close(udp_entry->sock);\r
+\r
+        if ((rv = getaddrinfo(udp_entry->addr, udp_entry->port, &hints, &servinfo)) != 0) {\r
+            LOG(log_error, logtype_afpd, "fce_init_udp: getaddrinfo(%s:%s): %s",\r
+                udp_entry->addr, udp_entry->port, gai_strerror(rv));\r
+            continue;\r
+        }\r
+\r
+        /* loop through all the results and make a socket */\r
+        for (p = servinfo; p != NULL; p = p->ai_next) {\r
+            if ((udp_entry->sock = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) {\r
+                LOG(log_error, logtype_afpd, "fce_init_udp: socket(%s:%s): %s",\r
+                    udp_entry->addr, udp_entry->port, strerror(errno));\r
+                continue;\r
+            }\r
+            break;\r
+        }\r
+\r
+        if (p == NULL) {\r
+            LOG(log_error, logtype_afpd, "fce_init_udp: no socket for %s:%s",\r
+                udp_entry->addr, udp_entry->port);\r
+        }\r
+        udp_entry->addrinfo = *p;\r
+        memcpy(&udp_entry->addrinfo, p, sizeof(struct addrinfo));\r
+        memcpy(&udp_entry->sockaddr, p->ai_addr, sizeof(struct sockaddr_storage));\r
+        freeaddrinfo(servinfo);\r
+    }\r
+\r
+    udp_initialized = FCE_TRUE;\r
+}\r
+\r
+void fce_cleanup()\r
+{\r
+    if (udp_initialized == FCE_FALSE )\r
+        return;\r
+\r
+    for (int i = 0; i < udp_sockets; i++)\r
+    {\r
+        struct udp_entry *udp_entry = udp_socket_list + i;\r
+\r
+        /* Close any pending sockets */\r
+        if (udp_entry->sock != -1)\r
+        {\r
+            close( udp_entry->sock );\r
+            udp_entry->sock = -1;\r
+        }\r
+    }\r
+    udp_initialized = FCE_FALSE;\r
+}\r
+\r
+\r
+/*\r
+ * Construct a UDP packet for our listeners and return packet size\r
+ * */\r
+static ssize_t build_fce_packet( struct fce_packet *packet, char *path, int mode, uint32_t event_id )\r
+{\r
+    size_t pathlen;\r
+    ssize_t data_len = 0;\r
+\r
+    strncpy(packet->magic, FCE_PACKET_MAGIC, sizeof(packet->magic) );\r
+    packet->version = FCE_PACKET_VERSION;\r
+    packet->mode = mode;\r
+    packet->event_id = event_id;\r
+\r
+    pathlen = strlen(path) + 1; /* include string terminator */\r
+\r
+    /* This should never happen, but before we bust this server, we send nonsense, fce listener has to cope */\r
+    if (pathlen >= MAXPATHLEN)\r
+        pathlen = MAXPATHLEN - 1;\r
+\r
+    /* This is the payload len. Means: the stream has len bytes more until packet is finished */\r
+    /* A server should read the first 16 byte, decode them and then fetch the rest */\r
+    data_len = FCE_PACKET_HEADER_SIZE + pathlen;\r
+    packet->datalen = pathlen;\r
+\r
+    switch (mode) {\r
+    case FCE_TM_SIZE:\r
+        tm_used = hton64(tm_used);\r
+        memcpy(packet->data, &tm_used, sizeof(tm_used));\r
+        strncpy(packet->data + sizeof(tm_used), path, pathlen);\r
+\r
+        packet->datalen += sizeof(tm_used);\r
+        data_len += sizeof(tm_used);\r
+        break;\r
+    default:\r
+        strncpy(packet->data, path, pathlen);\r
+        break;\r
+    }\r
+\r
+    /* return the packet len */\r
+    return data_len;\r
+}\r
+\r
+static int pack_fce_packet(struct fce_packet *packet, unsigned char *buf)\r
+{\r
+    unsigned char *p = buf;\r
+\r
+    memcpy(p, &packet->magic[0], sizeof(packet->magic));\r
+    p += sizeof(packet->magic);\r
+\r
+    *p = packet->version;\r
+    p++;\r
+    \r
+    *p = packet->mode;\r
+    p++;\r
+    \r
+    uint32_t id = htonl(packet->event_id);\r
+    memcpy(p, &id, sizeof(id));\r
+    p += sizeof(packet->event_id);\r
+\r
+    uint16_t l = htons(packet->datalen);\r
+    memcpy(p, &l, sizeof(l));\r
+    p += sizeof(l);\r
+\r
+    memcpy(p, &packet->data[0], packet->datalen);\r
+    p += packet->datalen;\r
+\r
+    return 0;\r
+}\r
+\r
+/*\r
+ * Send the fce information to all (connected) listeners\r
+ * We dont give return code because all errors are handled internally (I hope..)\r
+ * */\r
+static void send_fce_event( char *path, int mode )\r
+{    \r
+    struct fce_packet packet;\r
+    void *data = &packet;\r
+    static uint32_t event_id = 0; /* the unique packet couter to detect packet/data loss. Going from 0xFFFFFFFF to 0x0 is a valid increment */\r
+\r
+    LOG(log_debug, logtype_afpd, "send_fce_event: start");\r
+\r
+    time_t now = time(NULL);\r
+\r
+    /* build our data packet */\r
+    ssize_t data_len = build_fce_packet( &packet, path, mode, ++event_id );\r
+    pack_fce_packet(&packet, iobuf);\r
+\r
+    for (int i = 0; i < udp_sockets; i++)\r
+    {\r
+        int sent_data = 0;\r
+        struct udp_entry *udp_entry = udp_socket_list + i;\r
+\r
+        /* we had a problem earlier ? */\r
+        if (udp_entry->sock == -1)\r
+        {\r
+            /* We still have to wait ?*/\r
+            if (now < udp_entry->next_try_on_error)\r
+                continue;\r
+\r
+            /* Reopen socket */\r
+            udp_entry->sock = socket(udp_entry->addrinfo.ai_family,\r
+                                     udp_entry->addrinfo.ai_socktype,\r
+                                     udp_entry->addrinfo.ai_protocol);\r
+            \r
+            if (udp_entry->sock == -1) {\r
+                /* failed again, so go to rest again */\r
+                LOG(log_error, logtype_afpd, "Cannot recreate socket for fce UDP connection: errno %d", errno  );\r
+\r
+                udp_entry->next_try_on_error = now + FCE_SOCKET_RETRY_DELAY_S;\r
+                continue;\r
+            }\r
+\r
+            udp_entry->next_try_on_error = 0;\r
+\r
+            /* Okay, we have a running socket again, send server that we had a problem on our side*/\r
+            data_len = build_fce_packet( &packet, "", FCE_CONN_BROKEN, 0 );\r
+            pack_fce_packet(&packet, iobuf);\r
+\r
+            sendto(udp_entry->sock,\r
+                   iobuf,\r
+                   data_len,\r
+                   0,\r
+                   (struct sockaddr *)&udp_entry->sockaddr,\r
+                   udp_entry->addrinfo.ai_addrlen);\r
+\r
+            /* Rebuild our original data packet */\r
+            data_len = build_fce_packet( &packet, path, mode, event_id );\r
+            pack_fce_packet(&packet, iobuf);\r
+        }\r
+\r
+        sent_data = sendto(udp_entry->sock,\r
+                           iobuf,\r
+                           data_len,\r
+                           0,\r
+                           (struct sockaddr *)&udp_entry->sockaddr,\r
+                           udp_entry->addrinfo.ai_addrlen);\r
+\r
+        /* Problems ? */\r
+        if (sent_data != data_len) {\r
+            /* Argh, socket broke, we close and retry later */\r
+            LOG(log_error, logtype_afpd, "send_fce_event: error sending packet to %s:%s, transfered %d of %d: %s",\r
+                udp_entry->addr, udp_entry->port, sent_data, data_len, strerror(errno));\r
+\r
+            close( udp_entry->sock );\r
+            udp_entry->sock = -1;\r
+            udp_entry->next_try_on_error = now + FCE_SOCKET_RETRY_DELAY_S;\r
+        }\r
+    }\r
+}\r
+\r
+static int add_udp_socket(const char *target_ip, const char *target_port )\r
+{\r
+    if (target_port == NULL)\r
+        target_port = FCE_DEFAULT_PORT_STRING;\r
+\r
+    if (udp_sockets >= FCE_MAX_UDP_SOCKS) {\r
+        LOG(log_error, logtype_afpd, "Too many file change api UDP connections (max %d allowed)", FCE_MAX_UDP_SOCKS );\r
+        return AFPERR_PARAM;\r
+    }\r
+\r
+    udp_socket_list[udp_sockets].addr = strdup(target_ip);\r
+    udp_socket_list[udp_sockets].port = strdup(target_port);\r
+    udp_socket_list[udp_sockets].sock = -1;\r
+    memset(&udp_socket_list[udp_sockets].addrinfo, 0, sizeof(struct addrinfo));\r
+    memset(&udp_socket_list[udp_sockets].sockaddr, 0, sizeof(struct sockaddr_storage));\r
+    udp_socket_list[udp_sockets].next_try_on_error = 0;\r
+\r
+    udp_sockets++;\r
+\r
+    return AFP_OK;\r
+}\r
+\r
+/*\r
+ *\r
+ * Dispatcher for all incoming file change events\r
+ *\r
+ * */\r
+static int register_fce(const char *u_name, int is_dir, int mode)\r
+{\r
+    if (udp_sockets == 0)\r
+        /* No listeners configured */\r
+        return AFP_OK;\r
+\r
+    if (u_name == NULL)\r
+        return AFPERR_PARAM;\r
+\r
+    static int first_event = FCE_TRUE;\r
+\r
+       /* do some initialization on the fly the first time */\r
+       if (first_event) {\r
+               fce_initialize_history();\r
+       }\r
+\r
+       /* handle files which should not cause events (.DS_Store atc. ) */\r
+       for (int i = 0; skip_files[i] != NULL; i++)\r
+       {\r
+               if (!strcmp( u_name, skip_files[i]))\r
+                       return AFP_OK;\r
+       }\r
+\r
+\r
+       char full_path_buffer[MAXPATHLEN + 1] = {""};\r
+       const char *cwd = getcwdpath();\r
+\r
+    if (mode == FCE_TM_SIZE) {\r
+        strlcpy(full_path_buffer, u_name, MAXPATHLEN);\r
+    } else if (!is_dir || mode == FCE_DIR_DELETE) {\r
+               if (strlen( cwd ) + strlen( u_name) + 1 >= MAXPATHLEN) {\r
+                       LOG(log_error, logtype_afpd, "FCE file name too long: %s/%s", cwd, u_name );\r
+                       return AFPERR_PARAM;\r
+               }\r
+               sprintf( full_path_buffer, "%s/%s", cwd, u_name );\r
+       } else {\r
+               if (strlen( cwd ) >= MAXPATHLEN) {\r
+                       LOG(log_error, logtype_afpd, "FCE directory name too long: %s", cwd);\r
+                       return AFPERR_PARAM;\r
+               }\r
+               strcpy( full_path_buffer, cwd);\r
+       }\r
+\r
+       /* Can we ignore this event based on type or history? */\r
+       if (!(mode & FCE_TM_SIZE) && fce_handle_coalescation( full_path_buffer, is_dir, mode ))\r
+       {\r
+               LOG(log_debug9, logtype_afpd, "Coalesced fc event <%d> for <%s>", mode, full_path_buffer );\r
+               return AFP_OK;\r
+       }\r
+\r
+       LOG(log_debug9, logtype_afpd, "Detected fc event <%d> for <%s>", mode, full_path_buffer );\r
+\r
+\r
+    /* we do initilization on the fly, no blocking calls in here \r
+     * (except when using FQDN in broken DNS environment)\r
+     */\r
+    if (first_event == FCE_TRUE)\r
+    {\r
+        fce_init_udp();\r
+        \r
+        /* Notify listeners the we start from the beginning */\r
+        send_fce_event( "", FCE_CONN_START );\r
+        \r
+        first_event = FCE_FALSE;\r
+    }\r
+\r
+       /* Handle UDP transport */\r
+    send_fce_event( full_path_buffer, mode );\r
+\r
+    return AFP_OK;\r
+}\r
+\r
+\r
+/******************** External calls start here **************************/\r
+\r
+/*\r
+ * API-Calls for file change api, called form outside (file.c directory.c ofork.c filedir.c)\r
+ * */\r
+#ifndef FCE_TEST_MAIN\r
+\r
+int fce_register_delete_file( struct path *path )\r
+{\r
+    int ret = AFP_OK;\r
+\r
+    if (path == NULL)\r
+        return AFPERR_PARAM;\r
+\r
+    if (!(fce_ev_enabled & (1 << FCE_FILE_DELETE)))\r
+        return ret;\r
+       \r
+    ret = register_fce( path->u_name, FALSE, FCE_FILE_DELETE );\r
+\r
+    return ret;\r
+}\r
+int fce_register_delete_dir( char *name )\r
+{\r
+    int ret = AFP_OK;\r
+\r
+    if (name == NULL)\r
+        return AFPERR_PARAM;\r
+\r
+    if (!(fce_ev_enabled & (1 << FCE_DIR_DELETE)))\r
+        return ret;\r
+       \r
+    ret = register_fce( name, TRUE, FCE_DIR_DELETE);\r
+\r
+    return ret;\r
+}\r
+\r
+int fce_register_new_dir( struct path *path )\r
+{\r
+    int ret = AFP_OK;\r
+\r
+    if (path == NULL)\r
+        return AFPERR_PARAM;\r
+\r
+    if (!(fce_ev_enabled & (1 << FCE_DIR_CREATE)))\r
+        return ret;\r
+\r
+    ret = register_fce( path->u_name, TRUE, FCE_DIR_CREATE );\r
+\r
+    return ret;\r
+}\r
+\r
+\r
+int fce_register_new_file( struct path *path )\r
+{\r
+    int ret = AFP_OK;\r
+\r
+    if (path == NULL)\r
+        return AFPERR_PARAM;\r
+\r
+    if (!(fce_ev_enabled & (1 << FCE_FILE_CREATE)))\r
+        return ret;\r
+\r
+    ret = register_fce( path->u_name, FALSE, FCE_FILE_CREATE );\r
+\r
+    return ret;\r
+}\r
+\r
+int fce_register_file_modification( struct ofork *ofork )\r
+{\r
+    char *u_name = NULL;\r
+    struct vol *vol;\r
+    int ret = AFP_OK;\r
+\r
+    if (ofork == NULL || ofork->of_vol == NULL)\r
+        return AFPERR_PARAM;\r
+\r
+    if (!(fce_ev_enabled & (1 << FCE_FILE_MODIFY)))\r
+        return ret;\r
+\r
+    vol = ofork->of_vol;\r
+\r
+    if (NULL == (u_name = mtoupath(vol, of_name(ofork), ofork->of_did, utf8_encoding()))) \r
+    {\r
+        return AFPERR_MISC;\r
+    }\r
+    \r
+    ret = register_fce( u_name, FALSE, FCE_FILE_MODIFY );\r
+    \r
+    return ret;    \r
+}\r
+\r
+int fce_register_tm_size(const char *vol, size_t used)\r
+{\r
+    int ret = AFP_OK;\r
+\r
+    if (vol == NULL)\r
+        return AFPERR_PARAM;\r
+\r
+    if (!(fce_ev_enabled & (1 << FCE_TM_SIZE)))\r
+        return ret;\r
+\r
+    tm_used = used;             /* oh what a hack */\r
+    ret = register_fce(vol, FALSE, FCE_TM_SIZE);\r
+\r
+    return ret;\r
+}\r
+#endif\r
+\r
+/*\r
+ *\r
+ * Extern connect to afpd parameter, can be called multiple times for multiple listeners (up to MAX_UDP_SOCKS times)\r
+ *\r
+ * */\r
+int fce_add_udp_socket(const char *target)\r
+{\r
+       const char *port = FCE_DEFAULT_PORT_STRING;\r
+       char target_ip[256] = {""};\r
+\r
+       strncpy(target_ip, target, sizeof(target_ip) -1);\r
+\r
+       char *port_delim = strchr( target_ip, ':' );\r
+       if (port_delim) {\r
+               *port_delim = 0;\r
+               port = port_delim + 1;\r
+       }\r
+       return add_udp_socket(target_ip, port);\r
+}\r
+\r
+int fce_set_events(const char *events)\r
+{\r
+    char *e;\r
+    char *p;\r
+    \r
+    if (events == NULL)\r
+        return AFPERR_PARAM;\r
+\r
+    e = strdup(events);\r
+\r
+    fce_ev_enabled = 0;\r
+\r
+    for (p = strtok(e, ","); p; p = strtok(NULL, ",")) {\r
+        if (strcmp(p, "fmod") == 0) {\r
+            fce_ev_enabled |= (1 << FCE_FILE_MODIFY);\r
+        } else if (strcmp(p, "fdel") == 0) {\r
+            fce_ev_enabled |= (1 << FCE_FILE_DELETE);\r
+        } else if (strcmp(p, "ddel") == 0) {\r
+            fce_ev_enabled |= (1 << FCE_DIR_DELETE);\r
+        } else if (strcmp(p, "fcre") == 0) {\r
+            fce_ev_enabled |= (1 << FCE_FILE_CREATE);\r
+        } else if (strcmp(p, "dcre") == 0) {\r
+            fce_ev_enabled |= (1 << FCE_DIR_CREATE);\r
+        } else if (strcmp(p, "tmsz") == 0) {\r
+            fce_ev_enabled |= (1 << FCE_TM_SIZE);\r
+        }\r
+    }\r
+\r
+    free(e);\r
+}\r
+\r
+#ifdef FCE_TEST_MAIN\r
+\r
+\r
+void shortsleep( unsigned int us )\r
+{    \r
+    usleep( us );\r
+}\r
+int main( int argc, char*argv[] )\r
+{\r
+    int c,ret;\r
+\r
+    char *port = FCE_DEFAULT_PORT_STRING;\r
+    char *host = "localhost";\r
+    int delay_between_events = 1000;\r
+    int event_code = FCE_FILE_MODIFY;\r
+    char pathbuff[1024];\r
+    int duration_in_seconds = 0; // TILL ETERNITY\r
+    char target[256];\r
+    char *path = getcwd( pathbuff, sizeof(pathbuff) );\r
+\r
+    // FULLSPEED TEST IS "-s 1001" -> delay is 0 -> send packets without pause\r
+\r
+    while ((c = getopt(argc, argv, "d:e:h:p:P:s:")) != -1) {\r
+        switch(c) {\r
+        case '?':\r
+            fprintf(stdout, "%s: [ -p Port -h Listener1 [ -h Listener2 ...] -P path -s Delay_between_events_in_us -e event_code -d Duration ]\n", argv[0]);\r
+            exit(1);\r
+            break;\r
+        case 'd':\r
+            duration_in_seconds = atoi(optarg);\r
+            break;\r
+        case 'e':\r
+            event_code = atoi(optarg);\r
+            break;\r
+        case 'h':\r
+            host = strdup(optarg);\r
+            break;\r
+        case 'p':\r
+            port = strdup(optarg);\r
+            break;\r
+        case 'P':\r
+            path = strdup(optarg);\r
+            break;\r
+        case 's':\r
+            delay_between_events = atoi(optarg);\r
+            break;\r
+        }\r
+    }\r
+\r
+    sprintf(target, "%s:%s", host, port);\r
+    if (fce_add_udp_socket(target) != 0)\r
+        return 1;\r
+\r
+    int ev_cnt = 0;\r
+    time_t start_time = time(NULL);\r
+    time_t end_time = 0;\r
+\r
+    if (duration_in_seconds)\r
+        end_time = start_time + duration_in_seconds;\r
+\r
+    while (1)\r
+    {\r
+        time_t now = time(NULL);\r
+        if (now > start_time)\r
+        {\r
+            start_time = now;\r
+            fprintf( stdout, "%d events/s\n", ev_cnt );\r
+            ev_cnt = 0;\r
+        }\r
+        if (end_time && now >= end_time)\r
+            break;\r
+\r
+        register_fce( path, 0, event_code );\r
+        ev_cnt++;\r
+\r
+        \r
+        shortsleep( delay_between_events );\r
+    }\r
+}\r
+#endif /* TESTMAIN*/\r
diff --git a/etc/afpd/fce_api_internal.h b/etc/afpd/fce_api_internal.h
new file mode 100755 (executable)
index 0000000..d73b775
--- /dev/null
@@ -0,0 +1,42 @@
+/* \r
+ * File:   fce_api_internal.h\r
+ * Author: mw\r
+ *\r
+ * Created on 1. Oktober 2010, 23:48\r
+ */\r
+\r
+#ifndef _FCE_API_INTERNAL_H\r
+#define        _FCE_API_INTERNAL_H\r
+\r
+#define FCE_MAX_UDP_SOCKS 5     /* Allow a maximum of udp listeners for file change events */\r
+#define FCE_SOCKET_RETRY_DELAY_S 600 /* Pause this time in s after socket was broken */\r
+#define FCE_PACKET_VERSION  1\r
+#define FCE_HISTORY_LEN 10  /* This is used to coalesce events */\r
+#define MAX_COALESCE_TIME_MS 1000  /* Events oldeer than this are not coalesced */\r
+\r
+struct udp_entry\r
+{\r
+    int sock;\r
+    char *addr;\r
+    char *port;\r
+    struct addrinfo addrinfo;\r
+    struct sockaddr_storage sockaddr;\r
+    time_t next_try_on_error;      /* In case of error set next timestamp to retry */\r
+};\r
+\r
+struct fce_history\r
+{\r
+    unsigned char mode;\r
+       int is_dir;\r
+       char path[MAXPATHLEN + 1];\r
+       struct timeval tv;\r
+};\r
+\r
+#define PACKET_HDR_LEN (sizeof(struct fce_packet) - FCE_MAX_PATH_LEN)\r
+\r
+int fce_handle_coalescation( char *path, int is_dir, int mode );\r
+void fce_initialize_history();\r
+\r
+\r
+#endif /* _FCE_API_INTERNAL_H */\r
+\r
diff --git a/etc/afpd/fce_util.c b/etc/afpd/fce_util.c
new file mode 100755 (executable)
index 0000000..6959509
--- /dev/null
@@ -0,0 +1,223 @@
+/*\r
+ * $Id: fce_api.c,v 0.01 2010-10-01 00:00:0 mw Exp $\r
+ *\r
+ * Copyright (c) 2010 Mark Williams\r
+ *\r
+ * File change event API for netatalk\r
+ *\r
+ * for every detected filesystem change a UDP packet is sent to an arbitrary list\r
+ * of listeners. Each packet contains unix path of modified filesystem element,\r
+ * event reason, and a consecutive event id (32 bit). Technically we are UDP client and are sending\r
+ * out packets synchronuosly as they are created by the afp functions. This should not affect\r
+ * performance measurably. The only delaying calls occur during initialization, if we have to\r
+ * resolve non-IP hostnames to IP. All numeric data inside the packet is network byte order, so use\r
+ * ntohs / ntohl to resolve length and event id. Ideally a listener receives every packet with\r
+ * no gaps in event ids, starting with event id 1 and mode FCE_CONN_START followed by\r
+ * data events from id 2 up to 0xFFFFFFFF, followed by 0 to 0xFFFFFFFF and so on.\r
+ *\r
+ * A gap or not starting with 1 mode FCE_CONN_START or receiving mode FCE_CONN_BROKEN means that\r
+ * the listener has lost at least one filesystem event\r
+ * \r
+ * All Rights Reserved.  See COPYRIGHT.\r
+ */\r
+\r
+#ifdef HAVE_CONFIG_H\r
+#include "config.h"\r
+#endif /* HAVE_CONFIG_H */\r
+\r
+#include <stdio.h>\r
+\r
+#include <string.h>\r
+#include <stdlib.h>\r
+#include <errno.h>\r
+#include <time.h>\r
+\r
+\r
+#include <sys/param.h>\r
+#include <sys/socket.h>\r
+#include <netinet/in.h>\r
+#include <arpa/inet.h>\r
+#include <netdb.h>\r
+\r
+#include <netatalk/at.h>\r
+\r
+#include <atalk/adouble.h>\r
+#include <atalk/vfs.h>\r
+#include <atalk/logger.h>\r
+#include <atalk/afp.h>\r
+#include <atalk/util.h>\r
+#include <atalk/cnid.h>\r
+#include <atalk/unix.h>\r
+#include <atalk/fce_api.h>\r
+#include <atalk/globals.h>\r
+\r
+#include "fork.h"\r
+#include "file.h"\r
+#include "directory.h"\r
+#include "desktop.h"\r
+#include "volume.h"\r
+\r
+// ONLY USED IN THIS FILE\r
+#include "fce_api_internal.h"\r
+\r
+#define FCE_TRUE 1\r
+#define FCE_FALSE 0\r
+\r
+/* We store our connection data here */\r
+static char coalesce[80] = {""};\r
+static struct fce_history fce_history_list[FCE_HISTORY_LEN];\r
+\r
+\r
+\r
+\r
+/****\r
+* With coalesce we try to reduce the events over UDP, the eventlistener would throw these \r
+* events away anyway.\r
+* This works only, if the connected listener uses the events on a "per directory" base\r
+* It is a very simple aproach, but saves a lot of events sent to listeners.\r
+* Every "child element" event is ignored as long as its parent event is not older \r
+* than MAX_COALESCE_TIME_MS ms. If large directory trees or large files are created or deleted, \r
+* this probably will not work recursive, because the time to copy data will exceed this \r
+* event timeout. \r
+* \r
+****/\r
+static int coalesce_none()\r
+{\r
+       return coalesce[0] == 0;\r
+}\r
+static int coalesce_all()\r
+{\r
+       return !strcmp( coalesce, "all" );\r
+}\r
+static int coalesce_create()\r
+{\r
+       return !strcmp( coalesce, "create" ) || coalesce_all();\r
+}\r
+static int coalesce_delete()\r
+{\r
+       return !strcmp( coalesce, "delete" ) || coalesce_all();\r
+}\r
+\r
+void fce_initialize_history()\r
+{\r
+       for (int i = 0; i < FCE_HISTORY_LEN; i++)\r
+       {\r
+               memset( &fce_history_list[i], 0, sizeof(fce_history_list[i]) );\r
+       }\r
+}\r
+\r
+static long get_ms_difftime (  struct timeval *tv1, struct timeval *tv2 )\r
+{\r
+       unsigned long s = tv2->tv_sec - tv1->tv_sec;\r
+       long us = tv2->tv_usec - tv1->tv_usec;\r
+\r
+       return s * 1000 + us/1000;\r
+}\r
+\r
+int fce_handle_coalescation( char *path, int is_dir, int mode )\r
+{\r
+       if (coalesce_none())\r
+               return FALSE;\r
+\r
+               \r
+\r
+       // First one:\r
+       // After a file creation *ALWAYS* a file modification is produced\r
+       if (mode == FCE_FILE_CREATE)\r
+       {\r
+               if (coalesce_create())\r
+               {\r
+                       return TRUE;\r
+               }\r
+       }\r
+\r
+       /* get timestamp */\r
+       struct timeval tv;\r
+       gettimeofday(&tv, 0);\r
+\r
+\r
+       /* These two are used to eval our next index in history */\r
+       /* the history is unsorted, speed should not be a problem, length is 10 */\r
+       unsigned long oldest_entry = (unsigned long )((long)-1);\r
+       int oldest_entry_idx = -1;\r
+\r
+       /* Now detect events in the very near history */\r
+       for (int i = 0; i < FCE_HISTORY_LEN; i++)\r
+       {\r
+               struct fce_history *fh = &fce_history_list[i];\r
+\r
+               //* Not inited ? */\r
+               if (fh->tv.tv_sec == 0)\r
+               {\r
+                       /* we can use it for new elements */\r
+                       oldest_entry = 0;\r
+                       oldest_entry_idx = i;\r
+                       continue;\r
+               }\r
+\r
+               //* Too old ? */\r
+               if (get_ms_difftime( &fh->tv, &tv ) > MAX_COALESCE_TIME_MS)\r
+               {\r
+                       /* Invalidate entry */\r
+                       fh->tv.tv_sec = 0;\r
+\r
+                       oldest_entry = 0;\r
+                       oldest_entry_idx = i;                   \r
+                       continue;\r
+               }\r
+\r
+\r
+               /* If we find a parent dir wich was created we are done */\r
+               if (coalesce_create() && fh->mode == FCE_DIR_CREATE)\r
+               {\r
+                       //* Parent dir ? */\r
+                       if (!strncmp( fh->path, path, strlen( fh->path ) ) )\r
+                       {\r
+                               return TRUE;\r
+                       }\r
+               }\r
+\r
+               /* If we find a parent dir we should be DELETED we are done */\r
+               if (coalesce_delete() && fh->is_dir && (mode == FCE_FILE_DELETE || mode == FCE_DIR_DELETE))\r
+               {\r
+                       //* Parent dir ? */\r
+                       if (!strncmp( fh->path, path, strlen( fh->path ) ) )\r
+                       {\r
+                               return TRUE;\r
+                       }\r
+               }\r
+\r
+               //* Detect oldest entry for next new entry */\r
+               if (oldest_entry_idx == -1 || fh->tv.tv_sec < oldest_entry)\r
+               {\r
+                       oldest_entry = fh->tv.tv_sec;\r
+                       oldest_entry_idx = i;\r
+               }\r
+       }\r
+\r
+       /* We have a new entry for the history, register it */\r
+       fce_history_list[oldest_entry_idx].tv = tv;\r
+       fce_history_list[oldest_entry_idx].mode = mode;\r
+       fce_history_list[oldest_entry_idx].is_dir = is_dir;\r
+       strncpy( fce_history_list[oldest_entry_idx].path, path, MAXPATHLEN);\r
+\r
+       /* we have to handle this event */\r
+       return FALSE;\r
+}\r
+\r
+/*\r
+ *\r
+ * Set event coalescation to reduce number of events sent over UDP \r
+ * all|delete|create\r
+ *\r
+ *\r
+ * */\r
+\r
+int fce_set_coalesce( char *coalesce_opt )\r
+{\r
+       strncpy( coalesce, coalesce_opt, sizeof(coalesce) - 1 ); \r
+}\r
+\r
+\r
+\r
+\r
index b5a896373683c88e7380af2da72c36e6ca06f98c..549f19ddfd4e06bebd0634648a406419fcb02587 100644 (file)
@@ -22,6 +22,8 @@
 #include <atalk/util.h>
 #include <atalk/cnid.h>
 #include <atalk/unix.h>
+#include <atalk/globals.h>
+#include <atalk/fce_api.h>
 
 #include "directory.h"
 #include "dircache.h"
@@ -30,7 +32,6 @@
 #include "fork.h"
 #include "file.h"
 #include "filedir.h"
-#include "globals.h"
 #include "unix.h"
 
 /* the format for the finderinfo fields (from IM: Toolbox Essentials):
@@ -745,6 +746,7 @@ int afp_createfile(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_,
 
     ad_flush(&ad);
     ad_close(&ad, ADFLAGS_DF|ADFLAGS_HF );
+    fce_register_new_file(s_path);
 
 createfile_done:
     curdir->d_offcnt++;
index bd9f77645eb29f9d7e73f52b3724053fa14c83e8..654ce83061a4612f08e35e999fafd3271e5141fd 100644 (file)
@@ -28,8 +28,8 @@
 #include <sys/param.h>
 #include <arpa/inet.h>
 #include <atalk/adouble.h>
+#include <atalk/globals.h>
 
-#include "globals.h"
 #include "volume.h"
 #include "directory.h"
 
index 9453111b62349efb82113400fb9cb52b5ec94c39..fba0eacf768a5ef1a4a003c4deccb9c6c7174cbc 100644 (file)
@@ -23,6 +23,8 @@
 #include <atalk/bstrlib.h>
 #include <atalk/bstradd.h>
 #include <atalk/acl.h>
+#include <atalk/globals.h>
+#include <atalk/fce_api.h>
 
 #include "directory.h"
 #include "dircache.h"
@@ -30,7 +32,6 @@
 #include "volume.h"
 #include "fork.h"
 #include "file.h"
-#include "globals.h"
 #include "filedir.h"
 #include "unix.h"
 
@@ -504,10 +505,18 @@ int afp_delete(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size
 
     upath = s_path->u_name;
     if ( path_isadir( s_path) ) {
-        if (*s_path->m_name != '\0' || curdir->d_did == DIRDID_ROOT)
+        if (*s_path->m_name != '\0' || curdir->d_did == DIRDID_ROOT) {
             rc = AFPERR_ACCESS;
-        else
-            rc = deletecurdir( vol);
+        } else {
+            /* we have to cache this, the structs are lost in deletcurdir*/
+            /* but we need the positive returncode to send our event */
+            bstring dname;
+            if ((dname = bstrcpy(curdir->d_u_name)) == NULL)
+                return AFPERR_MISC;
+            if ((rc = deletecurdir(vol)) == AFP_OK)
+                fce_register_delete_dir(cfrombstr(dname));
+            bdestroy(dname);
+        }
     } else if (of_findname(s_path)) {
         rc = AFPERR_BUSY;
     } else {
@@ -517,10 +526,14 @@ int afp_delete(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size
          */
         if (s_path->st_valid && s_path->st_errno == ENOENT) {
             rc = AFPERR_NOOBJ;
-        }
-        else {
-            rc = deletefile(vol, -1, upath, 1);
-
+        } else {
+            if ((rc = deletefile(vol, -1, upath, 1)) == AFP_OK) {
+                               fce_register_delete_file( s_path );
+                if (vol->v_tm_used < s_path->st.st_size)
+                    vol->v_tm_used = 0;
+                else 
+                    vol->v_tm_used -= s_path->st.st_size;
+            }
             struct dir *cachedfile;
             if ((cachedfile = dircache_search_by_name(vol, dir, upath, strlen(upath)))) {
                 dircache_remove(vol, cachedfile, DIRCACHE | DIDNAME_INDEX | QUEUE_INDEX);
index 9645bc00823e01b95fc9dd26424d8d60b9b5d5e1..02c9ac15b5382ed99c5ee4cf7a84166d4e85cfda 100644 (file)
@@ -2,7 +2,7 @@
 #define AFPD_FILEDIR_H 1
 
 #include <sys/stat.h>
-#include "globals.h"
+#include <atalk/globals.h>
 #include "volume.h"
 
 extern struct afp_options default_options;
index 4133eebdbe40544bee0f1d77810f617ee8fb865a..e075945cc5253aa8d796790f029aab97db845aae 100644 (file)
@@ -16,7 +16,6 @@
 #include <sys/socket.h>
 #include <inttypes.h>
 
-#include <netatalk/at.h>
 #include <atalk/dsi.h>
 #include <atalk/afp.h>
 #include <atalk/adouble.h>
 #include <atalk/util.h>
 #include <atalk/cnid.h>
 #include <atalk/bstradd.h>
+#include <atalk/globals.h>
 
 #include "fork.h"
 #include "file.h"
-#include "globals.h"
 #include "directory.h"
 #include "desktop.h"
 #include "volume.h"
@@ -1304,6 +1303,12 @@ static int write_fork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, s
     if ( ad_meta_fileno( ofork->of_ad ) != -1 ) /* META */
         ofork->of_flags |= AFPFORK_DIRTY;
 
+    /* we have modified any fork, remember until close_fork */
+    ofork->of_flags |= AFPFORK_MODIFIED;
+
+    /* update write count */
+    ofork->of_vol->v_written += reqcount;
+
     *rbuflen = set_off_t (offset, rbuf, is64);
     return( AFP_OK );
 
index e950aa0ffdf6aa72cb47d8e167ab078ca32fcd41..7aaff0f5a26acbbae6f115caa4736da5571723d8 100644 (file)
@@ -45,6 +45,7 @@ struct ofork {
 #define AFPFORK_ACCRD   (1<<4)
 #define AFPFORK_ACCWR   (1<<5)
 #define AFPFORK_ACCMASK (AFPFORK_ACCRD | AFPFORK_ACCWR)
+#define AFPFORK_MODIFIED (1<<6) /* used in FCE for modified files */
 
 #ifdef AFS
 extern struct ofork *writtenfork;
index f8ef210a43361c04c3cd1a29a77e55cd0a754fda..fd48db688e1a56b39ca2d817efe00a15c6cf9f06 100644 (file)
@@ -14,7 +14,7 @@
 #include <ctype.h>
 #include <pwd.h>
 
-#include "globals.h"
+#include <atalk/globals.h>
 
 static char    *l_curr;
 static char    *l_end;
diff --git a/etc/afpd/globals.h b/etc/afpd/globals.h
deleted file mode 100644 (file)
index 4d81463..0000000
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * Copyright (c) 1990,1993 Regents of The University of Michigan.
- * All Rights Reserved.  See COPYRIGHT.
- */
-
-#ifndef AFPD_GLOBALS_H
-#define AFPD_GLOBALS_H 1
-
-#include <sys/param.h>
-
-#ifdef ADMIN_GRP
-#include <grp.h>
-#include <sys/types.h>
-#endif /* ADMIN_GRP */
-
-#ifdef HAVE_NETDB_H
-#include <netdb.h>  /* this isn't header-protected under ultrix */
-#endif /* HAVE_NETDB_H */
-
-#include <netatalk/at.h>
-#include <atalk/afp.h>
-#include <atalk/compat.h>
-#include <atalk/unicode.h>
-#include <atalk/uam.h>
-
-/* #define DOSFILELEN 12 */             /* Type1, DOS-compat*/
-#define MACFILELEN 31                   /* Type2, HFS-compat */
-#define UTF8FILELEN_EARLY 255           /* Type3, early Mac OS X 10.0-10.4.? */
-/* #define UTF8FILELEN_NAME_MAX 765 */  /* Type3, 10.4.?- , getconf NAME_MAX */
-/* #define UTF8FILELEN_SPEC 0xFFFF */   /* Type3, spec on document */
-/* #define HFSPLUSFILELEN 510 */        /* HFS+ spec, 510byte = 255codepoint */
-
-#define MAXUSERLEN 256
-
-#define OPTION_DEBUG         (1 << 0)
-#define OPTION_USERVOLFIRST  (1 << 1)
-#define OPTION_NOUSERVOL     (1 << 2)
-#define OPTION_PROXY         (1 << 3)
-#define OPTION_CUSTOMICON    (1 << 4)
-#define OPTION_NOSLP         (1 << 5)
-#define OPTION_ANNOUNCESSH   (1 << 6)
-#define OPTION_UUID          (1 << 7)
-#define OPTION_ACL2MACCESS   (1 << 8)
-#define OPTION_NOZEROCONF    (1 << 9)
-
-/* a couple of these options could get stuck in unions to save
- * space. */
-struct afp_volume_name {
-    time_t     mtime;
-    char       *name;
-    char       *full_name;
-    int        loaded;
-};
-
-struct afp_options {
-    int connections, transports, tickleval, timeout, server_notif, flags, dircachesize;
-    int sleep;                  /* Maximum time allowed to sleep (in tickles) */
-    int disconnected;           /* Maximum time in disconnected state (in tickles) */
-    unsigned int tcp_sndbuf, tcp_rcvbuf;
-    unsigned char passwdbits, passwdminlen, loginmaxfail;
-    u_int32_t server_quantum;
-    int dsireadbuf; /* scale factor for sizefof(dsi->buffer) = server_quantum * dsireadbuf */
-    char hostname[MAXHOSTNAMELEN + 1], *server, *ipaddr, *port, *configfile;
-    char *uampath, *fqdn;
-    char *pidfile;
-    char *sigconffile;
-    char *uuidconf;
-    struct afp_volume_name defaultvol, systemvol, uservol;
-    int  closevol;
-
-    char *guest, *loginmesg, *keyfile, *passwdfile;
-    char *uamlist;
-    char *authprintdir;
-    char *signatureopt;
-    unsigned char signature[16];
-    char *k5service, *k5realm, *k5keytab;
-    char *unixcodepage,*maccodepage;
-    charset_t maccharset, unixcharset; 
-    mode_t umask;
-    mode_t save_mask;
-#ifdef ADMIN_GRP
-    gid_t admingid;
-#endif /* ADMIN_GRP */
-    int    volnamelen;
-
-    /* default value for winbind authentication */
-    char *ntdomain, *ntseparator;
-    char *logconfig;
-};
-
-#define AFPOBJ_TMPSIZ (MAXPATHLEN)
-typedef struct _AFPObj {
-    int proto;
-    unsigned long servernum;
-    void *handle;               /* either (DSI *) or (ASP *) */
-    void *config; 
-    struct afp_options options;
-    char *Obj, *Type, *Zone;
-    char username[MAXUSERLEN];
-    void (*logout)(void), (*exit)(int);
-    int (*reply)(void *, int);
-    int (*attention)(void *, AFPUserBytes);
-    /* to prevent confusion, only use these in afp_* calls */
-    char oldtmp[AFPOBJ_TMPSIZ + 1], newtmp[AFPOBJ_TMPSIZ + 1];
-    void *uam_cookie; /* cookie for uams */
-    struct session_info  sinfo;
-    uid_t uid;         /* client running user id */
-    int ipc_fd; /* anonymous PF_UNIX socket for IPC with afpd parent */
-} AFPObj;
-
-/* typedef for AFP functions handlers */
-typedef int (*AFPCmd)(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf,  size_t *rbuflen);
-
-/* afp_dsi.c */
-extern AFPObj *AFPobj;
-
-extern int             afp_version;
-extern int             afp_errno;
-extern unsigned char   nologin;
-extern struct dir      *curdir;
-extern char            getwdbuf[];
-
-/* FIXME CNID */
-extern const char *Cnid_srv;
-extern const char *Cnid_port;
-
-extern int  get_afp_errno   (const int param);
-extern void afp_options_init (struct afp_options *);
-extern int afp_options_parse (int, char **, struct afp_options *);
-extern int afp_options_parseline (char *, struct afp_options *);
-extern void afp_options_free (struct afp_options *,
-                                      const struct afp_options *);
-extern void setmessage (const char *);
-extern void readmessage (AFPObj *);
-
-/* gettok.c */
-extern void initline   (int, char *);
-extern int  parseline  (int, char *);
-
-/* afp_util.c */
-extern const char *AfpNum2name (int );
-extern const char *AfpErr2name(int err);
-
-/* directory.c */
-extern struct dir rootParent;
-
-extern void afp_over_dsi (AFPObj *);
-
-#endif /* globals.h */
index 2c90683afc86fb6bd7bb104311b3e9b7fb9cda75..c26b6fd63e4e56cc647155f9f47e850a0274523f 100644 (file)
@@ -6,7 +6,7 @@
 #ifndef AFPD_ICON_H
 #define AFPD_ICON_H 1
 
-#include "globals.h"
+#include <atalk/globals.h>
 
 static const unsigned char apple_atalk_icon[] = { /* default appletalk icon */
     0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
index 37bb4bd4a0916ba6c54ce5b074fa081edca47fe1..68785537e3d7c945e7035577989a5aa3e73a47f7 100644 (file)
 #include <sys/poll.h>
 #include <errno.h>
 #include <sys/wait.h>
+#include <sys/resource.h>
 
 #include <atalk/logger.h>
 #include <atalk/adouble.h>
-#include <netatalk/at.h>
 #include <atalk/compat.h>
 #include <atalk/dsi.h>
 #include <atalk/afp.h>
 #include <atalk/server_ipc.h>
 #include <atalk/errchk.h>
 #include <atalk/locking.h>
+#include <atalk/globals.h>
 
 #include "event2/event.h"
 #include "event2/http.h"
 #include "event2/rpc.h"
 
-#include "globals.h"
 #include "afp_config.h"
 #include "status.h"
 #include "fork.h"
@@ -65,7 +65,7 @@ static struct pollfd *fdset;
 static struct polldata *polldata;
 static int fdset_size;          /* current allocated size */
 static int fdset_used;          /* number of used elements */
-
+static int disasociated_ipc_fd; /* disasociated sessions uses this fd for IPC */
 
 #ifdef TRU64
 void afp_get_cmdline( int *ac, char ***av)
@@ -96,6 +96,7 @@ static void fd_set_listening_sockets(void)
             continue;
         fdset_add_fd(&fdset, &polldata, &fdset_used, &fdset_size, config->fd, LISTEN_FD, config);
     }
+    fdset_add_fd(&fdset, &polldata, &fdset_used, &fdset_size, disasociated_ipc_fd, DISASOCIATED_IPC_FD, NULL);
 }
  
 static void fd_reset_listening_sockets(void)
@@ -107,17 +108,26 @@ static void fd_reset_listening_sockets(void)
             continue;
         fdset_del_fd(&fdset, &polldata, &fdset_used, &fdset_size, config->fd);
     }
+    fdset_del_fd(&fdset, &polldata, &fdset_used, &fdset_size, disasociated_ipc_fd);
 }
 
 /* ------------------ */
 static void afp_goaway(int sig)
 {
-    switch( sig ) {
+    AFPConfig *config;
 
-    case SIGTERM :
-        LOG(log_note, logtype_afpd, "AFP Server shutting down on SIGTERM");
-        AFPConfig *config;
+    switch( sig ) {
 
+    case SIGTERM:
+    case SIGQUIT:
+        switch (sig) {
+        case SIGTERM:
+            LOG(log_note, logtype_afpd, "AFP Server shutting down on SIGTERM");
+            break;
+        case SIGQUIT:
+            LOG(log_note, logtype_afpd, "AFP Server shutting down on SIGQUIT, NOT disconnecting clients");
+            break;
+        }
         if (server_children)
             server_child_kill(server_children, CHILD_DSIFORK, sig);
 
@@ -180,6 +190,26 @@ static void child_handler(int sig _U_)
     }
 }
 
+static int setlimits(void)
+{
+    struct rlimit rlim;
+
+    if (getrlimit(RLIMIT_NOFILE, &rlim) != 0) {
+        LOG(log_error, logtype_afpd, "setlimits: %s", strerror(errno));
+        exit(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);
+        }
+    }
+    return 0;
+}
+
 int main(int ac, char **av)
 {
     AFPConfig           *config;
@@ -247,7 +277,7 @@ int main(int ac, char **av)
     sigaddset(&sv.sa_mask, SIGHUP);
     sigaddset(&sv.sa_mask, SIGTERM);
     sigaddset(&sv.sa_mask, SIGUSR1);
-    
+    sigaddset(&sv.sa_mask, SIGQUIT);    
     sv.sa_flags = SA_RESTART;
     if ( sigaction( SIGCHLD, &sv, NULL ) < 0 ) {
         LOG(log_error, logtype_afpd, "main: sigaction: %s", strerror(errno) );
@@ -260,6 +290,7 @@ int main(int ac, char **av)
     sigaddset(&sv.sa_mask, SIGTERM);
     sigaddset(&sv.sa_mask, SIGHUP);
     sigaddset(&sv.sa_mask, SIGCHLD);
+    sigaddset(&sv.sa_mask, SIGQUIT);
     sv.sa_flags = SA_RESTART;
     if ( sigaction( SIGUSR1, &sv, NULL ) < 0 ) {
         LOG(log_error, logtype_afpd, "main: sigaction: %s", strerror(errno) );
@@ -271,6 +302,7 @@ int main(int ac, char **av)
     sigaddset(&sv.sa_mask, SIGTERM);
     sigaddset(&sv.sa_mask, SIGUSR1);
     sigaddset(&sv.sa_mask, SIGCHLD);
+    sigaddset(&sv.sa_mask, SIGQUIT);
     sv.sa_flags = SA_RESTART;
     if ( sigaction( SIGHUP, &sv, NULL ) < 0 ) {
         LOG(log_error, logtype_afpd, "main: sigaction: %s", strerror(errno) );
@@ -283,12 +315,25 @@ int main(int ac, char **av)
     sigaddset(&sv.sa_mask, SIGHUP);
     sigaddset(&sv.sa_mask, SIGUSR1);
     sigaddset(&sv.sa_mask, SIGCHLD);
+    sigaddset(&sv.sa_mask, SIGQUIT);
     sv.sa_flags = SA_RESTART;
     if ( sigaction( SIGTERM, &sv, NULL ) < 0 ) {
         LOG(log_error, logtype_afpd, "main: sigaction: %s", strerror(errno) );
         exit(EXITERR_SYS);
     }
 
+    sigemptyset( &sv.sa_mask );
+    sigaddset(&sv.sa_mask, SIGALRM);
+    sigaddset(&sv.sa_mask, SIGHUP);
+    sigaddset(&sv.sa_mask, SIGUSR1);
+    sigaddset(&sv.sa_mask, SIGCHLD);
+    sigaddset(&sv.sa_mask, SIGTERM);
+    sv.sa_flags = SA_RESTART;
+    if (sigaction(SIGQUIT, &sv, NULL ) < 0 ) {
+        LOG(log_error, logtype_afpd, "main: sigaction: %s", strerror(errno) );
+        exit(EXITERR_SYS);
+    }
+
     /* afpd.conf: not in config file: lockfile, connections, configfile
      *            preference: command-line provides defaults.
      *                        config file over-writes defaults.
@@ -324,9 +369,15 @@ int main(int ac, char **av)
 #endif
     
     /* watch atp, dsi sockets and ipc parent/child file descriptor. */
+    disasociated_ipc_fd = ipc_server_uds(_PATH_AFP_IPC);
     fd_set_listening_sockets();
 
+    /* set limits */
+    (void)setlimits();
+
     afp_child_t *child;
+    int fd[2];  /* we only use one, but server_child_add expects [2] */
+    pid_t pid;
 
     /* wait for an appleshare connection. parent remains in the loop
      * while the children get handled by afp_over_{asp,dsi}.  this is
@@ -378,8 +429,9 @@ int main(int ac, char **av)
         }
 
         for (int i = 0; i < fdset_used; i++) {
-            if (fdset[i].revents & POLLIN) {
+            if (fdset[i].revents & (POLLIN | POLLERR | POLLHUP)) {
                 switch (polldata[i].fdtype) {
+
                 case LISTEN_FD:
                     config = (AFPConfig *)polldata[i].data;
                     /* config->server_start is afp_config.c:dsi_start() for DSI */
@@ -388,15 +440,42 @@ int main(int ac, char **av)
                         fdset_add_fd(&fdset, &polldata, &fdset_used, &fdset_size, child->ipc_fds[0], IPC_FD, child);
                     }
                     break;
+
                 case IPC_FD:
                     child = (afp_child_t *)polldata[i].data;
                     LOG(log_debug, logtype_afpd, "main: IPC request from child[%u]", child->pid);
+
                     if ((ret = ipc_server_read(server_children, child->ipc_fds[0])) == 0) {
                         fdset_del_fd(&fdset, &polldata, &fdset_used, &fdset_size, child->ipc_fds[0]);
                         close(child->ipc_fds[0]);
                         child->ipc_fds[0] = -1;
+                        if (child->disasociated) {
+                            LOG(log_note, logtype_afpd, "main: removing reattached child[%u]", child->pid);
+                            server_child_remove(server_children, CHILD_DSIFORK, child->pid);
+                        }
                     }
                     break;
+
+                case DISASOCIATED_IPC_FD:
+                    LOG(log_debug, logtype_afpd, "main: IPC reconnect request");
+                    if ((fd[0] = accept(disasociated_ipc_fd, NULL, NULL)) == -1) {
+                        LOG(log_error, logtype_afpd, "main: accept: %s", strerror(errno));
+                        break;
+                    }
+                    if (readt(fd[0], &pid, sizeof(pid_t), 0, 1) != sizeof(pid_t)) {
+                        LOG(log_error, logtype_afpd, "main: readt: %s", strerror(errno));
+                        close(fd[0]);
+                    }
+                    LOG(log_note, logtype_afpd, "main: IPC reconnect from [%u]", pid);
+                    if ((child = server_child_add(server_children, CHILD_DSIFORK, pid, fd)) == NULL) {
+                        LOG(log_error, logtype_afpd, "main: server_child_add");
+                        close(fd[0]);
+                        break;
+                    }
+                    child->disasociated = 1;
+                    fdset_add_fd(&fdset, &polldata, &fdset_used, &fdset_size, fd[0], IPC_FD, child);
+                    break;
+
                 default:
                     LOG(log_debug, logtype_afpd, "main: IPC request for unknown type");
                     break;
index 6c6ed75dceefdd55ecbb7195d09a83426e93330d..dce7e61681ac8e646ad4ed5ef810d39dacade824 100644 (file)
@@ -13,8 +13,8 @@
 #include <atalk/adouble.h>
 #include <atalk/cnid.h>
 #include <atalk/logger.h>
+#include <atalk/globals.h>
 
-#include "globals.h"
 #include "volume.h"
 #include "directory.h"
 
index 975ec7a975fda8156ad4738e87152c006c80d2a4..e48585e353b1d2ab4dff76cc3ebb46812853a8ca 100644 (file)
@@ -16,7 +16,8 @@
 #include <atalk/dsi.h>
 #include <atalk/util.h>
 #include <atalk/logger.h>
-#include "globals.h"
+#include <atalk/globals.h>
+
 #include "misc.h"
 
 
index 33a83432c88243aec33451f596199d3f328f9145..b18826df7be9cb2907672161f5ce0ca38df362cb 100644 (file)
@@ -1,7 +1,7 @@
 #ifndef AFPD_MISC_H
 #define AFPD_MISC_H 1
 
-#include "globals.h"
+#include <atalk/globals.h>
 
 /* FP functions */
 /* messages.c */
index 7e2d3d57630a3b28a76011d227db44abacc8a5e0..4e0eb886901718f4a0a4f79d183714e1a1f14ea2 100644 (file)
 #include <atalk/util.h>
 #include <atalk/bstrlib.h>
 #include <atalk/bstradd.h>
+#include <atalk/globals.h>
+#include <atalk/fce_api.h>
 
-#include "globals.h"
 #include "volume.h"
 #include "directory.h"
 #include "fork.h"
 
-/* we need to have a hashed list of oforks (by dev inode). just hash
- * by first letter. */
+/* we need to have a hashed list of oforks (by dev inode) */
 #define OFORK_HASHSIZE  64
-static struct ofork     *ofork_table[OFORK_HASHSIZE];
-
-static struct ofork **oforks = NULL;
+static struct ofork *ofork_table[OFORK_HASHSIZE]; /* forks hashed by dev/inode */
+static struct ofork **oforks = NULL;              /* point to allocated table of open forks pointers */
 static int          nforks = 0;
 static u_short      lastrefnum = 0;
 
@@ -40,12 +39,6 @@ static u_short      lastrefnum = 0;
 /* OR some of each character for the hash*/
 static unsigned long hashfn(const struct file_key *key)
 {
-#if 0
-    unsigned long i = 0;
-    while (*name) {
-        i = ((i << 4) | (8*sizeof(i) - 4)) ^ *name++;
-    }
-#endif
     return key->inode & (OFORK_HASHSIZE - 1);
 }
 
@@ -404,6 +397,12 @@ int of_closefork(struct ofork *ofork)
             }
         }
     }
+
+    /* Somone has used write_fork, we assume file was changed, register it to file change event api */
+    if (ofork->of_flags & AFPFORK_MODIFIED) {
+        fce_register_file_modification(ofork);
+    }
+
     ret = 0;
 
     ad_unlock(ofork->of_ad, ofork->of_refnum);
index 24b6b8077a9223203a4fe4e78e817ee29113aa61..0782228ad952c3b99c31274cea6abacbf44489b0 100644 (file)
@@ -33,8 +33,8 @@
 #include <atalk/dsi.h>
 #include <atalk/unicode.h>
 #include <atalk/util.h>
+#include <atalk/globals.h>
 
-#include "globals.h"  /* includes <netdb.h> */
 #include "status.h"
 #include "afp_config.h"
 #include "icon.h"
index 260ca852a1dbaec6ba6aec606a4fd5250e81852e..6bae26fa6c8bc7b98c2bcb50c5252684a050c64a 100644 (file)
@@ -2,7 +2,8 @@
 #define AFPD_STATUS_H 1
 
 #include <atalk/dsi.h>
-#include "globals.h"
+#include <atalk/globals.h>
+
 #include "afp_config.h"
 
 /* we use these to prevent whacky alignment problems */
index 7dbd9ab77315f57eba5a8c4aa0d1c8bc0d360472..5c98e8df57d511565c8d3366a5306925efb74ff6 100644 (file)
@@ -31,8 +31,7 @@
 
 #include <atalk/afp.h>
 #include <atalk/uam.h>
-
-#include "globals.h"
+#include <atalk/globals.h>
 
 /* grab the FP functions */
 #include "auth.h" 
index 5ebf617cf84ab3933944cc0262eeae1d0a8e7312..0f5afb41c4a4e0f15e67f771d543e34fa5731a24 100644 (file)
@@ -29,8 +29,8 @@
 #include <atalk/dsi.h>
 #include <atalk/afp.h>
 #include <atalk/util.h>
+#include <atalk/globals.h>
 
-#include "globals.h"
 #include "afp_config.h"
 #include "auth.h"
 #include "uam_auth.h"
index 368dc3b60d0556c02c84f4ce08cdd30cb0643f1a..a553ffabff4aaac03c3f787c4e42b77d27c69a39 100644 (file)
@@ -11,7 +11,7 @@
 #include <pwd.h>
 
 #include <atalk/uam.h>
-#include "globals.h"
+#include <atalk/globals.h>
 
 struct uam_mod {
     void *uam_module;
index 23bd2c16444d62e68ed614fd60b1e1191f4e8ff7..1b442093239c31fc8dc190a65625b591868d0fca 100644 (file)
@@ -19,6 +19,8 @@
 #include <sys/socket.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
+#include <inttypes.h>
+#include <time.h>
 
 #include <atalk/dsi.h>
 #include <atalk/adouble.h>
 #include <atalk/ea.h>
 #include <atalk/bstrlib.h>
 #include <atalk/bstradd.h>
+#include <atalk/ftw.h>
+#include <atalk/globals.h>
+#include <atalk/fce_api.h>
 
 #ifdef CNID_DB
 #include <atalk/cnid.h>
 #endif /* CNID_DB*/
 
-#include "globals.h"
 #include "directory.h"
 #include "file.h"
 #include "volume.h"
@@ -52,17 +56,6 @@ extern int afprun(int root, char *cmd, int *outfd);
 #define MIN(a, b) ((a) < (b) ? (a) : (b))
 #endif /* ! MIN */
 
-#ifndef NO_LARGE_VOL_SUPPORT
-#if BYTE_ORDER == BIG_ENDIAN
-#define hton64(x)       (x)
-#define ntoh64(x)       (x)
-#else /* BYTE_ORDER == BIG_ENDIAN */
-#define hton64(x)       ((u_int64_t) (htonl(((x) >> 32) & 0xffffffffLL)) | \
-                         (u_int64_t) ((htonl(x) & 0xffffffffLL) << 32))
-#define ntoh64(x)       (hton64(x))
-#endif /* BYTE_ORDER == BIG_ENDIAN */
-#endif /* ! NO_LARGE_VOL_SUPPORT */
-
 #ifndef UUID_PRINTABLE_STRING_LENGTH
 #define UUID_PRINTABLE_STRING_LENGTH 37
 #endif
@@ -451,11 +444,8 @@ static void volset(struct vol_option *options, struct vol_option *save,
                 options[VOLOPT_FLAGS].i_value |= AFPVOL_TM;
             else if (strcasecmp(p, "searchdb") == 0)
                 options[VOLOPT_FLAGS].i_value |= AFPVOL_SEARCHDB;
-/* Found this in branch dir-rewrite, maybe we want to use it sometimes */
-#if 0
-            else if (strcasecmp(p, "cdrom") == 0)
-                options[VOLOPT_FLAGS].i_value |= AFPVOL_CDROM | AFPVOL_RO;
-#endif
+            else if (strcasecmp(p, "nonetids") == 0)
+                options[VOLOPT_FLAGS].i_value |= AFPVOL_NONETIDS;
             p = strtok(NULL, ",");
         }
 
@@ -1133,12 +1123,22 @@ static int readvolfile(AFPObj *obj, struct afp_volume_name *p1, char *p2, int us
         p1->mtime = st.st_mtime;
     }
 
-    if ((read_lock(fd, 0, SEEK_SET, 0)) != 0) {
-        LOG(log_error, logtype_afpd, "readvolfile: can't lock volume file \"%s\"", path);
-        if ( fclose( fp ) != 0 ) {
-            LOG(log_error, logtype_afpd, "readvolfile: fclose: %s", strerror(errno) );
+    /* try putting a read lock on the volume file twice, sleep 1 second if first attempt fails */
+    int retries = 2;
+    while (1) {
+        if ((read_lock(fd, 0, SEEK_SET, 0)) != 0) {
+            retries--;
+            if (!retries) {
+                LOG(log_error, logtype_afpd, "readvolfile: can't lock volume file \"%s\"", path);
+                if ( fclose( fp ) != 0 ) {
+                    LOG(log_error, logtype_afpd, "readvolfile: fclose: %s", strerror(errno) );
+                }
+                return -1;
+            }
+            sleep(1);
+            continue;
         }
-        return -1;
+        break;
     }
 
     memset(save_options, 0, sizeof(save_options));
@@ -1344,12 +1344,72 @@ static void volume_unlink(struct vol *volume)
     }
 }
 
+static off_t getused_size; /* result of getused() */
+
+/*!
+  nftw callback for getused()
+ */
+static int getused_stat(const char *path,
+                        const struct stat *statp,
+                        int tflag,
+                        struct FTW *ftw)
+{
+    off_t low, high;
+
+    if (tflag == FTW_F || tflag == FTW_D) {
+        getused_size += statp->st_blocks * 512;
+    }
+
+    return 0;
+}
+
+#define GETUSED_CACHETIME 5
+/*!
+ * Calculate used size of a volume with nftw
+ *
+ * The result is cached, we're try to avoid frequently calling nftw()
+ *
+ * 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
+ *
+ * @param vol     (rw) volume to calculate
+ */
+static int getused(struct vol *vol)
+{
+    static time_t vol_mtime = 0;
+    int ret = 0;
+    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);
+    }
+
+    return ret;
+}
+
 static int getvolspace(struct vol *vol,
                        u_int32_t *bfree, u_int32_t *btotal,
                        VolSpace *xbfree, VolSpace *xbtotal, u_int32_t *bsize)
 {
     int         spaceflag, rc;
     u_int32_t   maxsize;
+    VolSpace    used;
 #ifndef NO_QUOTA_SUPPORT
     VolSpace    qfree, qtotal;
 #endif
@@ -1388,45 +1448,14 @@ static int getvolspace(struct vol *vol,
 
 getvolspace_done:
     if (vol->v_limitsize) {
-        bstring cmdstr;
-        if ((cmdstr = bformat("du -sh \"%s\" 2> /dev/null | cut -f1", vol->v_path)) == NULL)
+        if (getused(vol) != 0)
             return AFPERR_MISC;
-
-        FILE *cmd = popen(cfrombstr(cmdstr), "r");
-        bdestroy(cmdstr);
-        if (cmd == NULL)
-            return AFPERR_MISC;
-
-        char buf[100];
-        fgets(buf, 100, cmd);
-
-        if (pclose(cmd) == -1)
-            return AFPERR_MISC;
-
-        size_t multi = 0;
-        if (buf[strlen(buf) - 2] == 'G' || buf[strlen(buf) - 2] == 'g')
-            /* GB */
-            multi = 1024 * 1024 * 1024;
-        else if (buf[strlen(buf) - 2] == 'M' || buf[strlen(buf) - 2] == 'm')
-            /* MB */
-            multi = 1024 * 1024;
-        else if (buf[strlen(buf) - 2] == 'K' || buf[strlen(buf) - 2] == 'k')
-            /* MB */
-            multi = 1024;
-
-        char *p;
-        if (p = strchr(buf, ','))
-            /* ignore fraction */
-            *p = 0;
-        else
-            /* remove G|M|K char */
-            buf[strlen(buf) - 2] = 0;
-        /* now buf contains only digits */
-        long long used = atoll(buf) * multi;
-        LOG(log_debug, logtype_afpd, "volparams: used on volume: %llu bytes", used);
+        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 < used ? 0 : *xbtotal - used);
+        *xbfree = min(*xbfree, *xbtotal < getused_size ? 0 : *xbtotal - getused_size);
     }
 
     *bfree = min( *xbfree, maxsize);
@@ -1434,6 +1463,22 @@ getvolspace_done:
     return( AFP_OK );
 }
 
+#define FCE_TM_DELTA 10  /* send notification every 10 seconds */
+void vol_fce_tm_event(void)
+{
+    static time_t last;
+    time_t now = time(NULL);
+    struct vol  *vol = Volumes;
+
+    if ((last + FCE_TM_DELTA) < now) {
+        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);
+        }
+    }
+}
+
 /* -----------------------
  * set volume creation date
  * avoid duplicate, well at least it tries
@@ -1544,7 +1589,8 @@ static int getvolparams( u_int16_t bitmap, struct vol *vol, struct stat *st, cha
                         ashort |= VOLPBIT_ATTR_UNIXPRIV;
                     if (vol->v_flags & AFPVOL_TM)
                         ashort |= VOLPBIT_ATTR_TM;
-
+                    if (vol->v_flags & AFPVOL_NONETIDS)
+                        ashort |= VOLPBIT_ATTR_NONETIDS;
                     if (afp_version >= 32) {
                         if (vol->v_vfs_ea)
                             ashort |= VOLPBIT_ATTR_EXT_ATTRS;
@@ -2389,12 +2435,6 @@ void setvoltime(AFPObj *obj, struct vol *vol)
 {
     struct timeval  tv;
 
-    /* just looking at vol->v_mtime is broken seriously since updates
-     * from other users afpd processes never are seen.
-     * This is not the most elegant solution (a shared memory between
-     * the afpd processes would come closer)
-     * [RS] */
-
     if ( gettimeofday( &tv, NULL ) < 0 ) {
         LOG(log_error, logtype_afpd, "setvoltime(%s): gettimeofday: %s", vol->v_path, strerror(errno) );
         return;
index a0b45940a1397036370df7029d3800c803100d08..f06dcd7bf2f4c33de5a42dbce9fdd53b5a941c91 100644 (file)
 #include <atalk/volume.h>
 #include <atalk/cnid.h>
 #include <atalk/unicode.h>
-
-#include "globals.h"
-#if 0
-#include "hash.h"
-#endif
+#include <atalk/globals.h>
 
 extern struct vol       *getvolbyvid (const u_int16_t);
 extern int              ustatfs_getvolspace (const struct vol *,
@@ -27,6 +23,7 @@ extern int              pollvoltime (AFPObj *);
 extern void             load_volumes (AFPObj *obj);
 extern const struct vol *getvolumes(void);
 extern void             unload_volumes_and_extmap(void);
+extern void             vol_fce_tm_event(void);
 
 /* FP functions */
 int afp_openvol      (AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf,  size_t *rbuflen);
index b23d57cf41d5f6208615d2ddcec968c98742d580..2c8e3c92e948528de237b8b3670474bdd0027c80 100644 (file)
@@ -407,6 +407,26 @@ static void set_signal(void)
     sigprocmask(SIG_BLOCK, &set, NULL);
 }
 
+static int setlimits(void)
+{
+    struct rlimit rlim;
+
+    if (getrlimit(RLIMIT_NOFILE, &rlim) != 0) {
+        LOG(log_error, logtype_afpd, "setlimits: %s", strerror(errno));
+        exit(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);
+        }
+    }
+    return 0;
+}
+
 /* ------------------ */
 int main(int argc, char *argv[])
 {
@@ -487,6 +507,8 @@ int main(int argc, char *argv[])
         daemon_exit(1);
     }
 
+    (void)setlimits();
+
     /* Check PID lockfile and become a daemon */
     switch(server_lock("cnid_metad", _PATH_CNID_METAD_LOCK, debug)) {
     case -1: /* error */
index 46c0d9700b7248fae5a424dd52d9109135dfdd29..b95e1587f7e81dc56fcaf1fd9039ac3bfb5a90f4 100644 (file)
@@ -32,7 +32,7 @@
 
 #include <atalk/afp.h>
 #include <atalk/uam.h>
-#include "../afpd/globals.h"
+#include <atalk/globals.h>
 
 /* Number of bits for p which we generate. Everybode out there uses 512, so we beet them */
 #define PRIMEBITS 1024
index b2084834fb63127b5b189883d9c26c8344ab68fc..fb1d55dc16839a2025b6d8904cfa39e81dafb3ea 100644 (file)
@@ -41,11 +41,13 @@ noinst_HEADERS = \
        compat.h \
        dsi.h \
        ldapconfig.h \
-       list.h
+       list.h \
+       globals.h \
+       fce_api.h
 
 BUILT_SOURCES = lockrpc.gen.h
 EXTRADIST = lockrpc.gen.h
 lockrpc.gen.h: $(top_srcdir)/libevent/event_rpcgen.py $(top_srcdir)/libatalk/rpc/lockrpc.rpc
        cd $(top_srcdir)/libatalk/rpc/ \
                && $(top_srcdir)/libevent/event_rpcgen.py lockrpc.rpc \
-               && mv lockrpc.gen.h $(top_srcdir)/include/atalk
\ No newline at end of file
+               && mv lockrpc.gen.h $(top_srcdir)/include/atalk
index 47434759232d7dde8a511e2cf53da1b7eaf637df..e474faf59fec95c9b1bdc27e81edaa767a1e54ad 100644 (file)
@@ -71,6 +71,8 @@ struct dir {
     uint32_t    d_offcnt;             /* offspring count */
     uint16_t    d_vid;                /* only needed in the dircache, because
                                          we put all directories in one cache. */
+    uint32_t    d_rights_cache;       /* cached rights combinded from mode and possible ACL */
+
     /* Stuff used in the dircache */
     time_t      dcache_ctime;         /* inode ctime, used and modified by dircache */
     ino_t       dcache_ino;           /* inode number, used to detect changes in the dircache */
index 7b90b38e561ab4c70eaee95c32718c889b5ddfb5..baaa960c9f031f838c025f4856231975ee406f23 100644 (file)
 #include <sys/socket.h>
 #include <signal.h>
 #include <arpa/inet.h>
-
 #include <netinet/in.h>
+
 #include <atalk/afp.h>
 #include <atalk/server_child.h>
+#include <atalk/globals.h>
 
 /* What a DSI packet looks like:
  0                               32
@@ -55,6 +56,7 @@ struct dsi_block {
 /* child and parent processes might interpret a couple of these
  * differently. */
 typedef struct DSI {
+  AFPObj *AFPobj;
   dsi_proto protocol;
   struct dsi_block header;
   struct sockaddr_storage server, client;
@@ -153,6 +155,7 @@ typedef struct DSI {
 #define DSI_RECONSOCKET      (1 << 7) /* we have a new socket from primary reconnect */
 #define DSI_RECONINPROG      (1 << 8) /* used in the new session in reconnect */
 #define DSI_AFP_LOGGED_OUT   (1 << 9) /* client called afp_logout, quit on next EOF from socket */
+#define DSI_GOT_ECONNRESET   (1 << 10) /* got ECONNRESET from client => exit */
 
 /* basic initialization: dsi_init.c */
 extern DSI *dsi_init (const dsi_proto /*protocol*/,
@@ -181,6 +184,7 @@ 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_disconnect(DSI *dsi);
 
 #ifdef WITH_SENDFILE
 extern ssize_t dsi_stream_read_file(DSI *, int, off_t off, const size_t len);
diff --git a/include/atalk/fce_api.h b/include/atalk/fce_api.h
new file mode 100755 (executable)
index 0000000..b6111e4
--- /dev/null
@@ -0,0 +1,60 @@
+/* 
+ * File:   fce_api.h
+ * Author: mw
+ *
+ * Created on 1. Oktober 2010, 21:35
+ *
+ * API calls for file change event api
+ */
+
+#ifndef _FCE_API_H
+#define        _FCE_API_H
+
+/* fce_packet.mode */
+#define FCE_FILE_MODIFY     1
+#define FCE_FILE_DELETE     2
+#define FCE_DIR_DELETE      3
+#define FCE_FILE_CREATE     4
+#define FCE_DIR_CREATE      5
+#define FCE_TM_SIZE         6
+#define FCE_CONN_START     42
+#define FCE_CONN_BROKEN    99
+
+
+/* fce_packet.fce_magic */
+#define FCE_PACKET_MAGIC  "at_fcapi"
+
+/* This packet goes over the network, so we want to
+ * be shure about datastructs and type sizes between platforms.
+ * Format is network byte order.
+ */
+#define FCE_PACKET_HEADER_SIZE 8+1+1+4+2
+struct fce_packet
+{
+    char magic[8];
+    unsigned char version;
+    unsigned char mode;
+    uint32_t event_id;
+    uint16_t datalen;
+    char data[MAXPATHLEN];
+};
+
+struct path;
+struct ofork;
+
+int fce_register_delete_file( struct path *path );
+int fce_register_delete_dir( char *name );
+int fce_register_new_dir( struct path *path );
+int fce_register_new_file( struct path *path );
+int fce_register_file_modification( struct ofork *ofork );
+int fce_register_tm_size(const char *vol, size_t used);
+
+int fce_add_udp_socket(const char *target );  // IP or IP:Port
+int fce_set_coalesce( char *coalesce_opt ); // all|delete|create
+int fce_set_events(const char *events);     /* fmod,fdel,ddel,fcre,dcre,tmsz (default is all except tmsz) */
+
+#define FCE_DEFAULT_PORT 12250
+#define FCE_DEFAULT_PORT_STRING "12250"
+
+#endif /* _FCE_API_H */
+
diff --git a/include/atalk/globals.h b/include/atalk/globals.h
new file mode 100644 (file)
index 0000000..f1b8bd5
--- /dev/null
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 1990,1993 Regents of The University of Michigan.
+ * All Rights Reserved.  See COPYRIGHT.
+ */
+
+#ifndef AFPD_GLOBALS_H
+#define AFPD_GLOBALS_H 1
+
+#include <sys/param.h>
+
+#ifdef ADMIN_GRP
+#include <grp.h>
+#include <sys/types.h>
+#endif /* ADMIN_GRP */
+
+#ifdef HAVE_NETDB_H
+#include <netdb.h>  /* this isn't header-protected under ultrix */
+#endif /* HAVE_NETDB_H */
+
+#include <netatalk/at.h>
+#include <atalk/afp.h>
+#include <atalk/compat.h>
+#include <atalk/unicode.h>
+#include <atalk/uam.h>
+
+/* #define DOSFILELEN 12 */             /* Type1, DOS-compat*/
+#define MACFILELEN 31                   /* Type2, HFS-compat */
+#define UTF8FILELEN_EARLY 255           /* Type3, early Mac OS X 10.0-10.4.? */
+/* #define UTF8FILELEN_NAME_MAX 765 */  /* Type3, 10.4.?- , getconf NAME_MAX */
+/* #define UTF8FILELEN_SPEC 0xFFFF */   /* Type3, spec on document */
+/* #define HFSPLUSFILELEN 510 */        /* HFS+ spec, 510byte = 255codepoint */
+
+#define MAXUSERLEN 256
+
+#define OPTION_DEBUG         (1 << 0)
+#define OPTION_USERVOLFIRST  (1 << 1)
+#define OPTION_NOUSERVOL     (1 << 2)
+#define OPTION_PROXY         (1 << 3)
+#define OPTION_CUSTOMICON    (1 << 4)
+#define OPTION_NOSLP         (1 << 5)
+#define OPTION_ANNOUNCESSH   (1 << 6)
+#define OPTION_UUID          (1 << 7)
+#define OPTION_ACL2MACCESS   (1 << 8)
+#define OPTION_NOZEROCONF    (1 << 9)
+
+/* a couple of these options could get stuck in unions to save
+ * space. */
+struct afp_volume_name {
+    time_t     mtime;
+    char       *name;
+    char       *full_name;
+    int        loaded;
+};
+
+struct afp_options {
+    int connections, transports, tickleval, timeout, server_notif, flags, dircachesize;
+    int sleep;                  /* Maximum time allowed to sleep (in tickles) */
+    int disconnected;           /* Maximum time in disconnected state (in tickles) */
+    unsigned int tcp_sndbuf, tcp_rcvbuf;
+    unsigned char passwdbits, passwdminlen, loginmaxfail;
+    u_int32_t server_quantum;
+    int dsireadbuf; /* scale factor for sizefof(dsi->buffer) = server_quantum * dsireadbuf */
+    char hostname[MAXHOSTNAMELEN + 1], *server, *ipaddr, *port, *configfile;
+    char *uampath, *fqdn;
+    char *pidfile;
+    char *sigconffile;
+    char *uuidconf;
+    struct afp_volume_name defaultvol, systemvol, uservol;
+    int  closevol;
+
+    char *guest, *loginmesg, *keyfile, *passwdfile;
+    char *uamlist;
+    char *authprintdir;
+    char *signatureopt;
+    unsigned char signature[16];
+    char *k5service, *k5realm, *k5keytab;
+    char *unixcodepage,*maccodepage;
+    charset_t maccharset, unixcharset; 
+    mode_t umask;
+    mode_t save_mask;
+#ifdef ADMIN_GRP
+    gid_t admingid;
+#endif /* ADMIN_GRP */
+    int    volnamelen;
+
+    /* default value for winbind authentication */
+    char *ntdomain, *ntseparator;
+    char *logconfig;
+
+    char *mimicmodel;
+};
+
+#define AFPOBJ_TMPSIZ (MAXPATHLEN)
+typedef struct _AFPObj {
+    int proto;
+    unsigned long servernum;
+    void *handle;               /* either (DSI *) or (ASP *) */
+    void *config; 
+    struct afp_options options;
+    char *Obj, *Type, *Zone;
+    char username[MAXUSERLEN];
+    void (*logout)(void), (*exit)(int);
+    int (*reply)(void *, int);
+    int (*attention)(void *, AFPUserBytes);
+    /* to prevent confusion, only use these in afp_* calls */
+    char oldtmp[AFPOBJ_TMPSIZ + 1], newtmp[AFPOBJ_TMPSIZ + 1];
+    void *uam_cookie; /* cookie for uams */
+    struct session_info  sinfo;
+    uid_t uid;         /* client running user id */
+    int ipc_fd; /* anonymous PF_UNIX socket for IPC with afpd parent */
+} AFPObj;
+
+/* typedef for AFP functions handlers */
+typedef int (*AFPCmd)(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf,  size_t *rbuflen);
+
+/* afp_dsi.c */
+extern AFPObj *AFPobj;
+
+extern int             afp_version;
+extern int             afp_errno;
+extern unsigned char   nologin;
+extern struct dir      *curdir;
+extern char            getwdbuf[];
+
+/* FIXME CNID */
+extern const char *Cnid_srv;
+extern const char *Cnid_port;
+
+extern int  get_afp_errno   (const int param);
+extern void afp_options_init (struct afp_options *);
+extern int afp_options_parse (int, char **, struct afp_options *);
+extern int afp_options_parseline (char *, struct afp_options *);
+extern void afp_options_free (struct afp_options *,
+                                      const struct afp_options *);
+extern void setmessage (const char *);
+extern void readmessage (AFPObj *);
+
+/* gettok.c */
+extern void initline   (int, char *);
+extern int  parseline  (int, char *);
+
+/* afp_util.c */
+extern const char *AfpNum2name (int );
+extern const char *AfpErr2name(int err);
+
+/* directory.c */
+extern struct dir rootParent;
+
+extern void afp_over_dsi (AFPObj *);
+
+#endif /* globals.h */
index 689d8b6133cf42eba0d2d9112d57a24d10e43d78..bca1d703fbf044079cdb5388f522f717ac94cbbf 100644 (file)
@@ -75,6 +75,7 @@
 #  define _PATH_AFPDLOCK       ATALKPATHCAT(_PATH_LOCKDIR,"afpd.pid")
 #else
 #  define _PATH_AFPDLOCK       ATALKPATHCAT(_PATH_LOCKDIR,"afpd")
+#define _PATH_AFP_IPC       ATALKPATHCAT(_PATH_LOCKDIR,"afpd_ipc")
 #endif
 
 /*
index 4ad6a2f29bdc755ae526b6d83d64295b082ad58b..6e4575ee5d8876784ace1e08c73bc865a6caaea4 100644 (file)
@@ -26,8 +26,9 @@ typedef struct server_child_data {
   pid_t     pid;               /* afpd worker process pid (from the worker afpd process )*/
   uid_t     uid;               /* user id of connected client (from the worker afpd process) */
   int       valid;             /* 1 if we have a clientid */
-  uint32_t  time;              /* client boot time (from the mac client) */
   int       killed;            /* 1 if we already tried to kill the client */
+  int       disasociated; /* 1 if this is not a child, but a child from a previous afpd master */
+  uint32_t  time;              /* client boot time (from the mac client) */
   uint32_t  idlen;             /* clientid len (from the Mac client) */
   char      *clientid;  /* clientid (from the Mac client) */
   int       ipc_fds[2]; /* socketpair for IPC bw */
index 332897a0993bd2f34ca3be79f942bfd75fe27818..aca04f80f8f33ea6b180083c252452836c21caff 100644 (file)
@@ -2,11 +2,15 @@
 #define ATALK_SERVER_IPC_H
 
 #include <atalk/server_child.h>
+#include <atalk/globals.h>
 
 #define IPC_DISCOLDSESSION   0
 #define IPC_GETSESSION       1
 
-int ipc_server_read(server_child *children, int fd);
-int ipc_child_write(int fd, uint16_t command, int len, void *token);
+extern int ipc_server_uds(const char *name);
+extern int ipc_client_uds(const char *name);
+extern int reconnect_ipc(AFPObj *);
+extern int ipc_server_read(server_child *children, int fd);
+extern int ipc_child_write(int fd, uint16_t command, int len, void *token);
 
 #endif /* IPC_GETSESSION_LOGIN */
index ea85325745cc6ae20bc2eb25fdd2f06a8ad1d29d..d0499c6fecefa16472bb75d36e95d1400595d7da 100644 (file)
@@ -76,6 +76,8 @@ struct session_info {
   size_t  cryptedkey_len;
   void    *sessiontoken;        /* session token sent to the client on FPGetSessionToken*/
   size_t  sessiontoken_len;
+  void    *clientid;          /* whole buffer cotaining eg idlen, id and boottime */
+  size_t  clientid_len;
 };
 
 /* register and unregister uams with these functions */
index 1a428bda88de08f5166f3bfe9c8c1176e92aaf4c..5149acd9c308104913e0955d399e1507f95689fa 100644 (file)
 #define ZERO_STRUCT(a) memset(&(a), 0, sizeof(a))
 #define ZERO_STRUCTP(a) memset((a), 0, sizeof(a))
 
+#if BYTE_ORDER == BIG_ENDIAN
+#define hton64(x)       (x)
+#define ntoh64(x)       (x)
+#else /* BYTE_ORDER == BIG_ENDIAN */
+#define hton64(x)       ((uint64_t) (htonl(((x) >> 32) & 0xffffffffLL)) | \
+                         (uint64_t) ((htonl(x) & 0xffffffffLL) << 32))
+#define ntoh64(x)       (hton64(x))
+#endif /* BYTE_ORDER == BIG_ENDIAN */
+
 #ifdef WITH_SENDFILE
 extern ssize_t sys_sendfile (int __out_fd, int __in_fd, off_t *__offset,size_t __count);
 #endif
@@ -131,7 +140,7 @@ extern void apply_ip_mask(struct sockaddr *ai, int maskbits);
 extern int compare_ip(const struct sockaddr *sa1, const struct sockaddr *sa2);
 
 /* Structures and functions dealing with dynamic pollfd arrays */
-enum fdtype {IPC_FD, LISTEN_FD};
+enum fdtype {IPC_FD, LISTEN_FD, DISASOCIATED_IPC_FD};
 struct polldata {
     enum fdtype fdtype; /* IPC fd or listening socket fd                 */
     void *data;         /* pointer to AFPconfig for listening socket and *
index 7746768116d5d96f34ece35fa1d97eaa01b3ce0f..ba47fd09a224db3eb73c424d4bc253198216b8da 100644 (file)
 typedef const unsigned char *uuidp_t;
 typedef unsigned char atalk_uuid_t[UUID_BINSIZE];
 
-typedef enum {UUID_USER = 1, UUID_GROUP, UUID_LOCAL} uuidtype_t;
+typedef enum {UUID_USER   = 0,
+              UUID_GROUP  = 1,
+              UUID_ENOENT = 4} /* used as bit flag */
+    uuidtype_t;
+#define UUIDTYPESTR_MASK 3
 extern char *uuidtype[];
 
 /* afp_options.c needs these. defined in libatalk/ldap.c */
@@ -45,5 +49,6 @@ extern int getnamefromuuid( const unsigned char *uuid, char **name, uuidtype_t *
 extern void localuuid_from_id(unsigned char *buf, uuidtype_t type, unsigned int id);
 extern const char *uuid_bin2string(const unsigned char *uuid);
 extern void uuid_string2bin( const char *uuidstring, unsigned char *uuid);
+extern void uuidcache_dump(void);
 
 #endif /* AFP_UUID_H */
index da367964c389f0cc98033b26be16b966fc2299d5..2d8019283bd0760f71fcb9ade7032b114182e4ad 100644 (file)
@@ -61,7 +61,9 @@ struct vol {
     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 */
+    
     /* only when opening/closing volumes or in error */
     int             v_casefold;
     char            *v_localname;   /* as defined in AppleVolumes.default */
@@ -127,10 +129,7 @@ struct vol {
 #define AFPVOL_TM        (1 << 23)   /* Supports TimeMachine */
 #define AFPVOL_ACLS      (1 << 24)   /* Volume supports ACLS */
 #define AFPVOL_SEARCHDB  (1 << 25)   /* Use fast CNID db search instead of filesystem */
-/* Found this in branch dir-rewrite, maybe we want to use it sometimes */
-#if 0
-#define AFPVOL_CDROM     (1 << XX)   /* Ejectable media eg CD -> in memory CNID db */
-#endif
+#define AFPVOL_NONETIDS  (1 << 26)   /* signal the client it shall do privelege mapping */
 
 /* Extended Attributes vfs indirection  */
 #define AFPVOL_EA_NONE           0   /* No EAs */
@@ -169,7 +168,7 @@ int wincheck(const struct vol *vol, const char *path);
 #define VOLPBIT_ATTR_BLANKACCESS  (1 << 4)
 #define VOLPBIT_ATTR_UNIXPRIV     (1 << 5)
 #define VOLPBIT_ATTR_UTF8         (1 << 6)
-#define VOLPBIT_ATTR_NONETUID     (1 << 7)
+#define VOLPBIT_ATTR_NONETIDS     (1 << 7)
 #define VOLPBIT_ATTR_EXT_ATTRS    (1 << 10)
 #define VOLPBIT_ATTR_ACLS         (1 << 11)
 #define VOLPBIT_ATTR_TM           (1 << 13)
index ee4d3f2295494306d54ca28853181e77ea8d93bd..86bc34dcfd59bf4bbb81c9785a072b502fda4e4c 100644 (file)
@@ -44,7 +44,7 @@ cacheduser_t *uuidcache[256];   /* indexed by hash of uuid */
  * helper function
  ********************************************************/
 
-static int dumpcache() {
+void uuidcache_dump(void) {
     int i;
     int ret = 0;
     cacheduser_t *entry;
@@ -59,8 +59,14 @@ static int dumpcache() {
                     continue;
                 if (strftime(timestr, 200, "%c", tmp) == 0)
                     continue;
-                LOG(log_debug9, logtype_default, "namecache{%d}: name:%s, uuid:%s, type: %s, cached: %s",
-                    i, entry->name, uuid_bin2string(entry->uuid), uuidtype[entry->type], timestr);
+                LOG(log_debug, logtype_default,
+                    "namecache{%d}: name:%s, uuid:%s, type%s: %s, cached: %s",
+                    i,
+                    entry->name,
+                    uuid_bin2string(entry->uuid),
+                    (entry->type & UUID_ENOENT) == UUID_ENOENT ? "[negative]" : "",
+                    uuidtype[entry->type & UUIDTYPESTR_MASK],
+                    timestr);
             } while ((entry = entry->next) != NULL);
         }
     }
@@ -74,13 +80,17 @@ static int dumpcache() {
                     continue;
                 if (strftime(timestr, 200, "%c", tmp) == 0)
                     continue;
-                LOG(log_debug9, logtype_default, "uuidcache{%d}: uuid:%s, name:%s, type: %s, cached: %s",
-                    i, uuid_bin2string(entry->uuid), entry->name, uuidtype[entry->type], timestr);
+                LOG(log_debug, logtype_default,
+                    "uuidcache{%d}: uuid:%s, name:%s, type%s: %s, cached: %s",
+                    i,
+                    uuid_bin2string(entry->uuid),
+                    entry->name,
+                    (entry->type & UUID_ENOENT) == UUID_ENOENT ? "[negative]" : "",
+                    uuidtype[entry->type & UUIDTYPESTR_MASK],
+                    timestr);
             } while ((entry = entry->next) != NULL);
         }
     }
-
-    return ret;
 }
 
 /* hash string it into unsigned char */
@@ -121,10 +131,6 @@ int add_cachebyname( const char *inname, const uuidp_t inuuid, const uuidtype_t
     cacheduser_t *cacheduser = NULL;
     unsigned char hash;
 
-#ifdef DEBUG
-    dumpcache();
-#endif
-
     /* allocate mem and copy values */
     name = malloc(strlen(inname)+1);
     if (!name) {
@@ -181,26 +187,25 @@ cleanup:
             free(cacheduser);
     }
 
-#ifdef DEBUG
-    dumpcache();
-#endif
-
     return ret;
 }
 
-/* 
- * Caller provides buffer uuid for result
+/*!
+ * Search cache by name and uuid type
+ *
+ * @args name     (r)  name to search
+ * @args type     (rw) type (user or group) of name, returns found type here which might
+ *                     mark it as a negative entry
+ * @args uuid     (w)  found uuid is returned here
+ * @returns       0 on sucess, entry found
+ *                -1 no entry found
  */
-int search_cachebyname( const char *name, uuidtype_t type, unsigned char *uuid) {
+int search_cachebyname( const char *name, uuidtype_t *type, unsigned char *uuid) {
     int ret;
     unsigned char hash;
     cacheduser_t *entry;
     time_t tim;
 
-#ifdef DEBUG
-    dumpcache();
-#endif
-
     hash = hashstring((unsigned char *)name);
 
     if (namecache[hash] == NULL)
@@ -209,11 +214,11 @@ int search_cachebyname( const char *name, uuidtype_t type, unsigned char *uuid)
     entry = namecache[hash];
     while (entry) {
         ret = strcmp(entry->name, name);
-        if (ret == 0 && type == entry->type) {
+        if (ret == 0 && *type == (entry->type & UUIDTYPESTR_MASK)) {
             /* found, now check if expired */
             tim = time(NULL);
             if ((tim - entry->creationtime) > CACHESECONDS) {
-                LOG(log_debug, logtype_default, "search_cachebyname: expired: name:\'%s\' in queue {%d}", entry->name, hash);
+                LOG(log_debug, logtype_default, "search_cachebyname: expired: name:\"%s\"", entry->name);
                 /* remove item */
                 if (entry->prev) {
                     /* 2nd to last in queue */
@@ -229,23 +234,16 @@ int search_cachebyname( const char *name, uuidtype_t type, unsigned char *uuid)
                 free(entry->name);
                 free(entry->uuid);
                 free(entry);
-#ifdef DEBUG
-                dumpcache();
-#endif
                 return -1;
             } else {
                 memcpy(uuid, entry->uuid, UUID_BINSIZE);
-#ifdef DEBUG
-                dumpcache();
-#endif
+                *type = entry->type;
                 return 0;
             }
         }
         entry = entry->next;
     }
-#ifdef DEBUG
-    dumpcache();
-#endif
+
     return -1;
 }
 
@@ -258,10 +256,6 @@ int search_cachebyuuid( uuidp_t uuidp, char **name, uuidtype_t *type) {
     cacheduser_t *entry;
     time_t tim;
 
-#ifdef DEBUG
-    dumpcache();
-#endif
-
     hash = hashuuid(uuidp);
 
     if (! uuidcache[hash])
@@ -288,27 +282,17 @@ int search_cachebyuuid( uuidp_t uuidp, char **name, uuidtype_t *type) {
                 free(entry->name);
                 free(entry->uuid);
                 free(entry);
-#ifdef DEBUG
-                dumpcache();
-#endif
                 return -1;
             } else {
                 *name = malloc(strlen(entry->name)+1);
                 strcpy(*name, entry->name);
                 *type = entry->type;
-#ifdef DEBUG
-                dumpcache();
-#endif
                 return 0;
             }
         }
         entry = entry->next;
     }
 
-#ifdef DEBUG
-    dumpcache();
-#endif
-
     return -1;
 }
 
@@ -320,10 +304,6 @@ int add_cachebyuuid( uuidp_t inuuid, const char *inname, uuidtype_t type, const
     cacheduser_t *entry;
     unsigned char hash;
 
-#ifdef DEBUG
-    dumpcache();
-#endif
-
     /* allocate mem and copy values */
     name = malloc(strlen(inname)+1);
     if (!name) {
@@ -380,9 +360,5 @@ cleanup:
             free(cacheduser);
     }
 
-#ifdef DEBUG
-    dumpcache();
-#endif
-
     return ret;
 }
index c83be1cd16dbd4a2152724c2343838b6a0f15d90..11731a26c69d5bdeb683be1667a8c2c6bd351e03 100644 (file)
  * Interface
  ********************************************************/
 
-/* 
- *   name: search for this name
- *   type: of type USER or GROUP
- *   uuid: if found copies uuid into this buffer
- * returns 0 on success, !=0 if not found or on errors
- */
-extern int search_cachebyname( const char *name, uuidtype_t type, unsigned char *uuid);
-
-/* 
- *   inname: name
- *   inuuid: uuid
- *   type: USER or GROUP
- *   (uid: unused)
- * returns 0 on success, !=0 on memory errors
- */
+extern int search_cachebyname( const char *name, uuidtype_t *type, unsigned char *uuid);
 extern int add_cachebyname( const char *inname, const uuidp_t inuuid, const uuidtype_t type, const unsigned long uid);
-
-/* same as above but for the uuid cache */
 extern int search_cachebyuuid( uuidp_t uuidp, char **name, uuidtype_t *type);
 extern int add_cachebyuuid( uuidp_t inuuid, const char *inname, uuidtype_t type, const unsigned long uid);
 
index 28f8e1b4e52228d997e3beb81a18b77903ccb148..4fad0407ae5b1fa60a8ea2243d68037313b79608 100644 (file)
@@ -34,7 +34,7 @@
 #include "aclldap.h"
 #include "cache.h"
 
-char *uuidtype[] = {"NULL","USER", "GROUP", "LOCAL"};
+char *uuidtype[] = {"USER", "GROUP", "LOCAL"};
 
 /********************************************************
  * Public helper function
@@ -42,7 +42,7 @@ char *uuidtype[] = {"NULL","USER", "GROUP", "LOCAL"};
 
 static unsigned char local_group_uuid[] = {0xab, 0xcd, 0xef,
                                            0xab, 0xcd, 0xef,
-                                           0xab, 0xcd, 0xef, 
+                                           0xab, 0xcd, 0xef,
                                            0xab, 0xcd, 0xef};
 
 static unsigned char local_user_uuid[] = {0xff, 0xff, 0xee, 0xee, 0xdd, 0xdd,
@@ -68,7 +68,7 @@ void localuuid_from_id(unsigned char *buf, uuidtype_t type, unsigned int id)
     return;
 }
 
-/* 
+/*
  * convert ascii string that can include dashes to binary uuid.
  * caller must provide a buffer.
  */
@@ -101,9 +101,9 @@ void uuid_string2bin( const char *uuidstring, unsigned char *uuid) {
 
 }
 
-/*! 
+/*!
  * Convert 16 byte binary uuid to neat ascii represantation including dashes.
- * 
+ *
  * Returns pointer to static buffer.
  */
 const char *uuid_bin2string(const unsigned char *uuid) {
@@ -133,24 +133,34 @@ const char *uuid_bin2string(const unsigned char *uuid) {
  *   type: and type (UUID_USER or UUID_GROUP)
  *   uuid: pointer to uuid_t storage that the caller must provide
  * returns 0 on success !=0 on errror
- */  
+ */
 int getuuidfromname( const char *name, uuidtype_t type, unsigned char *uuid) {
     int ret = 0;
+    uuidtype_t mytype = type;
+    char nulluuid[16] = {0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0};
 #ifdef HAVE_LDAP
     char *uuid_string = NULL;
 #endif
-    ret = search_cachebyname( name, type, uuid);
+
+    ret = search_cachebyname(name, &mytype, uuid);
+
     if (ret == 0) {
         /* found in cache */
-        LOG(log_debug, logtype_afpd, "getuuidfromname{cache}: name: %s, type: %s -> UUID: %s",
-            name, uuidtype[type], uuid_bin2string(uuid));
+        LOG(log_debug, logtype_afpd,
+            "getuuidfromname{cache}: name: %s, type%s: %s -> UUID: %s",
+            name,
+            (mytype & UUID_ENOENT) == UUID_ENOENT ? "[negative]" : "",
+            uuidtype[type & UUIDTYPESTR_MASK],
+            uuid_bin2string(uuid));
+        if ((mytype & UUID_ENOENT) == UUID_ENOENT)
+            return -1;
     } else  {
         /* if not found in cache */
 #ifdef HAVE_LDAP
         if ((ret = ldap_getuuidfromname( name, type, &uuid_string)) == 0) {
             uuid_string2bin( uuid_string, uuid);
-            LOG(log_debug, logtype_afpd, "getuuidfromname{local}: name: %s, type: %s -> UUID: %s",
-                name, uuidtype[type], uuid_bin2string(uuid));
+            LOG(log_debug, logtype_afpd, "getuuidfromname{LDAP}: name: %s, type: %s -> UUID: %s",
+                name, uuidtype[type & UUIDTYPESTR_MASK], uuid_bin2string(uuid));
         } else {
             LOG(log_debug, logtype_afpd, "getuuidfromname(\"%s\",t:%u): no result from ldap search",
                 name, type);
@@ -162,24 +172,31 @@ int getuuidfromname( const char *name, uuidtype_t type, unsigned char *uuid) {
                 struct passwd *pwd;
                 if ((pwd = getpwnam(name)) == NULL) {
                     LOG(log_error, logtype_afpd, "getuuidfromname(\"%s\",t:%u): unknown user",
-                        name, uuidtype[type]);
-                    goto cleanup;
+                        name, uuidtype[type & UUIDTYPESTR_MASK]);
+                    mytype |= UUID_ENOENT;
+                    memcpy(uuid, nulluuid, 16);
+                } else {
+                    localuuid_from_id(uuid, UUID_USER, pwd->pw_uid);
+                    ret = 0;
+                    LOG(log_debug, logtype_afpd, "getuuidfromname{local}: name: %s, type: %s -> UUID: %s",
+                        name, uuidtype[type & UUIDTYPESTR_MASK], uuid_bin2string(uuid));
                 }
-                localuuid_from_id(uuid, UUID_USER, pwd->pw_uid);
             } else {
                 struct group *grp;
                 if ((grp = getgrnam(name)) == NULL) {
                     LOG(log_error, logtype_afpd, "getuuidfromname(\"%s\",t:%u): unknown user",
-                        name, uuidtype[type]);
-                    goto cleanup;
+                        name, uuidtype[type & UUIDTYPESTR_MASK]);
+                    mytype |= UUID_ENOENT;
+                    memcpy(uuid, nulluuid, 16);
+                } else {
+                    localuuid_from_id(uuid, UUID_GROUP, grp->gr_gid);
+                    ret = 0;
+                    LOG(log_debug, logtype_afpd, "getuuidfromname{local}: name: %s, type: %s -> UUID: %s",
+                        name, uuidtype[type & UUIDTYPESTR_MASK], uuid_bin2string(uuid));
                 }
-                localuuid_from_id(uuid, UUID_GROUP, grp->gr_gid);
             }
-            LOG(log_debug, logtype_afpd, "getuuidfromname{local}: name: %s, type: %s -> UUID: %s",
-                name, uuidtype[type], uuid_bin2string(uuid));
         }
-        ret = 0;
-        add_cachebyname( name, uuid, type, 0);
+        add_cachebyname(name, uuid, mytype, 0);
     }
 
 cleanup:
@@ -198,40 +215,74 @@ cleanup:
  *
  * Caller must free name appropiately.
  */
-int getnamefromuuid(uuidp_t uuidp, char **name, uuidtype_t *type) {
-    int ret;
+int getnamefromuuid(const uuidp_t uuidp, char **name, uuidtype_t *type) {
+    int ret = 0;
+    uid_t uid;
+    gid_t gid;
+    struct passwd *pwd;
+    struct group *grp;
 
-    ret = search_cachebyuuid( uuidp, name, type);
-    if (ret == 0) {
+    if (search_cachebyuuid(uuidp, name, type) == 0) {
         /* found in cache */
-        LOG(log_debug9, logtype_afpd, "getnamefromuuid{cache}: UUID: %s -> name: %s, type:%s",
-            uuid_bin2string(uuidp), *name, uuidtype[*type]);
-    } else {
-        /* not found in cache */
-
-        /* Check if UUID is a client local one */
-        if (memcmp(uuidp, local_user_uuid, 12) == 0
-            || memcmp(uuidp, local_group_uuid, 12) == 0) {
-            LOG(log_debug, logtype_afpd, "getnamefromuuid: local UUID: %" PRIu32 "",
-                ntohl(*(uint32_t *)(uuidp + 12)));
-            *type = UUID_LOCAL;
-            *name = strdup("UUID_LOCAL");
-            return 0;
+        LOG(log_debug, logtype_afpd,
+            "getnamefromuuid{cache}: UUID: %s -> name: %s, type%s: %s",
+            uuid_bin2string(uuidp),
+            *name,
+            (*type & UUID_ENOENT) == UUID_ENOENT ? "[negative]" : "",
+            uuidtype[(*type) & UUIDTYPESTR_MASK]);
+        if ((*type & UUID_ENOENT) == UUID_ENOENT)
+            return -1;
+        return 0;
+    }
+
+    /* not found in cache */
+
+    /* Check if UUID is a client local one */
+    if (memcmp(uuidp, local_user_uuid, 12) == 0) {
+        *type = UUID_USER;
+        uid = ntohl(*(uint32_t *)(uuidp + 12));
+        if ((pwd = getpwuid(uid)) == NULL) {
+            /* not found, add negative entry to cache */
+            add_cachebyuuid(uuidp, "UUID_ENOENT", UUID_ENOENT, 0);
+            ret = -1;
+        } else {
+            *name = strdup(pwd->pw_name);
+            add_cachebyuuid(uuidp, *name, *type, 0);
+            ret = 0;
         }
+        LOG(log_debug, logtype_afpd,
+            "getnamefromuuid{local}: UUID: %s -> name: %s, type:%s",
+            uuid_bin2string(uuidp), *name, uuidtype[(*type) & UUIDTYPESTR_MASK]);
+        return ret;
+    } else if (memcmp(uuidp, local_group_uuid, 12) == 0) {
+        *type = UUID_GROUP;
+        gid = ntohl(*(uint32_t *)(uuidp + 12));
+        if ((grp = getgrgid(gid)) == NULL) {
+            /* not found, add negative entry to cache */
+            add_cachebyuuid(uuidp, "UUID_ENOENT", UUID_ENOENT, 0);
+            ret = -1;
+        } else {
+            *name = strdup(grp->gr_name);
+            add_cachebyuuid(uuidp, *name, *type, 0);
+            ret = 0;
+        }
+        return ret;
+    }
 
 #ifdef HAVE_LDAP
-        ret = ldap_getnamefromuuid(uuid_bin2string(uuidp), name, type);
-        if (ret != 0) {
-            LOG(log_warning, logtype_afpd, "getnamefromuuid(%s): no result from ldap_getnamefromuuid",
-                uuid_bin2string(uuidp));
-            goto cleanup;
-        }
-        add_cachebyuuid( uuidp, *name, *type, 0);
-        LOG(log_debug, logtype_afpd, "getnamefromuuid{LDAP}: UUID: %s -> name: %s, type:%s",
-            uuid_bin2string(uuidp), *name, uuidtype[*type]);
-#endif
+    ret = ldap_getnamefromuuid(uuid_bin2string(uuidp), name, type);
+    if (ret != 0) {
+        LOG(log_warning, logtype_afpd, "getnamefromuuid(%s): no result from ldap_getnamefromuuid",
+            uuid_bin2string(uuidp));
+        add_cachebyuuid(uuidp, "UUID_ENOENT", UUID_ENOENT, 0);
+        return -1;
     }
+#endif
 
-cleanup:
-    return ret;
+    add_cachebyuuid(uuidp, *name, *type, 0);
+
+    LOG(log_debug, logtype_afpd, "getnamefromuuid{LDAP}: UUID: %s -> name: %s, type:%s",
+        uuid_bin2string(uuidp), *name, uuidtype[(*type) & UUIDTYPESTR_MASK]);
+
+    return 0;
 }
index b7e1f4035f856b3480ef37bfd249139e77624a58..0d105ea920810801f99ce8d5bfa41c4717bd8197 100644 (file)
@@ -325,7 +325,7 @@ static int dbd_rpc(CNID_private *db, struct cnid_dbd_rqst *rqst, struct cnid_dbd
     ret = readt(db->fd, rply, sizeof(struct cnid_dbd_rply), 0, ONE_DELAY);
 
     if (ret != sizeof(struct cnid_dbd_rply)) {
-        LOG(log_error, logtype_cnid, "dbd_rpc: Error reading header from fd (db_dir %s): %s",
+        LOG(log_debug, logtype_cnid, "dbd_rpc: Error reading header from fd (db_dir %s): %s",
             db->db_dir, ret == -1 ? strerror(errno) : "closed");
         rply->name = nametmp;
         return -1;
index 5ea32b01a4afb8bccd46dce7ad76a2656a24880e..a50136db6a3d9ec3c4e04ca1f5fe196bd2200a74 100644 (file)
@@ -56,7 +56,7 @@ afp_child_t *dsi_getsession(DSI *dsi, server_child *serv_children, int tickleval
   default: /* parent */
     /* using SIGQUIT is hokey, but the child might not have
      * re-established its signal handler for SIGTERM yet. */
-    if ((child = server_child_add(serv_children, CHILD_DSIFORK, pid, ipc_fds)) < 0) {
+    if ((child = server_child_add(serv_children, CHILD_DSIFORK, pid, ipc_fds)) ==  NULL) {
       LOG(log_error, logtype_dsi, "dsi_getsess: %s", strerror(errno));
       dsi->header.dsi_flags = DSIFL_REPLY;
       dsi->header.dsi_code = DSIERR_SERVBUSY;
index 90df884efee6a1e054da359564a77f7e4122e4cd..4b92d2259ed7f5ea13a734909ed4c523ef90473d 100644 (file)
@@ -121,6 +121,135 @@ static int dsi_peek(DSI *dsi)
     return 0;
 }
 
+/* 
+ * Return all bytes up to count from dsi->buffer if there are any buffered there
+ */
+static size_t from_buf(DSI *dsi, u_int8_t *buf, size_t count)
+{
+    size_t nbe = 0;
+
+    if (dsi->buffer == NULL)
+        /* afpd master has no DSI buffering */
+        return 0;
+
+    LOG(log_maxdebug, logtype_dsi, "from_buf: %u bytes", count);
+    
+    nbe = dsi->eof - dsi->start;
+
+    if (nbe > 0) {
+        nbe = min((size_t)nbe, count);
+        memcpy(buf, dsi->start, nbe);
+        dsi->start += nbe;
+
+        if (dsi->eof == dsi->start)
+            dsi->start = dsi->eof = dsi->buffer;
+    }
+
+    LOG(log_debug, logtype_dsi, "from_buf(read: %u, unread:%u , space left: %u): returning %u",
+        dsi->start - dsi->buffer, dsi->eof - dsi->start, dsi->end - dsi->eof, nbe);
+
+    return nbe;
+}
+
+/*
+ * Get bytes from buffer dsi->buffer or read from socket
+ *
+ * 1. Check if there are bytes in the the dsi->buffer buffer.
+ * 2. Return bytes from (1) if yes.
+ *    Note: this may return fewer bytes then requested in count !!
+ * 3. If the buffer was empty, read from the socket.
+ */
+static ssize_t buf_read(DSI *dsi, u_int8_t *buf, size_t count)
+{
+    ssize_t len;
+
+    LOG(log_maxdebug, logtype_dsi, "buf_read(%u bytes)", count);
+
+    if (!count)
+        return 0;
+
+    len = from_buf(dsi, buf, count); /* 1. */
+    if (len)
+        return len;             /* 2. */
+  
+    len = readt(dsi->socket, buf, count, 0, 1); /* 3. */
+
+    LOG(log_maxdebug, logtype_dsi, "buf_read(%u bytes): got: %d", count, len);
+
+    return len;
+}
+
+/*
+ * Get "length" bytes from buffer and/or socket. In order to avoid frequent small reads
+ * this tries to read larger chunks (8192 bytes) into a buffer.
+ */
+static size_t dsi_buffered_stream_read(DSI *dsi, u_int8_t *data, const size_t length)
+{
+  size_t len;
+  size_t buflen;
+
+  LOG(log_maxdebug, logtype_dsi, "dsi_buffered_stream_read: %u bytes", length);
+  
+  len = from_buf(dsi, data, length); /* read from buffer dsi->buffer */
+  dsi->read_count += len;
+  if (len == length) {          /* got enough bytes from there ? */
+      return len;               /* yes */
+  }
+
+  /* fill the buffer with 8192 bytes or until buffer is full */
+  buflen = min(8192, dsi->end - dsi->eof);
+  if (buflen > 0) {
+      ssize_t ret;
+      ret = read(dsi->socket, dsi->eof, buflen);
+      if (ret > 0)
+          dsi->eof += ret;
+  }
+
+  /* now get the remaining data */
+  if ((buflen = dsi_stream_read(dsi, data + len, length - len)) != length - len)
+      return 0;
+  len += buflen;
+
+  return len;
+}
+
+/* ---------------------------------------
+*/
+static void block_sig(DSI *dsi)
+{
+  dsi->in_write++;
+}
+
+/* ---------------------------------------
+*/
+static void unblock_sig(DSI *dsi)
+{
+  dsi->in_write--;
+}
+
+/*********************************************************************************
+ * Public functions
+ *********************************************************************************/
+
+/*!
+ * Communication error with the client, enter disconnected state
+ *
+ * 1. close the socket
+ * 2. set the DSI_DISCONNECTED flag
+ *
+ * @returns  0 if successfully entered disconnected state
+ *          -1 if ppid is 1 which means afpd master died
+ *             or euid == 0 ie where still running as root (unauthenticated session)
+ */
+int dsi_disconnect(DSI *dsi)
+{
+    dsi->proto_close(dsi);          /* 1 */
+    dsi->flags |= DSI_DISCONNECTED; /* 2 */
+    if (geteuid() == 0)
+        return -1;
+    return 0;
+}
+
 /* ------------------------------
  * write raw data. return actual bytes read. checks against EINTR
  * aren't necessary if all of the signals have SA_RESTART
@@ -136,6 +265,9 @@ ssize_t dsi_stream_write(DSI *dsi, void *data, const size_t length, int mode)
 
   LOG(log_maxdebug, logtype_dsi, "dsi_stream_write: sending %u bytes", length);
 
+  if (dsi->flags & DSI_DISCONNECTED)
+      return -1;
+
   while (written < length) {
       len = send(dsi->socket, (u_int8_t *) data + written, length - written, flags);
       if (len >= 0) {
@@ -187,6 +319,9 @@ ssize_t dsi_stream_read_file(DSI *dsi, int fromfd, off_t offset, const size_t le
 
   LOG(log_maxdebug, logtype_dsi, "dsi_stream_read_file: sending %u bytes", length);
 
+  if (dsi->flags & DSI_DISCONNECTED)
+      return -1;
+
   dsi->in_write++;
   written = 0;
 
@@ -226,63 +361,6 @@ ssize_t dsi_stream_read_file(DSI *dsi, int fromfd, off_t offset, const size_t le
 }
 #endif
 
-/* 
- * Return all bytes up to count from dsi->buffer if there are any buffered there
- */
-static size_t from_buf(DSI *dsi, u_int8_t *buf, size_t count)
-{
-    size_t nbe = 0;
-
-    if (dsi->buffer == NULL)
-        /* afpd master has no DSI buffering */
-        return 0;
-
-    LOG(log_maxdebug, logtype_dsi, "from_buf: %u bytes", count);
-    
-    nbe = dsi->eof - dsi->start;
-
-    if (nbe > 0) {
-        nbe = min((size_t)nbe, count);
-        memcpy(buf, dsi->start, nbe);
-        dsi->start += nbe;
-
-        if (dsi->eof == dsi->start)
-            dsi->start = dsi->eof = dsi->buffer;
-    }
-
-    LOG(log_debug, logtype_dsi, "from_buf(read: %u, unread:%u , space left: %u): returning %u",
-        dsi->start - dsi->buffer, dsi->eof - dsi->start, dsi->end - dsi->eof, nbe);
-
-    return nbe;
-}
-
-/*
- * Get bytes from buffer dsi->buffer or read from socket
- *
- * 1. Check if there are bytes in the the dsi->buffer buffer.
- * 2. Return bytes from (1) if yes.
- *    Note: this may return fewer bytes then requested in count !!
- * 3. If the buffer was empty, read from the socket.
- */
-static ssize_t buf_read(DSI *dsi, u_int8_t *buf, size_t count)
-{
-    ssize_t len;
-
-    LOG(log_maxdebug, logtype_dsi, "buf_read(%u bytes)", count);
-
-    if (!count)
-        return 0;
-
-    len = from_buf(dsi, buf, count); /* 1. */
-    if (len)
-        return len;             /* 2. */
-  
-    len = readt(dsi->socket, buf, count, 0, 1); /* 3. */
-
-    LOG(log_maxdebug, logtype_dsi, "buf_read(%u bytes): got: %d", count, len);
-
-    return len;
-}
 
 /*
  * Essentially a loop around buf_read() to ensure "length" bytes are read
@@ -295,18 +373,23 @@ size_t dsi_stream_read(DSI *dsi, void *data, const size_t length)
   size_t stored;
   ssize_t len;
 
+  if (dsi->flags & DSI_DISCONNECTED)
+      return 0;
+
   LOG(log_maxdebug, logtype_dsi, "dsi_stream_read(%u bytes)", length);
 
   stored = 0;
   while (stored < length) {
       len = buf_read(dsi, (u_int8_t *) data + stored, length - stored);
       if (len == -1 && (errno == EINTR || errno == EAGAIN)) {
-          LOG(log_debug, logtype_dsi, "dsi_stream_read: select read loop");
+          LOG(log_maxdebug, logtype_dsi, "dsi_stream_read: select read loop");
           continue;
       } else if (len > 0) {
           stored += len;
       } else { /* eof or error */
           /* don't log EOF error if it's just after connect (OSX 10.3 probe) */
+          if (errno == ECONNRESET)
+              dsi->flags |= DSI_GOT_ECONNRESET;
           if (len || stored || dsi->read_count) {
               if (! (dsi->flags & DSI_DISCONNECTED)) {
                   LOG(log_error, logtype_dsi, "dsi_stream_read: len:%d, %s",
@@ -324,51 +407,6 @@ size_t dsi_stream_read(DSI *dsi, void *data, const size_t length)
   return stored;
 }
 
-/*
- * Get "length" bytes from buffer and/or socket. In order to avoid frequent small reads
- * this tries to read larger chunks (8192 bytes) into a buffer.
- */
-static size_t dsi_buffered_stream_read(DSI *dsi, u_int8_t *data, const size_t length)
-{
-  size_t len;
-  size_t buflen;
-
-  LOG(log_maxdebug, logtype_dsi, "dsi_buffered_stream_read: %u bytes", length);
-  
-  len = from_buf(dsi, data, length); /* read from buffer dsi->buffer */
-  dsi->read_count += len;
-  if (len == length) {          /* got enough bytes from there ? */
-      return len;               /* yes */
-  }
-
-  /* fill the buffer with 8192 bytes or until buffer is full */
-  buflen = min(8192, dsi->end - dsi->eof);
-  if (buflen > 0) {
-      ssize_t ret;
-      ret = read(dsi->socket, dsi->eof, buflen);
-      if (ret > 0)
-          dsi->eof += ret;
-  }
-
-  /* now get the remaining data */
-  len += dsi_stream_read(dsi, data + len, length - len);
-  return len;
-}
-
-/* ---------------------------------------
-*/
-static void block_sig(DSI *dsi)
-{
-  dsi->in_write++;
-}
-
-/* ---------------------------------------
-*/
-static void unblock_sig(DSI *dsi)
-{
-  dsi->in_write--;
-}
-
 /* ---------------------------------------
  * write data. 0 on failure. this assumes that dsi_len will never
  * cause an overflow in the data buffer. 
@@ -383,6 +421,9 @@ int dsi_stream_send(DSI *dsi, void *buf, size_t length)
   LOG(log_maxdebug, logtype_dsi, "dsi_stream_send: %u bytes",
       length ? length : sizeof(block));
 
+  if (dsi->flags & DSI_DISCONNECTED)
+      return 0;
+
   block[0] = dsi->header.dsi_flags;
   block[1] = dsi->header.dsi_command;
   memcpy(block + 2, &dsi->header.dsi_requestID, 
@@ -453,6 +494,9 @@ int dsi_stream_receive(DSI *dsi, void *buf, const size_t ilength,
 
   LOG(log_maxdebug, logtype_dsi, "dsi_stream_receive: %u bytes", ilength);
 
+  if (dsi->flags & DSI_DISCONNECTED)
+      return 0;
+
   /* read in the header */
   if (dsi_buffered_stream_read(dsi, (u_int8_t *)block, sizeof(block)) != sizeof(block)) 
     return 0;
index eb98f45b290d5817461b90498a399bfb5034bbf0..e13ada1750a8019900f9856ea6f8c902a7746768 100644 (file)
@@ -542,6 +542,7 @@ void make_log_entry(enum loglevels loglevel, enum logtypes logtype,
     if (type_configs[logtype].level >= log_debug)
         goto log; /* bypass flooding checks */
 
+    goto log;
     /* Prevent flooding: hash the message and check if we got the same one recently */
     int hash = hash_message(temp_buffer) + log_src_linenumber;
 
index 47e9baa2549bee28b42cbf1695f855e534476d89..34cec28d17d5b0d601a5fef0daacf0c8b3bbbe90 100644 (file)
@@ -273,6 +273,16 @@ int server_child_transfer_session(server_child *children,
     fork = (server_child_fork *) children->fork + forkid;
     if ((child = resolve_child(fork->table, pid)) == NULL) {
         LOG(log_note, logtype_default, "Reconnect: no child[%u]", pid);
+        if (kill(pid, 0) == 0) {
+            LOG(log_note, logtype_default, "Reconnect: terminating old session[%u]", pid);
+            kill(pid, SIGTERM);
+            sleep(2);
+            if (kill(pid, 0) == 0) {
+                LOG(log_error, logtype_default, "Reconnect: killing old session[%u]", pid);
+                kill(pid, SIGKILL);
+                sleep(2);
+            }
+        }
         return 0;
     }
 
index f00f83b39494d9d2be6e67414ba1c69c9feefca4..c258398d847d242944eb989d6348e59c84d2290e 100644 (file)
 #include <stdlib.h>
 #include <string.h>
 #include <sys/socket.h>
+#include <sys/un.h>
 #include <errno.h>
 #include <signal.h>
+#include <time.h>
 
 #include <atalk/server_child.h>
 #include <atalk/server_ipc.h>
 #include <atalk/logger.h>
 #include <atalk/util.h>
+#include <atalk/errchk.h>
+#include <atalk/paths.h>
+#include <atalk/globals.h>
+#include <atalk/dsi.h>
+
+#define IPC_HEADERLEN 14
+#define IPC_MAXMSGSIZE 90
 
 typedef struct ipc_header {
        uint16_t command;
@@ -97,8 +106,100 @@ static int ipc_get_session(struct ipc_header *ipc, server_child *children)
     return 0;
 }
 
-#define IPC_HEADERLEN 14
-#define IPC_MAXMSGSIZE 90
+/***********************************************************************************
+ * Public functions
+ ***********************************************************************************/
+
+/*!
+ * Listen on UNIX domain socket "name" for IPC from old sesssion
+ *
+ * @args name    (r) file name to use for UNIX domain socket
+ * @returns      socket fd, -1 on error
+ */
+int ipc_server_uds(const char *name)
+{
+    EC_INIT;
+    struct sockaddr_un address;
+    socklen_t address_length;
+    int fd = -1;
+
+    EC_NEG1_LOG( fd = socket(PF_UNIX, SOCK_STREAM, 0) );
+    EC_ZERO_LOG( setnonblock(fd, 1) );
+    unlink(name);
+    address.sun_family = AF_UNIX;
+    address_length = sizeof(address.sun_family) + sprintf(address.sun_path, name);
+    EC_ZERO_LOG( bind(fd, (struct sockaddr *)&address, address_length) );
+    EC_ZERO_LOG( listen(fd, 1024) );
+
+EC_CLEANUP:
+    if (ret != 0) {
+        return -1;
+    }
+
+    return fd;
+}
+
+/*!
+ * Connect to UNIX domain socket "name" for IPC with new afpd master
+ *
+ * 1. Connect
+ * 2. send pid, which establishes a child structure for us in the master
+ *
+ * @args name    (r) file name to use for UNIX domain socket
+ * @returns      socket fd, -1 on error
+ */
+int ipc_client_uds(const char *name)
+{
+    EC_INIT;
+    struct sockaddr_un address;
+    socklen_t address_length;
+    int fd = -1;
+    pid_t pid = getpid();
+
+    EC_NEG1_LOG( fd = socket(PF_UNIX, SOCK_STREAM, 0) );
+    EC_ZERO_LOG( setnonblock(fd, 1) );
+    address.sun_family = AF_UNIX;
+    address_length = sizeof(address.sun_family) + sprintf(address.sun_path, name);
+
+    EC_ZERO_LOG( connect(fd, (struct sockaddr *)&address, address_length) ); /* 1 */
+    LOG(log_debug, logtype_afpd, "ipc_client_uds: connected to master");
+
+    if (writet(fd, &pid, sizeof(pid_t), 0, 1) != sizeof(pid_t)) {
+        LOG(log_error, logtype_afpd, "ipc_client_uds: writet: %s", strerror(errno));
+        EC_FAIL;
+    }
+
+EC_CLEANUP:
+    if (ret != 0) {
+        return -1;
+    }
+    LOG(log_debug, logtype_afpd, "ipc_client_uds: fd: %d", fd);
+    return fd;
+}
+
+int reconnect_ipc(AFPObj *obj)
+{
+    int retrycount = 0;
+
+    LOG(log_debug, logtype_afpd, "reconnect_ipc: start");
+
+    close(obj->ipc_fd);
+    obj->ipc_fd = -1;
+
+    srandom(getpid());
+    sleep((random() % 5) + 5);  /* give it enough time to start */
+
+    while (retrycount++ < 10) {
+        if ((obj->ipc_fd = ipc_client_uds(_PATH_AFP_IPC)) == -1) {
+            LOG(log_error, logtype_afpd, "reconnect_ipc: cant reconnect to master");
+            sleep(1);
+            continue;
+        }
+        LOG(log_debug, logtype_afpd, "reconnect_ipc: succesfull IPC reconnect");
+        return 0;
+    }
+    return -1;
+}
 
 /* ----------------- 
  * Ipc format
@@ -106,7 +207,7 @@ static int ipc_get_session(struct ipc_header *ipc, server_child *children)
  * pid
  * uid
  * 
-*/
+ */
 
 /*!
  * Read a IPC message from a child
@@ -202,6 +303,8 @@ int ipc_child_write(int fd, uint16_t command, int len, void *msg)
    char block[IPC_MAXMSGSIZE], *p;
    pid_t pid;
    uid_t uid;
+   ssize_t ret;
+
    p = block;
 
    memset ( p, 0 , IPC_MAXMSGSIZE);
@@ -231,5 +334,9 @@ int ipc_child_write(int fd, uint16_t command, int len, void *msg)
 
    LOG(log_debug, logtype_afpd, "ipc_child_write(%s)", ipc_cmd_str[command]);
 
-   return write(fd, block, len+IPC_HEADERLEN );
+   if ((ret = writet(fd, block, len+IPC_HEADERLEN, 0, 1)) != len + IPC_HEADERLEN) {
+       return -1;
+   }
+
+   return 0;
 }
index 5bdc03c3a3d671a0a6f116b77444aba2276320ae..fe42cd76453c7ca9649817c344e2e9a5b0f82740 100644 (file)
 #include "config.h"
 #endif /* HAVE_CONFIG_H */
 
-#ifndef _XOPEN_SOURCE
-# define _XOPEN_SOURCE 600
-#endif
-#ifndef __EXTENSIONS__
-# define __EXTENSIONS__
-#endif
-#ifndef _GNU_SOURCE
-# define _GNU_SOURCE
+#if !defined(__FreeBSD__)
+# ifndef _XOPEN_SOURCE
+#  define _XOPEN_SOURCE 600
+# endif
+# ifndef __EXTENSIONS__
+#  define __EXTENSIONS__
+# endif
+# ifndef _GNU_SOURCE
+#  define _GNU_SOURCE
+# endif
 #endif
 #include <unistd.h>
 #include <fcntl.h>
@@ -128,10 +130,11 @@ ssize_t readt(int socket, void *data, const size_t length, int setnonblocking, i
                         goto exit;
 
                     default: /* -1 */
-                        if (errno == EINTR) {
+                        switch (errno) {
+                        case EINTR:
                             (void)gettimeofday(&now, NULL);
                             if (now.tv_sec >= end.tv_sec && now.tv_usec >= end.tv_usec) {
-                                LOG(log_warning, logtype_afpd, "select timeout %d s", timeout);
+                                LOG(log_debug, logtype_afpd, "select timeout %d s", timeout);
                                 goto exit;
                             }
                             if (now.tv_usec > end.tv_usec) {
@@ -143,10 +146,16 @@ ssize_t readt(int socket, void *data, const size_t length, int setnonblocking, i
                             }
                             FD_SET(socket, &rfds);
                             continue;
+                        case EBADF:
+                            /* possibly entered disconnected state, don't spam log here */
+                            LOG(log_debug, logtype_afpd, "select: %s", strerror(errno));
+                            stored = -1;
+                            goto exit;
+                        default:
+                            LOG(log_error, logtype_afpd, "select: %s", strerror(errno));
+                            stored = -1;
+                            goto exit;
                         }
-                        LOG(log_error, logtype_afpd, "select: %s", strerror(errno));
-                        stored = -1;
-                        goto exit;
                     }
                 } /* while (select) */
                 continue;
index f90603d0d37e20e4bf6c30cc2e0a764656398c68..6a32499079c6c5d58fed13632bbf9b14f354cf20 100644 (file)
@@ -594,13 +594,27 @@ if test x"$with_acl_support" = x"yes" ; then
                                        acl_perm_t perm;
                                        return acl_get_perm_np(permset_d, perm);
                                ],
-                               [samba_cv_HAVE_ACL_GET_PERM_NP=yes],
-                               [samba_cv_HAVE_ACL_GET_PERM_NP=no])
+                               [netatalk_cv_HAVE_ACL_GET_PERM_NP=yes],
+                               [netatalk_cv_HAVE_ACL_GET_PERM_NP=no])
                                LIBS=$acl_LIBS
                        ])
                        if test x"netatalk_cv_HAVE_ACL_GET_PERM_NP" = x"yes"; then
                                AC_DEFINE(HAVE_ACL_GET_PERM_NP,1,[Whether acl_get_perm_np() is available])
                        fi
+
+
+                       AC_CACHE_CHECK([for acl_from_mode], netatalk_cv_HAVE_ACL_FROM_MODE,[
+                               acl_LIBS=$LIBS
+                               LIBS="$LIBS $ACL_LIBS"
+                AC_CHECK_FUNCS(acl_from_mode,
+                               [netatalk_cv_HAVE_ACL_FROM_MODE=yes],
+                               [netatalk_cv_HAVE_ACL_FROM_MODE=no])
+                               LIBS=$acl_LIBS
+                       ])
+                       if test x"netatalk_cv_HAVE_ACL_FROM_MODE" = x"yes"; then
+                               AC_DEFINE(HAVE_ACL_FROM_MODE,1,[Whether acl_from_mode() is available])
+                       fi
+
                else
                        AC_MSG_NOTICE(ACL support is not avaliable)
                        AC_DEFINE(HAVE_NO_ACLS,1,[Whether no ACLs support is available])
@@ -610,6 +624,7 @@ if test x"$with_acl_support" = x"yes" ; then
 fi
 
 if test x"$with_acl_support" = x"yes" ; then
+   AC_CHECK_HEADERS([acl/libacl.h])
     AC_DEFINE(HAVE_ACLS,1,[Whether ACLs support is available])
     AC_SUBST(ACL_LIBS)
 fi
index 8d72f85c5477fdae3cabb6584fd0c55ebd59077a..8e9e5dfdd6f7362074d9ac3ee81cdfc7097aca02 100644 (file)
@@ -2,12 +2,12 @@
 .\"     Title: afppasswd
 .\"    Author: [FIXME: author] [see http://docbook.sf.net/el/author]
 .\" Generator: DocBook XSL Stylesheets v1.75.2 <http://docbook.sf.net/>
-.\"      Date: 22 Aug 2004
+.\"      Date: 31 May 2011
 .\"    Manual: Netatalk 2.2
 .\"    Source: Netatalk 2.2
 .\"  Language: English
 .\"
-.TH "AFPPASSWD" "1" "22 Aug 2004" "Netatalk 2.2" "Netatalk 2.2"
+.TH "AFPPASSWD" "1" "31 May 2011" "Netatalk 2.2" "Netatalk 2.2"
 .\" -----------------------------------------------------------------
 .\" * set default formatting
 .\" -----------------------------------------------------------------
@@ -43,7 +43,7 @@ can either be called by root with parameters, or can be called by local system u
 .ps -1
 .br
 .PP
-With this utility you can only change the passwords used by two specific UAMs\&. As they provide only weak password encryption, the use of the "Randnum exchange" and "2\-Way Randnum exchange" UAMs is deprecated unless one has to support very old AFP clients, that can not deal with the more secure "DHCAST128" UAM instead\&. Please compare with the
+With this utility you can only change the passwords used by two specific UAMs\&. As they provide only weak password encryption, the use of the "Randnum exchange" and "2\-Way Randnum exchange" UAMs is deprecated unless one has to support very old AFP clients, that can not deal with the more secure "DHCAST128" and "DHX2" UAM instead\&. Please compare with the
 Authentication chapter
 inside Netatalk\'s documentation\&.
 .sp .5v
index c6a1255bb7908c0ffd6885c5914dd2807ab4f7a8..716a7dc86e379df5154162b239e5e5adc338e9ce 100644 (file)
@@ -250,6 +250,11 @@ Use with
 \fBusedots\fR: make dot files invisible\&.
 .RE
 .PP
+nonetids
+.RS 4
+Try to force ACL unawareness on the client\&.
+.RE
+.PP
 limitsize
 .RS 4
 Limit disk size reporting to 2GB\&. This can be used for older Macintoshes using newer Appleshare clients\&.
@@ -277,7 +282,7 @@ a non\-zero return code from root_preexec closes the volume immediately, prevent
 .PP
 upriv
 .RS 4
-use AFP3 unix privileges\&. Become familiar with the new "unix privileges" AFP permissions concepts in MacOS X before using this option\&. See also:
+use AFP3 unix privileges\&. This should be set for OS X clients\&. Starting with Netatalk 2\&.1 it\'s part of the default config :DEFAULT: line\&. See also:
 \fBperm|fperm|dperm\fR\&.
 .RE
 .PP
index b3f099ff1641d7680581c5cecb5c7a7aa5045b2c..eb68d49a67ed34e243b02a2ec61f7b5198a02e16 100644 (file)
@@ -386,6 +386,25 @@ Maximum possible entries in the directory cache\&. The cache stores directories
 Default size is 8192, maximum size is 131072\&. Given value is rounded up to nearest power of 2\&. Each entry takes about 100 bytes, which is not much, but remember that every afpd child process for every connected user has its cache\&.
 .RE
 .PP
+\-fcelistener \fIhost[:port]\fR
+.RS 4
+Enables sending FCE events to the specified
+\fIhost\fR, default
+\fIport\fR
+is 12250 if not specified\&. Specifying mutliple listeners is done by having this option once for each of them\&.
+.RE
+.PP
+\-fceevents \fIfmod,fdel,ddel,fcre,dcre,tmsz\fR
+.RS 4
+Speficies which FCE events are active, default is
+\fIfmod,fdel,ddel,fcre,dcre\fR\&.
+.RE
+.PP
+\-fcecoalesce \fIall|delete|create\fR
+.RS 4
+Coalesce FCE events\&.
+.RE
+.PP
 \-guestname \fI[name]\fR
 .RS 4
 Specifies the user that guests should use (default is "nobody")\&. The name should be quoted\&.
@@ -403,6 +422,11 @@ Sets a message to be displayed when clients logon to the server\&. The message s
 and should be quoted\&. Extended characters are allowed\&.
 .RE
 .PP
+\-mimicmodel \fImodel\fR
+.RS 4
+Specifies the icon model that appears on clients\&. Defaults to off\&. Examples: RackMac (same as Xserve), PowerBook, PowerMac, Macmini, iMac, MacBook, MacBookPro, MacBookAir, MacPro, AppleTV1,1, AirPort\&.
+.RE
+.PP
 \-nodebug
 .RS 4
 Disables debugging\&.
index 63b340e443aae2480964367e66a7e715b5338dac..6ce60fd41ef68274000299dbcef1746e5557e6dc 100644 (file)
@@ -201,10 +201,6 @@ for the creation of folders in Netatalk\&.
 .RE
 .SH "SIGNALS"
 .PP
-Signals that are sent to the main
-\fBafpd\fR
-process are propagated to the children, so all will be affected\&.
-.PP
 To shut down a user\'s
 \fBafpd\fR
 process it is recommended that
@@ -216,6 +212,21 @@ is to send it a
 \fBSIGTERM (\-15)\fR
 signal and wait for it to die on its own\&.
 .PP
+SIGTERM and SIGUSR1 signals that are sent to the main
+\fBafpd\fR
+process are propagated to the children, so all will be affected\&.
+.PP
+SIGTERM
+.RS 4
+Clean exit\&. Propagates from master to childs\&.
+.RE
+.PP
+SIGQUIT
+.RS 4
+Send this to the master
+\fBafpd\fR, it will exit leaving all children running! Can be used to implement AFP service without downtime\&.
+.RE
+.PP
 SIGHUP
 .RS 4
 Sending a