]> arthur.barton.de Git - netatalk.git/blobdiff - etc/afpd/fork.c
remove gcc warnings and cleanup inline mess
[netatalk.git] / etc / afpd / fork.c
index 227c575e16d56ae16a542b304b1d29499a8911fb..c537c03b6ff16ad7daa79dcfd44a4cd34968d317 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: fork.c,v 1.16 2002-01-17 16:19:06 jmarcus Exp $
+ * $Id: fork.c,v 1.51.2.2.2.10.2.6 2008-11-25 15:16:33 didg Exp $
  *
  * Copyright (c) 1990,1993 Regents of The University of Michigan.
  * All Rights Reserved.  See COPYRIGHT.
 #endif /* HAVE_CONFIG_H */
 
 #include <stdio.h>
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif /* HAVE_UNISTD_H */
-#ifdef HAVE_FCNTL_H
-#include <fcntl.h>
-#endif /* HAVE_FCNTL_H */
+
 #include <dirent.h>
 #include <string.h>
 #include <errno.h>
+
+#include <atalk/adouble.h>
 #include <atalk/logger.h>
 
 #include <sys/param.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/time.h>
 #include <sys/socket.h>
 
-#include <netatalk/endian.h>
 #include <netatalk/at.h>
 
 #include <atalk/dsi.h>
 #include <atalk/atp.h>
 #include <atalk/asp.h>
 #include <atalk/afp.h>
-#include <atalk/adouble.h>
+
 #include <atalk/util.h>
-#ifdef CNID_DB
 #include <atalk/cnid.h>
-#endif
 
 #include "fork.h"
 #include "file.h"
 #include "desktop.h"
 #include "volume.h"
 
-#define BYTELOCK_MAX 0x7FFFFFFFU
+#ifdef DEBUG1
+#define Debug(a) ((a)->options.flags & OPTION_DEBUG)
+#else
+#define Debug(a) (0)
+#endif
 
 struct ofork           *writtenfork;
+extern int getmetadata(struct vol *vol,
+                 u_int16_t bitmap,
+                 struct path *path, struct dir *dir, char *buf, 
+                 int *buflen, struct adouble *adp, int attrbits );
 
 static int getforkparams(ofork, bitmap, buf, buflen, attrbits )
 struct ofork   *ofork;
@@ -58,1313 +57,1429 @@ char            *buf;
 int                    *buflen;
 const u_int16_t     attrbits;
 {
-#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;
+    struct path         path;
+    struct stat                *st;
 
-    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 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_hfileno( ofork->of_ad ) == -1 ) {
+        adp = NULL;
+    } else {
+        adp = ofork->of_ad;
+    }
+
+    vol = ofork->of_vol;
+    dir = ofork->of_dir;
+
+    if (NULL == (path.u_name = mtoupath(vol, of_name(ofork), dir->d_did, utf8_encoding()))) {
+        return( AFPERR_MISC );
+    }
+    path.m_name = of_name(ofork);
+    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_dfileno( ofork->of_ad ) == -1 ) {
-            if ( stat( upath, &st ) < 0 )
+            if (movecwd(vol, dir) < 0)
+                return( AFPERR_NOOBJ );
+            if ( stat( path.u_name, st ) < 0 )
                 return( AFPERR_NOOBJ );
         } else {
-            if ( fstat( ad_dfileno( ofork->of_ad ), &st ) < 0 ) {
+            if ( fstat( ad_dfileno( ofork->of_ad ), st ) < 0 ) {
                 return( AFPERR_BITMAP );
             }
         }
     }
+    return getmetadata(vol, bitmap, &path, dir, buf, buflen, adp, attrbits );    
+}
 
-    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;
+/* ---------------------------- */
+static off_t get_off_t(ibuf, is64)
+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;
+}
+
+/* ---------------------- */
+static int set_off_t(offset, rbuf, is64)
+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_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;
+    return ret;
+}
 
-        case FILPBIT_LNAME :
-            nameoff = data;
-            data += sizeof(u_int16_t);
-            break;
+/* ------------------------ 
+*/
+static int is_neg(int is64, off_t val)
+{
+    if (val < 0 || (sizeof(off_t) == 8 && !is64 && (val & 0x80000000U)))
+       return 1;
+    return 0;
+}
 
-        case FILPBIT_SNAME :
-            memset(data, 0, sizeof(u_int16_t));
-            data += sizeof(u_int16_t);
-            break;
+static int sum_neg(int is64, off_t offset, off_t reqcount) 
+{
+    if (is_neg(is64, offset +reqcount) ) 
+       return 1;
+    return 0;
+}
+
+/* -------------------------
+*/
+static int setforkmode(struct adouble *adp, int eid, int ofrefnum, int what)
+{
+    return ad_lock(adp, eid, ADLOCK_RD | ADLOCK_FILELOCK, what, 1, ofrefnum);
+}
 
-        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_MAX) {
-                switch (aint) {
-                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 */
-                }
+/* -------------------------
+*/
+int getforkmode(struct adouble *adp, int eid, int what)
+{
+    return ad_testlock(adp, eid,  what);
+}
 
-                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 setforkmode(adp, eid, ofrefnum, AD_FILELOCK_OPEN_NONE);
+    }
 
-            case FILPBIT_DFLEN :
-                aint = htonl( st.st_size );
-                memcpy(data, &aint, sizeof( aint ));
-                data += sizeof( aint );
-                break;
+    if ((access & (OPENACC_RD | OPENACC_DRD))) {
+        if ((readset = getforkmode(adp, eid, AD_FILELOCK_OPEN_RD)) <0)
+            return readset;
+        if ((denyreadset = getforkmode(adp, eid, AD_FILELOCK_DENY_RD)) <0)
+            return denyreadset;
 
-            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;
-
-            default :
-                return( AFPERR_BITMAP );
-            }
-            bitmap = bitmap>>1;
-            bit++;
+        if ((access & OPENACC_RD) && denyreadset) {
+            errno = EACCES;
+            return -1;
         }
