]> arthur.barton.de Git - netatalk.git/blobdiff - etc/afpd/directory.c
error code for dirlookup, cname.
[netatalk.git] / etc / afpd / directory.c
index c03c47ba5113ee95f4fc63b736f38d41613bee7e..7f4b44eb1e66254aeded9af2d2ad2b169d15db53 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: directory.c,v 1.49 2002-10-25 11:10:46 didg Exp $
+ * $Id: directory.c,v 1.64 2003-03-15 01:34:35 didg Exp $
  *
  * Copyright (c) 1990,1993 Regents of The University of Michigan.
  * All Rights Reserved.  See COPYRIGHT.
@@ -60,6 +60,7 @@ char *strchr (), *strrchr ();
 #include "unix.h"
 
 struct dir     *curdir;
+int             afp_errno;
 
 #define SENTINEL (&sentinel)
 static struct dir sentinel = { SENTINEL, SENTINEL, NULL, DIRTREE_COLOR_BLACK,
@@ -99,9 +100,10 @@ u_int32_t   did;
 
 
     /* check for 0 did */
-    if (!did)
+    if (!did) {
+        afp_errno = AFPERR_PARAM;
         return NULL;
-
+    }
     if ( did == DIRDID_ROOT_PARENT ) {
         if (!rootpar.d_did)
             rootpar.d_did = DIRDID_ROOT_PARENT;
@@ -110,6 +112,7 @@ u_int32_t   did;
     }
 
     dir = vol->v_root;
+    afp_errno = AFPERR_NOOBJ;
     while ( dir != SENTINEL ) {
         if (dir->d_did == did)
             return dir->d_m_name ? dir : NULL;
@@ -118,6 +121,43 @@ u_int32_t  did;
     return NULL;
 }
 
+/* ------------------- */
+#ifdef ATACC
+int path_isadir(struct path *o_path)
+{
+    return o_path->m_name == '\0' || /* we are in a it */
+           !o_path->st_valid ||      /* in cache but we can't chdir in it */ 
+           (!o_path->st_errno && S_ISDIR(o_path->st.st_mode)); /* not in cache an can't chdir */
+}
+#endif
+
+int get_afp_errno(const int param)
+{
+    if (afp_errno != AFPERR_DID1)
+        return afp_errno;
+    return param;
+}
+
+/* ------------------- */
+struct dir *
+            dirsearch_byname( cdir, name )
+            struct dir *cdir;
+            const char *name;
+{
+struct dir *dir;
+
+    if (!strcmp(name, "."))
+        return cdir;
+    dir = cdir->d_child;
+    while (dir) {
+        if ( strcmp( dir->d_u_name, name ) == 0 ) {
+            break;
+        }
+        dir = (dir == curdir->d_child->d_prev) ? NULL : dir->d_next;
+    }
+    return dir;
+}            
+
 /* -----------------------------------------
  * if did is not in the cache resolve it with cnid 
  * 
@@ -140,15 +180,19 @@ u_int32_t did;
     char *mpath;
     
     ret = dirsearch(vol, did);
-    if (ret != NULL)
+    if (ret != NULL || afp_errno == AFPERR_PARAM)
         return ret;
 
     id = did;
-    if ((upath = cnid_resolve(vol->v_db, &id, buffer, buflen)) == NULL) {
+    if (NULL == (upath = cnid_resolve(vol->v_db, &id, buffer, buflen)) ) {
+        afp_errno = AFPERR_NOOBJ;
         return NULL;
     }
     ptr = path + MAXPATHLEN;
-    mpath = utompath(vol, upath);
+    if (NULL == ( mpath = utompath(vol, upath, utf8_encoding()) ) ) {
+        afp_errno = AFPERR_NOOBJ;
+        return NULL;
+    }
     len = strlen(mpath);
     pathlen = len;          /* no 0 in the last part */
     len++;
@@ -159,13 +203,20 @@ u_int32_t did;
         if (ret != NULL) {
             break;
         }
-        if ((upath = cnid_resolve(vol->v_db, &id, buffer, buflen)) == NULL)
+        if ( NULL == (upath = cnid_resolve(vol->v_db, &id, buffer, buflen))
+             ||
+             NULL == (mpath = utompath(vol, upath, utf8_encoding()))
+        ) {
+            afp_errno = AFPERR_NOOBJ;
             return NULL;
-        mpath = utompath(vol, upath);
+        }
+
         len = strlen(mpath) + 1;
         pathlen += len;
-        if (pathlen > 255)
+        if (pathlen > 255) {
+            afp_errno = AFPERR_PARAM;
             return NULL;
+        }
         strcpy(ptr - len, mpath);
         ptr -= len;
     }
