]> arthur.barton.de Git - netatalk.git/blobdiff - etc/afpd/desktop.c
- merge branch-netatalk-afp-3x-dev, HEAD was tagged before
[netatalk.git] / etc / afpd / desktop.c
index 2cd1ae896d8934bbafc9dee44721393e907b9af6..390909946f4d9be7eca8b1cbdc5229c40cc36836 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: desktop.c,v 1.30 2003-06-09 14:42:38 srittau Exp $
+ * $Id: desktop.c,v 1.31 2005-04-28 20:49:41 bfernhomberg Exp $
  *
  * See COPYRIGHT.
  *
 #include "config.h"
 #endif /* HAVE_CONFIG_H */
 
-#include <atalk/logger.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
 #include <errno.h>
-#include <sys/types.h>
-#include <sys/time.h>
+#include <dirent.h>
+
+#include <atalk/adouble.h>
 #include <sys/uio.h>
 #include <sys/param.h>
-#include <sys/stat.h>
 #include <sys/socket.h>
 #include <netatalk/at.h>
 #include <netatalk/endian.h>
 #include <atalk/atp.h>
 #include <atalk/asp.h>
 #include <atalk/afp.h>
-#include <atalk/adouble.h>
 #include <atalk/util.h>
-#include <dirent.h>
-#ifdef HAVE_FCNTL_H
-#include <fcntl.h>
-#endif /* HAVE_FCNTL_H */
-#include <stdio.h>
-#include <string.h>
-#include <ctype.h>
-#ifdef HAVE_FCNTL_H
-#include <unistd.h>
-#endif /* HAVE_FCNTL_H */
-
+#include <atalk/logger.h>
 #include "volume.h"
 #include "directory.h"
 #include "fork.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;
+AFPObj  *obj _U_;
 char   *ibuf, *rbuf;
-int            ibuflen, *rbuflen;
+int    ibuflen _U_, *rbuflen;
 {
     struct vol *vol;
     u_int16_t  vid;
@@ -76,19 +62,26 @@ int         ibuflen, *rbuflen;
 }
 
 int afp_closedt(obj, ibuf, ibuflen, rbuf, rbuflen )
-AFPObj      *obj;
-char   *ibuf, *rbuf;
-int            ibuflen, *rbuflen;
+AFPObj  *obj _U_;
+char   *ibuf _U_, *rbuf _U_;
+int    ibuflen _U_, *rbuflen;
 {
     *rbuflen = 0;
     return( AFP_OK );
 }
 
-struct savedt  si = { { 0, 0, 0, 0 }, -1, 0 };
+struct savedt  si = { { 0, 0, 0, 0 }, -1, 0, 0 };
+
+static char *icon_dtfile(struct vol *vol, u_char creator[ 4 ])
+{
+    return dtfile( vol, creator, ".icon" );
+}
 
 static int iconopen( vol, creator, flags, mode )
 struct vol     *vol;
 u_char creator[ 4 ];
+int flags;
+int mode;
 {
     char       *dtf, *adt, *adts;
 
@@ -101,7 +94,7 @@ u_char       creator[ 4 ];
         si.sdt_fd = -1;
     }
 
