]> arthur.barton.de Git - netatalk.git/commitdiff
Merge dircache-rewrite
authorFrank Lahm <franklahm@googlemail.com>
Thu, 29 Apr 2010 09:56:36 +0000 (11:56 +0200)
committerFrank Lahm <franklahm@googlemail.com>
Thu, 29 Apr 2010 09:56:36 +0000 (11:56 +0200)
17 files changed:
1  2 
configure.in
etc/afpd/Makefile.am
etc/afpd/afp_dsi.c
etc/afpd/afp_options.c
etc/afpd/catsearch.c
etc/afpd/directory.c
etc/afpd/directory.h
etc/afpd/enumerate.c
etc/afpd/file.c
etc/afpd/file.h
etc/afpd/filedir.c
etc/afpd/globals.h
etc/afpd/ofork.c
etc/afpd/volume.c
include/atalk/util.h
include/atalk/volume.h
libatalk/cnid/dbd/cnid_dbd.c

diff --cc configure.in
index b90d14cea1284bb08224360b5937d4224c4417e4,a68111bfe3f336d45caeabf164a2573e238d3dc3..016ba88a9de4b1b75bee67a6f59869298dd8ac9c
@@@ -1,4 -1,4 +1,4 @@@
- dnl $Id: configure.in,v 1.244 2010-04-13 08:05:06 franklahm Exp $
 -dnl $Id: configure.in,v 1.237.2.1 2010-02-01 10:56:08 franklahm Exp $
++dnl $Id: configure.in,v 1.241 2010/04/03 07:11:33 franklahm Exp $
  dnl configure.in for netatalk
  
  AC_INIT(etc/afpd/main.c)