-
-        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;
+        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 = setforkmode(adp, eid, ofrefnum, AD_FILELOCK_OPEN_RD);
+            if (ret)
+                return ret;
+        }
+        if ((access & OPENACC_DRD)) {
+            ret = setforkmode(adp, eid, ofrefnum, AD_FILELOCK_DENY_RD);
+            if (ret)
+                return ret;
+        }
+    }
+    /* ------------same for writing -------------- */
+    if ((access & (OPENACC_WR | OPENACC_DWR))) {
+        if ((writeset = getforkmode(adp, eid, AD_FILELOCK_OPEN_WR)) <0)
+            return writeset;
+        if ((denywriteset = getforkmode(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 = setforkmode(adp, eid, ofrefnum, AD_FILELOCK_OPEN_WR);
+            if (ret)
+                return ret;
         }
+        if ((access & OPENACC_DWR)) {
+            ret = setforkmode(adp, eid, ofrefnum, AD_FILELOCK_DENY_WR);
+            if (ret)
+                return ret;
+        }
+    }
+    if ( access == (OPENACC_WR | OPENACC_RD | OPENACC_DWR | OPENACC_DRD)) {
+        return ad_excl_lock(adp, eid);
+    }
+    return 0;
+}
+
+/* ----------------------- */
+int afp_openfork(obj, ibuf, ibuflen, rbuf, rbuflen )
+AFPObj  *obj _U_;
+char   *ibuf, *rbuf;
+int    ibuflen _U_, *rbuflen;
+{
+    struct vol         *vol;
+    struct dir         *dir;
+    struct ofork       *ofork, *opened;
+    struct adouble      *adsame = NULL;
+    int                        buflen, ret, adflags, eid;
+    u_int32_t           did;
+    u_int16_t          vid, bitmap, access, ofrefnum, attrbits = 0;
+    char               fork, *path, *upath;
+    struct stat         *st;
+    u_int16_t           bshort;
+    struct path         *s_path;
+    
+    ibuf++;
+    fork = *ibuf++;
+    memcpy(&vid, ibuf, sizeof( vid ));
+    ibuf += sizeof(vid);
+
+    *rbuflen = 0;
+    if (NULL == ( vol = getvolbyvid( vid ))) {
+        return( AFPERR_PARAM );
+    }
 
-        *buflen = data - buf;
-        return( AFP_OK );
-    }
-
-    int afp_openfork(obj, ibuf, ibuflen, rbuf, rbuflen )
-    AFPObj      *obj;
-    char       *ibuf, *rbuf;
-    int                ibuflen, *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;
-
-        ibuf++;
-        fork = *ibuf++;
-        memcpy(&vid, ibuf, sizeof( vid ));
-        ibuf += sizeof(vid);
+    memcpy(&did, ibuf, sizeof( did ));
+    ibuf += sizeof( int );
 
-        *rbuflen = 0;
-        if (( vol = getvolbyvid( vid )) == NULL ) {
-            return( AFPERR_PARAM );
-        }
+    if (NULL == ( dir = dirlookup( vol, did ))) {
+       return afp_errno;    
+    }
 
-        memcpy(&did, ibuf, sizeof( did ));
-        ibuf += sizeof( int );
+    memcpy(&bitmap, ibuf, sizeof( bitmap ));
+    bitmap = ntohs( bitmap );
+    ibuf += sizeof( bitmap );
+    memcpy(&access, ibuf, sizeof( access ));
+    access = ntohs( access );
+    ibuf += sizeof( access );
 
-        if (( dir = dirsearch( vol, did )) == NULL ) {
-            return( AFPERR_NOOBJ );
-        }
+    if ((vol->v_flags & AFPVOL_RO) && (access & OPENACC_WR)) {
+        return AFPERR_VLOCK;
+    }
 
-        memcpy(&bitmap, ibuf, sizeof( bitmap ));
-        bitmap = ntohs( bitmap );
-        ibuf += sizeof( bitmap );
-        memcpy(&access, ibuf, sizeof( access ));
-        access = ntohs( access );
-        ibuf += sizeof( access );
+    if (NULL == ( s_path = cname( vol, dir, &ibuf ))) {
+       return get_afp_errno(AFPERR_PARAM);    
+    }
 
-        if ((vol->v_flags & AFPVOL_RO) && (access & OPENACC_WR)) {
-            return AFPERR_VLOCK;
-        }
+    if (*s_path->m_name == '\0') {
+       /* it's a dir ! */
+       return  AFPERR_BADTYPE;
+    }
 
-        if (( path = cname( vol, dir, &ibuf )) == NULL ) {
-            return( AFPERR_NOOBJ );
+    /* 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): ad_open: %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;
         }
-
-        if ( fork == OPENFORK_DATA ) {
-            eid = ADEID_DFORK;
-            adflags = ADFLAGS_DF|ADFLAGS_HF;
-        } else {
-            eid = ADEID_RFORK;
-            adflags = ADFLAGS_HF;
+    }
+    else {
+        if (file_access(s_path, access ) < 0) {
+            return AFPERR_ACCESS;
         }
+    }
 
-        /* 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);
-            adsame = opened->of_ad;
-        }
+    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.
+       FIXME: add the fork we are opening? 
+    */
+    if ((opened = of_findname(s_path))) {
+        attrbits = ((opened->of_ad->ad_df.adf_refcount > 0) ? ATTRBIT_DOPEN : 0);
+        attrbits |= ((opened->of_ad->ad_hf.adf_refcount > opened->of_ad->ad_df.adf_refcount)? ATTRBIT_ROPEN : 0);
+                   
+        adsame = opened->of_ad;
+    }
 
-        if (( ofork = of_alloc(vol, curdir, path, &ofrefnum, eid,
-                               adsame)) == NULL ) {
-            return( AFPERR_NFILE );
-        }
-        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) {
-                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
-                            goto openfork_err;
+    if ( fork == OPENFORK_DATA ) {
+        eid = ADEID_DFORK;
+        adflags = ADFLAGS_DF|ADFLAGS_HF;
+    } else {
+        eid = ADEID_RFORK;
+        adflags = ADFLAGS_HF;
+    }
+
+    path = s_path->m_name;
+    if (( ofork = of_alloc(vol, curdir, path, &ofrefnum, eid,
+                           adsame, st)) == NULL ) {
+        return( AFPERR_NFILE );
+    }
+
+    ret = AFPERR_NOOBJ;
+    if (access & OPENACC_WR) {
+        /* try opening in read-write mode */
+        if (ad_open(upath, adflags, O_RDWR, 0, ofork->of_ad) < 0) {
+            switch ( errno ) {
+            case EROFS:
+                ret = AFPERR_VLOCK;
+            case EACCES:
+                goto openfork_err;
+                break;
+            case ENOENT:
+                if (fork == OPENFORK_DATA) {
+                    /* try to open only the data fork */
+                    if (ad_open(upath, ADFLAGS_DF, O_RDWR, 0, ofork->of_ad) < 0) {
+                        goto openfork_err;
                     }
-                    break;
-                case EMFILE :
-                case ENFILE :
-                    ret = AFPERR_NFILE;
-                    goto openfork_err;
-                    break;
-                case EISDIR :
-                    ret = AFPERR_BADTYPE;
-                    goto openfork_err;
-                    break;
-                default:
-                    LOG(log_error, logtype_default, "afp_openfork: ad_open: %s", strerror(errno) );
-                    ret = AFPERR_PARAM;
-                    goto openfork_err;
-                    break;
+                    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(upath, adflags, O_RDWR | O_CREAT, 0666, ofork->of_ad) < 0)
+                        goto openfork_err;
+                    ofork->of_flags |= AFPFORK_OPEN;
+                }
+                break;
+            case EMFILE :
+            case ENFILE :
+                ret = AFPERR_NFILE;
+                goto openfork_err;
+                break;
+            case EISDIR :
+                ret = AFPERR_BADTYPE;
+                goto openfork_err;
+                break;
+            default:
+                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 {
-            /* 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) {
-                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))
+        }
+        else {
+            /* the ressource fork is open too */
+            ofork->of_flags |= AFPFORK_OPEN;
+        }
+    } else {
+        /* try opening in read-only mode */
+        ret = AFPERR_NOOBJ;
+        if (ad_open(upath, adflags, O_RDONLY, 0, ofork->of_ad) < 0) {
+            switch ( errno ) {
+            case EROFS:
+                ret = AFPERR_VLOCK;
+            case EACCES:
+                goto openfork_err;
+                break;
+            case ENOENT:
+                /* see if client asked for a read only 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;
-                    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) {
-                            goto openfork_err;
-                        }
                     }
-                    break;
-                case EMFILE :
-                case ENFILE :
-                    ret = AFPERR_NFILE;
-                    goto openfork_err;
-                    break;
-                case EISDIR :
-                    ret = AFPERR_BADTYPE;
-                    goto openfork_err;
-                    break;
-                default:
-                    LOG(log_error, logtype_default, "afp_openfork: ad_open: %s", strerror(errno) );
-                    goto openfork_err;
-                    break;
+                    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 :
+                ret = AFPERR_NFILE;
+                goto openfork_err;
+                break;
+            case EISDIR :
+                ret = AFPERR_BADTYPE;
+                goto openfork_err;
+                break;
+            default:
+                LOG(log_error, logtype_afpd, "afp_openfork(%s): ad_open: %s", s_path->m_name, strerror(errno) );
+                goto openfork_err;
+                break;
             }
         }
-
-        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 );
+        else {
+            /* the ressource fork is open too */
+            ofork->of_flags |= AFPFORK_OPEN;
         }
+    }
 
-        if (( ret = getforkparams(ofork, bitmap, rbuf + 2 * sizeof( u_int16_t ),
-                                  &buflen, attrbits )) != AFP_OK ) {
-            ad_close( ofork->of_ad, adflags );
-            goto openfork_err;
+    if ((adflags & ADFLAGS_HF) && (ad_get_HF_flags( ofork->of_ad) & O_CREAT)) {
+        if (ad_setname(ofork->of_ad, path)) {
+            ad_flush( ofork->of_ad, adflags );
         }
+    }
 
-        *rbuflen = buflen + 2 * sizeof( u_int16_t );
-        bitmap = htons( bitmap );
-        memcpy(rbuf, &bitmap, sizeof( u_int16_t ));
-        rbuf += sizeof( u_int16_t );
+    if (( ret = getforkparams(ofork, bitmap, rbuf + 2 * sizeof( u_int16_t ),
+                              &buflen, attrbits )) != AFP_OK ) {
+        ad_close( ofork->of_ad, adflags );
+        goto openfork_err;
+    }
 
-        /*
-         * 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.
-         */
+    *rbuflen = buflen + 2 * sizeof( u_int16_t );
+    bitmap = htons( bitmap );
+    memcpy(rbuf, &bitmap, sizeof( u_int16_t ));
+    rbuf += sizeof( u_int16_t );
 
-        /* don't try to lock non-existent rforks. */
-        if ((eid == ADEID_DFORK) || (ad_hfileno(ofork->of_ad) != -1)) {
+    /* check  WriteInhibit bit if we have a ressource fork
+     * the test is done here, after some Mac trafic capture 
+     */
+    if (ad_hfileno(ofork->of_ad) != -1) {
+        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_OLOCK);
+        }
+    }
 
-            /* 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);
-            }
+    /*
+     * synchronization locks:
+     */
 
-            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);
-            }
+    /* don't try to lock non-existent rforks. */
+    if ((eid == ADEID_DFORK) || (ad_hfileno(ofork->of_ad) != -1)) {
 
-            /* can we access the fork? */
-            if (ret < 0) {
-                ad_close( ofork->of_ad, adflags );
-                of_dealloc( ofork );
+        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 );
+            of_dealloc( ofork );
+            switch (ret) {
+            case EAGAIN: /* return data anyway */
+            case EACCES:
+            case EINVAL:
                 ofrefnum = 0;
                 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
-                return (AFPERR_DENYCONF);
-            }
-
-            /* 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);
-
-            if (ret < 0) {
-                ret = errno;
-                ad_close( ofork->of_ad, adflags );
-                of_dealloc( ofork );
-                switch (ret) {
-                case EAGAIN: /* return data anyway */
-                case EACCES:
-                case EINVAL:
-                    ofrefnum = 0;
-                    memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
-                    return( AFPERR_DENYCONF );
-                    break;
-                default:
-                    *rbuflen = 0;
-                    LOG(log_error, logtype_default, "afp_openfork: ad_lock: %s", strerror(errno) );
-                    return( AFPERR_PARAM );
-                }
+                return( AFPERR_DENYCONF );
+                break;
+            default:
+                *rbuflen = 0;
+                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 );
+    memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
+    return( AFP_OK );
 
 openfork_err:
-        of_dealloc( ofork );
-        if (errno == EACCES)
-            return (access & OPENACC_WR) ? AFPERR_LOCK : AFPERR_ACCESS;
-        return ret;
-    }
-
-    int afp_setforkparams(obj, ibuf, ibuflen, rbuf, rbuflen )
-    AFPObj      *obj;
-    char       *ibuf, *rbuf;
-    int                ibuflen, *rbuflen;
-    {
-        struct ofork   *ofork;
-        int32_t                size;
-        u_int16_t              ofrefnum, bitmap;
-        int                 err;
-
-        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 );
+    of_dealloc( ofork );
+    if (errno == EACCES)
+        return (access & OPENACC_WR) ? AFPERR_LOCK : AFPERR_ACCESS;
+    return ret;
+}
+
+int afp_setforkparams(obj, ibuf, ibuflen, rbuf, rbuflen )
+AFPObj  *obj _U_;
+char   *ibuf, *rbuf _U_;
+int    ibuflen, *rbuflen;
+{
+    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 );
+
+    *rbuflen = 0;
+    if (NULL == ( ofork = of_find( ofrefnum )) ) {
+        LOG(log_error, logtype_afpd, "afp_setforkparams: of_find(%d) could not locate fork", ofrefnum );
+        return( AFPERR_PARAM );
+    }
 
