/*
- * $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.
}
/*
- * 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:
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)) {
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 );
}
/*
- * $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.
#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);