]> arthur.barton.de Git - netatalk.git/blobdiff - etc/afpd/fork.c
of_findname: remove vol and dir
[netatalk.git] / etc / afpd / fork.c
index 2ba98a6cf3be52eb00d317524fcb4f2cc8ce5964..2d7446672ba942123b68b3dc19c8c30ca2f92359 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: fork.c,v 1.15 2002-01-16 19:55:15 jmarcus Exp $
+ * $Id: fork.c,v 1.36 2002-09-05 14:52:06 didg Exp $
  *
  * Copyright (c) 1990,1993 Regents of The University of Michigan.
  * All Rights Reserved.  See COPYRIGHT.
 #define BYTELOCK_MAX 0x7FFFFFFFU
 
 struct ofork           *writtenfork;
+extern int getmetadata(struct vol *vol,
+                 u_int16_t bitmap,
+                 char *path, struct dir *dir, struct stat *st,
+                 char *buf, int *buflen, struct adouble *adp, int attrbits );
 
 static int getforkparams(ofork, bitmap, buf, buflen, attrbits )
 struct ofork   *ofork;
@@ -59,27 +63,27 @@ int                 *buflen;
 const u_int16_t     attrbits;
 {
 #ifndef USE_LASTDID
-       struct stat             hst, lst, *lstp;
-#else /* USE_LASTDID */
-       struct stat     hst;
-#endif
+    struct stat                lst, *lstp;
+#endif /* !USE_LASTDID */
     struct stat                st;
-    struct extmap      *em;
-    char               *data, *nameoff = NULL, *upath;
-    int                        bit = 0, isad = 1;
-    u_int32_t           aint;
-    u_int16_t          ashort;
+    char               *upath;
+    u_int32_t          aint;
 
+    struct adouble     *adp;
+    struct dir         *dir;
+    struct vol         *vol;
+    
     if ( ad_hfileno( ofork->of_ad ) == -1 ) {
-        isad = 0;
+        adp = NULL;
     } 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) );
+            LOG(log_error, logtype_afpd, "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 );
+        adp = ofork->of_ad;
     }
 
     /* can only get the length of the opened fork */
@@ -88,11 +92,16 @@ const u_int16_t     attrbits;
         return( AFPERR_BITMAP );
     }
 
+    vol = ofork->of_vol;
+    dir = ofork->of_dir;
+
     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 ) {
+            upath = mtoupath(vol, ofork->of_name);
+            if (movecwd(vol, dir) < 0)
+                return( AFPERR_NOOBJ );
             if ( stat( upath, &st ) < 0 )
                 return( AFPERR_NOOBJ );
         } else {
@@ -101,152 +110,118 @@ const u_int16_t     attrbits;
             }
         }
     }