-    dtf = dtfile( vol, creator, ".icon" );
+    dtf = icon_dtfile( vol, creator);
 
     if (( si.sdt_fd = open( dtf, flags, ad_mode( dtf, mode ))) < 0 ) {
         if ( errno == ENOENT && ( flags & O_CREAT )) {
@@ -119,7 +112,7 @@ u_char      creator[ 4 ];
             *adts = '/';
 
             if (( si.sdt_fd = open( dtf, flags, ad_mode( dtf, mode ))) < 0 ) {
-                LOG(log_error, logtype_afpd, "iconopen: open %s: %s", dtf, strerror(errno) );
+                LOG(log_error, logtype_afpd, "iconopen(%s): open: %s", dtf, strerror(errno) );
                 return -1;
             }
         } else {
@@ -134,12 +127,14 @@ u_char    creator[ 4 ];
 }
 
 int afp_addicon(obj, ibuf, ibuflen, rbuf, rbuflen)
-AFPObj      *obj;
+AFPObj  *obj;
 char   *ibuf, *rbuf;
-int            ibuflen, *rbuflen;
+int    ibuflen _U_, *rbuflen;
 {
     struct vol         *vol;
+#ifndef NO_DDP
     struct iovec       iov[ 2 ];
+#endif
     u_char             fcreator[ 4 ], imh[ 12 ], irh[ 12 ], *p;
     int                        itype, cc = AFP_OK, iovcnt = 0, buflen;
     u_int32_t           ftype, itag;
@@ -184,7 +179,7 @@ int         ibuflen, *rbuflen;
     if (lseek( si.sdt_fd, (off_t) 0L, SEEK_SET ) < 0) {
         close(si.sdt_fd);
         si.sdt_fd = -1;
-        LOG(log_error, logtype_afpd, "afp_addicon: lseek: %s", strerror(errno) );
+        LOG(log_error, logtype_afpd, "afp_addicon(%s): lseek: %s", icon_dtfile(vol, fcreator), strerror(errno) );
         cc = AFPERR_PARAM;
         goto addicon_err;
     }
@@ -219,7 +214,7 @@ int         ibuflen, *rbuflen;
         }
 
         if ( lseek( si.sdt_fd, (off_t) rsize, SEEK_CUR ) < 0 ) {
-            LOG(log_error, logtype_afpd, "afp_addicon: lseek: %s", strerror(errno) );
+            LOG(log_error, logtype_afpd, "afp_addicon(%s): lseek: %s", icon_dtfile(vol, fcreator),strerror(errno) );
             cc = AFPERR_PARAM;
         }
     }
@@ -229,7 +224,6 @@ int         ibuflen, *rbuflen;
      */
 addicon_err:
     if ( cc < 0 ) {
-        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);
@@ -237,7 +231,6 @@ addicon_err:
         return cc;
     }
 
-
     switch (obj->proto) {
 #ifndef NO_DDP
     case AFPPROTO_ASP:
@@ -245,10 +238,12 @@ addicon_err:
         if ((asp_wrtcont(obj->handle, rbuf, &buflen) < 0) || buflen != bsize)
             return( AFPERR_PARAM );
 
+#ifdef DEBUG1
         if (obj->options.flags & OPTION_DEBUG) {
             printf("(write) len: %d\n", buflen);
             bprint(rbuf, buflen);
         }
+#endif
 
         /*
          * We're at the end of the file, add the headers, etc.  */
@@ -270,7 +265,7 @@ addicon_err:
         }
 
         if ( writev( si.sdt_fd, iov, iovcnt ) < 0 ) {
-            LOG(log_error, logtype_afpd, "afp_addicon: writev: %s", strerror(errno) );
+            LOG(log_error, logtype_afpd, "afp_addicon(%s): writev: %s", icon_dtfile(vol, fcreator), strerror(errno) );
             return( AFPERR_PARAM );
         }
         break;
@@ -283,25 +278,26 @@ addicon_err:
 
             /* add headers at end of file */
             if ((cc == 0) && (write(si.sdt_fd, imh, sizeof(imh)) < 0)) {
-                LOG(log_error, logtype_afpd, "afp_addicon: write: %s", strerror(errno));
+                LOG(log_error, logtype_afpd, "afp_addicon(%s): write: %s", icon_dtfile(vol, fcreator), strerror(errno));
                 dsi_writeflush(dsi);
                 return AFPERR_PARAM;
             }
 
             if ((cc = write(si.sdt_fd, rbuf, iovcnt)) < 0) {
-                LOG(log_error, logtype_afpd, "afp_addicon: write: %s", strerror(errno));
+                LOG(log_error, logtype_afpd, "afp_addicon(%s): write: %s", icon_dtfile(vol, fcreator), strerror(errno));
                 dsi_writeflush(dsi);
                 return AFPERR_PARAM;
             }
 
             while ((iovcnt = dsi_write(dsi, rbuf, buflen))) {
+#ifdef DEBUG1
                 if ( obj->options.flags & OPTION_DEBUG ) {
                     printf("(write) command cont'd: %d\n", iovcnt);
                     bprint(rbuf, iovcnt);
                 }
-
+#endif
                 if ((cc = write(si.sdt_fd, rbuf, iovcnt)) < 0) {
-                    LOG(log_error, logtype_afpd, "afp_addicon: write: %s", strerror(errno));
+                    LOG(log_error, logtype_afpd, "afp_addicon(%s): write: %s", icon_dtfile(vol, fcreator), strerror(errno));
                     dsi_writeflush(dsi);
                     return AFPERR_PARAM;
                 }
@@ -315,11 +311,11 @@ addicon_err:
     return( AFP_OK );
 }
 
