]> arthur.barton.de Git - netatalk.git/blobdiff - etc/afpd/desktop.c
error code for dirlookup, cname.
[netatalk.git] / etc / afpd / desktop.c
index db003f58b953c999b41a4b150c62998000f2129a..3df5481a387f25c629355051484ec86e9c9bafb6 100644 (file)
@@ -1,14 +1,19 @@
 /*
- * $Id: desktop.c,v 1.10 2002-01-03 17:49:38 sibaz Exp $
+ * $Id: desktop.c,v 1.25 2003-03-15 01:34:35 didg Exp $
  *
  * See COPYRIGHT.
+ *
+ * bug:
+ * afp_XXXcomment are (the only) functions able to open
+ * a ressource fork when there's no data fork, eg after
+ * it was removed with samba.
  */
 
 #ifdef HAVE_CONFIG_H
 #include "config.h"
 #endif /* HAVE_CONFIG_H */
 
-#include <syslog.h>
+#include <atalk/logger.h>
 #include <errno.h>
 #include <sys/types.h>
 #include <sys/time.h>
 #include "globals.h"
 #include "desktop.h"
 
+#ifdef FILE_MANGLING
+#include "mangle.h"
+#endif /* CNID_DB */
+
+#ifdef AFP3x
+#include <iconv.h>
+#endif
+
 int afp_opendt(obj, ibuf, ibuflen, rbuf, rbuflen )
 AFPObj      *obj;
 char   *ibuf, *rbuf;
@@ -52,7 +65,7 @@ int           ibuflen, *rbuflen;
     ibuf += 2;
 
     memcpy( &vid, ibuf, sizeof(vid));
-    if (( vol = getvolbyvid( vid )) == NULL ) {
+    if (NULL == ( vol = getvolbyvid( vid )) ) {
         *rbuflen = 0;
         return( AFPERR_PARAM );
     }
@@ -106,7 +119,7 @@ u_char      creator[ 4 ];
             *adts = '/';
 
             if (( si.sdt_fd = open( dtf, flags, ad_mode( dtf, mode ))) < 0 ) {
-                syslog( LOG_ERR, "iconopen: open %s: %s", dtf, strerror(errno) );
+                LOG(log_error, logtype_afpd, "iconopen: open %s: %s", dtf, strerror(errno) );
                 return -1;
             }
         } else {
@@ -171,7 +184,7 @@ int         ibuflen, *rbuflen;
     if (lseek( si.sdt_fd, (off_t) 0L, SEEK_SET ) < 0) {
         close(si.sdt_fd);
         si.sdt_fd = -1;
-        syslog( LOG_ERR, "afp_addicon: lseek: %s", strerror(errno) );
+        LOG(log_error, logtype_afpd, "afp_addicon: lseek: %s", strerror(errno) );
         cc = AFPERR_PARAM;
         goto addicon_err;
     }
@@ -206,7 +219,7 @@ int         ibuflen, *rbuflen;
         }
 
         if ( lseek( si.sdt_fd, (off_t) rsize, SEEK_CUR ) < 0 ) {
-            syslog( LOG_ERR, "afp_addicon: lseek: %s", strerror(errno) );
+            LOG(log_error, logtype_afpd, "afp_addicon: lseek: %s", strerror(errno) );
             cc = AFPERR_PARAM;
         }
     }