+    return getmetadata(vol, bitmap, ofork->of_name, dir, &st, 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;
-
-        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;
-
-        case FILPBIT_LNAME :
-            nameoff = data;
-            data += sizeof(u_int16_t);
-            break;
-
-        case FILPBIT_SNAME :
-            memset(data, 0, sizeof(u_int16_t));
-            data += sizeof(u_int16_t);
-            break;
+/* -------------------------
+*/
+#define SHARE 0
+#define EXCL  1
+static int setforkmode(struct adouble *adp, int eid, int ofrefnum, int what, int mode)
+{
+    int lockmode;
+    int lockop;
+    
+    /* 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. 
+     */
+    lockmode = (ad_getoflags(adp, eid) & O_RDWR) ?ADLOCK_WR : ADLOCK_RD;
+    lockop = (mode == EXCL)?lockmode:ADLOCK_RD;
+    
+    return ad_lock(adp, eid, lockop | ADLOCK_FILELOCK | ADLOCK_UPGRADE,
+                        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 */
+/* -------------------------
+*/
+extern int ad_testlock(struct adouble *adp, int eid, int off);
 
-#ifdef CNID_DB
-            aint = cnid_add(ofork->of_vol->v_db, &st,
-                            ofork->of_dir->d_did,
-                            upath, strlen(upath), aint);
-#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 getforkmode(struct adouble *adp, int eid, int what)
+{
+    return ad_testlock(adp, eid,  what);
+}
 
-            memcpy(data, &aint, sizeof( aint ));
-            data += sizeof( aint );
-            break;
+/* -------------------------- 
+   a lot of races, some can be remove. but I try first to get the semantic right
+*/
+#ifdef USE_FLOCK_LOCKS 
+#error sorry, for now configure --with-flock-locks is broken...
+#endif
 
-        case FILPBIT_DFLEN :
-            aint = htonl( st.st_size );
-            memcpy(data, &aint, sizeof( aint ));
-            data += sizeof( aint );
-            break;
+static int afp_setmode(struct adouble *adp, int eid, int access, int ofrefnum)
+{
+    int ret;
+    int readset;
+    int writeset;
+    int denyreadset;
+    int denywriteset;
+    int mode;    
+
+    if (! (access & (OPENACC_WR | OPENACC_RD | OPENACC_DWR | OPENACC_DRD))) {
+        return setforkmode(adp, eid, ofrefnum, AD_FILELOCK_OPEN_NONE, SHARE);
+    }
 
-        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 = getforkmode(adp, eid, AD_FILELOCK_OPEN_RD)) <0)
+            return readset;
+        if ((denyreadset = getforkmode(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 
+         */
+        mode = ((access & OPENACC_DRD))?EXCL: SHARE;
+        if ((access & OPENACC_RD)) {
+            ret = setforkmode(adp, eid, ofrefnum, AD_FILELOCK_OPEN_RD, mode);
+            if (ret)
+                return ret;
+        }
+        if ((access & OPENACC_DRD)) {
+            ret = setforkmode(adp, eid, ofrefnum, AD_FILELOCK_DENY_RD, SHARE);
+            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 = 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;
+        }   
+        mode = ((access & OPENACC_DWR))?EXCL: SHARE;
+        if ((access & OPENACC_WR)) {
+            ret = setforkmode(adp, eid, ofrefnum, AD_FILELOCK_OPEN_WR, mode);
+            if (ret)
+                return ret;
+        }
+        if ((access & OPENACC_DWR)) {
+            ret = setforkmode(adp, eid, ofrefnum, AD_FILELOCK_DENY_WR, SHARE);
+            if (ret)
+                return ret;
+        }
     }
-
-    *buflen = data - buf;
-    return( AFP_OK );
+    return 0;
 }
 
+/* ----------------------- */    
 int afp_openfork(obj, ibuf, ibuflen, rbuf, rbuflen )
 AFPObj      *obj;
 char   *ibuf, *rbuf;
@@ -260,6 +235,8 @@ int         ibuflen, *rbuflen;
     u_int32_t           did;
     u_int16_t          vid, bitmap, access, ofrefnum, attrbits = 0;
     char               fork, *path, *upath;
+    struct stat         st;
+    u_int16_t           bshort;
 
     ibuf++;
     fork = *ibuf++;
@@ -301,50 +278,63 @@ int               ibuflen, *rbuflen;
         adflags = ADFLAGS_HF;
     }
 
+    upath = mtoupath(vol, path);
+    if (check_access(upath, access ) < 0) {
+        return AFPERR_ACCESS;
+    }
+
+    /* stat() data fork */
+    if (stat(upath, &st) < 0) {
+        switch ( errno ) {
+        case ENOENT:
+            return AFPERR_NOOBJ;
+        case EACCES:
+            return (access & OPENACC_WR) ? AFPERR_LOCK : AFPERR_ACCESS;
+        default:
+            LOG(log_error, logtype_afpd, "afp_openfork: ad_open: %s", strerror(errno) );
+            return AFPERR_PARAM;
+        }
+    }
+
     /* 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);
+       ad_open so that we can keep file locks together.
+       FIXME: add the fork we are opening? 
+    */
+    if ((opened = of_findname(upath, &st))) {
+        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 ) {
+                           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) {
             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) {
+                    if (ad_open(upath, ADFLAGS_DF, O_RDWR, 0, ofork->of_ad) < 0) {
+                        goto openfork_err;
+                    }
+                    adflags = ADFLAGS_DF;
+
+                    /* 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;
                 }
                 break;
@@ -358,7 +348,7 @@ 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: ad_open: %s", strerror(errno) );
                 ret = AFPERR_PARAM;
                 goto openfork_err;
                 break;
@@ -366,7 +356,6 @@ int         ibuflen, *rbuflen;
         }
     } 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 ) {
@@ -381,19 +370,12 @@ int               ibuflen, *rbuflen;
                 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) {
+                /* 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;
                 }
                 break;
             case EMFILE :
@@ -406,7 +388,7 @@ 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: ad_open: %s", strerror(errno) );
                 goto openfork_err;
                 break;
             }
@@ -432,61 +414,25 @@ int               ibuflen, *rbuflen;
     memcpy(rbuf, &bitmap, sizeof( u_int16_t ));
     rbuf += sizeof( u_int16_t );
 
+    /* check  WriteInhibit bit, the test is done here, after some Mac trafic capture */
+    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);
+    }
+
     /*
      * 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.
      */
 
     /* 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);
-        }
-
+        ret = afp_setmode(ofork->of_ad, eid, access, ofrefnum);
         /* can we access the fork? */
-        if (ret < 0) {
-            ad_close( ofork->of_ad, adflags );
-            of_dealloc( ofork );
-            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 );
@@ -501,10 +447,14 @@ 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: ad_lock: %s", strerror(errno) );
                 return( AFPERR_PARAM );
             }
         }