-        *rbuflen = 0;
-        if (( ofork = of_find( ofrefnum )) == NULL ) {
-            LOG(log_error, logtype_default, "afp_setforkparams: of_find: %s", strerror(errno) );
-            return( AFPERR_PARAM );
+    if (ofork->of_vol->v_flags & AFPVOL_RO)
+        return AFPERR_VLOCK;
+
+    if ((ofork->of_flags & AFPFORK_ACCWR) == 0)
+        return AFPERR_ACCESS;
+
+    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) | (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 (ofork->of_vol->v_flags & AFPVOL_RO)
-            return AFPERR_VLOCK;
+    if (ibuflen < 2+ sizeof(ofrefnum) + sizeof(bitmap) + is64 +4)
+        return AFPERR_PARAM ;
+    
+    size = get_off_t(&ibuf, is64);
 
-        if ((ofork->of_flags & AFPFORK_ACCWR) == 0)
-            return AFPERR_ACCESS;
+    if (size < 0)
+        return AFPERR_PARAM; /* Some MacOS don't return an error they just don't change the size! */
 
-        if (size < 0)
-            return AFPERR_PARAM;
 
-        if ((bitmap == (1<<FILPBIT_DFLEN)) && (ofork->of_flags & AFPFORK_DATA)) {
-            err = ad_dtruncate( ofork->of_ad, size );
-            if (err < 0)
-                goto afp_setfork_err;
-        } else if ((bitmap == (1<<FILPBIT_RFLEN)) &&
-                   (ofork->of_flags & AFPFORK_RSRC)) {
-            ad_refresh( ofork->of_ad );
-            err = ad_rtruncate(ofork->of_ad, size);
-            if (err < 0)
-                goto afp_setfork_err;
+    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;
 
-            if (ad_flush( ofork->of_ad, ADFLAGS_HF ) < 0) {
-                LOG(log_error, logtype_default, "afp_setforkparams: ad_flush: %s",
-                    strerror(errno) );
-                return( AFPERR_PARAM );
-            }
-        } else
-            return AFPERR_BITMAP;
+        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) || 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;
 
-#ifdef AFS
-        if ( flushfork( ofork ) < 0 ) {
-            LOG(log_error, logtype_default, "afp_setforkparams: flushfork: %s", strerror(errno) );
+        if (ad_flush( ofork->of_ad, ADFLAGS_HF ) < 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_afpd, "afp_setforkparams(%s): flushfork: %s", of_name(ofork), strerror(errno) );
+    }
 #endif /* AFS */
 
-        return( AFP_OK );
+    return( AFP_OK );
 
 afp_setfork_err:
-        if (err == -2)
-            return AFPERR_LOCK;
-        else {
-            switch (errno) {
-            case EROFS:
-                return AFPERR_VLOCK;
-            case EPERM:
-            case EACCES:
-                return AFPERR_ACCESS;
-            case EDQUOT:
-            case EFBIG:
-            case ENOSPC:
-                return AFPERR_DFULL;
-            default:
-                return AFPERR_PARAM;
-            }
+    if (err == -2)
+        return AFPERR_LOCK;
+    else {
+        switch (errno) {
+        case EROFS:
+            return AFPERR_VLOCK;
+        case EPERM:
+        case EACCES:
+            return AFPERR_ACCESS;
+        case EDQUOT:
+        case EFBIG:
+        case ENOSPC:
+            return AFPERR_DFULL;
+        default:
+            return AFPERR_PARAM;
         }
     }
+}
 