-u_char utag[] = { 0, 0, 0, 0 };
-u_char ucreator[] = { 'U', 'N', 'I', 'X' };
-u_char utype[] = { 'T', 'E', 'X', 'T' };
-short  usize = 256;
-u_char uicon[] = {
+static const u_char    utag[] = { 0, 0, 0, 0 };
+static const u_char    ucreator[] = { 0, 0, 0, 0 };/* { 'U', 'N', 'I', 'X' };*/
+static const u_char    utype[] = { 0, 0, 0, 0 };/* { 'T', 'E', 'X', 'T' };*/
+static const short     usize = 256;
+static const u_char    uicon[] = {
     0x1F, 0xFF, 0xFC, 0x00, 0x10, 0x00, 0x06, 0x00,
     0x10, 0x00, 0x05, 0x00, 0x10, 0x00, 0x04, 0x80,
     0x10, 0x00, 0x04, 0x40, 0x10, 0x00, 0x04, 0x20,
@@ -355,9 +351,9 @@ u_char      uicon[] = {
 };
 
 int afp_geticoninfo(obj, ibuf, ibuflen, rbuf, rbuflen )
-AFPObj      *obj;
+AFPObj  *obj _U_;
 char   *ibuf, *rbuf;
-int            ibuflen, *rbuflen;
+int    ibuflen _U_, *rbuflen;
 {
     struct vol *vol;
     u_char     fcreator[ 4 ], ih[ 12 ];
@@ -415,7 +411,7 @@ int         ibuflen, *rbuflen;
         memcpy( &bsize, ih + 10, sizeof( bsize ));
         bsize = ntohs(bsize);
         if ( lseek( si.sdt_fd, (off_t) bsize, SEEK_CUR ) < 0 ) {
-            LOG(log_error, logtype_afpd, "afp_iconinfo: lseek: %s", strerror(errno) );
+            LOG(log_error, logtype_afpd, "afp_iconinfo(%s): lseek: %s", icon_dtfile(vol, fcreator), strerror(errno) );
             return( AFPERR_PARAM );
         }
         if ( si.sdt_index == iindex ) {
@@ -429,9 +425,9 @@ int         ibuflen, *rbuflen;
 
 
 int afp_geticon(obj, ibuf, ibuflen, rbuf, rbuflen )
-AFPObj      *obj;
+AFPObj  *obj;
 char   *ibuf, *rbuf;
-int            ibuflen, *rbuflen;
+int    ibuflen _U_, *rbuflen;
 {
     struct vol *vol;
     off_t       offset;
@@ -474,7 +470,7 @@ int         ibuflen, *rbuflen;
     if ( lseek( si.sdt_fd, (off_t) 0L, SEEK_SET ) < 0 ) {
         close(si.sdt_fd);
         si.sdt_fd = -1;
-        LOG(log_error, logtype_afpd, "afp_geticon: lseek: %s", strerror(errno));
+        LOG(log_error, logtype_afpd, "afp_geticon(%s): lseek: %s", icon_dtfile(vol, fcreator), strerror(errno));
         return( AFPERR_PARAM );
     }
 
@@ -490,14 +486,14 @@ int               ibuflen, *rbuflen;
         memcpy( &rsize, ih + 10, sizeof( rsize ));
         rsize = ntohs( rsize );
         if ( lseek( si.sdt_fd, (off_t) rsize, SEEK_CUR ) < 0 ) {
-            LOG(log_error, logtype_afpd, "afp_geticon: lseek: %s", strerror(errno) );
+            LOG(log_error, logtype_afpd, "afp_geticon(%s): lseek: %s", icon_dtfile(vol, fcreator), strerror(errno) );
             return( AFPERR_PARAM );
         }
         offset += rsize;
     }
 
     if ( rc < 0 ) {
-        LOG(log_error, logtype_afpd, "afp_geticon: read: %s", strerror(errno));
+        LOG(log_error, logtype_afpd, "afp_geticon(%s): read: %s", icon_dtfile(vol, fcreator), strerror(errno));
         return( AFPERR_PARAM );
     }
 
@@ -526,31 +522,30 @@ int               ibuflen, *rbuflen;
         /* do to the streaming nature, we have to exit if we encounter
          * a problem. much confusion results otherwise. */
         while (*rbuflen > 0) {
-#if defined(SENDFILE_FLAVOR_LINUX) || defined(SENDFILE_FLAVOR_BSD)
+#ifdef WITH_SENDFILE
             if (!obj->options.flags & OPTION_DEBUG) {
-#ifdef SENDFILE_FLAVOR_LINUX
-                if (sendfile(dsi->socket, si.sdt_fd, &offset, dsi->datasize) < 0)
-                    goto geticon_exit;
-#endif /* SENDFILE_FLAVOR_LINUX */
-
-#ifdef SENDFILE_FLAVOR_BSD
-                if (sendfile(si.sdt_fd, dsi->socket, offset, rc, NULL, NULL, 0) < 0)
-                    goto geticon_exit;
-#endif /* SENDFILE_FLAVOR_BSD */
-
+                if (sys_sendfile(dsi->socket, si.sdt_fd, &offset, dsi->datasize) < 0) {
+                    switch (errno) {
+                    case ENOSYS:
+                    case EINVAL:  /* there's no guarantee that all fs support sendfile */
+                        break;
+                    default:
+                        goto geticon_exit;
+                    }
+                }
                 goto geticon_done;
             }
-#endif /* SENDFILE_FLAVOR_LINUX || SENDFILE_FLAVOR_BSD */
-
+#endif
             buflen = read(si.sdt_fd, rbuf, *rbuflen);
             if (buflen < 0)
                 goto geticon_exit;
 
+#ifdef DEBUG1
             if (obj->options.flags & OPTION_DEBUG) {
                 printf( "(read) reply: %d, %d\n", buflen, dsi->clientID);
                 bprint(rbuf, buflen);
             }
-
+#endif
             /* dsi_read() also returns buffer size of next allocation */
             buflen = dsi_read(dsi, rbuf, buflen); /* send it off */
             if (buflen < 0)
@@ -564,9 +559,9 @@ geticon_done:
         return AFP_OK;
 
 geticon_exit:
-        LOG(log_info, logtype_afpd, "afp_geticon: %s", strerror(errno));
+        LOG(log_info, logtype_afpd, "afp_geticon(%s): %s", icon_dtfile(vol, fcreator), strerror(errno));
         dsi_readdone(dsi);
-        obj->exit(1);
+        obj->exit(EXITERR_SYS);
         return AFP_OK;
 
     } else {
@@ -574,12 +569,12 @@ geticon_exit:
             return( AFPERR_PARAM );
         }
         *rbuflen = rc;
-        return AFP_OK;
     }
+    return AFP_OK;
 }
 
-
-static char            hexdig[] = "0123456789abcdef";
+/* ---------------------- */
+static const char              hexdig[] = "0123456789abcdef";
 char *dtfile(const struct vol *vol, u_char creator[], char *ext )
 {
     static char        path[ MAXPATHLEN + 1];
@@ -616,437 +611,119 @@ char *dtfile(const struct vol *vol, u_char creator[], char *ext )
 
 /* ---------------------------
  * mpath is only a filename 
+ * did filename parent directory ID.
 */
-static char  upath[ MAXPATHLEN + 1];
-static char  mpath[ MAXPATHLEN + 1];
-#ifdef AFP3x
-static char  ucs2[ MAXPATHLEN + 1];
-#endif
-
-static char *old_mtoupath(const struct vol *vol, char *mpath)
-{
-    char       *m, *u;
-    int                 i = 0;
-    int          changed = 0;
-        
-    m = mpath;
-    u = upath;
-    if ((vol->v_casefold & (AFPVOL_MTOUUPPER| AFPVOL_MTOULOWER))) {
-        changed = 1;
-    }
-    while ( *m != '\0' ) {
-        /* handle case conversion first */
-        if (vol->v_casefold & AFPVOL_MTOUUPPER)
-            *m = diatoupper( *m );
-        else if (vol->v_casefold & AFPVOL_MTOULOWER)
-            *m = diatolower( *m );
-
-        /* we have a code page. we only use the ascii range
-         * if we have map ascii specified. */
-        if (vol->v_mtoupage && ((*m & 0x80) ||
-                                vol->v_flags & AFPVOL_MAPASCII)) {
-            *u = vol->v_mtoupage->map[(unsigned char) *m].value;
-            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 
-            if ((((vol->v_flags & AFPVOL_NOHEX) == 0) &&
-                    (!isprint(*m) || *m == '/')) ||
-                    (((vol->v_flags & AFPVOL_USEDOTS) == 0) &&
-                     ( i == 0 && (*m == '.' )))) {
-#endif
-                /* do hex conversion. */
-                *u++ = ':';
-                *u++ = hexdig[ ( *m & 0xf0 ) >> 4 ];
-                *u = hexdig[ *m & 0x0f ];
-                changed = 1;
-            } else
-                *u = *m;
-        }
-        u++;
-        i++;
-        m++;
-    }
-    *u = '\0';
-
-#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))
-
-static char *old_utompath(const struct vol *vol, char *upath)
-{
-    char        *m, *u;
-    int          h;
-    int          changed = 0;
-
-    /* do the hex conversion */
-    u = upath;
-    m = mpath;
-    if ((vol->v_casefold & (AFPVOL_MTOUUPPER| AFPVOL_MTOULOWER))) {
-        changed = 1;
-    }
-    while ( *u != '\0' ) {
-        /* we have a code page */
-        if (vol->v_utompage && ((*u & 0x80) ||
-                                (vol->v_flags & AFPVOL_MAPASCII))) {
-            *m = vol->v_utompage->map[(unsigned char) *u].value;
-            changed = 1;
-        } else
-            if ( *u == ':' && *(u+1) != '\0' && islxdigit( *(u+1)) &&
-                    *(u+2) != '\0' && islxdigit( *(u+2))) {
-                ++u;
-                h = hextoint( *u ) << 4;
-                ++u;
-                h |= hextoint( *u );
-                *m = h;
-                changed = 1;
-            } else
-                *m = *u;
-
-        /* handle case conversion */
-        if (vol->v_casefold & AFPVOL_UTOMLOWER)
-            *m = diatolower( *m );
-        else if (vol->v_casefold & AFPVOL_UTOMUPPER)
-            *m = diatoupper( *m );
-
-        u++;
-        m++;
-    }
-    *m = '\0';
-    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 );
-}
-
-/* --------------- */
-#ifdef AFP3x
-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)
+char *mtoupath(const struct vol *vol, char *mpath, cnid_t did, int utf8)
 {
-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;
-}
-#endif
-
-/* --------------------------- */
-char *mtoupath(const struct vol *vol, char *mpath, int utf8)
-{
-    int                i = 0;
+    static char  upath[ MAXPATHLEN + 1];
     char       *m, *u;
-#ifdef AFP3x
-    char       *r;
     size_t       inplen;
     size_t       outlen;
-#endif
+    u_int16_t   flags = 0;
         
     if ( *mpath == '\0' ) {
         return( "." );
     }
 
-#ifdef FILE_MANGLING
-    m = demangle(vol, mpath);
+    /* set conversion flags */
+    if (!(vol->v_flags & AFPVOL_NOHEX))
+        flags |= CONV_ESCAPEHEX;
+    if (!(vol->v_flags & AFPVOL_USEDOTS))
+        flags |= CONV_ESCAPEDOTS;
+
+    if ((vol->v_casefold & AFPVOL_MTOUUPPER))
+        flags |= CONV_TOUPPER;
+    else if ((vol->v_casefold & AFPVOL_MTOULOWER))
+        flags |= CONV_TOLOWER;
+
+    if ((vol->v_flags & AFPVOL_EILSEQ)) {
+        flags |= CONV__EILSEQ;
+    }
+
+    m = demangle(vol, mpath, did);
     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);
+
+    inplen = strlen(m);
     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;
+
+    if ((size_t)-1 == (outlen = convert_charset ( (utf8)?CH_UTF8_MAC:vol->v_maccharset, vol->v_volcharset, vol->v_maccharset, m, inplen, u, outlen, &flags)) ) {
+        LOG(log_error, logtype_afpd, "conversion from %s to %s for %s failed.", (utf8)?"UTF8-MAC":vol->v_maccodepage, vol->v_volcodepage, mpath);
+           return NULL;
     }
-    u[MAXPATHLEN -outlen] = 0;
-#endif
+    upath[outlen] = 0;
+
 #ifdef DEBUG
     LOG(log_debug, logtype_afpd, "mtoupath: '%s':'%s'", mpath, upath);
 #endif /* DEBUG */
-    return( u );
+    return( upath );
 }
 
-/* --------------- */
-char *utompath(const struct vol *vol, char *upath, int utf8)
+/* --------------- 
+ * id filename ID
+*/
+char *utompath(const struct vol *vol, char *upath, cnid_t id, int utf8)
 {
-    int          h;
-    int          mangleflag = 0;
-    char       *m, *u;
-#ifdef AFP3x
-    char       *r;
-    size_t       inplen;
+    static char  mpath[ MAXPATHLEN + 1];
+    char        *m, *u;
+    u_int16_t    flags = CONV_IGNORE | CONV_UNESCAPEHEX;
     size_t       outlen;
-#endif
 
-    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;
+    outlen = strlen(upath);
+
+    if ((vol->v_casefold & AFPVOL_UTOMUPPER))
+        flags |= CONV_TOUPPER;
+    else if ((vol->v_casefold & AFPVOL_UTOMLOWER))
+        flags |= CONV_TOLOWER;
+
+    if ((vol->v_flags & AFPVOL_EILSEQ)) {
+        flags |= CONV__EILSEQ;
     }
-    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;
-            }
-        }
+
+    u = upath;
+
+    /* convert charsets */
+    if ((size_t)-1 == ( outlen = convert_charset ( vol->v_volcharset, (utf8)?CH_UTF8_MAC:vol->v_maccharset, vol->v_maccharset, u, outlen, mpath, MAXPATHLEN, &flags)) ) { 
+        LOG(log_error, logtype_afpd, "Conversion from %s to %s for %s (%u) failed.", vol->v_volcodepage, vol->v_maccodepage, u, ntohl(id));
+       goto utompath_error;
     }