@@ -216,7 +229,7 @@ int         ibuflen, *rbuflen;
      */
 addicon_err:
     if ( cc < 0 ) {
-        syslog( LOG_ERR, "afp_addicon: %s", strerror(errno) );
+        LOG(log_error, logtype_afpd, "afp_addicon: %s", strerror(errno) );
         if (obj->proto == AFPPROTO_DSI) {
             dsi_writeinit(obj->handle, rbuf, buflen);
             dsi_writeflush(obj->handle);
@@ -257,7 +270,7 @@ addicon_err:
         }
 
         if ( writev( si.sdt_fd, iov, iovcnt ) < 0 ) {
-            syslog( LOG_ERR, "afp_addicon: writev: %s", strerror(errno) );
+            LOG(log_error, logtype_afpd, "afp_addicon: writev: %s", strerror(errno) );
             return( AFPERR_PARAM );
         }
         break;
@@ -270,13 +283,13 @@ addicon_err:
 
             /* add headers at end of file */
             if ((cc == 0) && (write(si.sdt_fd, imh, sizeof(imh)) < 0)) {
-                syslog(LOG_ERR, "afp_addicon: write: %s", strerror(errno));
+                LOG(log_error, logtype_afpd, "afp_addicon: write: %s", strerror(errno));
                 dsi_writeflush(dsi);
                 return AFPERR_PARAM;
             }
 
             if ((cc = write(si.sdt_fd, rbuf, iovcnt)) < 0) {
-                syslog(LOG_ERR, "afp_addicon: write: %s", strerror(errno));
+                LOG(log_error, logtype_afpd, "afp_addicon: write: %s", strerror(errno));
                 dsi_writeflush(dsi);
                 return AFPERR_PARAM;
             }
@@ -288,7 +301,7 @@ addicon_err:
                 }
 
                 if ((cc = write(si.sdt_fd, rbuf, iovcnt)) < 0) {
-                    syslog(LOG_ERR, "afp_addicon: write: %s", strerror(errno));
+                    LOG(log_error, logtype_afpd, "afp_addicon: write: %s", strerror(errno));
                     dsi_writeflush(dsi);
                     return AFPERR_PARAM;
                 }
@@ -355,7 +368,7 @@ int         ibuflen, *rbuflen;
 
     memcpy( &vid, ibuf, sizeof( vid ));
     ibuf += sizeof( vid );