-    /* for this to work correctly, we need to check for locks before each
    * 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. 
    */
+/* for this to work correctly, we need to check for locks before each
+ * 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. 
+ */
 #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;
-    {
-        struct ofork   *ofork;
-        int32_t             offset, length;
-        int                 eid;
-        u_int16_t              ofrefnum;
-        u_int8_t            flags;
-
-        *rbuflen = 0;
-
-        /* figure out parameters */
-        ibuf++;
-        flags = *ibuf; /* first bit = endflag, lastbit = lockflag */
-        ibuf++;
-        memcpy(&ofrefnum, ibuf, sizeof(ofrefnum));
-        ibuf += sizeof(ofrefnum);
-
-        if (( ofork = of_find( ofrefnum )) == NULL ) {
-            LOG(log_error, logtype_default, "afp_bytelock: of_find: %s", strerror(errno) );
-            return( AFPERR_PARAM );
-        }
-
-        if ( ofork->of_flags & AFPFORK_DATA) {
-            eid = ADEID_DFORK;
-        } else if (ofork->of_flags & AFPFORK_RSRC) {
-            eid = ADEID_RFORK;
-        } else
-            return AFPERR_PARAM;
 
-        memcpy(&offset, ibuf, sizeof( offset ));
-        offset = ntohl(offset);
-        ibuf += sizeof(offset);
 
-        memcpy(&length, ibuf, sizeof( length ));
-        length = ntohl(length);
-        if (length == 0xFFFFFFFF)
-            length = BYTELOCK_MAX;
-        else if (length <= 0) {
-            return AFPERR_PARAM;
-        } else if ((length >= AD_FILELOCK_BASE) &&
-                   (ad_hfileno(ofork->of_ad) == -1))
-            return AFPERR_LOCK;
+/* ---------------------- */
+static int byte_lock(obj, ibuf, ibuflen, rbuf, rbuflen, is64 )
+AFPObj  *obj _U_;
+char   *ibuf, *rbuf;
+int    ibuflen _U_, *rbuflen;
+int     is64;
+{
+    struct ofork       *ofork;
+    off_t               offset, length;
+    int                 eid;
+    u_int16_t          ofrefnum;
+    u_int8_t            flags;
+    int                 lockop;
+    
+    *rbuflen = 0;
+
+    /* figure out parameters */
+    ibuf++;
+    flags = *ibuf; /* first bit = endflag, lastbit = lockflag */
+    ibuf++;
+    memcpy(&ofrefnum, ibuf, sizeof(ofrefnum));
+    ibuf += sizeof(ofrefnum);
+
+    if (NULL == ( ofork = of_find( ofrefnum )) ) {
+        LOG(log_error, logtype_afpd, "afp_bytelock: of_find(%d) could not locate fork", ofrefnum );
+        return( AFPERR_PARAM );
+    }
 
-        if (ENDBIT(flags))
-            offset += ad_size(ofork->of_ad, eid);
+    if ( ofork->of_flags & AFPFORK_DATA) {
+        eid = ADEID_DFORK;
+    } else if (ofork->of_flags & AFPFORK_RSRC) {
+        eid = ADEID_RFORK;
+    } else
+        return AFPERR_PARAM;
+
+    offset = get_off_t(&ibuf, is64);
+    length = get_off_t(&ibuf, is64);
+
+    /* FIXME AD_FILELOCK test is surely wrong */
+    if (length == -1)
+        length = BYTELOCK_MAX;
+     else if (!length || is_neg(is64, length)) {
+       return AFPERR_PARAM;
+     } else if ((length >= AD_FILELOCK_BASE) && -1 == (ad_hfileno(ofork->of_ad))) {
+        return AFPERR_LOCK;
+    }
 
-        if (offset < 0)    /* error if we have a negative offset */
+    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. */
+    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:
+        case EAGAIN:
+            return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_LOCK;
+            break;
+        case ENOLCK:
+            return AFPERR_NLOCK;
+            break;
+        case EINVAL:
+            return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_RANGEOVR;
+            break;
+        case EBADF:
+        default:
             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,
-                    ofork->of_refnum) < 0) {
-            switch (errno) {
-            case EACCES:
-            case EAGAIN:
-                return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_LOCK;
-                break;
-            case ENOLCK:
-                return AFPERR_NLOCK;
-                break;
-            case EINVAL:
-                return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_RANGEOVR;
-                break;
-            case EBADF:
-            default:
-                return AFPERR_PARAM;
-                break;
-            }
+            break;
         }
-
-        offset = htonl(offset);
-        memcpy(rbuf, &offset, sizeof( offset ));
-        *rbuflen = sizeof( offset );
-        return( AFP_OK );
     }
+    *rbuflen = set_off_t (offset, rbuf, is64);
+    return( AFP_OK );
+}
+
+/* --------------------------- */
+int afp_bytelock(obj, ibuf, ibuflen, rbuf, rbuflen )
+AFPObj  *obj;
+char   *ibuf, *rbuf;
+int    ibuflen, *rbuflen;
+{
+   return byte_lock ( obj, ibuf, ibuflen, rbuf, rbuflen , 0);
+}
+
+/* --------------------------- */
+int afp_bytelock_ext(obj, ibuf, ibuflen, rbuf, rbuflen )
+AFPObj  *obj;
+char   *ibuf, *rbuf;
+int    ibuflen, *rbuflen;
+{
+   return byte_lock ( obj, ibuf, ibuflen, rbuf, rbuflen , 1);
+}
+
 #undef UNLOCKBIT
 
+/* --------------------------- */
+static int crlf( of )
+struct ofork   *of;
+{
+    struct extmap      *em;
 
-    static __inline__ int crlf( of )
-    struct ofork       *of;
-    {
-        struct extmap  *em;
+    if ( ad_hfileno( of->of_ad ) == -1 || !memcmp( ufinderi, ad_entry( of->of_ad, ADEID_FINDERI),8)) {
+        /* no resource fork or no finderinfo, use our files extension mapping */
+        if (!( em = getextmap( of_name(of) )) || memcmp( "TEXT", em->em_type, sizeof( em->em_type ))) {
+            return 0;
+        } 
+        /* file type is TEXT */
+        return 1;
 
-        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 );
-            }
-        }
+    } 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)
-    {
-        ssize_t cc;
-        int eof = 0;
-        char *p, *q;
+static ssize_t read_file(struct ofork *ofork, int eid,
+                                    off_t offset, u_char nlmask,
+                                    u_char nlchar, char *rbuf,
+                                    int *rbuflen, const int xlate)
+{
+    ssize_t cc;
+    int eof = 0;
+    char *p, *q;
 
-        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) );
-            *rbuflen = 0;
-            return( AFPERR_PARAM );
-        }
-        if ( cc < *rbuflen ) {
-            eof = 1;
-        }
+    cc = ad_read(ofork->of_ad, eid, offset, rbuf, *rbuflen);
+    if ( cc < 0 ) {
+        LOG(log_error, logtype_afpd, "afp_read(%s): ad_read: %s", of_name(ofork), strerror(errno) );
+        *rbuflen = 0;
+        return( AFPERR_PARAM );
+    }
+    if ( cc < *rbuflen ) {
+        eof = 1;
+    }
 