-    mpath[MAXPATHLEN -outlen] = 0;
-#endif
-#ifdef FILE_MANGLING
-    m = mangle(vol, mpath, upath, mangleflag);
-#else
-    if (mangleflag)
-        return NULL;
-    m = mpath;
-#endif /* FILE_MANGLING */
 
+    mpath[outlen] = 0; 
+    if (!(flags & CONV_REQMANGLE)) 
+        flags = 0;
+    else
+        flags = 1;
+
+    if (utf8)
+        flags |= 2;
+
+    m = mangle(vol, mpath, outlen, upath, id, flags);
+
+#ifdef DEBUG
+    LOG(log_debug, logtype_afpd, "utompath: '%s':'%s':'%2.2X'", upath, m, ntohl(id));
+#endif /* DEBUG */
+    return(m);
+
+utompath_error:
+    u = "???";
+    m = mangle(vol, u, strlen(u), upath, id, (utf8)?3:1);
     return(m);
 }
 
-/* ----------------------------- */
-int afp_addcomment(obj, ibuf, ibuflen, rbuf, rbuflen )
-AFPObj      *obj;
-char   *ibuf, *rbuf;
-int            ibuflen, *rbuflen;
+/* ------------------------- */
+static int ad_addcomment(struct vol *vol, struct path *path, char *ibuf)
 {
-    struct adouble     ad, *adp;
-    struct vol         *vol;
-    struct dir         *dir;
     struct ofork        *of;
-    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 (NULL == ( vol = getvolbyvid( vid )) ) {
-        return( AFPERR_PARAM );
-    }
-
-    memcpy( &did, ibuf, sizeof( did ));
-    ibuf += sizeof( did );
-    if (NULL == ( dir = dirlookup( vol, did )) ) {
-       return afp_errno;
-    }
-
-    if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
-       return get_afp_errno(AFPERR_NOOBJ);
-    }
-
-    if ((u_long)ibuf & 1 ) {
-        ibuf++;
-    }
+    int                        clen;
+    struct adouble     ad, *adp;
 
     clen = (u_char)*ibuf++;
     clen = min( clen, 199 );