+        if ((access & OPENACC_WR))
+            ofork->of_flags |= AFPFORK_ACCWR;
+        if ((access & OPENACC_RD))
+            ofork->of_flags |= AFPFORK_ACCRD;
     }
 
     memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
@@ -538,7 +488,7 @@ int         ibuflen, *rbuflen;
 
     *rbuflen = 0;
     if (( ofork = of_find( ofrefnum )) == NULL ) {
-        LOG(log_error, logtype_default, "afp_setforkparams: of_find: %s", strerror(errno) );
+        LOG(log_error, logtype_afpd, "afp_setforkparams: of_find could not locate open fork refnum: %u", ofrefnum );
         return( AFPERR_PARAM );
     }
 
@@ -563,8 +513,8 @@ int         ibuflen, *rbuflen;
             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) );
+            LOG(log_error, logtype_afpd, "afp_setforkparams: ad_flush: %s",
+                strerror(errno) );
             return( AFPERR_PARAM );
         }
     } else
@@ -572,7 +522,7 @@ int         ibuflen, *rbuflen;
 
 #ifdef AFS
     if ( flushfork( ofork ) < 0 ) {
-        LOG(log_error, logtype_default, "afp_setforkparams: flushfork: %s", strerror(errno) );
+        LOG(log_error, logtype_afpd, "afp_setforkparams: flushfork: %s", strerror(errno) );
     }
 #endif /* AFS */
 
@@ -627,7 +577,7 @@ int         ibuflen, *rbuflen;
     ibuf += sizeof(ofrefnum);
 
     if (( ofork = of_find( ofrefnum )) == NULL ) {
-        LOG(log_error, logtype_default, "afp_bytelock: of_find: %s", strerror(errno) );
+        LOG(log_error, logtype_afpd, "afp_bytelock: of_find");
         return( AFPERR_PARAM );
     }
 
@@ -727,7 +677,7 @@ 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: ad_read: %s", strerror(errno) );
         *rbuflen = 0;
         return( AFPERR_PARAM );
     }