-        /*
-         * Do Newline check.
-         */
-        if ( nlmask != 0 ) {
-            for ( p = rbuf, q = p + cc; p < q; ) {
-                if (( *p++ & nlmask ) == nlchar ) {
-                    break;
-                }
-            }
-            if ( p != q ) {
-                cc = p - rbuf;
-                eof = 0;
+    /*
+     * Do Newline check.
+     */
+    if ( nlmask != 0 ) {
+        for ( p = rbuf, q = p + cc; p < q; ) {
+            if (( *p++ & nlmask ) == nlchar ) {
+                break;
             }
         }
+        if ( p != q ) {
+            cc = p - rbuf;
+            eof = 0;
+        }
+    }
 
-        /*
-         * If this file is of type TEXT, then swap \012 to \015.
-         */
-        if (xlate) {
-            for ( p = rbuf, q = p + cc; p < q; p++ ) {
-                if ( *p == '\012' ) {
-                    *p = '\015';
-                } else if ( *p == '\015' ) {
-                    *p = '\012';
-                }
-
+    /*
+     * If this file is of type TEXT, then swap \012 to \015.
+     */
+    if (xlate) {
+        for ( p = rbuf, q = p + cc; p < q; p++ ) {
+            if ( *p == '\012' ) {
+                *p = '\015';
+            } else if ( *p == '\015' ) {
+                *p = '\012';
             }
-        }
 
-        *rbuflen = cc;
-        if ( eof ) {
-            return( AFPERR_EOF );
-        }
-        return AFP_OK;
-    }
-
-    int afp_read(obj, ibuf, ibuflen, rbuf, rbuflen)
-    AFPObj      *obj;
-    char       *ibuf, *rbuf;
-    int                ibuflen, *rbuflen;
-    {
-        struct ofork   *ofork;
-        off_t          size;
-        int32_t                offset, saveoff, reqcount;
-        int                    cc, err, 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: %s", strerror(errno) );
-            err = AFPERR_PARAM;
-            goto afp_read_err;
         }
+    }
 
-        if ((ofork->of_flags & AFPFORK_ACCRD) == 0) {
-            err = AFPERR_ACCESS;
-            goto afp_read_err;
-        }
+    *rbuflen = cc;
+    if ( eof ) {
+        return( AFPERR_EOF );
+    }
+    return AFP_OK;
+}
+
+/* -----------------------------
+ * 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(obj, ibuf, ibuflen, rbuf, rbuflen, is64)
+AFPObj  *obj;
+char   *ibuf, *rbuf;
+int    ibuflen _U_, *rbuflen;
+int     is64;
+{
+    struct ofork       *ofork;
+    off_t              offset, saveoff, reqcount, savereqcount;
+    int                        cc, err, eid, xlate = 0;
+    u_int16_t          ofrefnum;
+    u_char             nlmask, nlchar;
+    
+    ibuf += 2;
+    memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
+    ibuf += sizeof( u_short );
+
+    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;
+    }
 
-        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_flags & AFPFORK_ACCRD) == 0) {
+        err = AFPERR_ACCESS;
+        goto afp_read_err;
+    }
+    offset   = get_off_t(&ibuf, is64);
+    reqcount = get_off_t(&ibuf, is64);
 
+    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))
+     */
+    if (reqcount < 0 || offset < 0) {
+        err = AFPERR_PARAM;
+        goto afp_read_err;
+    }
 
-        /* if we wanted to be picky, we could add in the following
-         * bit: if (afp_version == 11 && !(nlmask == 0xFF || !nlmask))
-         */
-        if (reqcount < 0 || offset < 0) {
-            err = AFPERR_PARAM;
-            goto afp_read_err;
-        }
+    if ( ofork->of_flags & AFPFORK_DATA) {
+        eid = ADEID_DFORK;
+        xlate = (ofork->of_vol->v_flags & AFPVOL_CRLF) ? crlf(ofork) : 0;
+    } else if (ofork->of_flags & AFPFORK_RSRC) {
+        eid = ADEID_RFORK;
+    } else { /* fork wasn't opened. this should never really happen. */
+        err = AFPERR_ACCESS;
+        goto afp_read_err;
+    }
 
-        if ( ofork->of_flags & AFPFORK_DATA) {
-            eid = ADEID_DFORK;
-            xlate = (ofork->of_vol->v_flags & AFPVOL_CRLF) ? crlf(ofork) : 0;
-        } else if (ofork->of_flags & AFPFORK_RSRC) {
-            eid = ADEID_RFORK;
-        } else { /* fork wasn't opened. this should never really happen. */
-            err = AFPERR_ACCESS;
-            goto afp_read_err;
-        }
+    /* zero request count */
+    err = AFP_OK;
+    if (!reqcount) {
+        goto afp_read_err;
+    }
 
-        /* zero request count */
-        if (!reqcount) {
-            err = AFP_OK;
-            goto afp_read_err;
-        }
+    savereqcount = reqcount;
+    saveoff = offset;
+    if (ad_tmplock(ofork->of_ad, eid, ADLOCK_RD, saveoff, savereqcount,ofork->of_refnum) < 0) {
+        err = AFPERR_LOCK;
+        goto afp_read_err;
+    }
 
-        /* reqcount isn't always truthful. we need to deal with that. */
-        if ((size = ad_size(ofork->of_ad, eid)) == 0) {
-            err = AFPERR_EOF;
-            goto afp_read_err;
+#define min(a,b)       ((a)<(b)?(a):(b))
+    *rbuflen = min( reqcount, *rbuflen );
+    err = read_file(ofork, eid, offset, nlmask, nlchar, rbuf, rbuflen, xlate);
+    if (err < 0)
+        goto afp_read_done;
+
+    /* dsi can stream requests. we can only do this if we're not checking
+     * for an end-of-line character. oh well. */
+    if ((obj->proto == AFPPROTO_DSI) && (*rbuflen < reqcount) && !nlmask) {
+        DSI    *dsi = obj->handle;
+        off_t  size;
+        int    non_blocking = 0;
+
+#ifdef DEBUG1
+        if (obj->options.flags & OPTION_DEBUG) {
+            printf( "(read) reply: %d/%d, %d\n", *rbuflen,(int) reqcount, dsi->clientID);
+            bprint(rbuf, *rbuflen);
         }
+#endif        
+        /* reqcount isn't always truthful. we need to deal with that. */
+        size = ad_size(ofork->of_ad, eid);
 
-        saveoff = offset;
-        if (ad_tmplock(ofork->of_ad, eid, ADLOCK_RD, saveoff, reqcount) < 0) {
-            err = AFPERR_LOCK;
-            goto afp_read_err;
+        /* subtract off the offset */
+        size -= offset;
+        if (reqcount > size) {
+          reqcount = size;
+           err = AFPERR_EOF;
         }
 
-#define min(a,b)       ((a)<(b)?(a):(b))
-        *rbuflen = min( reqcount, *rbuflen );
-        err = read_file(ofork, eid, offset, nlmask, nlchar, rbuf, rbuflen,
-                        xlate);
-        if (err < 0)
+        offset += *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)
+            goto afp_read_exit;
+
+        /* due to the nature of afp packets, we have to exit if we get
+           an error. we can't do this with translation on. */
+#if 0 /* ifdef WITH_SENDFILE */
+        /* FIXME with OS X deadlock partial workaround we can't use sendfile */
+        if (!(xlate || Debug(obj) )) {
+            if (ad_readfile(ofork->of_ad, eid, dsi->socket, offset, dsi->datasize) < 0) {
+                if (errno == EINVAL || errno == ENOSYS)
+                    goto afp_read_loop;
+                else {
+                    LOG(log_error, logtype_afpd, "afp_read(%s): ad_readfile: %s", of_name(ofork), strerror(errno));
+                    goto afp_read_exit;
+                }
+            }
+
+            dsi_readdone(dsi);
             goto afp_read_done;
+        }
 
-        /* dsi can stream requests. we can only do this if we're not checking
-         * for an end-of-line character. oh well. */
-        if ((obj->proto == AFPPROTO_DSI) && (*rbuflen < reqcount) && !nlmask) {
-            DSI *dsi = obj->handle;
+afp_read_loop:
+#endif 
 
-            /* subtract off the offset */
-            size -= offset;
-            if (reqcount > size) {
-                reqcount = size;
-                err = AFPERR_EOF;
-            }
+        /* fill up our buffer. */
+        if (*rbuflen) {
+            /* set to non blocking mode */
+            non_blocking = 1;
+            dsi_block(dsi, 1);
+        }
+        /* fill up our buffer. */
+        while (*rbuflen > 0) {
+            cc = read_file(ofork, eid, offset, nlmask, nlchar, rbuf,rbuflen, xlate);
+            if (cc < 0)
+                goto afp_read_exit;
 
+            offset += *rbuflen;
+#ifdef DEBUG1
             if (obj->options.flags & OPTION_DEBUG) {
-                printf( "(read) reply: %d/%d, %d\n", *rbuflen,
-                        reqcount, dsi->clientID);
+                printf( "(read) reply: %d, %d\n", *rbuflen, dsi->clientID);
                 bprint(rbuf, *rbuflen);
             }
-
-            offset += *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)
+#endif
+            /* dsi_read() also returns buffer size of next allocation */
+            cc = dsi_read(dsi, rbuf, *rbuflen); /* send it off */
+            if (cc < 0)
                 goto afp_read_exit;
-
-            /* 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)
-                        goto afp_read_loop;
-                    else {
-                        LOG(log_error, logtype_default, "afp_read: ad_readfile: %s", strerror(errno));
-                        goto afp_read_exit;
-                    }
-                }
-
-                dsi_readdone(dsi);
-                goto afp_read_done;
-            }
-
-afp_read_loop:
-#endif /* HAVE_SENDFILE_READ */
-
-            /* fill up our buffer. */
-            while (*rbuflen > 0) {
-                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)
-                    goto afp_read_exit;
-                *rbuflen = cc;
-            }
-            dsi_readdone(dsi);
-            goto afp_read_done;
+            *rbuflen = cc;
+        }
+        if (non_blocking) {
+            /* set back to blocking mode */
+            dsi_block(dsi, 0);
+        }
+        dsi_readdone(dsi);
+        goto afp_read_done;
 
 afp_read_exit:
-            LOG(log_error, logtype_default, "afp_read: %s", strerror(errno));
-            dsi_readdone(dsi);
-            ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount);
-            obj->exit(1);
-        }
+        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,ofork->of_refnum);
+        obj->exit(EXITERR_CLNT);
+    }
 
 afp_read_done:
-        ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount);
-        return err;
+    ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount,ofork->of_refnum);
+    return err;
 
 afp_read_err:
-        *rbuflen = 0;
-        return err;
-    }
-
-    int afp_flush(obj, ibuf, ibuflen, rbuf, rbuflen )
-    AFPObj      *obj;
-    char       *ibuf, *rbuf;
-    int                ibuflen, *rbuflen;
-    {
-        struct vol *vol;
-        u_int16_t vid;
-
-        *rbuflen = 0;
-        ibuf += 2;
+    *rbuflen = 0;
+    return err;
+}
+
+/* ---------------------- */
+int afp_read(obj, ibuf, ibuflen, rbuf, rbuflen)
+AFPObj  *obj;
+char   *ibuf, *rbuf;
+int    ibuflen, *rbuflen;
+{
+    return read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 0);
+}
+
+/* ---------------------- */
+int afp_read_ext(obj, ibuf, ibuflen, rbuf, rbuflen)
+AFPObj  *obj;
+char   *ibuf, *rbuf;
+int    ibuflen, *rbuflen;
+{
+    return read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 1);
+}
+
+/* ---------------------- */
+int afp_flush(obj, ibuf, ibuflen, rbuf, rbuflen )
+AFPObj  *obj _U_;
+char   *ibuf, *rbuf _U_;
+int    ibuflen _U_, *rbuflen;
+{
+    struct vol *vol;
+    u_int16_t vid;
 
-        memcpy(&vid, ibuf, sizeof(vid));
-        if (( vol = getvolbyvid( vid )) == NULL ) {
-            return( AFPERR_PARAM );
-        }
+    *rbuflen = 0;
+    ibuf += 2;
 
-        of_flush(vol);
-        return( AFP_OK );
+    memcpy(&vid, ibuf, sizeof(vid));
+    if (NULL == ( vol = getvolbyvid( vid )) ) {
+        return( AFPERR_PARAM );
     }
 
-    int afp_flushfork(obj, ibuf, ibuflen, rbuf, rbuflen )
-    AFPObj      *obj;
-    char       *ibuf, *rbuf;
-    int                ibuflen, *rbuflen;
-    {
-        struct ofork   *ofork;
-        u_int16_t              ofrefnum;
+    of_flush(vol);
+    return( AFP_OK );
+}
 
-        *rbuflen = 0;
-        ibuf += 2;
-        memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
+int afp_flushfork(obj, ibuf, ibuflen, rbuf, rbuflen )
+AFPObj  *obj _U_;
+char   *ibuf, *rbuf _U_;
+int    ibuflen _U_, *rbuflen;
+{
+    struct ofork       *ofork;
+    u_int16_t          ofrefnum;
 
-        if (( ofork = of_find( ofrefnum )) == NULL ) {
-            LOG(log_error, logtype_default, "afp_flushfork: of_find: %s", strerror(errno) );
-            return( AFPERR_PARAM );
-        }
+    *rbuflen = 0;
+    ibuf += 2;
+    memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
 
-        if ( flushfork( ofork ) < 0 ) {
-            LOG(log_error, logtype_default, "afp_flushfork: %s", strerror(errno) );
-        }
+    if (NULL == ( ofork = of_find( ofrefnum )) ) {
+        LOG(log_error, logtype_afpd, "afp_flushfork: of_find(%d) could not locate fork", ofrefnum );
+        return( AFPERR_PARAM );
+    }
 
-        return( AFP_OK );
+    if ( flushfork( ofork ) < 0 ) {
+        LOG(log_error, logtype_afpd, "afp_flushfork(%s): %s", of_name(ofork), strerror(errno) );
     }
 
-    /* this is very similar to closefork */
-    int flushfork( ofork )
-    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) );
-            err = -1;
-        }
+    return( AFP_OK );
+}
 
-        if ( ad_hfileno( ofork->of_ad ) != -1 ) {
+/* this is very similar to closefork */
+int flushfork( ofork )
+struct ofork   *ofork;
+{
+    struct timeval tv;
 
-            /* read in the rfork length */
-            len = ad_getentrylen(ofork->of_ad, ADEID_RFORK);
-            ad_refresh(ofork->of_ad);
+    int err = 0, doflush = 0;
 
-            /* set the date if we're dirty */
-            if ((ofork->of_flags & AFPFORK_DIRTY) &&
-                    (gettimeofday(&tv, NULL) == 0)) {
-                ad_setdate(ofork->of_ad, AD_DATE_MODIFY|AD_DATE_UNIX, tv.tv_sec);
-                ofork->of_flags &= ~AFPFORK_DIRTY;
-                doflush++;
-            }
+    if ( ad_dfileno( ofork->of_ad ) != -1 &&
+            fsync( ad_dfileno( ofork->of_ad )) < 0 ) {
+        LOG(log_error, logtype_afpd, "flushfork(%s): dfile(%d) %s",
+            of_name(ofork), ad_dfileno(ofork->of_ad), strerror(errno) );
+        err = -1;
+    }
 
-            /* 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++;
-            }
+    if ( ad_hfileno( ofork->of_ad ) != -1 && 
+           (ofork->of_flags & AFPFORK_RSRC)) {
 
+        /* read in the rfork length */
+        ad_refresh(ofork->of_ad);
 
-            /* 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;
+        /* set the date if we're dirty */
+        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 (fsync( ad_hfileno( ofork->of_ad )) < 0)
+        /* flush the header */
+        if (doflush && ad_flush(ofork->of_ad, ADFLAGS_HF) < 0)
                 err = -1;
 
-            if (err < 0)
-                LOG(log_error, logtype_default, "flushfork: hfile(%d) %s",
-                    ad_hfileno(ofork->of_ad), strerror(errno) );
-        }
+        if (fsync( ad_hfileno( ofork->of_ad )) < 0)
+            err = -1;
 
-        return( err );
+        if (err < 0)
+            LOG(log_error, logtype_afpd, "flushfork(%s): hfile(%d) %s",
+                of_name(ofork), ad_hfileno(ofork->of_ad), strerror(errno) );
     }
 