@@ -1055,10 +732,10 @@ int              ibuflen, *rbuflen;
     if (!vol_unix_priv(vol) && check_access(upath, OPENACC_WR ) < 0) {
         return AFPERR_ACCESS;
     }
-
+    
     isadir = path_isadir(path);
     if (isadir || !(of = of_findname(path))) {
-        memset(&ad, 0, sizeof(ad));
+        ad_init(&ad, vol->v_adouble, vol->v_ad_options);
         adp = &ad;
     } else
         adp = of->of_ad;
@@ -1069,39 +746,35 @@ int              ibuflen, *rbuflen;
         return( AFPERR_ACCESS );
     }
 
-    if ( (ad_getoflags( adp, ADFLAGS_HF ) & O_CREAT) ) {
-        if ( *path->m_name == '\0' ) {
-            name = curdir->d_m_name;
-        } else {
-            name = path->m_name;
+    if (ad_getentryoff(adp, ADEID_COMMENT)) {
+        if ( (ad_getoflags( adp, ADFLAGS_HF ) & O_CREAT) ) {
+            if ( *path->m_name == '\0' ) {
+                name = curdir->d_m_name;
+            } else {
+                name = path->m_name;
+            }
+            ad_setname(adp, name);
         }
-        ad_setentrylen( adp, ADEID_NAME, strlen( name ));
-        memcpy( ad_entry( adp, ADEID_NAME ), name,
-                ad_getentrylen( adp, ADEID_NAME ));
+        ad_setentrylen( adp, ADEID_COMMENT, clen );
+        memcpy( ad_entry( adp, ADEID_COMMENT ), ibuf, clen );
+        ad_flush( adp, ADFLAGS_HF );
     }
-
-    ad_setentrylen( adp, ADEID_COMMENT, clen );
-    memcpy( ad_entry( adp, ADEID_COMMENT ), ibuf, clen );
-    ad_flush( adp, ADFLAGS_HF );
     ad_close( adp, ADFLAGS_HF );
     return( AFP_OK );
 }
 
-int afp_getcomment(obj, ibuf, ibuflen, rbuf, rbuflen )
-AFPObj      *obj;
-char   *ibuf, *rbuf;
-int            ibuflen, *rbuflen;
+/* ----------------------------- */
+int afp_addcomment(obj, ibuf, ibuflen, rbuf, rbuflen )
+AFPObj  *obj _U_;
+char   *ibuf, *rbuf _U_;
+int    ibuflen _U_, *rbuflen;
 {
-    struct adouble     ad, *adp;
     struct vol         *vol;
     struct dir         *dir;
-    struct ofork        *of;
-    struct path         *s_path;
-    char               *upath;
-    u_int32_t          did;
+    struct path         *path;
+    u_int32_t           did;
     u_int16_t          vid;
-    int                 isadir;
-    
+
     *rbuflen = 0;
     ibuf += 2;
 
@@ -1117,27 +790,45 @@ int              ibuflen, *rbuflen;
        return afp_errno;
     }
 
-    if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
+    if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
        return get_afp_errno(AFPERR_NOOBJ);
     }
 