@@ -771,6 +721,19 @@ static __inline__ ssize_t read_file(struct ofork *ofork, int eid,
     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? 
+*/
 int afp_read(obj, ibuf, ibuflen, rbuf, rbuflen)
 AFPObj      *obj;
 char   *ibuf, *rbuf;
@@ -778,7 +741,7 @@ int         ibuflen, *rbuflen;
 {
     struct ofork       *ofork;
     off_t              size;
-    int32_t            offset, saveoff, reqcount;
+    int32_t            offset, saveoff, reqcount, savereqcount;
     int                        cc, err, eid, xlate = 0;
     u_int16_t          ofrefnum;
     u_char             nlmask, nlchar;
@@ -788,7 +751,7 @@ int         ibuflen, *rbuflen;
     ibuf += sizeof( u_short );
 
     if (( ofork = of_find( ofrefnum )) == NULL ) {
-        LOG(log_error, logtype_default, "afp_read: of_find: %s", strerror(errno) );
+        LOG(log_error, logtype_afpd, "afp_read: of_find");
         err = AFPERR_PARAM;
         goto afp_read_err;
     }
@@ -827,19 +790,22 @@ int               ibuflen, *rbuflen;
     }
 
     /* zero request count */
+    err = AFP_OK;
     if (!reqcount) {
-        err = AFP_OK;
         goto afp_read_err;
     }
 
     /* reqcount isn't always truthful. we need to deal with that. */
-    if ((size = ad_size(ofork->of_ad, eid)) == 0) {
+    size = ad_size(ofork->of_ad, eid);
+
+    if (offset >= size) {
         err = AFPERR_EOF;
         goto afp_read_err;
     }
 
+    savereqcount = reqcount;
     saveoff = offset;
-    if (ad_tmplock(ofork->of_ad, eid, ADLOCK_RD, saveoff, reqcount) < 0) {
+    if (ad_tmplock(ofork->of_ad, eid, ADLOCK_RD, saveoff, savereqcount) < 0) {
         err = AFPERR_LOCK;
         goto afp_read_err;
     }
@@ -856,18 +822,17 @@ int               ibuflen, *rbuflen;
     if ((obj->proto == AFPPROTO_DSI) && (*rbuflen < reqcount) && !nlmask) {
         DSI *dsi = obj->handle;
 
-        /* subtract off the offset */
-        size -= offset;
-        if (reqcount > size) {
-            reqcount = size;
-            err = AFPERR_EOF;
-        }
-
         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;
 
@@ -886,7 +851,7 @@ int         ibuflen, *rbuflen;
                 if (errno == EINVAL)
                     goto afp_read_loop;
                 else {
-                    LOG(log_error, logtype_default, "afp_read: ad_readfile: %s", strerror(errno));
+                    LOG(log_error, logtype_afpd, "afp_read: ad_readfile: %s", strerror(errno));
                     goto afp_read_exit;
                 }
             }
@@ -921,14 +886,14 @@ afp_read_loop:
         goto afp_read_done;
 
 afp_read_exit:
-        LOG(log_error, logtype_default, "afp_read: %s", strerror(errno));
+        LOG(log_error, logtype_afpd, "afp_read: %s", strerror(errno));
         dsi_readdone(dsi);
-        ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount);
+        ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount);
         obj->exit(1);
     }
 
 afp_read_done:
-    ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount);
+    ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount);
     return err;
 
 afp_read_err:
@@ -969,12 +934,12 @@ int               ibuflen, *rbuflen;
     memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
 
     if (( ofork = of_find( ofrefnum )) == NULL ) {
-        LOG(log_error, logtype_default, "afp_flushfork: of_find: %s", strerror(errno) );
+        LOG(log_error, logtype_afpd, "afp_flushfork: of_find");
         return( AFPERR_PARAM );
     }
 
     if ( flushfork( ofork ) < 0 ) {
-        LOG(log_error, logtype_default, "afp_flushfork: %s", strerror(errno) );
+        LOG(log_error, logtype_afpd, "afp_flushfork: %s", strerror(errno) );
     }
 
     return( AFP_OK );