-    int afp_closefork(obj, ibuf, ibuflen, rbuf, rbuflen )
-    AFPObj      *obj;
-    char       *ibuf, *rbuf;
-    int                ibuflen, *rbuflen;
-    {
-        struct ofork   *ofork;
-        struct timeval      tv;
-        int                    adflags, aint, doflush = 0;
-        u_int16_t              ofrefnum;
-
-        *rbuflen = 0;
-        ibuf += 2;
-        memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
+    return( err );
+}
 
-        if (( ofork = of_find( ofrefnum )) == NULL ) {
-            LOG(log_error, logtype_default, "afp_closefork: of_find: %s", strerror(errno) );
-            return( AFPERR_PARAM );
-        }
+int afp_closefork(obj, ibuf, ibuflen, rbuf, rbuflen )
+AFPObj      *obj _U_;
+char   *ibuf, *rbuf _U_;
+int            ibuflen _U_, *rbuflen;
+{
+    struct ofork       *ofork;
+    struct timeval      tv;
+    int                        adflags, doflush = 0;
+    u_int16_t          ofrefnum;
+    int                        ret;
+    
+
+    *rbuflen = 0;
+    ibuf += 2;
+    memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
+
+    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 = 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 );
+    }
+    if ( (ofork->of_flags & AFPFORK_OPEN) && ad_hfileno( ofork->of_ad ) != -1 ) {
+        adflags |= ADFLAGS_HF;
+        /*
+         * Only set the rfork's length if we're closing the rfork.
+         */
+        if ((ofork->of_flags & AFPFORK_RSRC)) {
             ad_refresh( ofork->of_ad );
-            if ((ofork->of_flags & AFPFORK_DIRTY) &&
-                    (gettimeofday(&tv, NULL) == 0)) {
-                ad_setdate(ofork->of_ad, AD_DATE_MODIFY | AD_DATE_UNIX,
-                           tv.tv_sec);
-                doflush++;
-            }
-
-            /*
-             * 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 ((ofork->of_flags & AFPFORK_DIRTY) && !gettimeofday(&tv, NULL)) {
+                ad_setdate(ofork->of_ad, AD_DATE_MODIFY | AD_DATE_UNIX,tv.tv_sec);
+               doflush++;
             }
             if ( doflush ) {
-                ad_flush( ofork->of_ad, adflags );
+                 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) );
-            return( AFPERR_PARAM );
-        }
-
-        of_dealloc( ofork );
-        return( AFP_OK );
+    }
+    ret = AFP_OK;
+    if ( ad_close( ofork->of_ad, adflags ) < 0 ) {
+        LOG(log_error, logtype_afpd, "afp_closefork(%s): ad_close: %s", of_name(ofork), strerror(errno) );
+        ret = AFPERR_PARAM;
     }
 
+    of_dealloc( ofork );
+    return ret;
+}
 
-    static __inline__ 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;
 
-        /*
-         * If this file is of type TEXT, swap \015 to \012.
-         */
-        if (xlate) {
-            for ( p = rbuf, q = p + rbuflen; p < q; p++ ) {
-                if ( *p == '\015' ) {
-                    *p = '\012';
-                } else if ( *p == '\012' ) {
-                    *p = '\015';
-                }
-            }
-        }
+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;
 
-        if (( cc = ad_write(ofork->of_ad, eid, offset, 0,
-                            rbuf, rbuflen)) < 0 ) {
-            switch ( errno ) {
-            case EDQUOT :
-            case EFBIG :
-            case ENOSPC :
-                return( AFPERR_DFULL );
-            default :
-                LOG(log_error, logtype_default, "afp_write: ad_write: %s", strerror(errno) );
-                return( AFPERR_PARAM );
+    /*
+     * If this file is of type TEXT, swap \015 to \012.
+     */
+    if (xlate) {
+        for ( p = rbuf, q = p + rbuflen; p < q; p++ ) {
+            if ( *p == '\015' ) {
+                *p = '\012';
+            } else if ( *p == '\012' ) {
+                *p = '\015';
             }
         }
+    }
 
-        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 
-     * in reqcount et al. */
-    int afp_write(obj, ibuf, ibuflen, rbuf, rbuflen)
-    AFPObj              *obj;
-    char                *ibuf, *rbuf;
-    int                 ibuflen, *rbuflen;
-    {
-        struct ofork   *ofork;
-        int32_t                offset, saveoff, reqcount;
-        int                    endflag, eid, xlate = 0, err = AFP_OK;
-        u_int16_t              ofrefnum;
-        ssize_t             cc;
-
-        /* figure out parameters */
-        ibuf++;
-        endflag = ENDBIT(*ibuf);
-        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: %s", strerror(errno) );
-            err = AFPERR_PARAM;
-            goto afp_write_err;
+    if (( cc = ad_write(ofork->of_ad, eid, offset, 0,
+                        rbuf, rbuflen)) < 0 ) {
+        switch ( errno ) {
+        case EDQUOT :
+        case EFBIG :
+        case ENOSPC :
+            return( AFPERR_DFULL );
+        default :
+            LOG(log_error, logtype_afpd, "afp_write(%s): ad_write: %s", of_name(ofork), strerror(errno) );
+            return( AFPERR_PARAM );
         }
+    }
+
+    return cc;
+}
 
-        if ((ofork->of_flags & AFPFORK_ACCWR) == 0) {
-            err = AFPERR_ACCESS;
-            goto afp_write_err;
-        }
+
+/* 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 
+ * in reqcount et al. */
+static int write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, is64)
+AFPObj              *obj;
+char                *ibuf, *rbuf;
+int                 ibuflen _U_, *rbuflen;
+int                 is64;
+{
+    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 */
+    ibuf++;
+    endflag = ENDBIT(*ibuf);
+    ibuf++;
+    memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
+    ibuf += sizeof( ofrefnum );
+
+    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;
+    }
+
+    if ((ofork->of_flags & AFPFORK_ACCWR) == 0) {
+        err = AFPERR_ACCESS;
+        goto afp_write_err;
+    }
 
 #ifdef AFS
-        writtenfork = ofork;
+    writtenfork = ofork;
 #endif /* AFS */
 
-        if ( ofork->of_flags & AFPFORK_DATA) {
-            eid = ADEID_DFORK;
-            xlate = (ofork->of_vol->v_flags & AFPVOL_CRLF) ? crlf(ofork) : 0;
-        } else if (ofork->of_flags & AFPFORK_RSRC) {
-            eid = ADEID_RFORK;
-        } else {
-            err = AFPERR_ACCESS; /* should never happen */
-            goto afp_write_err;
-        }
+    if ( ofork->of_flags & AFPFORK_DATA) {
+        eid = ADEID_DFORK;
+        xlate = (ofork->of_vol->v_flags & AFPVOL_CRLF) ? crlf(ofork) : 0;
+    } else if (ofork->of_flags & AFPFORK_RSRC) {
+        eid = ADEID_RFORK;
+    } else {
+        err = AFPERR_ACCESS; /* should never happen */
+        goto afp_write_err;
+    }
 
-        if (endflag)
-            offset += ad_size(ofork->of_ad, eid);
+    if (endflag)
+        offset += ad_size(ofork->of_ad, eid);
 
-        /* handle bogus parameters */
-        if (reqcount < 0 || offset < 0) {
-            err = AFPERR_PARAM;
-            goto afp_write_err;
-        }
+    /* handle bogus parameters */
+    if (reqcount < 0 || offset < 0) {
+        err = AFPERR_PARAM;
+        goto afp_write_err;
+    }
 
-        /* offset can overflow on 64-bit capable filesystems.
-         * report disk full if that's going to happen. */
-        if (offset + reqcount < 0) {
-            err = AFPERR_DFULL;
-            goto afp_write_err;
-        }
+    /* offset can overflow on 64-bit capable filesystems.
+     * report disk full if that's going to happen. */
+     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));
-            goto afp_write_err;
-        }
+    if (!reqcount) { /* handle request counts of 0 */
+        err = AFP_OK;
+        *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) {
-            err = AFPERR_LOCK;
-            goto afp_write_err;
-        }
+    saveoff = offset;
+    if (ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, saveoff,
+                   reqcount, ofork->of_refnum) < 0) {
+        err = AFPERR_LOCK;
+        goto afp_write_err;
+    }
 