-    upath = s_path->u_name;
-    isadir = path_isadir(s_path);
-    if (isadir || !(of = of_findname(s_path))) {
-        memset(&ad, 0, sizeof(ad));
+    if ((u_long)ibuf & 1 ) {
+        ibuf++;
+    }
+
+    return ad_addcomment(vol, path, ibuf);
+}
+
+/* -------------------- */
+static int ad_getcomment(struct vol *vol, struct path *path, char *rbuf, int *rbuflen)
+{
+    struct adouble     ad, *adp;
+    struct ofork        *of;
+    char               *upath;
+    int                 isadir;
+
+
+    upath = path->u_name;
+    isadir = path_isadir(path);
+    if (isadir || !(of = of_findname(path))) {
+        ad_init(&ad, vol->v_adouble, vol->v_ad_options);
         adp = &ad;
     } else
         adp = of->of_ad;
-    if ( ad_open( upath,
-                  ( isadir) ? ADFLAGS_HF|ADFLAGS_DIR : ADFLAGS_HF,
-                  O_RDONLY, 0666, adp) < 0 ) {
+        
+    if ( ad_metadata( upath,( isadir) ? ADFLAGS_DIR : 0, adp) < 0 ) {
         return( AFPERR_NOITEM );
     }
 
+    if (!ad_getentryoff(adp, ADEID_COMMENT)) {
+        return AFPERR_NOITEM;
+    }
     /*
      * Make sure the AD file is not bogus.
      */
-    if ( ad_getentrylen( adp, ADEID_COMMENT ) < 0 ||
+    if ( ad_getentrylen( adp, ADEID_COMMENT ) <= 0 ||
             ad_getentrylen( adp, ADEID_COMMENT ) > 199 ) {
         ad_close( adp, ADFLAGS_HF );
         return( AFPERR_NOITEM );
@@ -1149,25 +840,21 @@ int              ibuflen, *rbuflen;
     *rbuflen = ad_getentrylen( adp, ADEID_COMMENT ) + 1;
     ad_close( adp, ADFLAGS_HF );
 
-    /* return AFPERR_NOITEM if len == 0 ? */
     return( AFP_OK );
 }
 
-int afp_rmvcomment(obj, ibuf, ibuflen, rbuf, rbuflen )
-AFPObj      *obj;
+/* -------------------- */
+int afp_getcomment(obj, ibuf, ibuflen, rbuf, rbuflen )
+AFPObj  *obj _U_;
 char   *ibuf, *rbuf;
-int            ibuflen, *rbuflen;
+int    ibuflen _U_, *rbuflen;
 {
-    struct adouble     ad, *adp;
     struct vol         *vol;
     struct dir         *dir;
-    struct ofork        *of;
     struct path         *s_path;
-    char               *upath;
     u_int32_t          did;
     u_int16_t          vid;
-    int                 isadir;
-
+    
     *rbuflen = 0;
     ibuf += 2;
 
@@ -1183,18 +870,29 @@ int              ibuflen, *rbuflen;
        return afp_errno;
     }
 
-    if (NULL == ( s_path = cname( vol, dir, &ibuf ))) {
+    if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
        return get_afp_errno(AFPERR_NOOBJ);
     }
 
-    upath = s_path->u_name;
+    return ad_getcomment(vol, s_path, rbuf, rbuflen);
+}
+
+/* ----------------------- */
+static int ad_rmvcomment(struct vol *vol, struct path *path)
+{
+    struct adouble     ad, *adp;
+    struct ofork        *of;
+    int                 isadir;
+    char               *upath;
+
+    upath = path->u_name;
     if (!vol_unix_priv(vol) && 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));
+    isadir = path_isadir(path);
+    if (isadir || !(of = of_findname(path))) {
+        ad_init(&ad, vol->v_adouble, vol->v_ad_options);
         adp = &ad;
     } else
         adp = of->of_ad;
@@ -1212,8 +910,44 @@ int               ibuflen, *rbuflen;
         }
     }
 