@@ -436,15 +487,15 @@ struct dir        *dir;
  * process. It's fixable within afpd if fnctl_lock, doable with smb and
  * next to impossible for nfs and local filesystem access.
  */
 static void dir_invalidate( vol, dir )
 const struct vol *vol;
 struct dir *dir;
 {
        if (curdir == dir) {
            /* v_root can't be deleted */
-               if (movecwd(vol, vol->v_root) < 0) 
-                       printf("Yuup cant change dir to v_root\n");
+               if (movecwd(vol, vol->v_root) < 0) {
+            LOG(log_error, logtype_afpd, "cname can't chdir to : %s", vol->v_root);
+        }
        }
        /* FIXME */
     dirchildremove(dir->d_parent, dir);
@@ -490,10 +541,13 @@ struct vol        *vol;
 struct dir     *dir;
 struct path *path;
 {
-    char       *p;
+    path->u_name = mtoupath(vol, path->m_name, utf8_encoding() );
 
-    path->u_name = p = mtoupath(vol, path->m_name );
-    if ( of_stat( path ) != 0 ) {
+    if ( path->u_name == NULL) {
+        afp_errno = AFPERR_PARAM;
+        return NULL;
+    }
+    if (of_stat( path ) != 0 ) {
         return( NULL );
     }
 
@@ -512,6 +566,79 @@ struct path *path;
     return( dir );
 }
 
+/* -------------------
+   system rmdir with afp error code.
+   ENOENT is not an error.
+ */
+static int netatalk_rmdir(const char *name)
+{
+    if (rmdir(name) < 0) {
+        switch ( errno ) {
+        case ENOENT :
+            break;
+        case ENOTEMPTY : 
+            return AFPERR_DIRNEMPT;
+        case EPERM:
+        case EACCES :
+            return AFPERR_ACCESS;
+        case EROFS:
+            return AFPERR_VLOCK;
+        default :
+            return AFPERR_PARAM;
+        }
+    }
+    return AFP_OK;
+}
+
+/* -------------------------
+   appledouble mkdir afp error code.
+*/
+static int netatalk_mkdir(const char *name)
+{
+    if (ad_mkdir(name, DIRBITS | 0777) < 0) {
+        switch ( errno ) {
+        case ENOENT :
+            return( AFPERR_NOOBJ );
+        case EROFS :
+            return( AFPERR_VLOCK );
+        case EPERM:
+        case EACCES :
+            return( AFPERR_ACCESS );
+        case EEXIST :
+            return( AFPERR_EXIST );
+        case ENOSPC :
+        case EDQUOT :
+            return( AFPERR_DFULL );
+        default :
+            return( AFPERR_PARAM );
+        }
+    }
+    return AFP_OK;
+}
+
+/* -------------------
+   system unlink with afp error code.
+   ENOENT is not an error.
+ */
+int netatalk_unlink(const char *name)
+{
+    if (unlink(name) < 0) {
+        switch (errno) {
+        case ENOENT :
+            break;
+        case EROFS:
+            return AFPERR_VLOCK;
+        case EPERM:
+        case EACCES :
+            return AFPERR_ACCESS;
+        default :
+            return AFPERR_PARAM;
+        }
+    }
+    return AFP_OK;
+}
+
+/* ------------------- */
 static int deletedir(char *dir)
 {
     char path[MAXPATHLEN + 1];
@@ -519,9 +646,10 @@ static int deletedir(char *dir)
     struct dirent      *de;
     struct stat st;
     size_t len;
-    int err;
+    int err = AFP_OK;
+    size_t remain;
 
-    if ((len = strlen(dir)) > sizeof(path))
+    if ((len = strlen(dir)) +2 > sizeof(path))
         return AFPERR_PARAM;
 
     /* already gone */
@@ -531,57 +659,34 @@ static int deletedir(char *dir)
     strcpy(path, dir);
     strcat(path, "/");
     len++;
-    while ((de = readdir(dp))) {
+    remain = sizeof(path) -len -1;
+    while ((de = readdir(dp)) && err == AFP_OK) {
         /* skip this and previous directory */
         if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
             continue;
 
-        strncpy(path + len, de->d_name, sizeof(path) - len);
-        if (stat(path, &st) == 0) {
-            if (S_ISDIR(st.st_mode)) {
-                if ((err = deletedir(path)) < 0) {
-                    closedir(dp);
-                    return err;
-                }
-            } else if (unlink(path) < 0) {
-                switch (errno) {
-                case ENOENT :
-                    continue; /* somebody went and deleted it behind our backs. */
-                case EROFS:
-                    err = AFPERR_VLOCK;
-                    break;
-                case EPERM:
-                case EACCES :
-                    err = AFPERR_ACCESS;
-                    break;
-                default :
-                    err = AFPERR_PARAM;
-                }
-                closedir(dp);
-                return err;
-            }
+        if (strlen(de->d_name) > remain) {
+            err = AFPERR_PARAM;
+            break;
+        }
+        strcpy(path + len, de->d_name);
+        if (stat(path, &st)) {
+            continue;
+        }
+        if (S_ISDIR(st.st_mode)) {
+            err = deletedir(path);
+        } else {
+            err = netatalk_unlink(path);
         }
     }
     closedir(dp);
 
     /* okay. the directory is empty. delete it. note: we already got rid
        of .AppleDouble.  */
-    if (rmdir(dir) < 0) {
-        switch ( errno ) {
-        case ENOENT :
-            break;
-        case ENOTEMPTY : /* should never happen */
-            return( AFPERR_DIRNEMPT );
-        case EPERM:
-        case EACCES :
-            return( AFPERR_ACCESS );
-        case EROFS:
-            return AFPERR_VLOCK;
-        default :
-            return( AFPERR_PARAM );
-        }
+    if (err == AFP_OK) {
+        err = netatalk_rmdir(dir);
     }
-    return AFP_OK;
+    return err;
 }
 
 /* do a recursive copy. */
@@ -593,6 +698,8 @@ static int copydir(char *src, char *dst, int noadouble)
     struct stat st;
     struct utimbuf      ut;
     size_t slen, dlen;
+    size_t srem, drem;
+    
     int err;
 
     /* doesn't exist or the path is too long. */
@@ -602,47 +709,45 @@ static int copydir(char *src, char *dst, int noadouble)
         return AFPERR_PARAM;
 
     /* try to create the destination directory */
-    if (ad_mkdir(dst, DIRBITS | 0777) < 0) {
+    if (AFP_OK != (err = netatalk_mkdir(dst)) ) {
         closedir(dp);
-        switch ( errno ) {
-        case ENOENT :
-            return( AFPERR_NOOBJ );
-        case EROFS :
-            return( AFPERR_VLOCK );
-        case EPERM:
-        case EACCES :
-            return( AFPERR_ACCESS );
-        case EEXIST :
-            return( AFPERR_EXIST );
-        case ENOSPC :
-        case EDQUOT :
-            return( AFPERR_DFULL );
-        default :
-            return( AFPERR_PARAM );
-        }
+        return err;
     }
 
     /* set things up to copy */
     strcpy(spath, src);
     strcat(spath, "/");
     slen++;
+    srem = sizeof(spath) - slen -1;
+    
     strcpy(dpath, dst);
     strcat(dpath, "/");
     dlen++;
+    drem = sizeof(dpath) - dlen -1;
+
     err = AFP_OK;
     while ((de = readdir(dp))) {
         /* skip this and previous directory */
         if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
             continue;
 
-        strncpy(spath + slen, de->d_name, sizeof(spath) - slen);
+        if (strlen(de->d_name) > srem) {
+            err = AFPERR_PARAM;
+            break;
+        }
+        strcpy(spath + slen, de->d_name);
+
         if (stat(spath, &st) == 0) {
-            strncpy(dpath + dlen, de->d_name, sizeof(dpath) - dlen);
+            if (strlen(de->d_name) > drem) {
+                err = AFPERR_PARAM;
+                break;
+            }
+            strcpy(dpath + dlen, de->d_name);
 
             if (S_ISDIR(st.st_mode)) {
-                if ((err = copydir(spath, dpath, noadouble)) < 0)
+                if (AFP_OK != (err = copydir(spath, dpath, noadouble)))
                     goto copydir_done;
-            } else if ((err = copyfile(spath, dpath, NULL, noadouble)) < 0) {
+            } else if (AFP_OK != (err = copyfile(spath, dpath, NULL, noadouble))) {
                 goto copydir_done;
 
             } else {
@@ -728,6 +833,14 @@ struct dir *dir;
 
 /* free everything down. we don't bother to recolor as this is only
  * called to free the entire tree */
+void dirfreename(struct dir *dir)
+{
+    if (dir->d_u_name != dir->d_m_name) {
+        free(dir->d_u_name);
+    }
+    free(dir->d_m_name);
+}
+
 void dirfree( dir )
 struct dir     *dir;
 {
@@ -742,10 +855,7 @@ struct dir *dir;
     }
 
     if (dir != SENTINEL) {
-        if (dir->d_u_name != dir->d_m_name) {
-            free(dir->d_u_name);
-        }
-        free(dir->d_m_name);
+        dirfreename(dir);
         free( dir );
     }
 }
@@ -781,24 +891,37 @@ struct dir *dirnew(const char *m_name, const char *u_name)
 }
 
 /* -------------------------------------------------- */
-/* XXX: this needs to be changed to handle path types 
+/* cname 
  return
  if it's a filename:
       in extenddir:
          compute unix name
-         stat the file
-      return mac name
+         stat the file or errno 
+      return 
+         filename
+         curdir: filename parent directory
+         
  if it's a dirname:
       not in the cache
           in extenddir
               compute unix name
-              stat the dir
+              stat the dir or errno
+          return
+              if chdir error 
+                 dirname 
+                 curdir: dir parent directory
+              sinon
+                 dirname: ""
+                 curdir: dir   
       in the cache 
-
-  u_name can be
-  XXXX u_name can be an alias on m_name if the m_name is
-  a valid unix name.
-  
+          return
+              if chdir error
+                 dirname
+                 curdir: dir parent directory 
+              else
+                 dirname: ""
+                 curdir: dir   
+                 
 */
 struct path *
 cname( vol, dir, cpath )
@@ -811,17 +934,16 @@ char      **cpath;
     static struct path ret;
 
     char               *data, *p;
-    char        *u;
     int                        extend = 0;
     int                        len;
-    int                        olen = 0;
     u_int32_t   hint;
     u_int16_t   len16;
     int         size = 0;
     char        sep;
                
     data = *cpath;
-    switch (*data) { /* path type */
+    afp_errno = AFPERR_NOOBJ;
+    switch (ret.m_type = *data) { /* path type */
     case 2:
        data++;
        len = (unsigned char) *data++;
@@ -839,63 +961,53 @@ char      **cpath;
            len = ntohs(len16);
            data += 2;
            size = 7;
-           sep = '/';
+           sep = 0; /* '/';*/
            break;
         }
         /* else it's an error */
     default:
+        afp_errno = AFPERR_PARAM;
         return( NULL );
     
     }
     *cpath += len + size;
     *path = '\0';
-    u = NULL;
     ret.m_name = path;
     ret.st_errno = 0;
     ret.st_valid = 0;
     for ( ;; ) {
         if ( len == 0 ) {
-            if ( !extend && movecwd( vol, dir ) < 0 ) {
+            if (movecwd( vol, dir ) < 0 ) {
                /* it's tricky:
-                  movecwd failed so dir is not there anymore.
+                  movecwd failed some of dir path are not there anymore.
                   FIXME Is it true with other errors?
-                  if path == '\0' ==> the cpath parameter is that dir,
-                  and maybe we are trying to recreate it! So we can't 
-                  fail here.
-                  
+                  so we remove dir from the cache 
                */
-                   if ( dir->d_did == DIRDID_ROOT_PARENT) 
-                               return NULL;                    
-               cdir = dir->d_parent;
-               dir_invalidate(vol, dir);
-               if (*path != '\0' || u == NULL) {
-                       /* FIXME: if path != '\0' then extend != 0 ?
-                        * u == NUL ==> cpath is something like:
-                        * toto\0\0\0
-                       */
-                       return NULL;
+               if (dir->d_did == DIRDID_ROOT_PARENT)
+                   return NULL;
+               if (afp_errno == AFPERR_ACCESS) {
+                    if ( movecwd( vol, dir->d_parent ) < 0 ) {
+                        return NULL;                   
+                   }
+                   ret.m_name = dir->d_m_name;
+                   ret.u_name = dir->d_u_name;
+                   return &ret;
                }
-               if (movecwd(vol, cdir) < 0) {
-                       printf("can't change to parent\n");
-                       return NULL; /* give up the whole tree is out of synch*/
-               }
-                               /* restore the previous token */
-                       strncpy(path, u, olen);
-                       path[olen] = '\0';
+
+               dir_invalidate(vol, dir);
+               return NULL;
             }
-            if (!ret.st_valid || *path == '\0') {
+            if (*path == '\0') {
                ret.u_name = ".";
             }               
             return &ret;
         }
 
-        if (!*data || *data == sep ) {
+        if (*data == sep ) {
             data++;
             len--;
         }
-       u = NULL;
-
-        while ( *data && *data == sep && len > 0 ) {
+        while (*data == sep && len > 0 ) {
             if ( dir->d_parent == NULL ) {
                 return NULL;
             }
@@ -906,11 +1018,7 @@ char      **cpath;
 
         /* would this be faster with strlen + strncpy? */
         p = path;
-        if (len > 0) {
-               u = data;
-               olen = len;
-               }        
-        while ( *data && *data != sep && len > 0 ) {
+        while ( *data != sep && len > 0 ) {
             *p++ = *data++;
             len--;
         }
@@ -927,7 +1035,7 @@ char       **cpath;
             if ( !extend ) {
                 cdir = dir->d_child;
                 while (cdir) {
-                    if ( strcasecmp( cdir->d_m_name, path ) == 0 ) {
+                    if ( strcmp( cdir->d_m_name, path ) == 0 ) {
                         break;
                     }
                     cdir = (cdir == dir->d_child->d_prev) ? NULL :
@@ -943,8 +1051,13 @@ char      **cpath;
                        /* dir is not valid anymore 
                           we delete dir from the cache and abort.
                        */
-                       if ( dir->d_did != DIRDID_ROOT_PARENT) 
-                           dir_invalidate(vol, dir);
+                       if ( dir->d_did == DIRDID_ROOT_PARENT) {
+                           afp_errno = AFPERR_NOOBJ;
+                           return NULL;
+                       }
+                       if (afp_errno == AFPERR_ACCESS)
+                           return NULL;
+                       dir_invalidate(vol, dir);
                         return NULL;
                     }
                     cdir = extenddir( vol, dir, &ret );
@@ -955,7 +1068,8 @@ char       **cpath;
             }
 
             if ( cdir == NULL ) {
-                if ( len > 0 ) {
+
+                if ( len > 0 || !ret.u_name) {
                     return NULL;
                 }
 
@@ -983,6 +1097,7 @@ struct dir *dir;
         return( 0 );
     }
     if ( dir->d_did == DIRDID_ROOT_PARENT) {
+        afp_errno = AFPERR_DID1; /* AFPERR_PARAM;*/
         return( -1 );
     }
 
@@ -990,19 +1105,36 @@ struct dir       *dir;
     *p-- = '\0';
     *p = '.';
     for ( d = dir; d->d_parent != NULL && d != curdir; d = d->d_parent ) {
-        *--p = '/';
         u = d->d_u_name;
         n = strlen( u );
+        if (p -n -1 < path) {
+            afp_errno = AFPERR_PARAM;
+            return -1;
+        }
+        *--p = '/';
         p -= n;
         strncpy( p, u, n );
     }
     if ( d != curdir ) {
-        *--p = '/';
         n = strlen( vol->v_path );
+        if (p -n -1 < path) {
+            afp_errno = AFPERR_PARAM;
+            return -1;
+        }
+        *--p = '/';
         p -= n;
         strncpy( p, vol->v_path, n );
     }
     if ( chdir( p ) < 0 ) {
+        switch (errno) {
+        case EACCES:
+        case EPERM:
+            afp_errno = AFPERR_ACCESS;
+            break;
+        default:
+            afp_errno = AFPERR_NOOBJ;
+        
+        }
         return( -1 );
     }
     curdir = dir;
@@ -1234,12 +1366,12 @@ int getdirparams(const struct vol *vol,
     if ( l_nameoff ) {
         ashort = htons( data - buf );
         memcpy( l_nameoff, &ashort, sizeof( ashort ));
-        data = set_name(data, dir->d_m_name, 0);
+        data = set_name(vol, data, dir->d_m_name, 0);
     }
     if ( utf_nameoff ) {
         ashort = htons( data - buf );
         memcpy( utf_nameoff, &ashort, sizeof( ashort ));
-        data = set_name(data, dir->d_m_name, utf8);
+        data = set_name(vol, data, dir->d_m_name, utf8);
     }
     if ( isad ) {
         ad_close( &ad, ADFLAGS_HF );
@@ -1266,7 +1398,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 );
     }
 
@@ -1276,20 +1408,21 @@ int             ibuflen, *rbuflen;
     memcpy( &did, ibuf, sizeof( did ));
     ibuf += sizeof( int );
 
-    if (( dir = dirlookup( vol, did )) == NULL ) {
-        return( AFPERR_NOOBJ );
+    if (NULL == ( dir = dirlookup( vol, did )) ) {
+        return afp_errno;
     }
 
     memcpy( &bitmap, ibuf, sizeof( bitmap ));
     bitmap = ntohs( bitmap );
     ibuf += sizeof( bitmap );
 
-    if (( path = cname( vol, dir, &ibuf )) == NULL ) {
-        return( AFPERR_NOOBJ );
+    if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
+        return get_afp_errno(AFPERR_NOOBJ); 
     }
 
+    /* FIXME access error or not a file */
     if ( *path->m_name != '\0' ) {
-        return( AFPERR_BADTYPE ); /* not a directory */
+        return (path_isadir( path))? afp_errno:AFPERR_BADTYPE ;
     }
 
     /*
@@ -1299,7 +1432,7 @@ int               ibuflen, *rbuflen;
         ibuf++;
     }
 
-    if (( rc = setdirparams(vol, path, bitmap, ibuf )) == AFP_OK ) {
+    if (AFP_OK == ( rc = setdirparams(vol, path, bitmap, ibuf )) ) {
         setvoltime(obj, vol );
     }
     return( rc );
@@ -1312,6 +1445,7 @@ int               ibuflen, *rbuflen;
 */
 
 struct path Cur_Path = {
+    0,
     "",  /* mac name */
     ".", /* unix name */
     0,  /* stat is not set */
@@ -1359,7 +1493,7 @@ int setdirparams(const struct vol *vol,
          * Check to see if a create was necessary. If it was, we'll want
          * to set our name, etc.
          */
-        if ( ad_getoflags( &ad, ADFLAGS_HF ) & O_CREAT ) {
+        if ( ad_get_HF_flags( &ad ) & O_CREAT ) {
             ad_setentrylen( &ad, ADEID_NAME, strlen( curdir->d_m_name ));
             memcpy( ad_entry( &ad, ADEID_NAME ), curdir->d_m_name,
                     ad_getentrylen( &ad, ADEID_NAME ));
@@ -1631,13 +1765,14 @@ int             ibuflen, *rbuflen;
     struct path         *s_path;
     u_int32_t          did;
     u_int16_t          vid;
-
+    int                 err;
+    
     *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 );
     }
 
@@ -1646,48 +1781,24 @@ int             ibuflen, *rbuflen;
 
     memcpy( &did, ibuf, sizeof( did ));
     ibuf += sizeof( did );
-    if (( dir = dirlookup( vol, did )) == NULL ) {
-        return( AFPERR_NOOBJ );
+    if (NULL == ( dir = dirlookup( vol, did )) ) {
+        return afp_errno; /* was AFPERR_NOOBJ */
     }
 
-    if (( s_path = cname( vol, dir, &ibuf )) == NULL ) {
-        switch( errno ) {
-        case EACCES:
-            return( AFPERR_ACCESS );
-        case EEXIST:                           /* FIXME this one is impossible? */
-            return( AFPERR_EXIST );
-        default:
-            return( AFPERR_NOOBJ );
-        }
+    if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
+        return get_afp_errno(AFPERR_PARAM);
     }
-    /* FIXME check done elswhere? cname was able to move curdir to it! */
+    /* cname was able to move curdir to it! */
     if (*s_path->m_name == '\0')
         return AFPERR_EXIST;
 
     upath = s_path->u_name;
-    {
-    int ret;
-        if (0 != (ret = check_name(vol, upath))) {
-            return  ret;
-        }
+    if (0 != (err = check_name(vol, upath))) {
+       return err;
     }
 
-    if ( ad_mkdir( upath, DIRBITS | 0777 ) < 0 ) {
-        switch ( errno ) {
-        case ENOENT :
-            return( AFPERR_NOOBJ );
-        case EROFS :
-            return( AFPERR_VLOCK );
-        case EACCES :
-            return( AFPERR_ACCESS );
-        case EEXIST :
-            return( AFPERR_EXIST );
-        case ENOSPC :
-        case EDQUOT :
-            return( AFPERR_DFULL );
-        default :
-            return( AFPERR_PARAM );
-        }
+    if (AFP_OK != (err = netatalk_mkdir( upath))) {
+        return err;
     }
 
     if (of_stat(s_path) < 0) {
@@ -1738,9 +1849,9 @@ const int noadouble;
     struct dir         *parent;
     char                *buf;
     int                        len, err;
-    
+        
     /* existence check moved to afp_moveandrename */
-    if ( rename( src, dst ) < 0 ) {
+    if ( unix_rename( src, dst ) < 0 ) {
         switch ( errno ) {
         case ENOENT :
             return( AFPERR_NOOBJ );
@@ -1767,27 +1878,17 @@ const int noadouble;
     }
 
     memset(&ad, 0, sizeof(ad));
-    if ( ad_open( dst, ADFLAGS_HF|ADFLAGS_DIR, O_RDWR, 0, &ad) < 0 ) {
-        switch ( errno ) {
-        case ENOENT :
-            if (noadouble) {
-                len = strlen(newname);
-                goto renamedir_done;
-            }
-            return( AFPERR_NOOBJ );
-        case EACCES :
-            return( AFPERR_ACCESS );
-        default :
-            return( AFPERR_PARAM );
-        }
-    }
     len = strlen( newname );
-    ad_setentrylen( &ad, ADEID_NAME, len );
-    memcpy( ad_entry( &ad, ADEID_NAME ), newname, len );
-    ad_flush( &ad, ADFLAGS_HF );
-    ad_close( &ad, ADFLAGS_HF );
-
-renamedir_done:
+    /* rename() succeeded so we need to update our tree even if we can't open
+     * .Parent
+    */
+    if ( !ad_open( dst, ADFLAGS_HF|ADFLAGS_DIR, O_RDWR, 0, &ad)) {
+        ad_setentrylen( &ad, ADEID_NAME, len );
+        memcpy( ad_entry( &ad, ADEID_NAME ), newname, len );
+        ad_flush( &ad, ADFLAGS_HF );
+        ad_close( &ad, ADFLAGS_HF );
+    }
+    
     if (dir->d_m_name == dir->d_u_name)
         dir->d_u_name = NULL;
 
@@ -1839,15 +1940,12 @@ int pathlen;
     DIR *dp;
     struct adouble     ad;
     u_int16_t          ashort;
+    int err;
 
     if ( curdir->d_parent == NULL ) {
         return( AFPERR_ACCESS );
     }
 
-    if ( curdir->d_child != NULL ) {
-        return( AFPERR_DIRNEMPT );
-    }
-
     fdir = curdir;
 
     memset(&ad, 0, sizeof(ad));
@@ -1878,38 +1976,16 @@ int pathlen;
             }
 
             strcpy(path + DOT_APPLEDOUBLE_LEN, de->d_name);
-            if (unlink(path) < 0) {
+            if ((err = netatalk_unlink(path))) {
                 closedir(dp);
-                switch (errno) {
-                case EPERM:
-                case EACCES :
-                    return( AFPERR_ACCESS );
-                case EROFS:
-                    return AFPERR_VLOCK;
-                case ENOENT :
-                    continue;
-                default :
-                    return( AFPERR_PARAM );
-                }
+                return err;
             }
         }
         closedir(dp);
     }
 
-    if ( rmdir( ".AppleDouble" ) < 0 ) {
-        switch ( errno ) {
-        case ENOENT :
-            break;
-        case ENOTEMPTY :
-            return( AFPERR_DIRNEMPT );
-        case EROFS:
-            return AFPERR_VLOCK;
-        case EPERM:
-        case EACCES :
-            return( AFPERR_ACCESS );
-        default :
-            return( AFPERR_PARAM );
-        }
+    if ( (err = netatalk_rmdir( ".AppleDouble" ))  ) {
+       return err;
     }
 
     /* now get rid of dangling symlinks */
@@ -1921,53 +1997,39 @@ int pathlen;
 
             /* bail if it's not a symlink */
             if ((lstat(de->d_name, &st) == 0) && !S_ISLNK(st.st_mode)) {
+               closedir(dp);
                 return AFPERR_DIRNEMPT;
             }
 
-            if (unlink(de->d_name) < 0) {
-                switch (errno) {
-                case EPERM:
-                case EACCES :
-                    return( AFPERR_ACCESS );
-                case EROFS:
-                    return AFPERR_VLOCK;
-                case ENOENT :
-                    continue;
-                default :
-                    return( AFPERR_PARAM );
-                }
+            if ((err = netatalk_unlink(de->d_name))) {
+               closedir(dp);
+               return err;
             }
         }
-        closedir(dp);
     }
 
     if ( movecwd( vol, curdir->d_parent ) < 0 ) {
-        return( AFPERR_NOOBJ );
-    }
-
-    if ( rmdir(fdir->d_u_name) < 0 ) {
-        switch ( errno ) {
-        case ENOENT :
-            return( AFPERR_NOOBJ );
-        case ENOTEMPTY :
-            return( AFPERR_DIRNEMPT );
-        case EPERM:
-        case EACCES :
-            return( AFPERR_ACCESS );
-        case EROFS:
-            return AFPERR_VLOCK;
-        default :
-            return( AFPERR_PARAM );
-        }
+        err = afp_errno;
+        goto delete_done;
     }
 
-    dirchildremove(curdir, fdir);
+    if ( !(err = netatalk_rmdir(fdir->d_u_name))) {
+        dirchildremove(curdir, fdir);
 #ifdef CNID_DB
-    cnid_delete(vol->v_db, fdir->d_did);
+        cnid_delete(vol->v_db, fdir->d_did);
 #endif /* CNID_DB */
-    dir_remove( vol, fdir );
-
-    return( AFP_OK );
+        dir_remove( vol, fdir );
+        err = AFP_OK;
+    }
+delete_done:
+    if (dp) {
+        /* inode is used as key for cnid.
+         * Close the descriptor only after cnid_delete
+         * has been called. 
+        */
+        closedir(dp);
+    }
+    return err;
 }
 
 int afp_mapid(obj, ibuf, ibuflen, rbuf, rbuflen )
@@ -2162,28 +2224,23 @@ int             ibuflen, *rbuflen;
     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 (( parentdir = dirlookup( vol, did )) == NULL ) {
-        return( AFPERR_NOOBJ );
+    if (NULL == ( parentdir = dirlookup( vol, did )) ) {
+        return afp_errno;
     }
 
-    if (( path = cname( vol, parentdir, &ibuf )) == NULL ) {
-        switch( errno ) {
-        case EACCES:
-            return( AFPERR_ACCESS );
-        default:
-            return( AFPERR_NOOBJ );
-        }
+    if (NULL == ( path = cname( vol, parentdir, &ibuf )) ) {
+        return get_afp_errno(AFPERR_PARAM);
     }
 
     if ( *path->m_name != '\0' ) {
-        return( AFPERR_BADTYPE ); /* not a directory */
+        return (path_isadir(path))? afp_errno:AFPERR_BADTYPE ;
     }
 
     if ( !path->st_valid && of_stat(path ) < 0 ) {