-        /* this is yucky, but dsi can stream i/o and asp can't */
-        switch (obj->proto) {
+    /* this is yucky, but dsi can stream i/o and asp can't */
+    switch (obj->proto) {
 #ifndef NO_DDP
-        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) );
-                return( AFPERR_PARAM );
-            }
+    case AFPPROTO_ASP:
+        if (asp_wrtcont(obj->handle, rbuf, rbuflen) < 0) {
+            *rbuflen = 0;
+            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);
-            }
+#ifdef DEBUG1
+        if (obj->options.flags & OPTION_DEBUG) {
+            printf("(write) len: %d\n", *rbuflen);
+            bprint(rbuf, *rbuflen);
+        }
+#endif
+        if ((cc = write_file(ofork, eid, offset, rbuf, *rbuflen,
+                             xlate)) < 0) {
+            *rbuflen = 0;
+            ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
+            return cc;
+        }
+        offset += cc;
+        break;
+#endif /* no afp/asp */
+
+    case AFPPROTO_DSI:
+        {
+            DSI *dsi = obj->handle;
 
-            if ((cc = write_file(ofork, eid, offset, rbuf, *rbuflen,
-                                 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);
+                ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
                 return cc;
             }
             offset += cc;
-            break;
-#endif /* no afp/asp */
 
-        case AFPPROTO_DSI:
-            {
-                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) {
+#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))) {
+#ifdef DEBUG1
+                if ( obj->options.flags & OPTION_DEBUG ) {
+                    printf("(write) command cont'd: %d\n", cc);
+                    bprint(rbuf, cc);
                 }
+#endif
+                if ((cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
+                    dsi_writeflush(dsi);
+                    *rbuflen = 0;
+                    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 )
-            ofork->of_flags |= AFPFORK_DIRTY;
+    ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount,  ofork->of_refnum);
+    if ( ad_hfileno( ofork->of_ad ) != -1 )
+        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);
-        return( AFP_OK );
+    *rbuflen = set_off_t (offset, rbuf, is64);
+    return( AFP_OK );
 
 afp_write_err:
-        if (obj->proto == AFPPROTO_DSI) {
-            dsi_writeinit(obj->handle, rbuf, *rbuflen);
-            dsi_writeflush(obj->handle);
-        }
-
-        *rbuflen = (err == AFP_OK) ? sizeof(offset) : 0;
-        return err;
+    if (obj->proto == AFPPROTO_DSI) {
+        dsi_writeinit(obj->handle, rbuf, *rbuflen);
+        dsi_writeflush(obj->handle);
     }
-
-
-    int afp_getforkparams(obj, ibuf, ibuflen, rbuf, rbuflen )
-    AFPObj      *obj;
-    char       *ibuf, *rbuf;
-    int                ibuflen, *rbuflen;
-    {
-        struct ofork   *ofork;
-        int                    buflen, ret;
-        u_int16_t              ofrefnum, bitmap;
-
-        ibuf += 2;
-        memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
-        ibuf += sizeof( ofrefnum );
-        memcpy(&bitmap, ibuf, sizeof( bitmap ));
-        bitmap = ntohs( bitmap );
-        ibuf += sizeof( bitmap );
-
+    if (err != AFP_OK) {
         *rbuflen = 0;
-        if (( ofork = of_find( ofrefnum )) == NULL ) {
-            LOG(log_error, logtype_default, "afp_getforkparams: of_find: %s", strerror(errno) );
-            return( AFPERR_PARAM );
-        }
+    }
+    return err;
+}
+
+/* ---------------------------- */
+int afp_write(obj, ibuf, ibuflen, rbuf, rbuflen)
+AFPObj              *obj;
+char                *ibuf, *rbuf;
+int                 ibuflen, *rbuflen;
+{
+    return write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 0);
+}
+
+/* ---------------------------- 
+ * FIXME need to deal with SIGXFSZ signal
+*/
+int afp_write_ext(obj, ibuf, ibuflen, rbuf, rbuflen)
+AFPObj              *obj;
+char                *ibuf, *rbuf;
+int                 ibuflen, *rbuflen;
+{
+    return write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 1);
+}
+
+/* ---------------------------- */
+int afp_getforkparams(obj, ibuf, ibuflen, rbuf, rbuflen )
+AFPObj  *obj _U_;
+char   *ibuf, *rbuf;
+int    ibuflen _U_, *rbuflen;
+{
+    struct ofork       *ofork;
+    int                        buflen, ret;
+    u_int16_t          ofrefnum, bitmap;
+    u_int16_t          attrbits = 0;
+
+    ibuf += 2;
+    memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
+    ibuf += sizeof( ofrefnum );
+    memcpy(&bitmap, ibuf, sizeof( bitmap ));
+    bitmap = ntohs( bitmap );
+    ibuf += sizeof( bitmap );
+
+    *rbuflen = 0;
+    if (NULL == ( ofork = of_find( ofrefnum )) ) {
+        LOG(log_error, logtype_afpd, "afp_getforkparams: of_find(%d) could not locate fork", ofrefnum );
+        return( AFPERR_PARAM );
+    }
+    attrbits = ((ofork->of_ad->ad_df.adf_refcount > 0) ? ATTRBIT_DOPEN : 0);
+    attrbits |= ((ofork->of_ad->ad_hf.adf_refcount > ofork->of_ad->ad_df.adf_refcount) ? ATTRBIT_ROPEN : 0);
 
-        if (( ret = getforkparams( ofork, bitmap,
-                                   rbuf + sizeof( u_short ), &buflen, 0 )) != AFP_OK ) {
-            return( ret );
+    if ( ad_hfileno( ofork->of_ad ) != -1 ) {
+        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 );
         }
+    }
 
-        *rbuflen = buflen + sizeof( u_short );
-        bitmap = htons( bitmap );
-        memcpy(rbuf, &bitmap, sizeof( bitmap ));
-        return( AFP_OK );
+    if (AFP_OK != ( ret = getforkparams( ofork, bitmap,
+                               rbuf + sizeof( u_short ), &buflen, attrbits ))) {
+        return( ret );
     }
 
+    *rbuflen = buflen + sizeof( u_short );
+    bitmap = htons( bitmap );
+    memcpy(rbuf, &bitmap, sizeof( bitmap ));
+    return( AFP_OK );
+}
+