Simple merge
index a3d40ded6ec3d8969d21d9706df1b9b29d0a6c09,efe1d241825a4123aeb3dd3886f40f2b93a07b65..1b10187a42c0e3e9d63449911491f078733f1550
@@@ -1,5 -1,5 +1,5 @@@
  /*
-  * $Id: afp_dsi.c,v 1.53 2010-03-30 12:55:26 franklahm Exp $
 - * $Id: afp_dsi.c,v 1.49.2.2 2010-02-04 14:34:31 franklahm Exp $
++ * $Id: afp_dsi.c,v 1.53 2010/03/30 12:55:26 franklahm Exp $
   *
   * Copyright (c) 1999 Adrian Sun (asun@zoology.washington.edu)
   * Copyright (c) 1990,1993 Regents of The University of Michigan.
@@@ -381,25 -349,9 +385,26 @@@ void afp_over_dsi(AFPObj *obj
          if (reload_request) {
              reload_request = 0;
              load_volumes(child.obj);
+             dircache_dump();
          }
  
 +        if (debug_request) {
 +            char logstr[50];
 +            debug_request = 0;
 +
 +            /* The first SIGINT enables debugging, the second one kills us */
 +            action.sa_handler = afp_dsi_die;
 +            sigfillset( &action.sa_mask );
 +            action.sa_flags = SA_RESTART;
 +            if ( sigaction( SIGINT, &action, NULL ) < 0 ) {
 +                LOG(log_error, logtype_afpd, "afp_over_dsi: sigaction: %s", strerror(errno) );
 +                afp_dsi_die(EXITERR_SYS);
 +            }
 +
 +            sprintf(logstr, "default log_maxdebug /tmp/afpd.%u.XXXXXX", getpid());
 +            setuplog(logstr);
 +        }
 +
          if (cmd == DSIFUNC_TICKLE) {
              /* timer is not every 30 seconds anymore, so we don't get killed on the client side. */
              if ((child.flags & CHILD_DIE))
index aa728512e0ba722be8133d4d5f23f1ea25b699fc,f23c370b3319842ea7f00b03464d29500583abb3..0761724f292760d73b7c14e1a785af8e869e32c9
@@@ -1,5 -1,5 +1,5 @@@
  /*
-  * $Id: afp_options.c,v 1.54 2010-04-02 16:17:22 hat001 Exp $
 - * $Id: afp_options.c,v 1.51.4.2 2010-02-05 10:27:58 franklahm Exp $
++ * $Id: afp_options.c,v 1.54 2010/04/02 16:17:22 hat001 Exp $
   *
   * Copyright (c) 1997 Adrian Sun (asun@zoology.washington.edu)
   * Copyright (c) 1990,1993 Regents of The University of Michigan.
@@@ -446,14 -450,10 +448,17 @@@ int afp_options_parseline(char *buf, st
  
      if ((c = getoption(buf, "-ntseparator")) && (opt = strdup(c)))
         options->ntseparator = opt;
+     if ((c = getoption(buf, "-dircachesize")))
+         options->dircachesize = atoi(c);
       
 +    if ((c = getoption(buf, "-signature")) && (opt = strdup(c))) {
 +        set_signature(opt, options);
 +    }
 +    else {
 +        set_signature("auto", options);
 +    }
 +
      return 1;
  }
  
index a1e96dfc50ab74649f67c09569f6ea8c99818e37,4a1d229f59e13c1036d9b5d974edb8a58ab249af..b266348ca0ca6a15073c1dfb003b70d90a426901
@@@ -49,7 -49,7 +49,9 @@@
  #ifdef CNID_DB
  #include <atalk/cnid.h>
  #endif /* CNID_DB */
++
 +#include <atalk/util.h>
+ #include <atalk/bstradd.h>
  
  #include "desktop.h"
  #include "directory.h"
@@@ -503,9 -505,7 +509,8 @@@ static int catsearch(struct vol *vol, s
        char *rrbuf = rbuf;
      time_t start_time;
      int num_rounds = NUM_ROUNDS;
-     int cached;
      int cwd = -1;
 +    int error;
          
        if (*pos != 0 && *pos != cur_pos) {
                result = AFPERR_CATCHNG;
          goto catsearch_end;
      }
        
 +      /* So we are beginning... */
 +    start_time = time(NULL);
 +
        while ((cidx = reducestack()) != -1) {
-               cached = 1;
 -              if (dirpos == NULL) {
 +              error = lchdir(dstack[cidx].path);
 +
-               if (!error && dirpos == NULL) {
++              if (!error && dirpos == NULL)
 +                      dirpos = opendir(".");
-                       cached = (dstack[cidx].dir->d_child != NULL);
-               }
++
++              if (dirpos == NULL)
+                       dirpos = opendir(dstack[cidx].path);
 -              }
 -              if (dirpos == NULL) {
++
 +              if (error || dirpos == NULL) {
                        switch (errno) {
                        case EACCES:
                                dstack[cidx].checked = 1;
index 6480ca7f65c83158d770194d2a5f7a3bdea973bb,e86bd10db80f88389e97f71abbfed7563509b21d..467bc62d89e936c2cf69988db42f66b27ea3fe36
@@@ -1,5 -1,5 +1,5 @@@
  /*
-  * $Id: directory.c,v 1.140 2010-03-12 15:16:49 franklahm Exp $
 - * $Id: directory.c,v 1.131.2.14 2010-02-11 14:13:06 franklahm Exp $
++ * $Id: directory.c,v 1.140 2010/03/12 15:16:49 franklahm Exp $
   *
   * Copyright (c) 1990,1993 Regents of The University of Michigan.
   * All Rights Reserved.  See COPYRIGHT.
  extern void addir_inherit_acl(const struct vol *vol);
  #endif
  
- /* 
-  * Directory caches
-  * ================
-  *
-  * There are currently two cache structures where afpd caches directory information
-  * a) a DID/dirname cache in a hashtable 
-  * b) a (red-black) tree with CNIDs as key
-  *
-  * a) is for searching by DID/dirname
-  * b) is for searching by CNID
-  *
-  * Through additional parent, child, previous and next pointers, b) is also used to
-  * represent the on-disk layout of the filesystem. parent and child point to parent
-  * and child directory respectively, linking 2 or more subdirectories in one
-  * directory with previous and next pointers.
-  *
-  * Usage examples, highlighting the main functions:
-  * 
-  * a) is eg used in enumerate():
-  * if IS_DIR
-  *     dir = dirsearch_byname() // search in cache
-  *     if (dir == NULL)         // not found
-  *         dir = adddir()       // add to cache
-  *      getdirparams()
-  *
-  * b) is eg used in afp_getfildirparams()
-  * dirlookup()             // wrapper for cache and db search
-  *   => dir = dirsearch()  // search in cache
-  *      if (dir)           // found
-  *          return
-  *      else               // not found,
-  *          cnid_resolve() // resolve with CNID database
-  *      cname()            // add to cache
-  */
- struct dir  *curdir;
- int         afp_errno;
- #define SENTINEL (&sentinel)
- static struct dir sentinel = { SENTINEL, SENTINEL, NULL, /* left, right, back */
-                                DIRTREE_COLOR_BLACK,      /* color */
-                                NULL, NULL,               /* parent, child */
-                                NULL, NULL,               /* previous, next */
-                                NULL, 0, 0,               /* oforks, did, flags */
-                                0, 0,                     /* ctime, offcnt */
-                                NULL, NULL, NULL};        /* mname, uname, ucs2-name */
- static struct dir rootpar  = { SENTINEL, SENTINEL, NULL,
-                                0,
-                                NULL, NULL,
-                                NULL, NULL,
-                                NULL, 0, 0,
-                                0, 0,
-                                NULL, NULL, NULL};
- /* (from IM: Toolbox Essentials)
-  * dirFinderInfo (DInfo) fields:
-  * field        bytes
-  * frRect       8    folder's window rectangle
-  * frFlags      2    flags
-  * frLocation   4    folder's location in window
-  * frView       2    folder's view (default == closedView (256))
-  *
-  * extended dirFinderInfo (DXInfo) fields:
-  * frScroll     4    scroll position
-  * frOpenChain: 4    directory ID chain of open folders
-  * frScript:    1    script flag and code
-  * frXFlags:    1    reserved
-  * frComment:   2    comment ID
-  * frPutAway:   4    home directory ID
-  */
- static struct dir *
- vol_tree_root(const struct vol *vol, u_int32_t did)
- {
-     struct dir *dir;
-     if (vol->v_curdir && vol->v_curdir->d_did == did) {
-         dir = vol->v_curdir;
-     }
-     else {
-         dir = vol->v_root;
-     }
-     return dir;
- }
  /*
-  * redid did assignment for directories. now we use red-black trees.
-  * how exciting.
+  * FIXMEs, loose ends after the dircache rewrite:
+  * o merge dircache_search_by_name and dir_add ??
+  * o case-insensitivity is gone from cname
   */
- struct dir *
- dirsearch(const struct vol *vol, u_int32_t did)
- {
-     struct dir  *dir;
-     /* check for 0 did */
-     if (!did) {
-         afp_errno = AFPERR_PARAM;
-         return NULL;
-     }
-     if ( did == DIRDID_ROOT_PARENT ) {
-         if (!rootpar.d_did)
-             rootpar.d_did = DIRDID_ROOT_PARENT;
-         rootpar.d_child = vol->v_dir;
-         return( &rootpar );
-     }
-     dir = vol_tree_root(vol, did);
-     afp_errno = AFPERR_NOOBJ;
-     while ( dir != SENTINEL ) {
-         if (dir->d_did == did)
-             return dir->d_m_name ? dir : NULL;
-         dir = (dir->d_did > did) ? dir->d_left : dir->d_right;
-     }
-     return NULL;
- }
  
- /* ------------------- */
- int get_afp_errno(const int param)
- {
-     if (afp_errno != AFPERR_DID1)
-         return afp_errno;
-     return param;
- }
- /* ------------------- */
- struct dir *
- dirsearch_byname( const struct vol *vol, struct dir *cdir, char *name)
- {
-     struct dir *dir = NULL;
-     if ((cdir->d_did != DIRDID_ROOT_PARENT) && (cdir->d_child)) {
-         struct dir key;
-         hnode_t *hn;
-         key.d_parent = cdir;
-         key.d_u_name = name;
-         hn = hash_lookup(vol->v_hash, &key);
-         if (hn) {
-             dir = hnode_get(hn);
-         }
-     }
-     return dir;
- }
- /* -----------------------------------------
-  * if did is not in the cache resolve it with cnid
-  *
-  * FIXME
-  * OSX call it with bogus id, ie file ID not folder ID,
-  * and we are really bad in this case.
-  */
- struct dir *
- dirlookup( struct vol *vol, u_int32_t did)
- {
-     struct dir   *ret;
-     char     *upath;
-     cnid_t       id, cnid;
-     static char  path[MAXPATHLEN + 1];
-     size_t len,  pathlen;
-     char         *ptr;
-     static char  buffer[12 + MAXPATHLEN + 1];
-     int          buflen = 12 + MAXPATHLEN + 1;
-     char         *mpath;
-     int          utf8;
-     size_t       maxpath;
-     ret = dirsearch(vol, did);
-     if (ret != NULL || afp_errno == AFPERR_PARAM)
-         return ret;
-     utf8 = utf8_encoding();
-     maxpath = (utf8)?MAXPATHLEN -7:255;
-     id = did;
-     if (NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, buflen)) ) {
-         afp_errno = AFPERR_NOOBJ;
-         return NULL;
-     }
-     ptr = path + MAXPATHLEN;
-     if (NULL == ( mpath = utompath(vol, upath, did, utf8) ) ) {
-         afp_errno = AFPERR_NOOBJ;
-         return NULL;
-     }
-     len = strlen(mpath);
-     pathlen = len;          /* no 0 in the last part */
-     len++;
-     strcpy(ptr - len, mpath);
-     ptr -= len;
-     while (1) {
-         ret = dirsearch(vol,id);
-         if (ret != NULL) {
-             break;
-         }
-         cnid = id;
-         if ( NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, buflen))
-              ||
-              NULL == (mpath = utompath(vol, upath, cnid, utf8))
-             ) {
-             afp_errno = AFPERR_NOOBJ;
-             return NULL;
-         }
-         len = strlen(mpath) + 1;
-         pathlen += len;
-         if (pathlen > maxpath) {
-             afp_errno = AFPERR_PARAM;
-             return NULL;
-         }
-         strcpy(ptr - len, mpath);
-         ptr -= len;
-     }
-     /* fill the cache, another place where we know about the path type */
-     if (utf8) {
-         u_int16_t temp16;
-         u_int32_t temp;
-         ptr -= 2;
-         temp16 = htons(pathlen);
-         memcpy(ptr, &temp16, sizeof(temp16));
-         temp = htonl(kTextEncodingUTF8);
-         ptr -= 4;
-         memcpy(ptr, &temp, sizeof(temp));
-         ptr--;
-         *ptr = 3;
-     }
-     else {
-         ptr--;
-         *ptr = (unsigned char)pathlen;
-         ptr--;
-         *ptr = 2;
-     }
-     /* cname is not efficient */
-     if (cname( vol, ret, &ptr ) == NULL )
-         return NULL;
-     return dirsearch(vol, did);
- }
- /* child addition/removal */
- static void dirchildadd(const struct vol *vol, struct dir *a, struct dir *b)
- {
-     if (!a->d_child)
-         a->d_child = b;
-     else {
-         b->d_next = a->d_child;
-         b->d_prev = b->d_next->d_prev;
-         b->d_next->d_prev = b;
-         b->d_prev->d_next = b;
-     }
-     if (!hash_alloc_insert(vol->v_hash, b, b)) {
-         LOG(log_error, logtype_afpd, "dirchildadd: can't hash %s", b->d_u_name);
-     }
- }
- static void dirchildremove(struct dir *a,struct dir *b)
- {
-     if (a->d_child == b)
-         a->d_child = (b == b->d_next) ? NULL : b->d_next;
-     b->d_next->d_prev = b->d_prev;
-     b->d_prev->d_next = b->d_next;
-     b->d_next = b->d_prev = b;
- }
- /* --------------------------- */
- /* rotate the tree to the left */
- static void dir_leftrotate(struct vol *vol, struct dir *dir)
- {
-     struct dir *right = dir->d_right;
-     /* whee. move the right's left tree into dir's right tree */
-     dir->d_right = right->d_left;
-     if (right->d_left != SENTINEL)
-         right->d_left->d_back = dir;
-     if (right != SENTINEL) {
-         right->d_back = dir->d_back;
-         right->d_left = dir;
-     }
-     if (!dir->d_back) /* no parent. move the right tree to the top. */
-         vol->v_root = right;
-     else if (dir == dir->d_back->d_left) /* we were on the left */
-         dir->d_back->d_left = right;
-     else
-         dir->d_back->d_right = right; /* we were on the right */
-     /* re-insert dir on the left tree */
-     if (dir != SENTINEL)
-         dir->d_back = right;
- }
- /* rotate the tree to the right */
- static void dir_rightrotate(struct vol *vol, struct dir *dir)
- {
-     struct dir *left = dir->d_left;
-     /* whee. move the left's right tree into dir's left tree */
-     dir->d_left = left->d_right;
-     if (left->d_right != SENTINEL)
-         left->d_right->d_back = dir;
-     if (left != SENTINEL) {
-         left->d_back = dir->d_back;
-         left->d_right = dir;
-     }
-     if (!dir->d_back) /* no parent. move the left tree to the top. */
-         vol->v_root = left;
-     else if (dir == dir->d_back->d_right) /* we were on the right */
-         dir->d_back->d_right = left;
-     else
-         dir->d_back->d_left = left; /* we were on the left */
-     /* re-insert dir on the right tree */
-     if (dir != SENTINEL)
-         dir->d_back = left;
- }
- #if 0
- /* recolor after a removal */
- static struct dir *dir_rmrecolor(struct vol *vol, struct dir *dir)
- {
-     struct dir *leaf;
-     while ((dir != vol->v_root) && (dir->d_color == DIRTREE_COLOR_BLACK)) {
-         /* are we on the left tree? */
-         if (dir == dir->d_back->d_left) {
-             leaf = dir->d_back->d_right; /* get right side */
-             if (leaf->d_color == DIRTREE_COLOR_RED) {
-                 /* we're red. we need to change to black. */
-                 leaf->d_color = DIRTREE_COLOR_BLACK;
-                 dir->d_back->d_color = DIRTREE_COLOR_RED;
-                 dir_leftrotate(vol, dir->d_back);
-                 leaf = dir->d_back->d_right;
-             }
-             /* right leaf has black end nodes */
-             if ((leaf->d_left->d_color == DIRTREE_COLOR_BLACK) &&
-                 (leaf->d_right->d_color = DIRTREE_COLOR_BLACK)) {
-                 leaf->d_color = DIRTREE_COLOR_RED; /* recolor leaf as red */
-                 dir = dir->d_back; /* ascend */
-             } else {
-                 if (leaf->d_right->d_color == DIRTREE_COLOR_BLACK) {
-                     leaf->d_left->d_color = DIRTREE_COLOR_BLACK;
-                     leaf->d_color = DIRTREE_COLOR_RED;
-                     dir_rightrotate(vol, leaf);
-                     leaf = dir->d_back->d_right;
-                 }
-                 leaf->d_color = dir->d_back->d_color;
-                 dir->d_back->d_color = DIRTREE_COLOR_BLACK;
-                 leaf->d_right->d_color = DIRTREE_COLOR_BLACK;
-                 dir_leftrotate(vol, dir->d_back);
-                 dir = vol->v_root;
-             }
-         } else { /* right tree */
-             leaf = dir->d_back->d_left; /* left tree */
-             if (leaf->d_color == DIRTREE_COLOR_RED) {
-                 leaf->d_color = DIRTREE_COLOR_BLACK;
-                 dir->d_back->d_color = DIRTREE_COLOR_RED;
-                 dir_rightrotate(vol, dir->d_back);
-                 leaf = dir->d_back->d_left;
-             }
-             /* left leaf has black end nodes */
-             if ((leaf->d_right->d_color == DIRTREE_COLOR_BLACK) &&
-                 (leaf->d_left->d_color = DIRTREE_COLOR_BLACK)) {
-                 leaf->d_color = DIRTREE_COLOR_RED; /* recolor leaf as red */
-                 dir = dir->d_back; /* ascend */
-             } else {
-                 if (leaf->d_left->d_color == DIRTREE_COLOR_BLACK) {
-                     leaf->d_right->d_color = DIRTREE_COLOR_BLACK;
-                     leaf->d_color = DIRTREE_COLOR_RED;
-                     dir_leftrotate(vol, leaf);
-                     leaf = dir->d_back->d_left;
-                 }
-                 leaf->d_color = dir->d_back->d_color;
-                 dir->d_back->d_color = DIRTREE_COLOR_BLACK;
-                 leaf->d_left->d_color = DIRTREE_COLOR_BLACK;
-                 dir_rightrotate(vol, dir->d_back);
-                 dir = vol->v_root;
-             }
-         }
-     }
-     dir->d_color = DIRTREE_COLOR_BLACK;
-     return dir;
- }
- #endif /* 0 */
- /* --------------------- */
- static void dir_hash_del(const struct vol *vol, struct dir *dir)
- {
-     hnode_t *hn;
-     hn = hash_lookup(vol->v_hash, dir);
-     if (!hn) {
-         LOG(log_error, logtype_afpd, "dir_hash_del: %s not hashed", dir->d_u_name);
-     }
-     else {
-         hash_delete(vol->v_hash, hn);
-     }
- }
- /* remove the node from the tree. this is just like insertion, but
-  * different. actually, it has to worry about a bunch of things that
-  * insertion doesn't care about. */
- static void dir_remove( struct vol *vol, struct dir *dir)
- {
- #ifdef REMOVE_NODES
-     struct ofork *of, *last;
-     struct dir *node, *leaf;
- #endif /* REMOVE_NODES */
-     if (!dir || (dir == SENTINEL))
-         return;
-     /* i'm not sure if it really helps to delete stuff. */
-     dir_hash_del(vol, dir);
-     vol->v_curdir = NULL;
- #ifndef REMOVE_NODES
-     dirfreename(dir);
-     dir->d_m_name = NULL;
-     dir->d_u_name = NULL;
-     dir->d_m_name_ucs2 = NULL;
- #else /* ! REMOVE_NODES */
-     /* go searching for a node with at most one child */
-     if ((dir->d_left == SENTINEL) || (dir->d_right == SENTINEL)) {
-         node = dir;
-     } else {
-         node = dir->d_right;
-         while (node->d_left != SENTINEL)
-             node = node->d_left;
-     }
  
-     /* get that child */
-     leaf = (node->d_left != SENTINEL) ? node->d_left : node->d_right;
+ /*******************************************************************************************
+  * Globals
+  ******************************************************************************************/
  
-     /* detach node */
-     leaf->d_back = node->d_back;
-     if (!node->d_back) {
-         vol->v_root = leaf;
-     } else if (node == node->d_back->d_left) { /* left tree */
-         node->d_back->d_left = leaf;
-     } else {
-         node->d_back->d_right = leaf;
-     }
-     /* we want to free node, but we also want to free the data in dir.
-      * currently, that's d_name and the directory traversal bits.
-      * we just copy the necessary bits and then fix up all the
-      * various pointers to the directory. needless to say, there are
-      * a bunch of places that store the directory struct. */
-     if (node != dir) {
-         struct dir save, *tmp;
-         memcpy(&save, dir, sizeof(save));
-         memcpy(dir, node, sizeof(struct dir));
-         /* restore the red-black bits */
-         dir->d_left = save.d_left;
-         dir->d_right = save.d_right;
-         dir->d_back = save.d_back;
-         dir->d_color = save.d_color;
-         if (node == vol->v_dir) {/* we may need to fix up this pointer */
-             vol->v_dir = dir;
-             rootpar.d_child = vol->v_dir;
-         } else {
-             /* if we aren't the root directory, we have parents and
-              * siblings to worry about */
-             if (dir->d_parent->d_child == node)
-                 dir->d_parent->d_child = dir;
-             dir->d_next->d_prev = dir;
-             dir->d_prev->d_next = dir;
-         }
-         /* fix up children. */
-         tmp = dir->d_child;
-         while (tmp) {
-             tmp->d_parent = dir;
-             tmp = (tmp == dir->d_child->d_prev) ? NULL : tmp->d_next;
-         }
-         if (node == curdir) /* another pointer to fixup */
-             curdir = dir;
-         /* we also need to fix up oforks. bleah */
-         if ((of = dir->d_ofork)) {
-             last = of->of_d_prev;
-             while (of) {
-                 of->of_dir = dir;
-                 of = (last == of) ? NULL : of->of_d_next;
-             }
-         }
-         /* set the node's d_name */
-         node->d_m_name = save.d_m_name;
-         node->d_u_name = save.d_u_name;
-         node->d_m_name_ucs2 = save.d_m_name_ucs2;
-     }
-     if (node->d_color == DIRTREE_COLOR_BLACK)
-         dir_rmrecolor(vol, leaf);
-     if (node->d_m_name_ucs2)
-         free(node->d_u_name_ucs2);
-     if (node->d_u_name != node->d_m_name) {
-         free(node->d_u_name);
-     }
-     free(node->d_m_name);
-     free(node);
- #endif /* ! REMOVE_NODES */
- }
- /* ---------------------------------------
-  * remove the node and its childs from the tree
-  *
-  * FIXME what about opened forks with refs to it?
-  * it's an afp specs violation because you can't delete
-  * an opened forks. Now afpd doesn't care about forks opened by other
-  * 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( struct vol *vol, struct dir *dir)
- {
-     if (curdir == dir) {
-         /* v_root can't be deleted */
-         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);
-     dir_remove( vol, dir );
- }
- /* ------------------------------------ */
- static struct dir *dir_insert(const struct vol *vol, struct dir *dir)
- {
-     struct dir  *pdir;
-     pdir = vol_tree_root(vol, dir->d_did);
-     while (pdir->d_did != dir->d_did ) {
-         if ( pdir->d_did > dir->d_did ) {
-             if ( pdir->d_left == SENTINEL ) {
-                 pdir->d_left = dir;
-                 dir->d_back = pdir;
-                 return NULL;
-             }
-             pdir = pdir->d_left;
-         } else {
-             if ( pdir->d_right == SENTINEL ) {
-                 pdir->d_right = dir;
-                 dir->d_back = pdir;
-                 return NULL;
-             }
-             pdir = pdir->d_right;
-         }
-     }
-     return pdir;
- }
- #define ENUMVETO "./../Network Trash Folder/TheVolumeSettingsFolder/TheFindByContentFolder/:2eDS_Store/Contents/Desktop Folder/Trash/Benutzer/"
- int
- caseenumerate(const struct vol *vol, struct path *path, struct dir *dir)
- {
-     DIR               *dp;
-     struct dirent     *de;
-     int               ret;
-     static u_int32_t  did = 0;
-     static char       cname[MAXPATHLEN];
-     static char       lname[MAXPATHLEN];
-     ucs2_t        u2_path[MAXPATHLEN];
-     ucs2_t        u2_dename[MAXPATHLEN];
-     char          *tmp, *savepath;
-     if (!(vol->v_flags & AFPVOL_CASEINSEN))
-         return -1;
-     if (veto_file(ENUMVETO, path->u_name))
-         return -1;
-     savepath = path->u_name;
-     /* very simple cache */
-     if ( dir->d_did == did && strcmp(lname, path->u_name) == 0) {
-         path->u_name = cname;
-         path->d_dir = NULL;
-         if (of_stat( path ) == 0 ) {
-             return 0;
-         }
-         /* something changed, we cannot stat ... */
-         did = 0;
-     }
-     if (NULL == ( dp = opendir( "." )) ) {
-         LOG(log_debug, logtype_afpd, "caseenumerate: opendir failed: %s", dir->d_u_name);
-         return -1;
-     }
-     /* LOG(log_debug, logtype_afpd, "caseenumerate: for %s", path->u_name); */
-     if ((size_t) -1 == convert_string(vol->v_volcharset, CH_UCS2, path->u_name, -1, u2_path, sizeof(u2_path)) )
-         LOG(log_debug, logtype_afpd, "caseenumerate: conversion failed for %s", path->u_name);
-     /*LOG(log_debug, logtype_afpd, "caseenumerate: dir: %s, path: %s", dir->d_u_name, path->u_name); */
-     ret = -1;
-     for ( de = readdir( dp ); de != NULL; de = readdir( dp )) {
-         if (NULL == check_dirent(vol, de->d_name))
-             continue;
-         if ((size_t) -1 == convert_string(vol->v_volcharset, CH_UCS2, de->d_name, -1, u2_dename, sizeof(u2_dename)) )
-             continue;
-         if (strcasecmp_w( u2_path, u2_dename) == 0) {
-             tmp = path->u_name;
-             strlcpy(cname, de->d_name, sizeof(cname));
-             path->u_name = cname;
-             path->d_dir = NULL;
-             if (of_stat( path ) == 0 ) {
-                 LOG(log_debug, logtype_afpd, "caseenumerate: using dir: %s, path: %s", de->d_name, path->u_name);
-                 strlcpy(lname, tmp, sizeof(lname));
-                 did = dir->d_did;
-                 ret = 0;
-                 break;
-             }
-             else
-                 path->u_name = tmp;
-         }
-     }
-     closedir(dp);
-     if (ret) {
-         /* invalidate cache */
-         cname[0] = 0;
-         did = 0;
-         path->u_name = savepath;
-     }
-     /* LOG(log_debug, logtype_afpd, "caseenumerate: path on ret: %s", path->u_name); */
-     return ret;
- }
- /*
-  * attempt to extend the current dir. tree to include path
-  * as a side-effect, movecwd to that point and return the new dir
-  */
- static struct dir *
- extenddir(struct vol *vol, struct dir *dir, struct path *path)
- {
-     path->d_dir = NULL;
-     if ( path->u_name == NULL) {
-         afp_errno = AFPERR_PARAM;
-         return NULL;
-     }
-     if (check_name(vol, path->u_name)) {
-         /* the name is illegal */
-         LOG(log_info, logtype_afpd, "extenddir: illegal path: '%s'", path->u_name);
-         path->u_name = NULL;
-         afp_errno = AFPERR_PARAM;
-         return NULL;
-     }
-     if (of_stat( path ) != 0 ) {
-         if (!(vol->v_flags & AFPVOL_CASEINSEN))
-             return NULL;
-         else if(caseenumerate(vol, path, dir) != 0)
-             return(NULL);
-     }
-     if (!S_ISDIR(path->st.st_mode)) {
-         return( NULL );
-     }
+ int         afp_errno;
+ struct dir rootParent  = {
+     NULL, NULL, NULL, NULL,          /* path, d_m_name, d_u_name, d_m_name_ucs2 */
+     NULL, NULL, 0, 0,                /* qidx_node, d_ofork, ctime, d_flags */
+     0, 0, 0, 0                       /* pdid, did, offcnt, d_vid */
+ };
+ struct dir  *curdir = &rootParent;
+ struct path Cur_Path = {
+     0,
+     "",  /* mac name */
+     ".", /* unix name */
+     0,   /* id */
 -    NULL,/* struct dir */
++    NULL,/* struct dir * */
+     0,   /* stat is not set */
++    0,   /* errno */
++    {0} /* struct stat */
+ };
  
-     /* mac name is always with the right encoding (from cname()) */
-     if (( dir = adddir( vol, dir, path)) == NULL ) {
-         return( NULL );
-     }
  
-     path->d_dir = dir;
-     if ( movecwd( vol, dir ) < 0 ) {
-         return( NULL );
-     }
+ /*******************************************************************************************
+  * Locals
+  ******************************************************************************************/
  
-     return( dir );
- }
  
  /* -------------------------
     appledouble mkdir afp error code.
@@@ -1536,65 -1191,34 +1193,47 @@@ struct path *cname(struct vol *vol, str
  }
  
  /*
-  * Move curdir to dir, with a possible chdir()
+  * @brief chdir() to dir
+  *
+  * @param vol   (r) pointer to struct vol
+  * @param dir   (r) pointer to struct dir
+  *
+  * @returns 0 on success, -1 on error with afp_errno set appropiately
   */