-    if (( vol = getvolbyvid( vid )) == NULL ) {
+    if (NULL == ( vol = getvolbyvid( vid )) ) {
         return( AFPERR_PARAM );
     }
 
@@ -402,7 +415,7 @@ int         ibuflen, *rbuflen;
         memcpy( &bsize, ih + 10, sizeof( bsize ));
         bsize = ntohs(bsize);
         if ( lseek( si.sdt_fd, (off_t) bsize, SEEK_CUR ) < 0 ) {
-            syslog( LOG_ERR, "afp_iconinfo: lseek: %s", strerror(errno) );
+            LOG(log_error, logtype_afpd, "afp_iconinfo: lseek: %s", strerror(errno) );
             return( AFPERR_PARAM );
         }
         if ( si.sdt_index == iindex ) {
@@ -432,7 +445,7 @@ int         ibuflen, *rbuflen;
 
     memcpy( &vid, ibuf, sizeof( vid ));
     ibuf += sizeof( vid );
-    if (( vol = getvolbyvid( vid )) == NULL ) {
+    if (NULL == ( vol = getvolbyvid( vid )) ) {
         return( AFPERR_PARAM );
     }
 
@@ -461,7 +474,7 @@ int         ibuflen, *rbuflen;
     if ( lseek( si.sdt_fd, (off_t) 0L, SEEK_SET ) < 0 ) {
         close(si.sdt_fd);
         si.sdt_fd = -1;
-        syslog(LOG_ERR, "afp_geticon: lseek: %s", strerror(errno));
+        LOG(log_error, logtype_afpd, "afp_geticon: lseek: %s", strerror(errno));
         return( AFPERR_PARAM );
     }
 
@@ -477,14 +490,14 @@ int               ibuflen, *rbuflen;
         memcpy( &rsize, ih + 10, sizeof( rsize ));
         rsize = ntohs( rsize );
         if ( lseek( si.sdt_fd, (off_t) rsize, SEEK_CUR ) < 0 ) {
-            syslog( LOG_ERR, "afp_geticon: lseek: %s", strerror(errno) );
+            LOG(log_error, logtype_afpd, "afp_geticon: lseek: %s", strerror(errno) );
             return( AFPERR_PARAM );
         }
         offset += rsize;
     }
 
     if ( rc < 0 ) {
-        syslog(LOG_ERR, "afp_geticon: read: %s", strerror(errno));
+        LOG(log_error, logtype_afpd, "afp_geticon: read: %s", strerror(errno));
         return( AFPERR_PARAM );
     }
 
@@ -551,7 +564,7 @@ geticon_done:
         return AFP_OK;
 
 geticon_exit:
-        syslog(LOG_INFO, "afp_geticon: %s", strerror(errno));
+        LOG(log_info, logtype_afpd, "afp_geticon: %s", strerror(errno));
         dsi_readdone(dsi);
         obj->exit(1);
         return AFP_OK;
@@ -571,7 +584,7 @@ char *dtfile(const struct vol *vol, u_char creator[], char *ext )
 {
     static char        path[ MAXPATHLEN + 1];
     char       *p;
-    int                i;
+    unsigned int i;
 
     strcpy( path, vol->v_path );
     strcat( path, "/.AppleDesktop/" );
@@ -601,16 +614,19 @@ char *dtfile(const struct vol *vol, u_char creator[], char *ext )
     return( path );
 }
 
-char *mtoupath(const struct vol *vol, char *mpath)
+/* ---------------------------
+ * mpath is only a filename 
+*/
+static char  upath[ MAXPATHLEN + 1];
+static char  mpath[ MAXPATHLEN + 1];
+static char  ucs2[ MAXPATHLEN + 1];
+
+static char *old_mtoupath(const struct vol *vol, char *mpath)
 {
-    static char  upath[ MAXPATHLEN + 1];
     char       *m, *u;
     int                 i = 0;
-
-    if ( *mpath == '\0' ) {
-        return( "." );
-    }
-
+    int          changed = 0;
+        
     m = mpath;
     u = upath;
     while ( *m != '\0' ) {
@@ -622,58 +638,74 @@ char *mtoupath(const struct vol *vol, char *mpath)
 
         /* we have a code page. we only use the ascii range
          * if we have map ascii specified. */
-#if 1
         if (vol->v_mtoupage && ((*m & 0x80) ||
                                 vol->v_flags & AFPVOL_MAPASCII)) {
             *u = vol->v_mtoupage->map[(unsigned char) *m].value;
-        } else
-#endif /* 1 */
+            changed = 1;
+            if (!*u && *m) {
+                /* if conversion failed, encode in hex
+                 * to prevent silly truncation
+                 * H.P. Jansen <hpj@urpla.net> */
+#ifdef DEBUG
+                LOG(log_debug, logtype_afpd, "mtoupath: hex encode: 0x%x", (unsigned char) *m);
+#endif
+                *u++ = ':';
+                *u++ = hexdig[ ( *m & 0xf0 ) >> 4 ];
+                *u = hexdig[ *m & 0x0f ];
+            }
+        } else {
 #if AD_VERSION == AD_VERSION1
             if ((((vol->v_flags & AFPVOL_NOHEX) == 0) &&
                     (!isascii(*m) || *m == '/')) ||
                     (((vol->v_flags & AFPVOL_USEDOTS) == 0) &&
                      ( i == 0 && (*m == '.' )))) {
-#else /* AD_VERSION == AD_VERSION1 */
+#else 
             if ((((vol->v_flags & AFPVOL_NOHEX) == 0) &&
                     (!isprint(*m) || *m == '/')) ||
                     (((vol->v_flags & AFPVOL_USEDOTS) == 0) &&
                      ( i == 0 && (*m == '.' )))) {
-#endif /* AD_VERSION == AD_VERSION1 */
+#endif
                 /* do hex conversion. */
                 *u++ = ':';
                 *u++ = hexdig[ ( *m & 0xf0 ) >> 4 ];
                 *u = hexdig[ *m & 0x0f ];
+                changed = 1;
             } else
                 *u = *m;
+        }
         u++;
         i++;
         m++;
     }
     *u = '\0';
 
-    return( upath );
+#ifdef DEBUG
+    LOG(log_debug, logtype_afpd, "mtoupath: '%s':'%s'", mpath, upath);
+#endif /* DEBUG */
+
+    return( (changed)?upath:mpath );
 }
 
+/* ---------------------------- */
 #define hextoint( c )  ( isdigit( c ) ? c - '0' : c + 10 - 'a' )
 #define islxdigit(x)   (!isupper(x)&&isxdigit(x))
 
-char *utompath(const struct vol *vol, char *upath)
+static char *old_utompath(const struct vol *vol, char *upath)
 {
-    static char  mpath[ MAXPATHLEN + 1];
     char        *m, *u;
     int          h;
+    int          changed = 0;
 
     /* do the hex conversion */
     u = upath;
     m = mpath;
     while ( *u != '\0' ) {
         /* we have a code page */
-#if 1
         if (vol->v_utompage && ((*u & 0x80) ||
                                 (vol->v_flags & AFPVOL_MAPASCII))) {
             *m = vol->v_utompage->map[(unsigned char) *u].value;
+            changed = 1;
         } else
-#endif /* 1 */
             if ( *u == ':' && *(u+1) != '\0' && islxdigit( *(u+1)) &&
                     *(u+2) != '\0' && islxdigit( *(u+2))) {
                 ++u;
@@ -681,6 +713,7 @@ char *utompath(const struct vol *vol, char *upath)
                 ++u;
                 h |= hextoint( *u );
                 *m = h;
+                changed = 1;
             } else
                 *m = *u;
 
@@ -694,9 +727,268 @@ char *utompath(const struct vol *vol, char *upath)
         m++;
     }
     *m = '\0';
-    return( mpath );
+    m = mpath;
+
+#ifdef FILE_MANGLING
+    m = mangle(vol, mpath, upath, 0);
+    if (m != mpath) {
+        changed = 1;
+    }
+#endif /* FILE_MANGLING */
+
+#ifdef DEBUG
+    LOG(log_debug, logtype_afpd, "utompath: '%s':'%s'", upath, mpath);
+#endif /* DEBUG */
+
+    return((changed)? m:upath );
+}
+
+/* --------------- */
+extern unsigned int do_precomposition(unsigned int base, unsigned int comb);
+
+static char comp[MAXPATHLEN +1];
+
+static char *precompose(u_int16_t  *name, size_t inplen, size_t *outlen)
+{
+size_t i;
+u_int16_t base, comb;
+u_int16_t *in, *out;
+u_int16_t result;
+
+    if (!inplen || (inplen & 1) || inplen > sizeof(comp)/sizeof(u_int16_t))
+        return NULL;
+    i = 0;
+    in  = name;
+    out = (u_int16_t *)comp;
+    *outlen = 0;
+    
+    base = *in;
+    while (1) {
+        i += 2;
+        in++;
+        if (i == inplen) {
+           *out = base;
+           *outlen += 2;
+           return comp;
+        }
+        comb = *in;
+        if (comb >= 0x300 && (result = do_precomposition(base, comb))) {
+           *out = result;
+           out++;
+           *outlen += 2;
+           i += 2;
+           in++;
+           if (i == inplen) 
+              return comp;
+           base = *in;
+        }
+        else {
+           *out = base;
+           out++;
+           *outlen += 2;
+           base = comb;
+        }
+    }
+}
+
+/* --------------- */
+extern unsigned int do_decomposition(unsigned int base);
+
+static char *decompose(u_int16_t  *name, size_t inplen, size_t *outlen)
+{
+size_t i;
+u_int16_t base;
+u_int16_t *in, *out;
+unsigned int result;
+
+    if (!inplen || (inplen & 1))
+        return NULL;
+    i = 0;
+    in  = name;
+    out = (u_int16_t *)comp;
+    *outlen = 0;
+    
+    while (i < inplen) {
+        if (*outlen >= sizeof(comp)/sizeof(u_int16_t) +2) {
+            return NULL;
+        }
+        base = *in;
+        if ((result = do_decomposition(base))) {
+           *out = result  >> 16;
+           out++;
+           *outlen += 2;
+           *out = result & 0xffff;
+           out++;
+           *outlen += 2;
+        }
+        else {
+           *out = base;
+           out++;
+           *outlen += 2;
+        }
+        i += 2;
+        in++;
+     }
+     return comp;
+}
+
+/* --------------------------- */
+char *mtoupath(const struct vol *vol, char *mpath, int utf8)
+{
+    char       *m, *u, *r;
+    int                 i = 0;
+    size_t       inplen;
+    size_t       outlen;
+        
+    if ( *mpath == '\0' ) {
+        return( "." );
+    }
+
+#ifdef FILE_MANGLING
+    m = demangle(vol, mpath);
+    if (m != mpath) {
+        return m;
+    }
+#endif /* FILE_MANGLING */
+
+    if (!vol_utf8(vol))
+       return old_mtoupath(vol, mpath);
+
+    m = mpath;
+    u = upath;
+    while ( *m != '\0' ) {
+        if ( (!(vol->v_flags & AFPVOL_NOHEX) && *m == '/') ||
+             (!(vol->v_flags & AFPVOL_USEDOTS) && i == 0 && *m == '.') ||
+             (!utf8 && (unsigned char)*m == 0xf0) /* Apple logo */
+        ) {
+          /* do hex conversion. */
+          *u++ = ':';
+          *u++ = hexdig[ ( *m & 0xf0 ) >> 4 ];
+          *u = hexdig[ *m & 0x0f ];
+        } else
+           *u = *m;
+        u++;
+        i++;
+        m++;
+    }
+    *u = '\0';
+    u = upath;
+#ifdef AFP3x
+    inplen = strlen(u);
+    outlen = MAXPATHLEN;
+    r = ucs2;
+    if (!utf8) {
+        if ((size_t)(-1) == iconv(vol->v_mactoutf8, 0,0,0,0) )
+            return NULL;
+        /* assume precompose */
+        if ((size_t)(-1) == iconv(vol->v_mactoutf8, &u, &inplen, &r, &outlen))
+            return NULL;
+        u = ucs2;
+    }
+    else { 
+        if ((size_t)(-1) == iconv(vol->v_utf8toucs2, 0,0,0,0) )
+            return NULL;
+
+        if ((size_t)(-1) == iconv(vol->v_utf8toucs2, &u, &inplen, &r, &outlen))
+            return NULL;
+
+        u = precompose((u_int16_t *)ucs2, MAXPATHLEN -outlen, &inplen);
+
+        if ((size_t)(-1) == iconv(vol->v_ucs2toutf8, 0,0,0,0))
+            return NULL;
+            
+        outlen = MAXPATHLEN;
+        r = upath;
+        if ((size_t)(-1) == iconv(vol->v_ucs2toutf8, &u, &inplen, &r, &outlen))
+            return NULL;
+        u = upath;
+    }
+    u[MAXPATHLEN -outlen] = 0;
+#endif
+#ifdef DEBUG
+    LOG(log_debug, logtype_afpd, "mtoupath: '%s':'%s'", mpath, upath);
+#endif /* DEBUG */
+    return( u );
+}
+
+/* --------------- */
+char *utompath(const struct vol *vol, char *upath, int utf8)
+{
+    char        *m, *u, *r;
+    int          h;
+    int          mangleflag = 0;
+    size_t       inplen;
+    size_t       outlen;
+
+    if (!vol_utf8(vol))
+       return old_utompath(vol, upath);
+    /* do the hex conversion */
+    u = upath;
+    m = mpath;
+    while ( *u != '\0' ) {
+        if ( *u == ':' && islxdigit( *(u+1)) && islxdigit( *(u+2))) {
+            ++u;
+            h = hextoint( *u ) << 4;
+            ++u;
+            h |= hextoint( *u );
+            *m = h;
+        } else
+            *m = *u;
+        u++;
+        m++;
+    }
+    *m = '\0';
+    m = mpath;
+#ifdef AFP3x    
+    if ((size_t)(-1) == iconv(vol->v_utf8toucs2, 0,0,0,0) )
+        return NULL;
+    inplen = strlen(mpath);
+    outlen = MAXPATHLEN;
+    r = ucs2;
+    if ((size_t)(-1) == iconv(vol->v_utf8toucs2, &m, &inplen, &r, &outlen))
+        return NULL;
+
+    if (utf8) {
+        if ( NULL == (m = decompose((u_int16_t *)ucs2, MAXPATHLEN -outlen, &inplen)))
+            return NULL;
+
+        if ((size_t)(-1) == iconv(vol->v_ucs2toutf8, 0,0,0,0))
+            return NULL;
+            
+        outlen = MAXPATHLEN;
+        r = mpath;
+        if ((size_t)(-1) == iconv(vol->v_ucs2toutf8, &m, &inplen, &r, &outlen))
+            return NULL;
+    }
+    else {
+        m = precompose((u_int16_t *)ucs2, MAXPATHLEN -outlen, &inplen);
+
+        if ((size_t)(-1) == iconv(vol->v_ucs2tomac, 0,0,0,0))
+            return NULL;
+            
+        outlen = MAXPATHLEN;
+        r = mpath;
+        if ((size_t)(-1) == iconv(vol->v_ucs2tomac, &m, &inplen, &r, &outlen)) {
+            switch (errno) {
+            case EILSEQ:
+                if (outlen != MAXPATHLEN) {
+                    mangleflag = 1;
+                }
+            default:
+                return NULL;
+            }
+        }
+    }
+    mpath[MAXPATHLEN -outlen] = 0;
+#endif
+#ifdef FILE_MANGLING
+    m = mangle(vol, mpath, upath, mangleflag);
+#endif /* FILE_MANGLING */
+
+    return(m);
 }
 
+/* ----------------------------- */
 int afp_addcomment(obj, ibuf, ibuflen, rbuf, rbuflen )
 AFPObj      *obj;
 char   *ibuf, *rbuf;
@@ -706,28 +998,30 @@ int               ibuflen, *rbuflen;
     struct vol         *vol;
     struct dir         *dir;
     struct ofork        *of;
-    char               *path, *name;
+    struct path         *path;
+    char                *name, *upath;
     int                        clen;
     u_int32_t           did;
     u_int16_t          vid;
+    int                 isadir;
 
     *rbuflen = 0;
     ibuf += 2;
 
     memcpy( &vid, ibuf, sizeof( vid ));
     ibuf += sizeof( vid );
-    if (( vol = getvolbyvid( vid )) == NULL ) {
+    if (NULL == ( vol = getvolbyvid( vid )) ) {
         return( AFPERR_PARAM );
     }
 
     memcpy( &did, ibuf, sizeof( did ));
     ibuf += sizeof( did );
-    if (( dir = dirsearch( vol, did )) == NULL ) {
-        return( AFPERR_NOOBJ );
+    if (NULL == ( dir = dirlookup( vol, did )) ) {
+       return afp_errno;
     }
 
-    if (( path = cname( vol, dir, &ibuf )) == NULL ) {
-        return( AFPERR_NOOBJ );
+    if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
+       return get_afp_errno(AFPERR_NOOBJ);
     }
 
     if ((u_long)ibuf & 1 ) {
@@ -737,22 +1031,29 @@ int              ibuflen, *rbuflen;
     clen = (u_char)*ibuf++;
     clen = min( clen, 199 );
 
-    if ((*path == '\0') || !(of = of_findname(vol, curdir, path))) {
+    upath = path->u_name;
+    if (check_access(upath, OPENACC_WR ) < 0) {
+        return AFPERR_ACCESS;
+    }
+
+    isadir = path_isadir(path);
+    if (isadir || !(of = of_findname(path))) {
         memset(&ad, 0, sizeof(ad));
         adp = &ad;
     } else
         adp = of->of_ad;
-    if (ad_open( mtoupath( vol, path ), vol_noadouble(vol) |
-                 (( *path == '\0' ) ? ADFLAGS_HF|ADFLAGS_DIR : ADFLAGS_HF),
+
+    if (ad_open( upath , vol_noadouble(vol) |
+                 (( isadir) ? ADFLAGS_HF|ADFLAGS_DIR : ADFLAGS_HF),
                  O_RDWR|O_CREAT, 0666, adp) < 0 ) {
         return( AFPERR_ACCESS );
     }
 
-    if ( ad_getoflags( adp, ADFLAGS_HF ) & O_CREAT ) {
-        if ( *path == '\0' ) {
-            name = curdir->d_name;
+    if ( (ad_getoflags( adp, ADFLAGS_HF ) & O_CREAT) ) {
+        if ( *path->m_name == '\0' ) {
+            name = curdir->d_m_name;
         } else {
-            name = path;
+            name = path->m_name;
         }
         ad_setentrylen( adp, ADEID_NAME, strlen( name ));
         memcpy( ad_entry( adp, ADEID_NAME ), name,
@@ -775,36 +1076,40 @@ int              ibuflen, *rbuflen;
     struct vol         *vol;
     struct dir         *dir;
     struct ofork        *of;
-    char               *path;
+    struct path         *s_path;
+    char               *upath;
     u_int32_t          did;
     u_int16_t          vid;
-
+    int                 isadir;
+    
     *rbuflen = 0;
     ibuf += 2;
 
     memcpy( &vid, ibuf, sizeof( vid ));
     ibuf += sizeof( vid );
-    if (( vol = getvolbyvid( vid )) == NULL ) {
+    if (NULL == ( vol = getvolbyvid( vid )) ) {
         return( AFPERR_PARAM );
     }
 
     memcpy( &did, ibuf, sizeof( did ));
     ibuf += sizeof( did );
-    if (( dir = dirsearch( vol, did )) == NULL ) {
-        return( AFPERR_NOOBJ );
+    if (NULL == ( dir = dirlookup( vol, did )) ) {
+       return afp_errno;
     }
 
-    if (( path = cname( vol, dir, &ibuf )) == NULL ) {
-        return( AFPERR_NOOBJ );
+    if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
+       return get_afp_errno(AFPERR_NOOBJ);
     }
 
-    if ((*path == '\0') || !(of = of_findname(vol, curdir, path))) {
+    upath = s_path->u_name;
+    isadir = path_isadir(s_path);
+    if (isadir || !(of = of_findname(s_path))) {
         memset(&ad, 0, sizeof(ad));
         adp = &ad;
     } else
         adp = of->of_ad;
-    if ( ad_open( mtoupath( vol, path ),
-                  (( *path == '\0' ) ? ADFLAGS_HF|ADFLAGS_DIR : ADFLAGS_HF),
+    if ( ad_open( upath,
+                  ( isadir) ? ADFLAGS_HF|ADFLAGS_DIR : ADFLAGS_HF,
                   O_RDONLY, 0666, adp) < 0 ) {
         return( AFPERR_NOITEM );
     }
@@ -823,6 +1128,8 @@ int                ibuflen, *rbuflen;
             ad_getentrylen( adp, ADEID_COMMENT ));
     *rbuflen = ad_getentrylen( adp, ADEID_COMMENT ) + 1;
     ad_close( adp, ADFLAGS_HF );
+
+    /* return AFPERR_NOITEM if len == 0 ? */
     return( AFP_OK );
 }
 
@@ -835,36 +1142,45 @@ int              ibuflen, *rbuflen;
     struct vol         *vol;
     struct dir         *dir;
     struct ofork        *of;
-    char               *path;
+    struct path         *s_path;
+    char               *upath;
     u_int32_t          did;
     u_int16_t          vid;
+    int                 isadir;
 
     *rbuflen = 0;
     ibuf += 2;
 
     memcpy( &vid, ibuf, sizeof( vid ));
     ibuf += sizeof( vid );
-    if (( vol = getvolbyvid( vid )) == NULL ) {
+    if (NULL == ( vol = getvolbyvid( vid )) ) {
         return( AFPERR_PARAM );
     }
 
     memcpy( &did, ibuf, sizeof( did ));
     ibuf += sizeof( did );
-    if (( dir = dirsearch( vol, did )) == NULL ) {
-        return( AFPERR_NOOBJ );
+    if (NULL == ( dir = dirlookup( vol, did )) ) {
+       return afp_errno;
     }
 
-    if (( path = cname( vol, dir, &ibuf )) == NULL ) {
-        return( AFPERR_NOOBJ );
+    if (NULL == ( s_path = cname( vol, dir, &ibuf ))) {
+       return get_afp_errno(AFPERR_NOOBJ);
     }
 
-    if ((*path == '\0') || !(of = of_findname(vol, curdir, path))) {
+    upath = s_path->u_name;
+    if (check_access(upath, OPENACC_WR ) < 0) {
+        return AFPERR_ACCESS;
+    }
+
+    isadir = path_isadir(s_path);
+    if (isadir || !(of = of_findname(s_path))) {
         memset(&ad, 0, sizeof(ad));
         adp = &ad;
     } else
         adp = of->of_ad;
-    if ( ad_open( mtoupath( vol, path ),
-                  (( *path == '\0' ) ? ADFLAGS_HF|ADFLAGS_DIR : ADFLAGS_HF),
+
+    if ( ad_open( upath,
+                   (isadir) ? ADFLAGS_HF|ADFLAGS_DIR : ADFLAGS_HF,
                   O_RDWR, 0, adp) < 0 ) {
         switch ( errno ) {
         case ENOENT :