]> arthur.barton.de Git - netatalk.git/blobdiff - etc/afpd/fork.c
Big configure.in cleanup
[netatalk.git] / etc / afpd / fork.c
index cfeccb1984543a979e1e65d07b1d09dd731126fc..0c9ccef9c3c6f5e318532cce3f653c0cbd425276 100644 (file)
@@ -1,7 +1,7 @@
 /*
- * $Id: fork.c,v 1.24 2002-03-07 16:06:01 jmarcus Exp $
- *
  * Copyright (c) 1990,1993 Regents of The University of Michigan.
+ * Copyright (c) 2010      Frank Lahm
+ *
  * All Rights Reserved.  See COPYRIGHT.
  */
 
 #endif /* HAVE_CONFIG_H */
 
 #include <stdio.h>
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif /* HAVE_UNISTD_H */
-#ifdef HAVE_FCNTL_H
-#include <fcntl.h>
-#endif /* HAVE_FCNTL_H */
-#include <dirent.h>
 #include <string.h>
 #include <errno.h>
-#include <atalk/logger.h>
-
 #include <sys/param.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/time.h>
 #include <sys/socket.h>
+#include <inttypes.h>
 
-#include <netatalk/endian.h>
 #include <netatalk/at.h>
-
 #include <atalk/dsi.h>
 #include <atalk/atp.h>
 #include <atalk/asp.h>
 #include <atalk/afp.h>
 #include <atalk/adouble.h>
+#include <atalk/logger.h>
 #include <atalk/util.h>
-#ifdef CNID_DB
 #include <atalk/cnid.h>
-#endif
+#include <atalk/bstradd.h>
 
 #include "fork.h"
 #include "file.h"
 #include "desktop.h"
 #include "volume.h"
 
-#define BYTELOCK_MAX 0x7FFFFFFFU
-
-struct ofork           *writtenfork;
+#ifdef AFS
+struct ofork *writtenfork;
+#endif
 
