- /* 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;
-
- /* 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 );
- }