- int movecwd(struct vol *vol, struct dir *dir)
+ int movecwd(const struct vol *vol, struct dir *dir)
  {
-     char path[MAXPATHLEN + 1];
-     struct dir  *d;
-     char    *p, *u;
-     int     n;
-     int     ret;
 -    AFP_ASSERT(vol);
++    int ret;
 -    if (dir == NULL)
 -        return -1;
++    AFP_ASSERT(vol);
++    AFP_ASSERT(dir);
  
-     if ( dir == curdir ) {
+     LOG(log_maxdebug, logtype_afpd, "movecwd(curdir:'%s', cwd:'%s')",
+         cfrombstring(curdir->d_fullpath), getcwdpath());
+     if ( dir == curdir)
          return( 0 );
-     }
-     if ( dir->d_did == DIRDID_ROOT_PARENT) {
-         afp_errno = AFPERR_DID1; /* AFPERR_PARAM;*/
-         return( -1 );
+     if (dir->d_did == DIRDID_ROOT_PARENT) {
+         curdir = &rootParent;
+         return 0;
      }
  
-     p = path + sizeof(path) - 1;
-     *p = '\0';
-     for ( d = dir; d->d_parent != NULL && d != curdir; d = d->d_parent ) {
-         u = d->d_u_name;
-         if (!u) {
-             /* parent directory is deleted */
-             afp_errno = AFPERR_NOOBJ;
-             return -1;
-         }
-         n = strlen( u );
-         if (p -n -1 < path) {
-             afp_errno = AFPERR_PARAM;
-             return -1;
-         }
-         *--p = '/';
-         p -= n;
-         memcpy( p, u, n );
-     }
-     if ( d != curdir ) {
-         n = strlen( vol->v_path );
-         if (p -n -1 < path) {
-             afp_errno = AFPERR_PARAM;
-             return -1;
-         }
-         *--p = '/';
-         p -= n;
-         memcpy( p, vol->v_path, n );
-     }
-     if ( (ret = lchdir(p )) != 0 ) {
-         LOG(log_debug, logtype_afpd, "movecwd('%s'): ret:%d, %u/%s", p, ret, errno, strerror(errno));
+     LOG(log_debug, logtype_afpd, "movecwd(did:%u, '%s')", ntohl(dir->d_did), cfrombstring(dir->d_fullpath));
  
 -    if ( chdir(cfrombstring(dir->d_fullpath)) < 0 ) {
 -        LOG(log_debug, logtype_afpd, "movecwd('%s'): %s", cfrombstring(dir->d_fullpath), strerror(errno));
++    if ((ret = lchdir(cfrombstring(dir->d_fullpath))) != 0 ) {
++        LOG(log_debug, logtype_afpd, "movecwd('%s'): ret: %u, %s",
++            cfrombstring(dir->d_fullpath), ret, strerror(errno));
 +        if (ret == 1) {
 +            /* p is a symlink or getcwd failed */
 +            afp_errno = AFPERR_BADTYPE;
-             vol->v_curdir = curdir = vol->v_dir;
++
 +            if (chdir(vol->v_path ) < 0) {
-                 LOG(log_debug, logtype_afpd, "can't chdir back'%s': %s", vol->v_path, strerror(errno));
++                LOG(log_error, logtype_afpd, "can't chdir back'%s': %s", vol->v_path, strerror(errno));
 +                /* XXX what do we do here? */
 +            }
++            curdir = vol->v_root;
 +            return -1;
 +        }
++
          switch (errno) {
          case EACCES:
          case EPERM:
@@@ -2545,12 -2124,10 +2143,10 @@@ int renamedir(const struct vol *vol
                char *newname)
  {
      struct adouble  ad;
-     struct dir      *parent;
-     char                *buf;
-     int         len, err;
+     int             err;
  
      /* existence check moved to afp_moveandrename */
 -    if ( unix_rename( src, dst ) < 0 ) {
 +    if ( unix_rename(dirfd, src, -1, dst ) < 0 ) {
          switch ( errno ) {
          case ENOENT :
              return( AFPERR_NOOBJ );
          }
      }
  
 -    vol->vfs->vfs_renamedir(vol, src, dst);
 +    vol->vfs->vfs_renamedir(vol, dirfd, src, dst);
  
-     len = strlen( newname );
-     /* rename() succeeded so we need to update our tree even if we can't open
-      * metadata
-      */
      ad_init(&ad, vol->v_adouble, vol->v_ad_options);
  
      if (!ad_open_metadata( dst, ADFLAGS_DIR, 0, &ad)) {
@@@ -2695,9 -2228,8 +2247,8 @@@ int deletecurdir(struct vol *vol
          goto delete_done;
      }
  
-     err = netatalk_rmdir_all_errors(-1, fdir->d_u_name);
 -    err = netatalk_rmdir_all_errors(cfrombstring(fdir->d_u_name));
++    err = netatalk_rmdir_all_errors(-1, cfrombstring(fdir->d_u_name));
      if ( err ==  AFP_OK || err == AFPERR_NOOBJ) {
-         dirchildremove(curdir, fdir);
          cnid_delete(vol->v_cdb, fdir->d_did);
          dir_remove( vol, fdir );
      }
index 5334be5d5610817c7e117f2efd3390c4420f2aff,852d5343ddd06c4e8acd6eb2df381ac063c36e8f..0fe65e7000af0f02fe5a7e3e7049e013d4c96e16
@@@ -1,5 -1,5 +1,5 @@@
  /*
-  * $Id: directory.h,v 1.34 2010-03-12 15:16:49 franklahm Exp $
 - * $Id: directory.h,v 1.33.4.2 2010-02-05 10:27:59 franklahm Exp $
++ * $Id: directory.h,v 1.34 2010/03/12 15:16:49 franklahm Exp $
   *
   * Copyright (c) 1990,1991 Regents of The University of Michigan.
   * All Rights Reserved.
@@@ -113,46 -106,35 +106,39 @@@ struct maccess 
  #define       AR_UWRITE       (1<<2)
  #define       AR_UOWN         (1<<7)
  
- extern struct dir       *dirnew (const char *, const char *);
- extern void             dirfreename (struct dir *);
- extern void             dirfree (struct dir *);
- extern struct dir     *dirsearch (const struct vol *, u_int32_t);
- extern struct dir     *dirlookup (struct vol *, u_int32_t);
- extern struct dir       *dirsearch_byname (const struct vol *, struct dir *,char *);
- extern struct dir     *adddir (struct vol *, struct dir *, 
-                                                struct path *);
- extern int              movecwd (struct vol *, struct dir *);
- extern int              deletecurdir (struct vol *);
- extern struct path      *cname (struct vol *, struct dir *,
-                              char **);
- extern mode_t           mtoumode (struct maccess *);
- extern void             utommode (struct stat *, struct maccess *);
- extern int getdirparams (const struct vol *, u_int16_t, struct path *,
-                                  struct dir *, char *, size_t *);
- extern int setdirparams (struct vol *, struct path *, u_int16_t, char *);
- extern int renamedir(const struct vol *, int, char *, char *, struct dir *,
-                      struct dir *, char *);
- extern int path_error (struct path *, int error);
- extern void setdiroffcnt (struct dir *dir, struct stat *st,  u_int32_t count);
- extern int dirreenumerate (struct dir *dir, struct stat *st);
  typedef int (*dir_loop)(struct dirent *, char *, void *);
  
- extern int  for_each_dirent (const struct vol *, char *, dir_loop , void *);
- extern int  check_access (char *name , int mode);
- extern int file_access   (struct path *path, int mode);
- extern int netatalk_unlink (const char *name);
 -extern struct dir *dir_new(const char *mname, const char *uname, const struct vol *, cnid_t pdid, cnid_t did, bstring fullpath); /* volume.c needs it once */
++extern struct dir *dir_new(const char *mname, const char *uname, const struct vol *,
++                           cnid_t pdid, cnid_t did, bstring fullpath); /* volume.c needs it once */
+ extern void        dir_free (struct dir *);
+ extern struct dir  *dir_add(const struct vol *, const struct dir *, struct path *, int);
 -extern int         dir_modify(const struct vol *vol, struct dir *dir, cnid_t pdid, cnid_t did, const char *new_mname, const char *new_uname, bstring pdir_fullpath);
++extern int         dir_modify(const struct vol *vol, struct dir *dir, cnid_t pdid, cnid_t did,
++                              const char *new_mname, const char *new_uname, bstring pdir_fullpath);
+ extern int         dir_remove(const struct vol *vol, struct dir *dir);
+ extern struct dir  *dirlookup (const struct vol *, cnid_t);
+ extern int         movecwd (const struct vol *, struct dir *);
+ extern struct path *cname (struct vol *, struct dir *, char **);
+ extern int         deletecurdir (struct vol *);
+ extern mode_t      mtoumode (struct maccess *);
+ extern void        utommode (struct stat *, struct maccess *);
+ extern int         getdirparams (const struct vol *, u_int16_t, struct path *,
+                                  struct dir *, char *, size_t *);
 -extern int         setdirparams (struct vol *, struct path *, u_int16_t, char *);
 -extern int         renamedir (const struct vol *, char *, char *, struct dir *,
 -                              struct dir *, char *);
 -extern int         path_error (struct path *, int error);
 -extern void        setdiroffcnt (struct dir *dir, struct stat *st,  u_int32_t count);
 -extern int         dirreenumerate (struct dir *dir, struct stat *st);
 -extern int         for_each_dirent (const struct vol *, char *, dir_loop , void *);
 -extern int         check_access (char *name , int mode);
 -extern int         file_access   (struct path *path, int mode);
 +
- extern int caseenumerate (const struct vol *, struct path *, struct dir *);
++extern int         setdirparams(struct vol *, struct path *, u_int16_t, char *);
++extern int         renamedir(const struct vol *, int, char *, char *, struct dir *,
++                             struct dir *, char *);
++extern int         path_error(struct path *, int error);
++extern void        setdiroffcnt(struct dir *dir, struct stat *st,  u_int32_t count);
++extern int         dirreenumerate(struct dir *dir, struct stat *st);
++extern int         for_each_dirent(const struct vol *, char *, dir_loop , void *);
++extern int         check_access(char *name , int mode);
++extern int         file_access(struct path *path, int mode);
+ extern int         netatalk_unlink (const char *name);
+ extern int         caseenumerate (const struct vol *, struct path *, struct dir *);
 +
- extern hash_t *dirhash (void);
  /* from enumerate.c */
--extern char *check_dirent (const struct vol *, char *);
++extern char        *check_dirent (const struct vol *, char *);
  
  /* FP functions */
  int afp_createdir (AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf,  size_t *rbuflen);
index c06ef20300f3f296e4e2b0d41b2b40404a4538b0,3f754a26d19ba07be8ae24d4a06b017c9cd89614..daa83a693a2557e82c106839f5d2dcc278046f2e
@@@ -1,5 -1,5 +1,5 @@@
  /*
-  * $Id: enumerate.c,v 1.49 2010-02-10 14:05:37 franklahm Exp $
 - * $Id: enumerate.c,v 1.48.2.2 2010-02-04 14:34:31 franklahm Exp $
++ * $Id: enumerate.c,v 1.49 2010/02/10 14:05:37 franklahm Exp $
   *
   * Copyright (c) 1990,1993 Regents of The University of Michigan.
   * All Rights Reserved.  See COPYRIGHT.
diff --cc etc/afpd/file.c
index aa692842ed4a5c8d919080336292528d33dbcbd2,30e077d0a4ba2a3a0b705919f560788061fd4365..93b1a169612ab5c4f25e6fd69fc4fb01c0e8baa2
@@@ -1,5 -1,5 +1,5 @@@
  /*
-  * $Id: file.c,v 1.141 2010-03-12 15:16:49 franklahm Exp $
 - * $Id: file.c,v 1.131.2.3 2010-02-04 14:34:31 franklahm Exp $
++ * $Id: file.c,v 1.141 2010/03/12 15:16:49 franklahm Exp $
   *
   * Copyright (c) 1990,1993 Regents of The University of Michigan.
   * All Rights Reserved.  See COPYRIGHT.
diff --cc etc/afpd/file.h
index 6cf4ae22f8184d15319dddb26d6d25b75bf5c832,ad4e312a5c7502a72869b6eb6263d7a95e7bde40..58a574c6c1aa44180868b1fa4464602c4d04b43e
@@@ -1,5 -1,5 +1,5 @@@
  /*
-  * $Id: file.h,v 1.26 2010-03-12 15:16:49 franklahm Exp $
 - * $Id: file.h,v 1.24.4.1 2010-02-01 10:56:08 franklahm Exp $
++ * $Id: file.h,v 1.26 2010/03/12 15:16:49 franklahm Exp $
   *
   * Copyright (c) 1990,1991 Regents of The University of Michigan.
   * All Rights Reserved.
index 3e5cb2f5ee8048597a75d0552c971f7c769821f9,b79e1251c65d17add04d1c6541eafc8032ea33b4..fd7cc8899e46283f3c90cf8c3972dbb1f0cf711e
@@@ -1,5 -1,5 +1,5 @@@
  /*
-  * $Id: filedir.c,v 1.73 2010-03-12 15:16:49 franklahm Exp $
 - * $Id: filedir.c,v 1.69.2.3 2010-02-04 14:34:31 franklahm Exp $
++ * $Id: filedir.c,v 1.73 2010/03/12 15:16:49 franklahm Exp $
   *
   * Copyright (c) 1990,1993 Regents of The University of Michigan.
   * All Rights Reserved.  See COPYRIGHT.
@@@ -361,47 -355,31 +367,46 @@@ static int moveandrename(const struct v
              /* reuse struct adouble so it won't break locks */
              adp = opened->of_ad;
          }
 -    }
 -    else {
 +    } else {
          id = sdir->d_did; /* we already have the CNID */
-         p = ctoupath( vol, sdir->d_parent, oldname );
+         p = ctoupath( vol, dirlookup(vol, sdir->d_pdid), oldname );
          if (!p) {
              return AFPERR_PARAM;
          }
          adflags = ADFLAGS_DIR;
      }
 +
      /*
 -     * p now points to the full pathname of the source fs object.
 -     *
 -     * we are in the dest folder so we need to use p for ad_open
 +     * p now points to either
 +     *   a) full pathname of the source fs object (if renameat is not available)
 +     *   b) the oldname (renameat is available)
 +     * we are in the dest folder so we need to use 
 +     *   a) p for ad_open
 +     *   b) fchdir sdir_fd before eg ad_open or use *at functions where appropiate
       */
  
 +    if (sdir_fd != -1) {
 +        if ((cwd_fd = open(".", O_RDONLY)) == -1)
 +            return AFPERR_MISC;
 +        if (fchdir(sdir_fd) != 0)
 +            return AFPERR_MISC;
 +    }
      if (!ad_metadata(p, adflags, adp)) {
          u_int16_t bshort;
  
          ad_getattr(adp, &bshort);
          ad_close_metadata( adp);
-         if ((bshort & htons(ATTRBIT_NORENAME))) 
+         if ((bshort & htons(ATTRBIT_NORENAME)))
              return(AFPERR_OLOCK);
      }
 +    if (sdir_fd != -1) {
 +        if (fchdir(cwd_fd) != 0) {
 +            LOG(log_error, logtype_afpd, "moveandrename: %s", strerror(errno) );
 +            return AFPERR_MISC;
 +        }
 +    }
  
-     if (NULL == (upath = mtoupath(vol, newname, curdir->d_did, utf8_encoding()))){ 
+     if (NULL == (upath = mtoupath(vol, newname, curdir->d_did, utf8_encoding()))){
          return AFPERR_PARAM;
      }
      path.u_name = upath;
@@@ -637,21 -600,19 +626,21 @@@ char *ctoupath(const struct vol *vol, s
  /* ------------------------- */
  int afp_moveandrename(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
  {
-     struct vol        *vol;
-     struct dir        *sdir, *ddir;
+     struct vol  *vol;
+     struct dir  *sdir, *ddir;
      int         isdir;
-     char      *oldname, *newname;
+     char    *oldname, *newname;
      struct path *path;
-     int               did;
-     int               pdid;
+     int     did;
+     int     pdid;
      int         plen;
-     u_int16_t vid;
+     u_int16_t   vid;
      int         rc;
  #ifdef DROPKLUDGE
-     int               retvalue;
+     int     retvalue;
  #endif /* DROPKLUDGE */
 +    int     sdir_fd = -1;
 +
  
      *rbuflen = 0;
      ibuf += 2;
          }
          strcpy(oldname, path->m_name); /* an extra copy for of_rename */
      } else {
-         strcpy(oldname, sdir->d_m_name);
+         memcpy(oldname, cfrombstring(sdir->d_m_name), blength(sdir->d_m_name) + 1);
      }
  
 +#ifdef HAVE_RENAMEAT
 +    if ((sdir_fd = open(".", O_RDONLY)) == -1)
 +        return AFPERR_MISC;
 +#endif
 +
      /* get the destination directory */
      if (NULL == ( ddir = dirlookup( vol, did )) ) {
 -        return afp_errno; /*  was AFPERR_PARAM */
 +        rc = afp_errno; /*  was AFPERR_PARAM */
 +        goto exit;
      }
      if (NULL == ( path = cname( vol, ddir, &ibuf ))) {
 -        return( AFPERR_NOOBJ );
 +        rc = AFPERR_NOOBJ;
 +        goto exit;
      }
      pdid = curdir->d_did;
      if ( *path->m_name != '\0' ) {
          strcpy(newname, oldname);
      }
  
 -    LOG(log_debug, logtype_afpd, "afp_move: {oldname:'%s', newname:'%s', isdir:%u}",
 +    /* This does the work */
++    LOG(log_debug, logtype_afpd, "afp_move(oldname:'%s', newname:'%s', isdir:%u)",
+         oldname, newname, isdir);
 -    rc = moveandrename(vol, sdir, oldname, newname, isdir);
 +    rc = moveandrename(vol, sdir, sdir_fd, oldname, newname, isdir);
  
      if ( rc == AFP_OK ) {
          char *upath = mtoupath(vol, newname, pdid, utf8_encoding());
-         
          if (NULL == upath) {
 -            return AFPERR_PARAM;
 +            rc = AFPERR_PARAM;
 +            goto exit;
          }
          curdir->offcnt++;
          sdir->offcnt--;
index e096044a2603d63bfcce5860aafd19606b66e306,e6989e39bada6eb6a779633ef92d08c73ecb06c2..31f7b4a8b720d91397e8d162114f3af7c69b699b
@@@ -1,5 -1,5 +1,5 @@@
  /*
-  * $Id: globals.h,v 1.33 2010-03-29 15:22:57 franklahm Exp $
 - * $Id: globals.h,v 1.31.2.2 2010-02-04 14:34:31 franklahm Exp $
++ * $Id: globals.h,v 1.33 2010/03/29 15:22:57 franklahm Exp $
   *
   * Copyright (c) 1990,1993 Regents of The University of Michigan.
   * All Rights Reserved.  See COPYRIGHT.
index 49c014ccef9befec7be7f15068e5c7039e757139,687809e3e5ad7262c5d615d519adcead56dc2be2..a6359ad29329373e5db2fdb7b673cfbf3fee6241
@@@ -1,5 -1,5 +1,5 @@@
  /*
-  * $Id: ofork.c,v 1.32 2010-03-12 15:16:49 franklahm Exp $
 - * $Id: ofork.c,v 1.30.4.4 2010-02-09 14:56:30 franklahm Exp $
++ * $Id: ofork.c,v 1.32 2010/03/12 15:16:49 franklahm Exp $
   *
   * Copyright (c) 1996 Regents of The University of Michigan.
   * All Rights Reserved.  See COPYRIGHT.
@@@ -279,32 -282,21 +281,39 @@@ struct ofork *of_find(const u_int16_t o
  }
  
  /* -------------------------- */
- int of_stat  (struct path *path)
+ int of_stat(struct path *path)
  {
- int ret;
+     int ret;
      path->st_errno = 0;
      path->st_valid = 1;
-     if ((ret = lstat(path->u_name, &path->st)) < 0)
 -    if ((ret = stat(path->u_name, &path->st)) < 0) {
 -        LOG(log_debug, logtype_afpd, "of_stat: {'%s/%s': %s}",
++
++    if ((ret = lstat(path->u_name, &path->st)) < 0) {
++        LOG(log_debug, logtype_afpd, "of_stat('%s/%s': %s)",
+             cfrombstring(curdir->d_fullpath), path->u_name, strerror(errno));
 -        path->st_errno = errno;
 +      path->st_errno = errno;
-    return ret;
+     }
++
+     return ret;
  }
  
 -/* --------------------------
++
 +#ifdef HAVE_RENAMEAT
 +int of_fstatat(int dirfd, struct path *path)
 +{
 +    int ret;
 +
 +    path->st_errno = 0;
 +    path->st_valid = 1;
 +
 +    if ((ret = fstatat(dirfd, path->u_name, &path->st, AT_SYMLINK_NOFOLLOW)) < 0)
 +      path->st_errno = errno;
 +
 +   return ret;
 +}
 +#endif /* HAVE_RENAMEAT */
 +
 +/* -------------------------- 
     stat the current directory.
     stat(".") works even if "." is deleted thus
     we have to stat ../name because we want to know if it's there
@@@ -321,20 -315,27 +332,28 @@@ int of_statdir(struct vol *vol, struct 
      path->st_errno = 0;
      path->st_valid = 1;
      /* FIXME, what about: we don't have r-x perm anymore ? */
-     strlcpy(pathname +3, path->d_dir->d_u_name, sizeof (pathname) -3);
+     len = blength(path->d_dir->d_u_name);
+     if (len > (MAXPATHLEN - 3))
+         len = MAXPATHLEN - 3;
+     strncpy(pathname + 3, cfrombstring(path->d_dir->d_u_name), len + 1);
+     LOG(log_debug, logtype_afpd, "of_statdir: stating: '%s'", pathname);
  
 -    if (!(ret = stat(pathname, &path->st)))
 +    if (!(ret = lstat(pathname, &path->st)))
          return 0;
-         
      path->st_errno = errno;
      /* hmm, can't stat curdir anymore */
-     if (errno == EACCES && curdir->d_parent ) {
-        if (movecwd(vol, curdir->d_parent)) 
+     if (errno == EACCES && (dir = dirlookup(vol, curdir->d_pdid))) {
 -        if (movecwd(vol, dir))
 -            return -1;
 -        path->st_errno = 0;
 -        if ((ret = stat(cfrombstring(path->d_dir->d_u_name), &path->st)) < 0)
 -            path->st_errno = errno;
++       if (movecwd(vol, dir)) 
 +           return -1;
 +       path->st_errno = 0;
-        if ((ret = lstat(path->d_dir->d_u_name, &path->st)) < 0) 
++
++       if ((ret = lstat(cfrombstring(path->d_dir->d_u_name), &path->st)) < 0) 
 +           path->st_errno = errno;
      }
      return ret;
  }
  
index f43d65c48b68b0fa28f5c6d446c5f5a61942964e,368dd50c0c8c355c2d987318533e957796765d01..5d61d69408cdc0513858c3d4ac7140b90ada8adf
@@@ -1,5 -1,5 +1,5 @@@
  /*
-  * $Id: volume.c,v 1.127 2010-04-16 18:28:45 franklahm Exp $
 - * $Id: volume.c,v 1.115.2.2 2010-02-09 14:56:30 franklahm Exp $
++ * $Id$
   *
   * Copyright (c) 1990,1993 Regents of The University of Michigan.
   * All Rights Reserved.  See COPYRIGHT.
@@@ -459,7 -466,9 +459,11 @@@ static void volset(struct vol_option *o
                  options[VOLOPT_FLAGS].i_value &= ~AFPVOL_CACHE;
              else if (strcasecmp(p, "tm") == 0)
                  options[VOLOPT_FLAGS].i_value |= AFPVOL_TM;
 -            else if (strcasecmp(p, "eject") == 0)
 -                options[VOLOPT_FLAGS].i_value |= AFPVOL_EJECT | AFPVOL_RO;
--
++/* Found this in branch dir-rewrite, maybe we want to use it sometimes */
++#if 0
++            else if (strcasecmp(p, "cdrom") == 0)
++                options[VOLOPT_FLAGS].i_value |= AFPVOL_CDROM | AFPVOL_RO;
++#endif
              p = strtok(NULL, ",");
          }
  
@@@ -1839,21 -1821,34 +1843,45 @@@ static int volume_openDB(struct vol *vo
          LOG(log_info, logtype_afpd, "Volume %s use CNID scheme %s.", volume->v_path, volume->v_cnidscheme);
      }
  
 -    if (volume->v_flags & AFPVOL_EJECT) {
 +    LOG(log_info, logtype_afpd, "%s:%s",
 +        volume->v_cnidserver ? volume->v_cnidserver : Cnid_srv,
 +        volume->v_cnidport ? volume->v_cnidport : Cnid_port);
 +    
++#if 0
++/* Found this in branch dir-rewrite, maybe we want to use it sometimes */
++
+     /* Legacy pre 2.1 way of sharing eg CD-ROM */
+     if (strcmp(volume->v_cnidscheme, "last") == 0) {
+         /* "last" is gone. We support it by switching to in-memory "tdb" */
+         volume->v_cnidscheme = strdup("tdb");
+         flags |= CNID_FLAG_MEMORY;
+     }
+     /* New way of sharing CD-ROM */
++    if (volume->v_flags & AFPVOL_CDROM) {
+         flags |= CNID_FLAG_MEMORY;
+         if (strcmp(volume->v_cnidscheme, "tdb") != 0) {
+             free(volume->v_cnidscheme);
+             volume->v_cnidscheme = strdup("tdb");
+             LOG(log_info, logtype_afpd, "Volume %s is ejectable, switching to scheme %s.",
+                 volume->v_path, volume->v_cnidscheme);
+         }
+     }
++#endif
++
 +    volume->v_cdb = cnid_open(volume->v_dbpath ? volume->v_dbpath : volume->v_path,
 +                              volume->v_umask,
 +                              volume->v_cnidscheme,
 +                              flags,
 +                              volume->v_cnidserver ? volume->v_cnidserver : Cnid_srv,
 +                              volume->v_cnidport ? volume->v_cnidport : Cnid_port);
  
-     if (!volume->v_cdb) {
 -    if (volume->v_dbpath)
 -        volume->v_cdb = cnid_open (volume->v_dbpath, volume->v_umask, volume->v_cnidscheme, flags);
 -    else
 -        volume->v_cdb = cnid_open (volume->v_path, volume->v_umask, volume->v_cnidscheme, flags);
+     if ( ! volume->v_cdb && ! (flags & CNID_FLAG_MEMORY)) {
+         /* The first attempt failed and it wasn't yet an attempt to open in-memory */
          flags |= CNID_FLAG_MEMORY;
          LOG(log_error, logtype_afpd, "Reopen volume %s using in memory temporary CNID DB.", volume->v_path);
 -        volume->v_cdb = cnid_open (volume->v_path, volume->v_umask, "tdb", flags);
 +        volume->v_cdb = cnid_open (volume->v_path, volume->v_umask, "tdb", flags, NULL, NULL);
  #ifdef SERVERTEXT
          /* kill ourself with SIGUSR2 aka msg pending */
          if (volume->v_cdb) {
index 0d1f59ae8f1c502811bc4db2edd02ab4a9d2af18,3e1885c57a3de632af1fbc43f872a7e9c5bb1a24..080b13408a216f153d18120bf3f3a075f7d7c9f3
@@@ -1,5 -1,5 +1,5 @@@
  /*
-  * $Id: util.h,v 1.21 2010-02-28 22:29:16 didg Exp $
 - * $Id: util.h,v 1.18.2.1 2010-02-11 13:06:55 franklahm Exp $
++ * $Id: util.h,v 1.21 2010/02/28 22:29:16 didg Exp $
   */
  
  /*!
index f1b2084b0c9fb6ebf47e01103fc898d20f110741,c0516a41495f4bcc8c8cfc60f688c2079a605a7e..de1134f2ede26930a144a0aaf99784a4df75b1c8
@@@ -1,5 -1,5 +1,5 @@@
  /*
-  * $Id: volume.h,v 1.17 2010-04-10 08:24:54 franklahm Exp $
 - * $Id: volume.h,v 1.11.2.2 2010-02-09 14:56:30 franklahm Exp $
++ * $Id: volume.h,v 1.16 2010/03/31 09:47:32 franklahm Exp $
   *
   * Copyright (c) 1990,1994 Regents of The University of Michigan.
   * All Rights Reserved.  See COPYRIGHT.
@@@ -137,6 -136,7 +135,7 @@@ struct vol 
  #define AFPVOL_INV_DOTS  (1 << 22)   /* dots files are invisible */
  #define AFPVOL_TM        (1 << 24)   /* Supports TimeMachine */
  #define AFPVOL_ACLS      (1 << 25)   /* Volume supports ACLS */
 -#define AFPVOL_EJECT     (1 << 25)   /* Ejectable media eg CD -> in memory CNID db */
++#define AFPVOL_CDROM     (1 << 25)   /* Ejectable media eg CD -> in memory CNID db */
  
  /* Extended Attributes vfs indirection  */
  #define AFPVOL_EA_NONE           0   /* No EAs */
index 13d5a6ebe4e0b6f9e86de995337569b523aba8a7,b915c65baea448c86c5ef985df7e458d06fd858b..570da3d9342e4d9d20021b0b6776244e284fa470
@@@ -1,5 -1,5 +1,5 @@@
  /*
-  * $Id: cnid_dbd.c,v 1.17 2010-03-31 09:47:32 franklahm Exp $
 - * $Id: cnid_dbd.c,v 1.16.2.1 2010-02-04 14:34:31 franklahm Exp $
++ * $Id: cnid_dbd.c,v 1.17 2010/03/31 09:47:32 franklahm Exp $
   *
   * Copyright (C) Joerg Lenneis 2003
   * All Rights Reserved.  See COPYING.