-    ad_setentrylen( adp, ADEID_COMMENT, 0 );
-    ad_flush( adp, ADFLAGS_HF );
+    if (ad_getentryoff(adp, ADEID_COMMENT)) {
+        ad_setentrylen( adp, ADEID_COMMENT, 0 );
+        ad_flush( adp, ADFLAGS_HF );
+    }
     ad_close( adp, ADFLAGS_HF );
     return( AFP_OK );
 }
+
+/* ----------------------- */
+int afp_rmvcomment(obj, ibuf, ibuflen, rbuf, rbuflen )
+AFPObj  *obj _U_;
+char   *ibuf, *rbuf _U_;
+int    ibuflen _U_, *rbuflen;
+{
+    struct vol         *vol;
+    struct dir         *dir;
+    struct path         *s_path;
+    u_int32_t          did;
+    u_int16_t          vid;
+
+    *rbuflen = 0;
+    ibuf += 2;
+
+    memcpy( &vid, ibuf, sizeof( vid ));
+    ibuf += sizeof( vid );
+    if (NULL == ( vol = getvolbyvid( vid )) ) {
+        return( AFPERR_PARAM );
+    }
+
+    memcpy( &did, ibuf, sizeof( did ));
+    ibuf += sizeof( did );
+    if (NULL == ( dir = dirlookup( vol, did )) ) {
+       return afp_errno;
+    }
+
+    if (NULL == ( s_path = cname( vol, dir, &ibuf ))) {
+       return get_afp_errno(AFPERR_NOOBJ);
+    }
+    
+    return ad_rmvcomment(vol, s_path);
+}