@@ -989,8 +954,8 @@ struct ofork        *ofork;
 
     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) );
+        LOG(log_error, logtype_afpd, "flushfork: dfile(%d) %s",
+            ad_dfileno(ofork->of_ad), strerror(errno) );
         err = -1;
     }
 
@@ -1026,8 +991,8 @@ struct ofork       *ofork;
             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: hfile(%d) %s",
+                ad_hfileno(ofork->of_ad), strerror(errno) );
     }
 
     return( err );
@@ -1048,7 +1013,7 @@ int               ibuflen, *rbuflen;
     memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
 
     if (( ofork = of_find( ofrefnum )) == NULL ) {
-        LOG(log_error, logtype_default, "afp_closefork: of_find: %s", strerror(errno) );
+        LOG(log_error, logtype_afpd, "afp_closefork: of_find");
         return( AFPERR_PARAM );
     }
 
@@ -1084,7 +1049,7 @@ int               ibuflen, *rbuflen;
     }
 
     if ( ad_close( ofork->of_ad, adflags ) < 0 ) {
-        LOG(log_error, logtype_default, "afp_closefork: ad_close: %s", strerror(errno) );
+        LOG(log_error, logtype_afpd, "afp_closefork: ad_close: %s", strerror(errno) );
         return( AFPERR_PARAM );
     }
 
@@ -1121,7 +1086,7 @@ static __inline__ ssize_t write_file(struct ofork *ofork, int eid,
         case ENOSPC :
             return( AFPERR_DFULL );
         default :
-            LOG(log_error, logtype_default, "afp_write: ad_write: %s", strerror(errno) );
+            LOG(log_error, logtype_afpd, "afp_write: ad_write: %s", strerror(errno) );
             return( AFPERR_PARAM );
         }
     }
@@ -1157,7 +1122,7 @@ int                 ibuflen, *rbuflen;
     ibuf += sizeof( reqcount );
 
     if (( ofork = of_find( ofrefnum )) == NULL ) {
-        LOG(log_error, logtype_default, "afp_write: of_find: %s", strerror(errno) );
+        LOG(log_error, logtype_afpd, "afp_write: of_find");
         err = AFPERR_PARAM;
         goto afp_write_err;
     }
@@ -1217,7 +1182,7 @@ 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 );
         }
 
@@ -1262,7 +1227,7 @@ int                 ibuflen, *rbuflen;
                         cc = AFPERR_DFULL;
                         break;
                     default :
-                        LOG(log_error, logtype_default, "afp_write: ad_writefile: %s", strerror(errno) );
+                        LOG(log_error, logtype_afpd, "afp_write: ad_writefile: %s", strerror(errno) );
                         goto afp_write_loop;
                     }
                     dsi_writeflush(dsi);
@@ -1279,7 +1244,6 @@ int                 ibuflen, *rbuflen;
 
             /* 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);
@@ -1299,7 +1263,6 @@ afp_write_loop:
         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;
@@ -1332,6 +1295,7 @@ int               ibuflen, *rbuflen;
     struct ofork       *ofork;
     int                        buflen, ret;
     u_int16_t          ofrefnum, bitmap;
+    u_int16_t          attrbits = 0;
 
     ibuf += 2;
     memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
@@ -1342,12 +1306,14 @@ int             ibuflen, *rbuflen;
 
     *rbuflen = 0;
     if (( ofork = of_find( ofrefnum )) == NULL ) {
-        LOG(log_error, logtype_default, "afp_getforkparams: of_find: %s", strerror(errno) );
+        LOG(log_error, logtype_afpd, "afp_getforkparams: of_find");
         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 ) {
+                               rbuf + sizeof( u_short ), &buflen, attrbits )) != AFP_OK ) {
         return( ret );
     }