-static int getforkparams(ofork, bitmap, buf, buflen, attrbits )
-struct ofork   *ofork;
-u_int16_t              bitmap;
-char           *buf;
-int                    *buflen;
-const u_int16_t     attrbits;
+static int getforkparams(struct ofork *ofork, u_int16_t bitmap, char *buf, size_t *buflen)
 {
-#ifndef USE_LASTDID
-    struct stat                hst, lst, *lstp;
-#else /* USE_LASTDID */
-    struct stat     hst;
-#endif
-    struct stat                st;
-    struct extmap      *em;
-    char               *data, *nameoff = NULL, *upath;
-    int                        bit = 0, isad = 1;
-    u_int32_t           aint;
-    u_int16_t          ashort;
-
-    if ( ad_hfileno( ofork->of_ad ) == -1 ) {
-        isad = 0;
-    } else {
-        aint = ad_getentrylen( ofork->of_ad, ADEID_RFORK );
-        if ( ad_refresh( ofork->of_ad ) < 0 ) {
-            LOG(log_error, logtype_default, "getforkparams: ad_refresh: %s", strerror(errno) );
-            return( AFPERR_PARAM );
-        }
-        /* See afp_closefork() for why this is bad */
-        ad_setentrylen( ofork->of_ad, ADEID_RFORK, aint );
-    }
+    struct path         path;
+    struct stat     *st;
+
+    struct adouble  *adp;
+    struct dir      *dir;
+    struct vol      *vol;
+
 
     /* can only get the length of the opened fork */
-    if (((bitmap & (1<<FILPBIT_DFLEN)) && (ofork->of_flags & AFPFORK_RSRC)) ||
-            ((bitmap & (1<<FILPBIT_RFLEN)) && (ofork->of_flags & AFPFORK_DATA))) {
+    if ( ( (bitmap & ((1<<FILPBIT_DFLEN) | (1<<FILPBIT_EXTDFLEN)))
+           && (ofork->of_flags & AFPFORK_RSRC))
+         ||
+         ( (bitmap & ((1<<FILPBIT_RFLEN) | (1<<FILPBIT_EXTRFLEN)))
+           && (ofork->of_flags & AFPFORK_DATA))) {
         return( AFPERR_BITMAP );
     }
 
-    if ( bitmap & ( 1<<FILPBIT_DFLEN | 1<<FILPBIT_FNUM |
-                    (1 << FILPBIT_CDATE) | (1 << FILPBIT_MDATE) |
-                    (1 << FILPBIT_BDATE))) {
-        upath = mtoupath(ofork->of_vol, ofork->of_name);
-        if ( ad_dfileno( ofork->of_ad ) == -1 ) {
-            if ( stat( upath, &st ) < 0 )
+    if ( ad_reso_fileno( ofork->of_ad ) == -1 ) { /* META ? */
+        adp = NULL;
+    } else {
+        adp = ofork->of_ad;
+    }
+
+    vol = ofork->of_vol;
+    dir = dirlookup(vol, ofork->of_did);
+
+    if (NULL == (path.u_name = mtoupath(vol, of_name(ofork), dir->d_did, utf8_encoding()))) {
+        return( AFPERR_MISC );
+    }
+    path.m_name = of_name(ofork);
+    path.id = 0;
+    st = &path.st;
+    if ( bitmap & ( (1<<FILPBIT_DFLEN) | (1<<FILPBIT_EXTDFLEN) |
+                    (1<<FILPBIT_FNUM) | (1 << FILPBIT_CDATE) |
+                    (1 << FILPBIT_MDATE) | (1 << FILPBIT_BDATE))) {
+        if ( ad_data_fileno( ofork->of_ad ) <= 0 ) {
+            /* 0 is for symlink */
+            if (movecwd(vol, dir) < 0)
+                return( AFPERR_NOOBJ );
+            if ( lstat( path.u_name, st ) < 0 )
                 return( AFPERR_NOOBJ );
         } else {
-            if ( fstat( ad_dfileno( ofork->of_ad ), &st ) < 0 ) {
+            if ( fstat( ad_data_fileno( ofork->of_ad ), st ) < 0 ) {
                 return( AFPERR_BITMAP );
             }
         }
     }
+    return getmetadata(vol, bitmap, &path, dir, buf, buflen, adp );
+}
 
-    data = buf;
-    while ( bitmap != 0 ) {
-        while (( bitmap & 1 ) == 0 ) {
-            bitmap = bitmap>>1;
-            bit++;
-        }
-
-        switch ( bit ) {
-        case FILPBIT_ATTR :
-            if ( isad ) {
-                ad_getattr(ofork->of_ad, &ashort);
-            } else {
-                ashort = 0;
-            }
-            if (attrbits)
-                ashort = htons(ntohs(ashort) | attrbits);
-            memcpy(data, &ashort, sizeof( ashort ));
-            data += sizeof( ashort );
-            break;
-
-        case FILPBIT_PDID :
-            memcpy(data, &ofork->of_dir->d_did, sizeof( aint ));
-            data += sizeof( aint );
-            break;
-
-        case FILPBIT_CDATE :
-            if (!isad ||
-                    (ad_getdate(ofork->of_ad, AD_DATE_CREATE, &aint) < 0))
-                aint = AD_DATE_FROM_UNIX(st.st_mtime);
-            memcpy(data, &aint, sizeof( aint ));
-            data += sizeof( aint );
-            break;
-
-        case FILPBIT_MDATE :
-            if (!isad ||
-                    (ad_getdate(ofork->of_ad, AD_DATE_MODIFY, &aint) < 0) ||
-                    (AD_DATE_TO_UNIX(aint) < st.st_mtime))
-                aint = AD_DATE_FROM_UNIX(st.st_mtime);
-            memcpy(data, &aint, sizeof( aint ));
-            data += sizeof( aint );
-            break;
-
-        case FILPBIT_BDATE :
-            if (!isad ||
-                    (ad_getdate(ofork->of_ad, AD_DATE_BACKUP, &aint) < 0))
-                aint = AD_DATE_START;
-            memcpy(data, &aint, sizeof( aint ));
-            data += sizeof( aint );
-            break;
-
-        case FILPBIT_FINFO :
-            memcpy(data, isad ?
-                   (void *) ad_entry(ofork->of_ad, ADEID_FINDERI) :
-                   (void *) ufinderi, 32);
-            if ( !isad ||
-                    memcmp( ad_entry( ofork->of_ad, ADEID_FINDERI ),
-                            ufinderi, 8 ) == 0 ) {
-                memcpy(data, ufinderi, 8 );
-                if (( em = getextmap( ofork->of_name )) != NULL ) {
-                    memcpy(data, em->em_type, sizeof( em->em_type ));
-                    memcpy(data + 4, em->em_creator,
-                           sizeof( em->em_creator ));
-                }
-            }
-            data += 32;
-            break;
+static off_t get_off_t(char **ibuf, int is64)
+{
+    u_int32_t             temp;
+    off_t                 ret;
+
+    ret = 0;
+    memcpy(&temp, *ibuf, sizeof( temp ));
+    ret = ntohl(temp); /* ntohl is unsigned */
+    *ibuf += sizeof(temp);
+
+    if (is64) {
+        memcpy(&temp, *ibuf, sizeof( temp ));
+        *ibuf += sizeof(temp);
+        ret = ntohl(temp)| (ret << 32);
+    }
+    else {
+        ret = (int)ret; /* sign extend */
+    }
+    return ret;
+}
 
-        case FILPBIT_LNAME :
-            nameoff = data;
-            data += sizeof(u_int16_t);
-            break;
+static int set_off_t(off_t offset, char *rbuf, int is64)
+{
+    u_int32_t  temp;
+    int        ret;
+
+    ret = 0;
+    if (is64) {
+        temp = htonl(offset >> 32);
+        memcpy(rbuf, &temp, sizeof( temp ));
+        rbuf += sizeof(temp);
+        ret = sizeof( temp );
+        offset &= 0xffffffff;
+    }
+    temp = htonl(offset);
+    memcpy(rbuf, &temp, sizeof( temp ));
+    ret += sizeof( temp );
 
-        case FILPBIT_SNAME :
-            memset(data, 0, sizeof(u_int16_t));
-            data += sizeof(u_int16_t);
-            break;
+    return ret;
+}
 
-        case FILPBIT_FNUM :
-            aint = 0;
-#if AD_VERSION > AD_VERSION1
-            /* look in AD v2 header */
-            if (isad)
-                memcpy(&aint, ad_entry(ofork->of_ad, ADEID_DID), sizeof(aint));
-#endif /* AD_VERSION > AD_VERSION1 */
-
-#ifdef CNID_DB
-            aint = cnid_add(ofork->of_vol->v_db, &st,
-                            ofork->of_dir->d_did,
-                            upath, strlen(upath), aint);
-            if (aint == CNID_INVALID) {
-                switch (errno) {
-                case CNID_ERR_PARAM:
-                    LOG(log_error, logtype_default, "getforkparams: Incorrect parameters passed to cnid_add");
-                    return(AFPERR_PARAM);
-                case CNID_ERR_PATH:
-                    return(AFPERR_PARAM);
-                case CNID_ERR_DB:
-                case CNID_ERR_MAX:
-                    return(AFPERR_MISC);
-                }
-            }
-#endif /* CNID_DB */
-
-            if (aint == 0) {
-#ifdef USE_LASTDID
-                aint = htonl(( st.st_dev << 16 ) | ( st.st_ino & 0x0000ffff ));
-#else /* USE_LASTDID */
-                lstp = lstat(upath, &lst) < 0 ? &st : &lst;
-#ifdef DID_MTAB
-                aint = htonl( afpd_st_cnid ( lstp ) );
-#else /* DID_MTAB */
-                aint = htonl(CNID(lstp, 1));
-#endif /* DID_MTAB */
-#endif /* USE_LASTDID */
-            }
+static int is_neg(int is64, off_t val)
+{
+    if (val < 0 || (sizeof(off_t) == 8 && !is64 && (val & 0x80000000U)))
+        return 1;
+    return 0;
+}
 
-            memcpy(data, &aint, sizeof( aint ));
-            data += sizeof( aint );
-            break;
+static int sum_neg(int is64, off_t offset, off_t reqcount)
+{
+    if (is_neg(is64, offset +reqcount) )
+        return 1;
+    return 0;
+}
 
-        case FILPBIT_DFLEN :
-            aint = htonl( st.st_size );
-            memcpy(data, &aint, sizeof( aint ));
-            data += sizeof( aint );
-            break;
+static int fork_setmode(struct adouble *adp, int eid, int access, int ofrefnum)
+{
+    int ret;
+    int readset;
+    int writeset;
+    int denyreadset;
+    int denywriteset;
+
+    if (! (access & (OPENACC_WR | OPENACC_RD | OPENACC_DWR | OPENACC_DRD))) {
+        return ad_lock(adp, eid, ADLOCK_RD | ADLOCK_FILELOCK, AD_FILELOCK_OPEN_NONE, 1, ofrefnum);
+    }
 
-        case FILPBIT_RFLEN :
-            if ( isad ) {
-                aint = htonl( ad_getentrylen( ofork->of_ad, ADEID_RFORK ));
-            } else {
-                aint = 0;
-            }
-            memcpy(data, &aint, sizeof( aint ));
-            data += sizeof( aint );
-            break;
+    if ((access & (OPENACC_RD | OPENACC_DRD))) {
+        if ((readset = ad_testlock(adp, eid, AD_FILELOCK_OPEN_RD)) <0)
+            return readset;
+        if ((denyreadset = ad_testlock(adp, eid, AD_FILELOCK_DENY_RD)) <0)
+            return denyreadset;
 
-        default :
-            return( AFPERR_BITMAP );
+        if ((access & OPENACC_RD) && denyreadset) {
+            errno = EACCES;
+            return -1;
+        }
+        if ((access & OPENACC_DRD) && readset) {
+            errno = EACCES;
+            return -1;
+        }
+        /* boolean logic is not enough, because getforkmode is not always telling the
+         * true
+         */
+        if ((access & OPENACC_RD)) {
+            ret = ad_lock(adp, eid, ADLOCK_RD | ADLOCK_FILELOCK, AD_FILELOCK_OPEN_RD, 1, ofrefnum);
+            if (ret)
+                return ret;
+        }
+        if ((access & OPENACC_DRD)) {
+            ret = ad_lock(adp, eid, ADLOCK_RD | ADLOCK_FILELOCK, AD_FILELOCK_DENY_RD, 1, ofrefnum);
+            if (ret)
+                return ret;
         }
-        bitmap = bitmap>>1;
-        bit++;
     }
-
-    if ( nameoff ) {
-        ashort = htons( data - buf );
-        memcpy(nameoff, &ashort, sizeof( ashort ));
-        aint = strlen( ofork->of_name );
-        aint = ( aint > MACFILELEN ) ? MACFILELEN : aint;
-        *data++ = aint;
-        memcpy(data, ofork->of_name, aint );
-        data += aint;
+    /* ------------same for writing -------------- */
+    if ((access & (OPENACC_WR | OPENACC_DWR))) {
+        if ((writeset = ad_testlock(adp, eid, AD_FILELOCK_OPEN_WR)) <0)
+            return writeset;
+        if ((denywriteset = ad_testlock(adp, eid, AD_FILELOCK_DENY_WR)) <0)
+            return denywriteset;
+
+        if ((access & OPENACC_WR) && denywriteset) {
+            errno = EACCES;
+            return -1;
+        }
+        if ((access & OPENACC_DWR) && writeset) {
+            errno = EACCES;
+            return -1;
+        }
+        if ((access & OPENACC_WR)) {
+            ret = ad_lock(adp, eid, ADLOCK_RD | ADLOCK_FILELOCK, AD_FILELOCK_OPEN_WR, 1, ofrefnum);
+            if (ret)
+                return ret;
+        }
+        if ((access & OPENACC_DWR)) {
+            ret = ad_lock(adp, eid, ADLOCK_RD | ADLOCK_FILELOCK, AD_FILELOCK_DENY_WR, 1, ofrefnum);
+            if (ret)
+                return ret;
+        }
     }
-
-    *buflen = data - buf;
-    return( AFP_OK );
+    if ( access == (OPENACC_WR | OPENACC_RD | OPENACC_DWR | OPENACC_DRD)) {
+        return ad_excl_lock(adp, eid);
+    }
+    return 0;
 }
 
-int afp_openfork(obj, ibuf, ibuflen, rbuf, rbuflen )
-AFPObj      *obj;
-char   *ibuf, *rbuf;
-int            ibuflen, *rbuflen;
+/* ----------------------- */
+int afp_openfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
 {
-    struct vol         *vol;
-    struct dir         *dir;
-    struct ofork       *ofork, *opened;
-    struct adouble      *adsame = NULL;
-    int                        buflen, ret, adflags, eid, lockop;
-    u_int32_t           did;
-    u_int16_t          vid, bitmap, access, ofrefnum, attrbits = 0;
-    char               fork, *path, *upath;
+    struct vol      *vol;
+    struct dir      *dir;
+    struct ofork    *ofork, *opened;
+    struct adouble  *adsame = NULL;
+    size_t          buflen;
+    int             ret, adflags, eid;
+    uint32_t        did;
+    uint16_t        vid, bitmap, access, ofrefnum;
+    char            fork, *path, *upath;
+    struct stat     *st;
+    uint16_t        bshort;
+    struct path     *s_path;
 
     ibuf++;
     fork = *ibuf++;
@@ -279,15 +239,15 @@ int               ibuflen, *rbuflen;
     ibuf += sizeof(vid);
 
     *rbuflen = 0;
-    if (( vol = getvolbyvid( vid )) == NULL ) {
+    if (NULL == ( vol = getvolbyvid( vid ))) {
         return( AFPERR_PARAM );
     }
 
     memcpy(&did, ibuf, sizeof( did ));
     ibuf += sizeof( int );
 
-    if (( dir = dirsearch( vol, did )) == NULL ) {
-        return( AFPERR_NOOBJ );
+    if (NULL == ( dir = dirlookup( vol, did ))) {
+        return afp_errno;
     }
 
     memcpy(&bitmap, ibuf, sizeof( bitmap ));
@@ -301,63 +261,93 @@ int               ibuflen, *rbuflen;
         return AFPERR_VLOCK;
     }
 
-    if (( path = cname( vol, dir, &ibuf )) == NULL ) {
-        return( AFPERR_NOOBJ );
+    if (NULL == ( s_path = cname( vol, dir, &ibuf ))) {
+        return get_afp_errno(AFPERR_PARAM);
     }
 
-    if ( fork == OPENFORK_DATA ) {
-        eid = ADEID_DFORK;
-        adflags = ADFLAGS_DF|ADFLAGS_HF;
+    if (*s_path->m_name == '\0') {
+        /* it's a dir ! */
+        return  AFPERR_BADTYPE;
+    }
+
+    LOG(log_debug, logtype_afpd,
+        "afp_openfork(\"%s\", %s)",
+        abspath(s_path->u_name),
+        (fork & OPENFORK_RSCS) ? "OPENFORK_RSCS" : "OPENFORK_DATA");
+
+    /* stat() data fork st is set because it's not a dir */
+    switch ( s_path->st_errno ) {
+    case 0:
+        break;
+    case ENOENT:
+        return AFPERR_NOOBJ;
+    case EACCES:
+        return (access & OPENACC_WR) ? AFPERR_LOCK : AFPERR_ACCESS;
+    default:
+        LOG(log_error, logtype_afpd, "afp_openfork(%s): %s", s_path->m_name, strerror(errno));
+        return AFPERR_PARAM;
+    }
+    /* FIXME should we check it first ? */
+    upath = s_path->u_name;
+    if (!vol_unix_priv(vol)) {
+        if (check_access(upath, access ) < 0) {
+            return AFPERR_ACCESS;
+        }
     } else {
-        eid = ADEID_RFORK;
-        adflags = ADFLAGS_HF;
+        if (file_access(s_path, access ) < 0) {
+            return AFPERR_ACCESS;
+        }
     }
 
+    st   = &s_path->st;
     /* XXX: this probably isn't the best way to do this. the already
        open bits should really be set if the fork is opened by any
        program, not just this one. however, that's problematic to do
-       if we can't write lock files somewhere. opened is also passed to 
-       ad_open so that we can keep file locks together. */
-    if ((opened = of_findname(vol, curdir, path))) {
-        attrbits = ((opened->of_flags & AFPFORK_RSRC) ? ATTRBIT_ROPEN : 0) |
-                   ((opened->of_flags & AFPFORK_DATA) ? ATTRBIT_DOPEN : 0);
+       if we can't write lock files somewhere. opened is also passed to
+       ad_open so that we can keep file locks together.
+       FIXME: add the fork we are opening?
+    */
+    if ((opened = of_findname(s_path))) {
         adsame = opened->of_ad;
     }
 
+    if ( fork == OPENFORK_DATA ) {
+        eid = ADEID_DFORK;
+        adflags = ADFLAGS_DF | ADFLAGS_HF ;
+    } else {
+        eid = ADEID_RFORK;
+        adflags = ADFLAGS_RF | ADFLAGS_HF;
+    }
+
+    path = s_path->m_name;
     if (( ofork = of_alloc(vol, curdir, path, &ofrefnum, eid,
-                           adsame)) == NULL ) {
+                           adsame, st)) == NULL ) {
         return( AFPERR_NFILE );
     }
+
+    ret = AFPERR_NOOBJ;
     if (access & OPENACC_WR) {
         /* try opening in read-write mode */
-        upath = mtoupath(vol, path);
-        ret = AFPERR_NOOBJ;
-        if (ad_open(upath, adflags, O_RDWR, 0, ofork->of_ad) < 0) {
+        if (ad_open(ofork->of_ad, upath, adflags, O_RDWR, O_RDWR) < 0) {
             switch ( errno ) {
             case EROFS:
                 ret = AFPERR_VLOCK;
             case EACCES:
                 goto openfork_err;
-
                 break;
             case ENOENT:
-                {
-                    struct stat st;
-
-                    /* see if client asked for the data fork */
-                    if (fork == OPENFORK_DATA) {
-                        if (ad_open(upath, ADFLAGS_DF, O_RDWR, 0, ofork->of_ad) < 0) {
-                            goto openfork_err;
-                        }
-                        adflags = ADFLAGS_DF;
-
-                    } else if (stat(upath, &st) == 0) {
-                        /* here's the deal. we only try to create the resource
-                         * fork if the user wants to open it for write acess. */
-                        if (ad_open(upath, adflags, O_RDWR | O_CREAT, 0666, ofork->of_ad) < 0)
-                            goto openfork_err;
-                    } else
+                if (fork == OPENFORK_DATA) {
+                    /* try to open only the data fork */
+                    if (ad_open(ofork->of_ad, upath, ADFLAGS_DF, O_RDWR) < 0) {
                         goto openfork_err;
+                    }
+                    adflags = ADFLAGS_DF;
+                } else {
+                    /* here's the deal. we only try to create the resource
+                     * fork if the user wants to open it for write acess. */
+                    if (ad_open(ofork->of_ad, upath, adflags, O_RDWR | O_CREAT, 0666, O_RDWR | O_CREAT, 0666) < 0)
+                        goto openfork_err;
+                    ofork->of_flags |= AFPFORK_OPEN;
                 }
                 break;
             case EMFILE :
@@ -370,43 +360,42 @@ int               ibuflen, *rbuflen;
                 goto openfork_err;
                 break;
             default:
-                LOG(log_error, logtype_default, "afp_openfork: ad_open: %s", strerror(errno) );
+                LOG(log_error, logtype_afpd, "afp_openfork(%s): ad_open: %s", s_path->m_name, strerror(errno) );
                 ret = AFPERR_PARAM;
                 goto openfork_err;
                 break;
             }
         }
+        else {
+            /* the ressource fork is open too */
+            ofork->of_flags |= AFPFORK_OPEN;
+        }
     } else {
         /* try opening in read-only mode */
-        upath = mtoupath(vol, path);
         ret = AFPERR_NOOBJ;
-        if (ad_open(upath, adflags, O_RDONLY, 0, ofork->of_ad) < 0) {
+        if (ad_open(ofork->of_ad, upath, adflags, O_RDONLY, O_RDONLY) < 0) {
             switch ( errno ) {
             case EROFS:
                 ret = AFPERR_VLOCK;
             case EACCES:
-                /* check for a read-only data fork */
-                if ((adflags != ADFLAGS_HF) &&
-                        (ad_open(upath, ADFLAGS_DF, O_RDONLY, 0, ofork->of_ad) < 0))
-                    goto openfork_err;
-
-                adflags = ADFLAGS_DF;
+                goto openfork_err;
                 break;
             case ENOENT:
-                {
-                    struct stat st;
-
-                    /* see if client asked for the data fork */
-                    if (fork == OPENFORK_DATA) {
-                        if (ad_open(upath, ADFLAGS_DF, O_RDONLY, 0, ofork->of_ad) < 0) {
-                            goto openfork_err;
-                        }
-                        adflags = ADFLAGS_DF;
-
-                    } else if (stat(upath, &st) != 0) {
+                /* see if client asked for a read only data fork */
+                if (fork == OPENFORK_DATA) {
+                    if (ad_open(ofork->of_ad, upath, ADFLAGS_DF, O_RDONLY) < 0) {
                         goto openfork_err;
                     }
+                    adflags = ADFLAGS_DF;
                 }
+                /* else we don't set AFPFORK_OPEN because there's no ressource fork file
+                 * We need to check AFPFORK_OPEN in afp_closefork(). eg fork open read-only
+                 * then create in open read-write.
+                 * FIXME , it doesn't play well with byte locking example:
+                 * ressource fork open read only
+                 * locking set on it (no effect, there's no file!)
+                 * ressource fork open read write now
+                 */
                 break;
             case EMFILE :
             case ENFILE :
@@ -418,23 +407,25 @@ int               ibuflen, *rbuflen;
                 goto openfork_err;
                 break;
             default:
-                LOG(log_error, logtype_default, "afp_openfork: ad_open: %s", strerror(errno) );
+                LOG(log_error, logtype_afpd, "afp_openfork(\"%s\"): %s",
+                    abspath(s_path->m_name), strerror(errno) );
                 goto openfork_err;
                 break;
             }
         }
+        else {
+            /* the ressource fork is open too */
+            ofork->of_flags |= AFPFORK_OPEN;
+        }
     }
 
-    if ((adflags & ADFLAGS_HF) &&
-            (ad_getoflags( ofork->of_ad, ADFLAGS_HF ) & O_CREAT)) {
-        ad_setentrylen( ofork->of_ad, ADEID_NAME, strlen( path ));
-        memcpy(ad_entry( ofork->of_ad, ADEID_NAME ), path,
-               ad_getentrylen( ofork->of_ad, ADEID_NAME ));
-        ad_flush( ofork->of_ad, adflags );
+    if ((adflags & ADFLAGS_RF) && (ad_get_RF_flags( ofork->of_ad) & O_CREAT)) {
+        if (ad_setname(ofork->of_ad, path)) {
+            ad_flush( ofork->of_ad );
+        }
     }
 
-    if (( ret = getforkparams(ofork, bitmap, rbuf + 2 * sizeof( u_int16_t ),
-                              &buflen, attrbits )) != AFP_OK ) {
+    if ((ret = getforkparams(ofork, bitmap, rbuf + 2 * sizeof(int16_t), &buflen)) != AFP_OK) {
         ad_close( ofork->of_ad, adflags );
         goto openfork_err;
     }
@@ -444,61 +435,29 @@ int               ibuflen, *rbuflen;
     memcpy(rbuf, &bitmap, sizeof( u_int16_t ));
     rbuf += sizeof( u_int16_t );
 
-    /*
-     * synchronization locks:
-     *
-     * here's the ritual:
-     *  1) attempt a read lock to see if we have read or write
-     *     privileges.
-     *  2) if that succeeds, set a write lock to correspond to the
-     *     deny mode requested.
-     *  3) whenever a file is read/written, locks get set which
-     *     prevent conflicts.
+    /* check  WriteInhibit bit if we have a ressource fork
+     * the test is done here, after some Mac trafic capture
      */
-
-    /* don't try to lock non-existent rforks. */
-    if ((eid == ADEID_DFORK) || (ad_hfileno(ofork->of_ad) != -1)) {
-
-        /* try to see if we have access. */
-        ret = 0;
-        if (access & OPENACC_WR) {
-            ofork->of_flags |= AFPFORK_ACCWR;
-            ret = ad_lock(ofork->of_ad, eid, ADLOCK_RD | ADLOCK_FILELOCK,
-                          AD_FILELOCK_WR, 1, ofrefnum);
-        }
-
-        if (!ret && (access & OPENACC_RD)) {
-            ofork->of_flags |= AFPFORK_ACCRD;
-            ret = ad_lock(ofork->of_ad, eid, ADLOCK_RD | ADLOCK_FILELOCK,
-                          AD_FILELOCK_RD, 1, ofrefnum);
-        }
-
-        /* can we access the fork? */
-        if (ret < 0) {
+    if (ad_meta_fileno(ofork->of_ad) != -1) {   /* META */
+        ad_getattr(ofork->of_ad, &bshort);
+        if ((bshort & htons(ATTRBIT_NOWRITE)) && (access & OPENACC_WR)) {
             ad_close( ofork->of_ad, adflags );
             of_dealloc( ofork );
             ofrefnum = 0;
             memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
-            return (AFPERR_DENYCONF);
+            return(AFPERR_OLOCK);
         }
+    }
+
+    /*
+     * synchronization locks:
+     */
 
-        /* now try to set the deny lock. if the fork is open for read or
-         * write, a read lock will already have been set. otherwise, we upgrade
-         * our lock to a write lock. 
-         *
-         * NOTE: we can't write lock a read-only file. on those, we just
-         * make sure that we have a read lock set. that way, we at least prevent
-         * someone else from really setting a deny read/write on the file. */
-        lockop = (ad_getoflags(ofork->of_ad, eid) & O_RDWR) ?
-                 ADLOCK_WR : ADLOCK_RD;
-        ret = (access & OPENACC_DWR) ? ad_lock(ofork->of_ad, eid,
-                                               lockop | ADLOCK_FILELOCK |
-                                               ADLOCK_UPGRADE, AD_FILELOCK_WR, 1,
-                                               ofrefnum) : 0;
-        if (!ret && (access & OPENACC_DRD))
-            ret = ad_lock(ofork->of_ad, eid, lockop | ADLOCK_FILELOCK |
-                          ADLOCK_UPGRADE, AD_FILELOCK_RD, 1, ofrefnum);
+    /* don't try to lock non-existent rforks. */
+    if ((eid == ADEID_DFORK) || (ad_meta_fileno(ofork->of_ad) != -1)) { /* META */
 
+        ret = fork_setmode(ofork->of_ad, eid, access, ofrefnum);
+        /* can we access the fork? */
         if (ret < 0) {
             ret = errno;
             ad_close( ofork->of_ad, adflags );
@@ -513,11 +472,16 @@ int               ibuflen, *rbuflen;
                 break;
             default:
                 *rbuflen = 0;
-                LOG(log_error, logtype_default, "afp_openfork: ad_lock: %s", strerror(errno) );
+                LOG(log_error, logtype_afpd, "afp_openfork(%s): ad_lock: %s", s_path->m_name, strerror(ret) );
                 return( AFPERR_PARAM );
             }
         }
+        if ((access & OPENACC_WR))
+            ofork->of_flags |= AFPFORK_ACCWR;
     }
+    /* the file may be open read only without ressource fork */
+    if ((access & OPENACC_RD))
+        ofork->of_flags |= AFPFORK_ACCRD;
 
     memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
     return( AFP_OK );
@@ -529,28 +493,28 @@ openfork_err:
     return ret;
 }
 
-int afp_setforkparams(obj, ibuf, ibuflen, rbuf, rbuflen )
-AFPObj      *obj;
-char   *ibuf, *rbuf;
-int            ibuflen, *rbuflen;
+int afp_setforkparams(AFPObj *obj _U_, char *ibuf, size_t ibuflen, char *rbuf _U_, size_t *rbuflen)
 {
-    struct ofork       *ofork;
-    int32_t            size;
-    u_int16_t          ofrefnum, bitmap;
+    struct ofork    *ofork;
+    off_t       size;
+    u_int16_t       ofrefnum, bitmap;
     int                 err;
+    int                 is64;
+    int                 eid;
+    off_t       st_size;
 
     ibuf += 2;
+
     memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
     ibuf += sizeof( ofrefnum );
+
     memcpy(&bitmap, ibuf, sizeof(bitmap));
     bitmap = ntohs(bitmap);
     ibuf += sizeof( bitmap );
-    memcpy(&size, ibuf, sizeof( size ));
-    size = ntohl( size );
 
     *rbuflen = 0;
-    if (( ofork = of_find( ofrefnum )) == NULL ) {
-        LOG(log_error, logtype_default, "afp_setforkparams: of_find could not locate open fork refnum: %u", ofrefnum );
+    if (NULL == ( ofork = of_find( ofrefnum )) ) {
+        LOG(log_error, logtype_afpd, "afp_setforkparams: of_find(%d) could not locate fork", ofrefnum );
         return( AFPERR_PARAM );
     }
 
@@ -560,31 +524,76 @@ int               ibuflen, *rbuflen;
     if ((ofork->of_flags & AFPFORK_ACCWR) == 0)
         return AFPERR_ACCESS;
 
-    if (size < 0)
+    if ( ofork->of_flags & AFPFORK_DATA) {
+        eid = ADEID_DFORK;
+    } else if (ofork->of_flags & AFPFORK_RSRC) {
+        eid = ADEID_RFORK;
+    } else
         return AFPERR_PARAM;
 
-    if ((bitmap == (1<<FILPBIT_DFLEN)) && (ofork->of_flags & AFPFORK_DATA)) {
+    if ( ( (bitmap & ( (1<<FILPBIT_DFLEN) | (1<<FILPBIT_EXTDFLEN) ))
+           && eid == ADEID_RFORK
+             ) ||
+         ( (bitmap & ( (1<<FILPBIT_RFLEN) | (1<<FILPBIT_EXTRFLEN) ))
+           && eid == ADEID_DFORK)) {
+        return AFPERR_BITMAP;
+    }
+
+    is64 = 0;
+    if ((bitmap & ( (1<<FILPBIT_EXTDFLEN) | (1<<FILPBIT_EXTRFLEN) ))) {
+        if (afp_version >= 30) {
+            is64 = 4;
+        }
+        else
+            return AFPERR_BITMAP;
+    }
+
+    if (ibuflen < 2+ sizeof(ofrefnum) + sizeof(bitmap) + is64 +4)
+        return AFPERR_PARAM ;
+
+    size = get_off_t(&ibuf, is64);
+
+    if (size < 0)
+        return AFPERR_PARAM; /* Some MacOS don't return an error they just don't change the size! */
+
+
+    if (bitmap == (1<<FILPBIT_DFLEN) || bitmap == (1<<FILPBIT_EXTDFLEN)) {
+        st_size = ad_size(ofork->of_ad, eid);
+        err = -2;
+        if (st_size > size &&
+            ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, size, st_size -size, ofork->of_refnum) < 0)
+            goto afp_setfork_err;
+
         err = ad_dtruncate( ofork->of_ad, size );
+        if (st_size > size)
+            ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, size, st_size -size, ofork->of_refnum);
         if (err < 0)
             goto afp_setfork_err;
-    } else if ((bitmap == (1<<FILPBIT_RFLEN)) &&
-               (ofork->of_flags & AFPFORK_RSRC)) {
+    } else if (bitmap == (1<<FILPBIT_RFLEN) || bitmap == (1<<FILPBIT_EXTRFLEN)) {
         ad_refresh( ofork->of_ad );
+
+        st_size = ad_size(ofork->of_ad, eid);
+        err = -2;
+        if (st_size > size &&
+            ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, size, st_size -size, ofork->of_refnum) < 0) {
+            goto afp_setfork_err;
+        }
         err = ad_rtruncate(ofork->of_ad, size);
+        if (st_size > size)
+            ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, size, st_size -size, ofork->of_refnum);
         if (err < 0)
             goto afp_setfork_err;
 
-        if (ad_flush( ofork->of_ad, ADFLAGS_HF ) < 0) {
-            LOG(log_error, logtype_default, "afp_setforkparams: ad_flush: %s",
-                strerror(errno) );
-            return( AFPERR_PARAM );
+        if (ad_flush( ofork->of_ad ) < 0) {
+            LOG(log_error, logtype_afpd, "afp_setforkparams(%s): ad_flush: %s", of_name(ofork), strerror(errno) );
+            return AFPERR_PARAM;
         }
     } else
         return AFPERR_BITMAP;
 
 #ifdef AFS
     if ( flushfork( ofork ) < 0 ) {
-        LOG(log_error, logtype_default, "afp_setforkparams: flushfork: %s", strerror(errno) );
+        LOG(log_error, logtype_afpd, "afp_setforkparams(%s): flushfork: %s", of_name(ofork), strerror(errno) );
     }
 #endif /* AFS */
 
@@ -614,20 +623,21 @@ afp_setfork_err:
  * read and write. that's most easily handled by always doing an
  * appropriate check before each ad_read/ad_write. other things
  * that can change files like truncate are handled internally to those
- * functions. 
+ * functions.
  */
 #define ENDBIT(a)  ((a) & 0x80)
 #define UNLOCKBIT(a) ((a) & 0x01)
-int afp_bytelock(obj, ibuf, ibuflen, rbuf, rbuflen )
-AFPObj      *obj;
-char   *ibuf, *rbuf;
-int            ibuflen, *rbuflen;
+
+
+/* ---------------------- */
+static int byte_lock(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen, int is64)
 {
-    struct ofork       *ofork;
-    int32_t             offset, length;
+    struct ofork    *ofork;
+    off_t               offset, length;
     int                 eid;
-    u_int16_t          ofrefnum;
+    u_int16_t       ofrefnum;
     u_int8_t            flags;
+    int                 lockop;
 
     *rbuflen = 0;
 
@@ -638,8 +648,8 @@ int         ibuflen, *rbuflen;
     memcpy(&ofrefnum, ibuf, sizeof(ofrefnum));
     ibuf += sizeof(ofrefnum);
 
-    if (( ofork = of_find( ofrefnum )) == NULL ) {
-        LOG(log_error, logtype_default, "afp_bytelock: of_find");
+    if (NULL == ( ofork = of_find( ofrefnum )) ) {
+        LOG(log_error, logtype_afpd, "afp_bytelock: of_find(%d) could not locate fork", ofrefnum );
         return( AFPERR_PARAM );
     }
 
@@ -650,32 +660,32 @@ int               ibuflen, *rbuflen;
     } else
         return AFPERR_PARAM;
 
-    memcpy(&offset, ibuf, sizeof( offset ));
-    offset = ntohl(offset);
-    ibuf += sizeof(offset);
+    offset = get_off_t(&ibuf, is64);
+    length = get_off_t(&ibuf, is64);
 
-    memcpy(&length, ibuf, sizeof( length ));
-    length = ntohl(length);
-    if (length == 0xFFFFFFFF)
+    /* FIXME AD_FILELOCK test is surely wrong */
+    if (length == -1)
         length = BYTELOCK_MAX;
-    else if (length <= 0) {
+    else if (!length || is_neg(is64, length)) {
         return AFPERR_PARAM;
-    } else if ((length >= AD_FILELOCK_BASE) &&
-               (ad_hfileno(ofork->of_ad) == -1))
+    } else if ((length >= AD_FILELOCK_BASE) && -1 == (ad_reso_fileno(ofork->of_ad))) { /* HF ?*/
         return AFPERR_LOCK;
+    }
 
-    if (ENDBIT(flags))
+    if (ENDBIT(flags)) {
         offset += ad_size(ofork->of_ad, eid);
-
+        /* FIXME what do we do if file size > 2 GB and
+           it's not byte_lock_ext?
+        */
+    }
     if (offset < 0)    /* error if we have a negative offset */
         return AFPERR_PARAM;
 
     /* if the file is a read-only file, we use read locks instead of
      * write locks. that way, we can prevent anyone from initiating
      * a write lock. */
-    if (ad_lock(ofork->of_ad, eid, UNLOCKBIT(flags) ? ADLOCK_CLR :
-                ((ad_getoflags(ofork->of_ad, eid) & O_RDWR) ?
-                 ADLOCK_WR : ADLOCK_RD), offset, length,
+    lockop = UNLOCKBIT(flags) ? ADLOCK_CLR : ADLOCK_WR;
+    if (ad_lock(ofork->of_ad, eid, lockop, offset, length,
                 ofork->of_refnum) < 0) {
         switch (errno) {
         case EACCES:
@@ -694,44 +704,48 @@ int               ibuflen, *rbuflen;
             break;
         }
     }
-
-    offset = htonl(offset);
-    memcpy(rbuf, &offset, sizeof( offset ));
-    *rbuflen = sizeof( offset );
+    *rbuflen = set_off_t (offset, rbuf, is64);
     return( AFP_OK );
 }
-#undef UNLOCKBIT
 
+/* --------------------------- */
+int afp_bytelock(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
+{
+    return byte_lock ( obj, ibuf, ibuflen, rbuf, rbuflen , 0);
+}
 
-static __inline__ int crlf( of )
-struct ofork   *of;
+/* --------------------------- */
+int afp_bytelock_ext(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
 {
-    struct extmap      *em;
-
-    if ( ad_hfileno( of->of_ad ) == -1 ||
-            memcmp( ufinderi, ad_entry( of->of_ad, ADEID_FINDERI ),
-                    8) == 0 ) {
-        if (( em = getextmap( of->of_name )) == NULL ||
-                memcmp( "TEXT", em->em_type, sizeof( em->em_type )) == 0 ) {
-            return( 1 );
-        } else {
-            return( 0 );
-        }
-    } else {
-        if ( memcmp( ufinderi,
-                     ad_entry( of->of_ad, ADEID_FINDERI ), 4 ) == 0 ) {
-            return( 1 );
-        } else {
-            return( 0 );
+    return byte_lock ( obj, ibuf, ibuflen, rbuf, rbuflen , 1);
+}
+
+#undef UNLOCKBIT
+
+/* --------------------------- */
+static int crlf(struct ofork *of)
+{
+    struct extmap   *em;
+
+    if ( ad_meta_fileno( of->of_ad ) == -1 || !memcmp( ufinderi, ad_entry( of->of_ad, ADEID_FINDERI),8)) { /* META */
+        /* no resource fork or no finderinfo, use our files extension mapping */
+        if (!( em = getextmap( of_name(of) )) || memcmp( "TEXT", em->em_type, sizeof( em->em_type ))) {
+            return 0;
         }
+        /* file type is TEXT */
+        return 1;
+
+    } else if ( !memcmp( "TEXT", ad_entry( of->of_ad, ADEID_FINDERI ), 4 )) {
+        return 1;
     }
+    return 0;
 }
 
 
-static __inline__ ssize_t read_file(struct ofork *ofork, int eid,
-                                    int offset, u_char nlmask,
-                                    u_char nlchar, char *rbuf,
-                                    int *rbuflen, const int xlate)
+static ssize_t read_file(struct ofork *ofork, int eid,
+                         off_t offset, u_char nlmask,
+                         u_char nlchar, char *rbuf,
+                         size_t *rbuflen, const int xlate)
 {
     ssize_t cc;
     int eof = 0;
@@ -739,11 +753,11 @@ static __inline__ ssize_t read_file(struct ofork *ofork, int eid,
 
     cc = ad_read(ofork->of_ad, eid, offset, rbuf, *rbuflen);
     if ( cc < 0 ) {
-        LOG(log_error, logtype_default, "afp_read: ad_read: %s", strerror(errno) );
+        LOG(log_error, logtype_afpd, "afp_read(%s): ad_read: %s", of_name(ofork), strerror(errno) );
         *rbuflen = 0;
         return( AFPERR_PARAM );
     }
-    if ( cc < *rbuflen ) {
+    if ( (size_t)cc < *rbuflen ) {
         eof = 1;
     }
 
@@ -783,24 +797,34 @@ static __inline__ ssize_t read_file(struct ofork *ofork, int eid,
     return AFP_OK;
 }
 
-int afp_read(obj, ibuf, ibuflen, rbuf, rbuflen)
-AFPObj      *obj;
-char   *ibuf, *rbuf;
-int            ibuflen, *rbuflen;
+/* -----------------------------
+ * with ddp, afp_read can return fewer bytes than in reqcount
+ * so return EOF only if read actually past end of file not
+ * if offset +reqcount > size of file
+ * e.g.:
+ * getfork size ==> 10430
+ * read fork offset 0 size 10752 ????  ==> 4264 bytes (without EOF)
+ * read fork offset 4264 size 6128 ==> 4264 (without EOF)
+ * read fork offset 9248 size 1508 ==> 1182 (EOF)
+ * 10752 is a bug in Mac 7.5.x finder
+ *
+ * with dsi, should we check that reqcount < server quantum?
+ */
+static int read_fork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen, int is64)
 {
-    struct ofork       *ofork;
-    off_t              size;
-    int32_t            offset, saveoff, reqcount, savereqcount;
-    int                        cc, err, saveerr, eid, xlate = 0;
-    u_int16_t          ofrefnum;
-    u_char             nlmask, nlchar;
+    struct ofork    *ofork;
+    off_t       offset, saveoff, reqcount, savereqcount;
+    ssize_t     cc, err;
+    int         eid, xlate = 0;
+    u_int16_t       ofrefnum;
+    u_char      nlmask, nlchar;
 
     ibuf += 2;
     memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
     ibuf += sizeof( u_short );
 
-    if (( ofork = of_find( ofrefnum )) == NULL ) {
-        LOG(log_error, logtype_default, "afp_read: of_find");
+    if (NULL == ( ofork = of_find( ofrefnum )) ) {
+        LOG(log_error, logtype_afpd, "afp_read: of_find(%d) could not locate fork", ofrefnum );
         err = AFPERR_PARAM;
         goto afp_read_err;
     }
@@ -809,17 +833,21 @@ int               ibuflen, *rbuflen;
         err = AFPERR_ACCESS;
         goto afp_read_err;
     }
+    offset   = get_off_t(&ibuf, is64);
+    reqcount = get_off_t(&ibuf, is64);
 
-    memcpy(&offset, ibuf, sizeof( offset ));
-    offset = ntohl( offset );
-    ibuf += sizeof( offset );
-    memcpy(&reqcount, ibuf, sizeof( reqcount ));
-    reqcount = ntohl( reqcount );
-    ibuf += sizeof( reqcount );
-
-    nlmask = *ibuf++;
-    nlchar = *ibuf++;
+    LOG(log_debug, logtype_afpd,
+         "afp_read(\"%s\", off: %" PRIu64 ", size: %" PRIu64 ", fork: %s)",
+         cfrombstr(ofork->of_ad->ad_fullpath), offset, reqcount,
+         (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
 
+    if (is64) {
+        nlmask = nlchar = 0;
+    }
+    else {
+        nlmask = *ibuf++;
+        nlchar = *ibuf++;
+    }
     /* if we wanted to be picky, we could add in the following
      * bit: if (afp_version == 11 && !(nlmask == 0xFF || !nlmask))
      */
@@ -844,48 +872,33 @@ int               ibuflen, *rbuflen;
         goto afp_read_err;
     }
 
-    /* reqcount isn't always truthful. we need to deal with that. */
-    size = ad_size(ofork->of_ad, eid);
-
-    if (offset >= size) {
-        err = AFPERR_EOF;
-        goto afp_read_err;
-    }
-
-    /* subtract off the offset */
-    size -= offset;
     savereqcount = reqcount;
-    if (reqcount > size) {
-       reqcount = size;
-        err = AFPERR_EOF;
-    }
-
     saveoff = offset;
-    /* if EOF lock on the old reqcount, some prg may need it */
-    if (ad_tmplock(ofork->of_ad, eid, ADLOCK_RD, saveoff, savereqcount) < 0) {
+    if (ad_tmplock(ofork->of_ad, eid, ADLOCK_RD, saveoff, savereqcount,ofork->of_refnum) < 0) {
         err = AFPERR_LOCK;
         goto afp_read_err;
     }
 
-#define min(a,b)       ((a)<(b)?(a):(b))
+#define min(a,b)    ((a)<(b)?(a):(b))
     *rbuflen = min( reqcount, *rbuflen );
-    saveerr = err;
-    err = read_file(ofork, eid, offset, nlmask, nlchar, rbuf, rbuflen,
-                    xlate);
+    err = read_file(ofork, eid, offset, nlmask, nlchar, rbuf, rbuflen, xlate);
     if (err < 0)
         goto afp_read_done;
-    if (saveerr < 0) {
-       err = saveerr;
-    }
+
     /* dsi can stream requests. we can only do this if we're not checking
      * for an end-of-line character. oh well. */
     if ((obj->proto == AFPPROTO_DSI) && (*rbuflen < reqcount) && !nlmask) {
-        DSI *dsi = obj->handle;
+        DSI    *dsi = obj->handle;
+        off_t  size;
+
+        /* reqcount isn't always truthful. we need to deal with that. */
+        size = ad_size(ofork->of_ad, eid);
 
-        if (obj->options.flags & OPTION_DEBUG) {
-            printf( "(read) reply: %d/%d, %d\n", *rbuflen,
-                    reqcount, dsi->clientID);
-            bprint(rbuf, *rbuflen);
+        /* subtract off the offset */
+        size -= offset;
+        if (reqcount > size) {
+            reqcount = size;
+            err = AFPERR_EOF;
         }
 
         offset += *rbuflen;
@@ -893,19 +906,21 @@ int               ibuflen, *rbuflen;
         /* dsi_readinit() returns size of next read buffer. by this point,
          * we know that we're sending some data. if we fail, something
          * horrible happened. */
-        if ((*rbuflen = dsi_readinit(dsi, rbuf, *rbuflen, reqcount, err)) < 0)
+        if ((cc = dsi_readinit(dsi, rbuf, *rbuflen, reqcount, err)) < 0)
             goto afp_read_exit;
-
+        *rbuflen = cc;
         /* due to the nature of afp packets, we have to exit if we get
            an error. we can't do this with translation on. */
-#ifdef HAVE_SENDFILE_READ
-        if (!(xlate || (obj->options.flags & OPTION_DEBUG))) {
-            if (ad_readfile(ofork->of_ad, eid, dsi->socket, offset,
-                            dsi->datasize) < 0) {
-                if (errno == EINVAL)
+#ifdef WITH_SENDFILE
+        if (!(xlate)) {
+            int fd;
+
+            fd = ad_readfile_init(ofork->of_ad, eid, &offset, 0);
+            if (dsi_stream_read_file(dsi, fd, offset, dsi->datasize) < 0) {
+                if (errno == EINVAL || errno == ENOSYS)
                     goto afp_read_loop;
                 else {
-                    LOG(log_error, logtype_default, "afp_read: ad_readfile: %s", strerror(errno));
+                    LOG(log_error, logtype_afpd, "afp_read(%s): ad_readfile: %s", of_name(ofork), strerror(errno));
                     goto afp_read_exit;
                 }
             }
@@ -914,22 +929,16 @@ int               ibuflen, *rbuflen;
             goto afp_read_done;
         }
 
-afp_read_loop:
-#endif /* HAVE_SENDFILE_READ */
+    afp_read_loop:
+#endif
 
         /* fill up our buffer. */
         while (*rbuflen > 0) {
-            cc = read_file(ofork, eid, offset, nlmask, nlchar, rbuf,
-                           rbuflen, xlate);
+            cc = read_file(ofork, eid, offset, nlmask, nlchar, rbuf,rbuflen, xlate);
             if (cc < 0)
                 goto afp_read_exit;
 
             offset += *rbuflen;
-            if (obj->options.flags & OPTION_DEBUG) {
-                printf( "(read) reply: %d, %d\n", *rbuflen, dsi->clientID);
-                bprint(rbuf, *rbuflen);
-            }
-
             /* dsi_read() also returns buffer size of next allocation */
             cc = dsi_read(dsi, rbuf, *rbuflen); /* send it off */
             if (cc < 0)
@@ -939,15 +948,15 @@ afp_read_loop:
         dsi_readdone(dsi);
         goto afp_read_done;
 
-afp_read_exit:
-        LOG(log_error, logtype_default, "afp_read: %s", strerror(errno));
+    afp_read_exit:
+        LOG(log_error, logtype_afpd, "afp_read(%s): %s", of_name(ofork), strerror(errno));
         dsi_readdone(dsi);
-        ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount);
-        obj->exit(1);
+        ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount,ofork->of_refnum);
+        obj->exit(EXITERR_CLNT);
     }
 
 afp_read_done:
-    ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount);
+    ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount,ofork->of_refnum);
     return err;
 
 afp_read_err:
@@ -955,10 +964,20 @@ afp_read_err:
     return err;
 }
 
-int afp_flush(obj, ibuf, ibuflen, rbuf, rbuflen )
-AFPObj      *obj;
-char   *ibuf, *rbuf;
-int            ibuflen, *rbuflen;
+/* ---------------------- */
+int afp_read(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
+{
+    return read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 0);
+}
+
+/* ---------------------- */
+int afp_read_ext(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
+{
+    return read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 1);
+}
+
+/* ---------------------- */
+int afp_flush(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
 {
     struct vol *vol;
     u_int16_t vid;
@@ -967,7 +986,7 @@ int         ibuflen, *rbuflen;
     ibuf += 2;
 
     memcpy(&vid, ibuf, sizeof(vid));
-    if (( vol = getvolbyvid( vid )) == NULL ) {
+    if (NULL == ( vol = getvolbyvid( vid )) ) {
         return( AFPERR_PARAM );
     }
 
@@ -975,146 +994,140 @@ int             ibuflen, *rbuflen;
     return( AFP_OK );
 }
 
-int afp_flushfork(obj, ibuf, ibuflen, rbuf, rbuflen )
-AFPObj      *obj;
-char   *ibuf, *rbuf;
-int            ibuflen, *rbuflen;
+int afp_flushfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
 {
-    struct ofork       *ofork;
-    u_int16_t          ofrefnum;
+    struct ofork    *ofork;
+    u_int16_t       ofrefnum;
 
     *rbuflen = 0;
     ibuf += 2;
     memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
 
-    if (( ofork = of_find( ofrefnum )) == NULL ) {
-        LOG(log_error, logtype_default, "afp_flushfork: of_find");
+    if (NULL == ( ofork = of_find( ofrefnum )) ) {
+        LOG(log_error, logtype_afpd, "afp_flushfork: of_find(%d) could not locate fork", ofrefnum );
+        return( AFPERR_PARAM );
+    }
+
+    LOG(log_debug, logtype_afpd,
+        "afp_flushfork(\"%s\", fork: %s)",
+        cfrombstr(ofork->of_ad->ad_fullpath),
+        (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
+
+    if ( flushfork( ofork ) < 0 ) {
+        LOG(log_error, logtype_afpd, "afp_flushfork(%s): %s", of_name(ofork), strerror(errno) );
+    }
+
+    return( AFP_OK );
+}
+
+/*
+  FIXME
+  There is a lot to tell about fsync, fdatasync, F_FULLFSYNC.
+  fsync(2) on OSX is implemented differently than on other platforms.
+  see: http://mirror.linux.org.au/pub/linux.conf.au/2007/video/talks/278.pdf.
+*/
+int afp_syncfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
+{
+    struct ofork        *ofork;
+    u_int16_t           ofrefnum;
+
+    *rbuflen = 0;
+    ibuf += 2;
+
+    memcpy(&ofrefnum, ibuf, sizeof(ofrefnum));
+    ibuf += sizeof( ofrefnum );
+
+    if (NULL == ( ofork = of_find( ofrefnum )) ) {
+        LOG(log_error, logtype_afpd, "afpd_syncfork: of_find(%d) could not locate fork", ofrefnum );
         return( AFPERR_PARAM );
     }
 
+    LOG(log_debug, logtype_afpd,
+        "afp_syncfork(\"%s\", fork: %s)",
+        cfrombstr(ofork->of_ad->ad_fullpath),
+        (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
+
     if ( flushfork( ofork ) < 0 ) {
-        LOG(log_error, logtype_default, "afp_flushfork: %s", strerror(errno) );
+        LOG(log_error, logtype_afpd, "flushfork(%s): %s", of_name(ofork), strerror(errno) );
+        return AFPERR_MISC;
     }
 
     return( AFP_OK );
 }
 
 /* this is very similar to closefork */
-int flushfork( ofork )
-struct ofork   *ofork;
+int flushfork(struct ofork *ofork)
 {
     struct timeval tv;
-    int len, err = 0, doflush = 0;
 
-    if ( ad_dfileno( ofork->of_ad ) != -1 &&
-            fsync( ad_dfileno( ofork->of_ad )) < 0 ) {
-        LOG(log_error, logtype_default, "flushfork: dfile(%d) %s",
-            ad_dfileno(ofork->of_ad), strerror(errno) );
+    int err = 0, doflush = 0;
+
+    if ( ad_data_fileno( ofork->of_ad ) != -1 &&
+         fsync( ad_data_fileno( ofork->of_ad )) < 0 ) {
+        LOG(log_error, logtype_afpd, "flushfork(%s): dfile(%d) %s",
+            of_name(ofork), ad_data_fileno(ofork->of_ad), strerror(errno) );
         err = -1;
     }
 
-    if ( ad_hfileno( ofork->of_ad ) != -1 ) {
+    if ( ad_reso_fileno( ofork->of_ad ) != -1 &&  /* HF */
+         (ofork->of_flags & AFPFORK_RSRC)) {
 
         /* read in the rfork length */
-        len = ad_getentrylen(ofork->of_ad, ADEID_RFORK);
         ad_refresh(ofork->of_ad);
 
         /* set the date if we're dirty */
-        if ((ofork->of_flags & AFPFORK_DIRTY) &&
-                (gettimeofday(&tv, NULL) == 0)) {
+        if ((ofork->of_flags & AFPFORK_DIRTY) && !gettimeofday(&tv, NULL)) {
             ad_setdate(ofork->of_ad, AD_DATE_MODIFY|AD_DATE_UNIX, tv.tv_sec);
             ofork->of_flags &= ~AFPFORK_DIRTY;
             doflush++;
         }
 
-        /* if we're actually flushing this fork, make sure to set the
-         * length. otherwise, just use the stored length */
-        if ((ofork->of_flags & AFPFORK_RSRC) &&
-                (len != ad_getentrylen(ofork->of_ad, ADEID_RFORK))) {
-            ad_setentrylen(ofork->of_ad, ADEID_RFORK, len);
-            doflush++;
-        }
-
-
-        /* flush the header (if it is a resource fork) */
-        if (ofork->of_flags & AFPFORK_RSRC)
-            if (doflush && (ad_flush(ofork->of_ad, ADFLAGS_HF) < 0))
-                err = -1;
+        /* flush the header */
+        if (doflush && ad_flush(ofork->of_ad) < 0)
+            err = -1;
 
-        if (fsync( ad_hfileno( ofork->of_ad )) < 0)
+        if (fsync( ad_reso_fileno( ofork->of_ad )) < 0)
             err = -1;
 
         if (err < 0)
-            LOG(log_error, logtype_default, "flushfork: hfile(%d) %s",
-                ad_hfileno(ofork->of_ad), strerror(errno) );
+            LOG(log_error, logtype_afpd, "flushfork(%s): hfile(%d) %s",
+                of_name(ofork), ad_reso_fileno(ofork->of_ad), strerror(errno) );
     }
 
     return( err );
 }
 
-int afp_closefork(obj, ibuf, ibuflen, rbuf, rbuflen )
-AFPObj      *obj;
-char   *ibuf, *rbuf;
-int            ibuflen, *rbuflen;
+int afp_closefork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
 {
-    struct ofork       *ofork;
-    struct timeval      tv;
-    int                        adflags, aint, doflush = 0;
-    u_int16_t          ofrefnum;
+    struct ofork    *ofork;
+    u_int16_t       ofrefnum;
 
     *rbuflen = 0;
     ibuf += 2;
     memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
 
-    if (( ofork = of_find( ofrefnum )) == NULL ) {
-        LOG(log_error, logtype_default, "afp_closefork: of_find");
+    if (NULL == ( ofork = of_find( ofrefnum )) ) {
+        LOG(log_error, logtype_afpd, "afp_closefork: of_find(%d) could not locate fork", ofrefnum );
         return( AFPERR_PARAM );
     }
 
-    adflags = 0;
-    if ((ofork->of_flags & AFPFORK_DATA) &&
-            (ad_dfileno( ofork->of_ad ) != -1)) {
-        adflags |= ADFLAGS_DF;
-    }
-
-    if ( ad_hfileno( ofork->of_ad ) != -1 ) {
-        adflags |= ADFLAGS_HF;
-
-        aint = ad_getentrylen( ofork->of_ad, ADEID_RFORK );
-        ad_refresh( ofork->of_ad );
-        if ((ofork->of_flags & AFPFORK_DIRTY) &&
-                (gettimeofday(&tv, NULL) == 0)) {
-            ad_setdate(ofork->of_ad, AD_DATE_MODIFY | AD_DATE_UNIX,
-                       tv.tv_sec);
-            doflush++;
-        }
+    LOG(log_debug, logtype_afpd,
+        "afp_closefork(\"%s\", fork: %s)",
+        cfrombstr(ofork->of_ad->ad_fullpath),
+        (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
 
-        /*
-         * Only set the rfork's length if we're closing the rfork.
-         */
-        if ((ofork->of_flags & AFPFORK_RSRC) && aint !=
-                ad_getentrylen( ofork->of_ad, ADEID_RFORK )) {
-            ad_setentrylen( ofork->of_ad, ADEID_RFORK, aint );
-            doflush++;
-        }
-        if ( doflush ) {
-            ad_flush( ofork->of_ad, adflags );
-        }
-    }
-
-    if ( ad_close( ofork->of_ad, adflags ) < 0 ) {
-        LOG(log_error, logtype_default, "afp_closefork: ad_close: %s", strerror(errno) );
+    if ( of_closefork( ofork ) < 0 ) {
+        LOG(log_error, logtype_afpd, "afp_closefork(%s): of_closefork: %s", of_name(ofork), strerror(errno) );
         return( AFPERR_PARAM );
     }
 
-    of_dealloc( ofork );
     return( AFP_OK );
 }
 
 
-static __inline__ ssize_t write_file(struct ofork *ofork, int eid,
-                                     off_t offset, char *rbuf,
-                                     size_t rbuflen, const int xlate)
+static ssize_t write_file(struct ofork *ofork, int eid,
+                          off_t offset, char *rbuf,
+                          size_t rbuflen, const int xlate)
 {
     char *p, *q;
     ssize_t cc;
@@ -1139,8 +1152,10 @@ static __inline__ ssize_t write_file(struct ofork *ofork, int eid,
         case EFBIG :
         case ENOSPC :
             return( AFPERR_DFULL );
+        case EACCES:
+            return AFPERR_ACCESS;
         default :
-            LOG(log_error, logtype_default, "afp_write: ad_write: %s", strerror(errno) );
+            LOG(log_error, logtype_afpd, "afp_write(%s): ad_write: %s", of_name(ofork), strerror(errno) );
             return( AFPERR_PARAM );
         }
     }
@@ -1148,18 +1163,16 @@ static __inline__ ssize_t write_file(struct ofork *ofork, int eid,
     return cc;
 }
 
+
 /* FPWrite. NOTE: on an error, we always use afp_write_err as
- * the client may have sent us a bunch of data that's not reflected 
+ * the client may have sent us a bunch of data that's not reflected
  * in reqcount et al. */
-int afp_write(obj, ibuf, ibuflen, rbuf, rbuflen)
-AFPObj              *obj;
-char                *ibuf, *rbuf;
-int                 ibuflen, *rbuflen;
+static int write_fork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen, int is64)
 {
-    struct ofork       *ofork;
-    int32_t            offset, saveoff, reqcount;
-    int                        endflag, eid, xlate = 0, err = AFP_OK;
-    u_int16_t          ofrefnum;
+    struct ofork    *ofork;
+    off_t               offset, saveoff, reqcount;
+    int             endflag, eid, xlate = 0, err = AFP_OK;
+    u_int16_t       ofrefnum;
     ssize_t             cc;
 
     /* figure out parameters */
@@ -1168,19 +1181,21 @@ int                 ibuflen, *rbuflen;
     ibuf++;
     memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
     ibuf += sizeof( ofrefnum );
-    memcpy(&offset, ibuf, sizeof( offset ));
-    offset = ntohl( offset );
-    ibuf += sizeof( offset );
-    memcpy(&reqcount, ibuf, sizeof( reqcount ));
-    reqcount = ntohl( reqcount );
-    ibuf += sizeof( reqcount );
-
-    if (( ofork = of_find( ofrefnum )) == NULL ) {
-        LOG(log_error, logtype_default, "afp_write: of_find");
+
+    offset   = get_off_t(&ibuf, is64);
+    reqcount = get_off_t(&ibuf, is64);
+
+    if (NULL == ( ofork = of_find( ofrefnum )) ) {
+        LOG(log_error, logtype_afpd, "afp_write: of_find(%d) could not locate fork", ofrefnum );
         err = AFPERR_PARAM;
         goto afp_write_err;
     }
 
+    LOG(log_debug, logtype_afpd,
+        "afp_write(\"%s\", off: %" PRIu64 ", size: %" PRIu64 ", fork: %s)",
+        cfrombstr(ofork->of_ad->ad_fullpath), offset, reqcount,
+        (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
+
     if ((ofork->of_flags & AFPFORK_ACCWR) == 0) {
         err = AFPERR_ACCESS;
         goto afp_write_err;
@@ -1211,21 +1226,20 @@ int                 ibuflen, *rbuflen;
 
     /* offset can overflow on 64-bit capable filesystems.
      * report disk full if that's going to happen. */
-    if (offset + reqcount < 0) {
+    if (sum_neg(is64, offset, reqcount)) {
         err = AFPERR_DFULL;
         goto afp_write_err;
     }
 
     if (!reqcount) { /* handle request counts of 0 */
         err = AFP_OK;
-        offset = htonl(offset);
-        memcpy(rbuf, &offset, sizeof(offset));
+        *rbuflen = set_off_t (offset, rbuf, is64);
         goto afp_write_err;
     }
 
     saveoff = offset;
     if (ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, saveoff,
-                   reqcount) < 0) {
+                   reqcount, ofork->of_refnum) < 0) {
         err = AFPERR_LOCK;
         goto afp_write_err;
     }
@@ -1236,19 +1250,14 @@ int                 ibuflen, *rbuflen;
     case AFPPROTO_ASP:
         if (asp_wrtcont(obj->handle, rbuf, rbuflen) < 0) {
             *rbuflen = 0;
-            LOG(log_error, logtype_default, "afp_write: asp_wrtcont: %s", strerror(errno) );
+            LOG(log_error, logtype_afpd, "afp_write: asp_wrtcont: %s", strerror(errno) );
             return( AFPERR_PARAM );
         }
 
-        if (obj->options.flags & OPTION_DEBUG) {
-            printf("(write) len: %d\n", *rbuflen);
-            bprint(rbuf, *rbuflen);
-        }
-
         if ((cc = write_file(ofork, eid, offset, rbuf, *rbuflen,
                              xlate)) < 0) {
             *rbuflen = 0;
-            ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount);
+            ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
             return cc;
         }
         offset += cc;
@@ -1256,80 +1265,66 @@ int                 ibuflen, *rbuflen;
 #endif /* no afp/asp */
 
     case AFPPROTO_DSI:
-        {
-            DSI *dsi = obj->handle;
+    {
+        DSI *dsi = obj->handle;
 
-            /* find out what we have already and write it out. */
-            cc = dsi_writeinit(dsi, rbuf, *rbuflen);
-            if (!cc ||
-                    (cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
+        /* find out what we have already and write it out. */
+        cc = dsi_writeinit(dsi, rbuf, *rbuflen);
+        if (!cc || (cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
+            dsi_writeflush(dsi);
+            *rbuflen = 0;
+            ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
+            return cc;
+        }
+        offset += cc;
+
+#if 0 /*def HAVE_SENDFILE_WRITE*/
+        if (!(xlate || obj->options.flags & OPTION_DEBUG)) {
+            if ((cc = ad_writefile(ofork->of_ad, eid, dsi->socket,
+                                   offset, dsi->datasize)) < 0) {
+                switch (errno) {
+                case EDQUOT :
+                case EFBIG :
+                case ENOSPC :
+                    cc = AFPERR_DFULL;
+                    break;
+                default :
+                    LOG(log_error, logtype_afpd, "afp_write: ad_writefile: %s", strerror(errno) );
+                    goto afp_write_loop;
+                }
                 dsi_writeflush(dsi);
                 *rbuflen = 0;
-                ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount);
+                ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
+                           reqcount,  ofork->of_refnum);
                 return cc;
             }
-            offset += cc;
-
-#if 0 /*def HAVE_SENDFILE_WRITE*/
-            if (!(xlate || obj->options.flags & OPTION_DEBUG)) {
-                if ((cc = ad_writefile(ofork->of_ad, eid, dsi->socket,
-                                       offset, dsi->datasize)) < 0) {
-                    switch (errno) {
-                    case EDQUOT :
-                    case EFBIG :
-                    case ENOSPC :
-                        cc = AFPERR_DFULL;
-                        break;
-                    default :
-                        LOG(log_error, logtype_default, "afp_write: ad_writefile: %s", strerror(errno) );
-                        goto afp_write_loop;
-                    }
-                    dsi_writeflush(dsi);
-                    *rbuflen = 0;
-                    ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
-                               reqcount);
-                    return cc;
-                }
 
-                offset += cc;
-                goto afp_write_done;
-            }
+            offset += cc;
+            goto afp_write_done;
+        }
 #endif /* 0, was HAVE_SENDFILE_WRITE */
 
-            /* loop until everything gets written. currently
-                    * dsi_write handles the end case by itself. */
-afp_write_loop:
-            while ((cc = dsi_write(dsi, rbuf, *rbuflen))) {
-                if ( obj->options.flags & OPTION_DEBUG ) {
-                    printf("(write) command cont'd: %d\n", cc);
-                    bprint(rbuf, cc);
-                }
-
-                if ((cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
-                    dsi_writeflush(dsi);
-                    *rbuflen = 0;
-                    ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
-                               reqcount);
-                    return cc;
-                }
-                offset += cc;
+        /* loop until everything gets written. currently
+         * dsi_write handles the end case by itself. */
+        while ((cc = dsi_write(dsi, rbuf, *rbuflen))) {
+            if ((cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
+                dsi_writeflush(dsi);
+                *rbuflen = 0;
+                ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
+                           reqcount,  ofork->of_refnum);
+                return cc;
             }
+            offset += cc;
         }
-        break;
+    }
+    break;
     }
 
-afp_write_done:
-    ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount);
-    if ( ad_hfileno( ofork->of_ad ) != -1 )
+    ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount,  ofork->of_refnum);
+    if ( ad_meta_fileno( ofork->of_ad ) != -1 ) /* META */
         ofork->of_flags |= AFPFORK_DIRTY;
 
-    offset = htonl( offset );
-#if defined(__GNUC__) && defined(HAVE_GCC_MEMCPY_BUG)
-    bcopy(&offset, rbuf, sizeof(offset));
-#else /* __GNUC__ && HAVE_GCC_MEMCPY_BUG */
-    memcpy(rbuf, &offset, sizeof(offset));
-#endif /* __GNUC__ && HAVE_GCC_MEMCPY_BUG */
-    *rbuflen = sizeof(offset);
+    *rbuflen = set_off_t (offset, rbuf, is64);
     return( AFP_OK );
 
 afp_write_err:
@@ -1337,21 +1332,33 @@ afp_write_err:
         dsi_writeinit(obj->handle, rbuf, *rbuflen);
         dsi_writeflush(obj->handle);
     }
-
-    *rbuflen = (err == AFP_OK) ? sizeof(offset) : 0;
+    if (err != AFP_OK) {
+        *rbuflen = 0;
+    }
     return err;
 }
 
+/* ---------------------------- */
+int afp_write(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
+{
+    return write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 0);
+}
 
-int afp_getforkparams(obj, ibuf, ibuflen, rbuf, rbuflen )
-AFPObj      *obj;
-char   *ibuf, *rbuf;
-int            ibuflen, *rbuflen;
+/* ----------------------------
+ * FIXME need to deal with SIGXFSZ signal
+ */
+int afp_write_ext(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
 {
-    struct ofork       *ofork;
-    int                        buflen, ret;
-    u_int16_t          ofrefnum, bitmap;
+    return write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 1);
+}
 
+/* ---------------------------- */
+int afp_getforkparams(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
+{
+    struct ofork    *ofork;
+    int             ret;
+    u_int16_t       ofrefnum, bitmap;
+    size_t          buflen;
     ibuf += 2;
     memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
     ibuf += sizeof( ofrefnum );
@@ -1360,13 +1367,20 @@ int             ibuflen, *rbuflen;
     ibuf += sizeof( bitmap );
 
     *rbuflen = 0;
-    if (( ofork = of_find( ofrefnum )) == NULL ) {
-        LOG(log_error, logtype_default, "afp_getforkparams: of_find");
+    if (NULL == ( ofork = of_find( ofrefnum )) ) {
+        LOG(log_error, logtype_afpd, "afp_getforkparams: of_find(%d) could not locate fork", ofrefnum );
         return( AFPERR_PARAM );
     }
 
-    if (( ret = getforkparams( ofork, bitmap,
-                               rbuf + sizeof( u_short ), &buflen, 0 )) != AFP_OK ) {
+    if ( ad_meta_fileno( ofork->of_ad ) != -1 ) { /* META */
+        if ( ad_refresh( ofork->of_ad ) < 0 ) {
+            LOG(log_error, logtype_afpd, "getforkparams(%s): ad_refresh: %s", of_name(ofork), strerror(errno) );
+            return( AFPERR_PARAM );
+        }
+    }
+
+    if (AFP_OK != ( ret = getforkparams( ofork, bitmap,
+                                         rbuf + sizeof( u_short ), &buflen ))) {
         return( ret );
     }