X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=etc%2Fafpd%2Fdirectory.c;h=467bc62d89e936c2cf69988db42f66b27ea3fe36;hb=dfd4a2594c2123549b2fd1e6d5dc43d15aafc850;hp=cd834419e2fb66fe92bb394b47ccf8a46d1a2e1a;hpb=1a8fee3f065c4d4dee0427d796b03132de8b9902;p=netatalk.git diff --git a/etc/afpd/directory.c b/etc/afpd/directory.c index cd834419..467bc62d 100644 --- a/etc/afpd/directory.c +++ b/etc/afpd/directory.c @@ -1,5 +1,5 @@ /* - * $Id: directory.c,v 1.131.2.8 2010-02-02 14:39:48 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. @@ -49,12 +49,8 @@ extern void addir_inherit_acl(const struct vol *vol); /* * FIXMEs, loose ends after the dircache rewrite: - * o case-insensitivity is gone - * o catsearch doesn't work, see FIXMEs in catsearch.c - * o curdir per volume caching is gone - * o directory offspring count calculation probably broken - * o doesn't work with CNID backend last and the like. - * CNID backend must support persistent CNIDs. + * o merge dircache_search_by_name and dir_add ?? + * o case-insensitivity is gone from cname */ @@ -74,8 +70,10 @@ struct path Cur_Path = { "", /* mac name */ ".", /* unix name */ 0, /* id */ - NULL,/* struct dir */ + NULL,/* struct dir * */ 0, /* stat is not set */ + 0, /* errno */ + {0} /* struct stat */ }; @@ -111,7 +109,7 @@ static int netatalk_mkdir(const char *name) } /* ------------------- */ -static int deletedir(char *dir) +static int deletedir(int dirfd, char *dir) { char path[MAXPATHLEN + 1]; DIR *dp; @@ -125,7 +123,7 @@ static int deletedir(char *dir) return AFPERR_PARAM; /* already gone */ - if ((dp = opendir(dir)) == NULL) + if ((dp = opendirat(dirfd, dir)) == NULL) return AFP_OK; strcpy(path, dir); @@ -142,13 +140,13 @@ static int deletedir(char *dir) break; } strcpy(path + len, de->d_name); - if (stat(path, &st)) { + if (lstatat(dirfd, path, &st)) { continue; } if (S_ISDIR(st.st_mode)) { - err = deletedir(path); + err = deletedir(dirfd, path); } else { - err = netatalk_unlink(path); + err = netatalk_unlinkat(dirfd, path); } } closedir(dp); @@ -156,13 +154,13 @@ static int deletedir(char *dir) /* okay. the directory is empty. delete it. note: we already got rid of .AppleDouble. */ if (err == AFP_OK) { - err = netatalk_rmdir(dir); + err = netatalk_rmdir(dirfd, dir); } return err; } /* do a recursive copy. */ -static int copydir(const struct vol *vol, char *src, char *dst) +static int copydir(const struct vol *vol, int dirfd, char *src, char *dst) { char spath[MAXPATHLEN + 1], dpath[MAXPATHLEN + 1]; DIR *dp; @@ -176,7 +174,7 @@ static int copydir(const struct vol *vol, char *src, char *dst) /* doesn't exist or the path is too long. */ if (((slen = strlen(src)) > sizeof(spath) - 2) || ((dlen = strlen(dst)) > sizeof(dpath) - 2) || - ((dp = opendir(src)) == NULL)) + ((dp = opendirat(dirfd, src)) == NULL)) return AFPERR_PARAM; /* try to create the destination directory */ @@ -208,7 +206,7 @@ static int copydir(const struct vol *vol, char *src, char *dst) } strcpy(spath + slen, de->d_name); - if (stat(spath, &st) == 0) { + if (lstatat(dirfd, spath, &st) == 0) { if (strlen(de->d_name) > drem) { err = AFPERR_PARAM; break; @@ -216,9 +214,9 @@ static int copydir(const struct vol *vol, char *src, char *dst) strcpy(dpath + dlen, de->d_name); if (S_ISDIR(st.st_mode)) { - if (AFP_OK != (err = copydir(vol, spath, dpath))) + if (AFP_OK != (err = copydir(vol, dirfd, spath, dpath))) goto copydir_done; - } else if (AFP_OK != (err = copyfile(vol, vol, spath, dpath, NULL, NULL))) { + } else if (AFP_OK != (err = copyfile(vol, vol, dirfd, spath, dpath, NULL, NULL))) { goto copydir_done; } else { @@ -230,7 +228,7 @@ static int copydir(const struct vol *vol, char *src, char *dst) } /* keep the same time stamp. */ - if (stat(src, &st) == 0) { + if (lstatat(dirfd, src, &st) == 0) { ut.actime = ut.modtime = st.st_mtime; utime(dst, &ut); } @@ -339,23 +337,25 @@ static int cname_mtouname(const struct vol *vol, const struct dir *dir, struct p * * The final movecwd in cname failed, possibly with EPERM or ENOENT. We: * 1. move cwd into parent dir (we're often already there, but not always) + * 2. set struct path to the dirname + * 3. in case of + * AFPERR_ACCESS: the dir is there, we just cant chdir into it + * AFPERR_NOOBJ: the dir was there when we stated it in cname, so we have a race + * 4. indicate there's no dir for this path + * 5. remove the dir */ static struct path *path_from_dir(struct vol *vol, struct dir *dir, struct path *ret) { - /* - * it's tricky: movecwd failed some of dir path are not there anymore. - * FIXME: Is it true with other errors? - */ if (dir->d_did == DIRDID_ROOT_PARENT || dir->d_did == DIRDID_ROOT) return NULL; switch (afp_errno) { case AFPERR_ACCESS: - if (movecwd( vol, dirlookup(vol, dir->d_pdid)) < 0 ) + if (movecwd( vol, dirlookup(vol, dir->d_pdid)) < 0 ) /* 1 */ return NULL; - memcpy(ret->m_name, cfrombstring(dir->d_m_name), blength(dir->d_m_name) + 1); + memcpy(ret->m_name, cfrombstring(dir->d_m_name), blength(dir->d_m_name) + 1); /* 3 */ if (dir->d_m_name == dir->d_u_name) { ret->u_name = ret->m_name; } else { @@ -364,12 +364,8 @@ static struct path *path_from_dir(struct vol *vol, struct dir *dir, struct path } ret->d_dir = dir; -#if 0 - ret->st_valid = 1; - ret->st_errno = EACCES; -#endif - LOG(log_debug, logtype_afpd, "cname(AFPERR_ACCESS:'%s') {path-from-dir: curdir:'%s', path:'%s'}", + LOG(log_debug, logtype_afpd, "cname('%s') {path-from-dir: AFPERR_ACCESS. curdir:'%s', path:'%s'}", cfrombstring(dir->d_fullpath), cfrombstring(curdir->d_fullpath), ret->u_name); @@ -377,7 +373,7 @@ static struct path *path_from_dir(struct vol *vol, struct dir *dir, struct path return ret; case AFPERR_NOOBJ: - if (movecwd(vol, dirlookup(vol, dir->d_pdid)) < 0 ) + if (movecwd(vol, dirlookup(vol, dir->d_pdid)) < 0 ) /* 1 */ return NULL; memcpy(ret->m_name, cfrombstring(dir->d_m_name), blength(dir->d_m_name) + 1); @@ -388,12 +384,8 @@ static struct path *path_from_dir(struct vol *vol, struct dir *dir, struct path memcpy(ret->u_name, cfrombstring(dir->d_u_name), blength(dir->d_u_name) + 1); } -#if 0 - ret->st_valid = 1; - ret->st_errno = ENOENT; -#endif - ret->d_dir = NULL; - dir_remove(vol, dir); + ret->d_dir = NULL; /* 4 */ + dir_remove(vol, dir); /* 5 */ return ret; default: @@ -439,11 +431,10 @@ int get_afp_errno(const int param) struct dir *dirlookup(const struct vol *vol, cnid_t did) { static char buffer[12 + MAXPATHLEN + 1]; - struct bstrList *pathlist = NULL; - bstring fullpath = NULL; struct stat st; - struct dir *ret = NULL; - char *upath, *mpath; + struct dir *ret = NULL, *pdir; + bstring fullpath = NULL; + char *upath = NULL, *mpath; cnid_t cnid, pdid; size_t maxpath; int buflen = 12 + MAXPATHLEN + 1; @@ -487,61 +478,33 @@ struct dir *dirlookup(const struct vol *vol, cnid_t did) utf8 = utf8_encoding(); maxpath = (utf8) ? MAXPATHLEN - 7 : 255; - /* Create list for path elements, request 16 list elements for now*/ - if ((pathlist = bstListCreateMin(16)) == NULL) { /* 4 */ - LOG(log_error, logtype_afpd, "dirlookup(did: %u): OOM: %s", ntohl(did), strerror(errno)); - return NULL; - } - /* Get it from the database */ cnid = did; - if ( (upath = cnid_resolve(vol->v_cdb, &cnid, buffer, buflen)) == NULL ) { /* 3 */ + if ( (upath = cnid_resolve(vol->v_cdb, &cnid, buffer, buflen)) == NULL + || (upath = strdup(upath)) == NULL) { /* 3 */ afp_errno = AFPERR_NOOBJ; err = 1; goto exit; } pdid = cnid; - /* construct path, copy already found uname to path element list*/ - if ((bstrListPush(pathlist, bfromcstr(upath))) != BSTR_OK) { /* 4 */ - afp_errno = AFPERR_MISC; - err = 1; - goto exit; - } - - LOG(log_debug, logtype_afpd, "dirlookup(did: %u) {%u, %s}", ntohl(did), ntohl(pdid), upath); - - /* The stuff that follows is for building the full path to the directory */ - - /* work upwards until we reach volume root */ - while (cnid != DIRDID_ROOT) { - /* construct path, copy already found uname to path element list*/ - if ((bstrListPush(pathlist, bfromcstr(upath))) != BSTR_OK) { /* 4 */ - afp_errno = AFPERR_MISC; - err = 1; - goto exit; - } - - /* next part */ - if ((upath = cnid_resolve(vol->v_cdb, &cnid, buffer, buflen)) == NULL ) { /* 3 */ - afp_errno = AFPERR_NOOBJ; - err = 1; - goto exit; - } - } - - if ((bstrListPush(pathlist, bfromcstr(vol->v_path))) != BSTR_OK) { /* 4 */ - afp_errno = AFPERR_MISC; + /* + * Recurse up the tree, terminates in dirlookup when either + * - DIRDID_ROOT is hit + * - a cached entry is found + */ + if ((pdir = dirlookup(vol, pdid)) == NULL) { err = 1; goto exit; } - if ((fullpath = bjoinInv(pathlist, bfromcstr("/"))) == NULL) { /* 4 */ - afp_errno = AFPERR_MISC; + /* build the fullpath */ + if ((fullpath = bstrcpy(pdir->d_fullpath)) == NULL + || bconchar(fullpath, '/') != BSTR_OK + || bcatcstr(fullpath, upath) != BSTR_OK) { err = 1; goto exit; } - /* Finished building the fullpath */ /* stat it and check if it's a dir */ LOG(log_debug, logtype_afpd, "dirlookup: {stating %s}", cfrombstring(fullpath)); @@ -593,12 +556,10 @@ struct dir *dirlookup(const struct vol *vol, cnid_t did) ntohl(did), ntohl(pdid), cfrombstring(ret->d_fullpath)); exit: - if (pathlist) - bstrListDestroy(pathlist); - if (err) { LOG(log_debug, logtype_afpd, "dirlookup(did: %u) {exit_error: %s}", ntohl(did), AfpErr2name(afp_errno)); + free(upath); if (fullpath) bdestroy(fullpath); if (ret) { @@ -771,7 +732,7 @@ void dir_free(struct dir *dir) * * Create a new struct dir from struct path. Then add it to the cache. * The caller must have assured that the dir is not already in the cache, - * cf the assertion. + * cf theAFP_ASSERTion. * 1. Open adouble file, get CNID from it. * 2. Search the database, hinting with the CNID from (1). * 3. Build fullpath and create struct dir. @@ -795,12 +756,12 @@ struct dir *dir_add(const struct vol *vol, const struct dir *dir, struct path *p struct adouble *adp = NULL; bstring fullpath; - assert(vol); - assert(dir); - assert(path); - assert(len > 0); + AFP_ASSERT(vol); + AFP_ASSERT(dir); + AFP_ASSERT(path); + AFP_ASSERT(len > 0); - if ((cdir = dircache_search_by_name(vol, dir->d_did, path->u_name, strlen(path->u_name))) != NULL) { + if ((cdir = dircache_search_by_name(vol, dir, path->u_name, strlen(path->u_name))) != NULL) { /* there's a stray entry in the dircache */ LOG(log_debug, logtype_afpd, "dir_add(did:%u,'%s/%s'): {stray cache entry: did:%u,'%s', removing}", ntohl(dir->d_did), cfrombstring(dir->d_fullpath), path->u_name, @@ -878,29 +839,39 @@ exit: /*! * @brief Remove a dir from a cache and free it and any ressources with it * + * 1. Check if the dir is locked or has opened forks + * 2. If it's a request to remove curdir, just chdir to volume root + * 3. Remove it from the cache + * 4. Remove the dir plus any allocated resources it references + * * @param (r) pointer to struct vol * @param (rw) pointer to struct dir */ int dir_remove(const struct vol *vol, struct dir *dir) { - assert(vol); - assert(dir); + AFP_ASSERT(vol); + AFP_ASSERT(dir); if (dir->d_did == DIRDID_ROOT_PARENT || dir->d_did == DIRDID_ROOT) return 0; - if (curdir == dir) { + if (dir->d_flags & DIRF_CACHELOCK || dir->d_ofork) { /* 1 */ + LOG(log_warning, logtype_afpd, "dir_remove(did:%u,'%s'): dir is locked or has opened forks", + ntohl(dir->d_did), cfrombstring(dir->d_fullpath)); + return 0; + } + + if (curdir == dir) { /* 2 */ if (movecwd(vol, vol->v_root) < 0) { LOG(log_error, logtype_afpd, "dir_remove: can't chdir to : %s", vol->v_root); } } - LOG(log_debug, logtype_afpd, "dir_remove(did:%u,'%s'): {removing}", ntohl(dir->d_did), cfrombstring(dir->d_fullpath)); - dircache_remove(vol, dir, DIRCACHE | DIDNAME_INDEX | QUEUE_INDEX); - dir_free(dir); + dircache_remove(vol, dir, DIRCACHE | DIDNAME_INDEX | QUEUE_INDEX); /* 3 */ + dir_free(dir); /* 4 */ return 0; } @@ -986,39 +957,29 @@ int dir_modify(const struct vol *vol, /*! * @brief Resolve a catalog node name path * - * If it's a filename: - * 1. compute unix name - * 2. stat the file, storing struct stat or errno in struct path - * 3. cwd (and curdir) is filename parent directory - * 4. return path with with filename - * - * If it's a dirname: - * 5. search the dircache - * 6. if not in the cache: - * 7. compute unix name - * 8. stat the dir, storing struct stat or errno in struct path - * 9. chdir dirname - * 10. if chdir failed, return path with dirname - * cwd is dir parent directory - * if chdir succeeded, add to dircache - * return path with "" and "." - * cwd is dirname - * 11. else in the cache: - * 12. stat the dir, storing struct stat or errno in struct path - * 13. chdir dirname - * 14. if chdir failed - * if ENOENT - * remove from cache - * if not last path part, return NULL - * else - return - if chdir error - dirname - curdir: dir parent directory - else - dirname: "" - curdir: dir -*/ + * 1. Evaluate path type + * 2. Move to start dir, if we cant, it might eg because of EACCES, build + * path from dirname, so eg getdirparams has sth it can chew on. curdir + * is dir parent then. All this is done in path_from_dir(). + * 3. Parse next cnode name in path, cases: + * 4. single "\0" -> do nothing + * 5. two or more consecutive "\0" -> chdir("..") one or more times + * 6. cnode name -> copy it to path.m_name + * 7. Get unix name from mac name + * 8. Special handling of request with did 1 + * 9. stat the cnode name + * 10. If it's not there, it's probably an afp_createfile|dir, + * return with curdir = dir parent, struct path = dirname + * 11. If it's there and it's a file, it must should be the last element of the requested + * path. Return with curdir = cnode name parent dir, struct path = filename + * 12. Treat symlinks like files, dont follow them + * 13. If it's a dir: + * 14. Search the dircache for it + * 15. If it's not in the cache, create a struct dir for it and add it to the cache + * 16. chdir into the dir and + * 17. set m_name to the mac equivalent of "." + * 18. goto 3 + */ struct path *cname(struct vol *vol, struct dir *dir, char **cpath) { static char path[ MAXPATHLEN + 1]; @@ -1032,13 +993,13 @@ struct path *cname(struct vol *vol, struct dir *dir, char **cpath) int size = 0; int toUTF8 = 0; - LOG(log_debug, logtype_afpd, "came('%s'): {start}", cfrombstring(dir->d_fullpath)); + LOG(log_maxdebug, logtype_afpd, "came('%s'): {start}", cfrombstring(dir->d_fullpath)); data = *cpath; afp_errno = AFPERR_NOOBJ; memset(&ret, 0, sizeof(ret)); - switch (ret.m_type = *data) { /* path type */ + switch (ret.m_type = *data) { /* 1 */ case 2: data++; len = (unsigned char) *data++; @@ -1080,19 +1041,11 @@ struct path *cname(struct vol *vol, struct dir *dir, char **cpath) return NULL; } - while (len) { - /* - * Three cases: - * 1. single 0 -> delimiter - * 2. additional 0 -> chdir(..) - * 3. a name - * a) name is a file, build struct path from it etc., exit while loop - * b) name is a dir, add it to the dircache, chdir to it, continue - */ - if (*data == 0) { /* case 1 or 2 */ + while (len) { /* 3 */ + if (*data == 0) { /* 4 or 5 */ data++; len--; - while (len > 0 && *data == 0) { /* case 2 */ + while (len > 0 && *data == 0) { /* 5 */ /* chdir to parrent dir */ if ((dir = dirlookup(vol, dir->d_pdid)) == NULL) return NULL; @@ -1106,7 +1059,7 @@ struct path *cname(struct vol *vol, struct dir *dir, char **cpath) continue; } - /* case 3: copy name from packet buffer to ret.m_name and process it */ + /* 6*/ for ( p = path; *data != 0 && len > 0; len-- ) { *p++ = *data++; if (p > &path[ MAXPATHLEN]) { @@ -1117,8 +1070,7 @@ struct path *cname(struct vol *vol, struct dir *dir, char **cpath) *p = 0; /* Terminate string */ ret.u_name = NULL; - /* Get u_name from m_name */ - if (cname_mtouname(vol, dir, &ret, toUTF8) != 0) { + if (cname_mtouname(vol, dir, &ret, toUTF8) != 0) { /* 7 */ LOG(log_error, logtype_afpd, "cname('%s'): error from cname_mtouname", path); return NULL; } @@ -1133,7 +1085,7 @@ struct path *cname(struct vol *vol, struct dir *dir, char **cpath) return NULL; } - if (dir->d_did == DIRDID_ROOT_PARENT) { + if (dir->d_did == DIRDID_ROOT_PARENT) { /* 8 */ /* * Special case: CNID 1 * root parent (did 1) has one child: the volume. Requests for did=1 with @@ -1152,7 +1104,7 @@ struct path *cname(struct vol *vol, struct dir *dir, char **cpath) * and thus call continue which should terminate the while loop because * len = 0. Ok? */ - if (of_stat(&ret) != 0) { + if (of_stat(&ret) != 0) { /* 9 */ /* * ret.u_name doesn't exist, might be afp_createfile|dir * that means it should have been the last part @@ -1167,11 +1119,11 @@ struct path *cname(struct vol *vol, struct dir *dir, char **cpath) * probably afp_createfile|dir */ LOG(log_maxdebug, logtype_afpd, "came('%s'): {leave-cnode ENOENT (possile create request): '%s'}", cfrombstring(dir->d_fullpath), ret.u_name); - continue; + continue; /* 10 */ } switch (ret.st.st_mode & S_IFMT) { - case S_IFREG: + case S_IFREG: /* 11 */ LOG(log_debug, logtype_afpd, "came('%s'): {file: '%s'}", cfrombstring(dir->d_fullpath), ret.u_name); if (len > 0) { /* it wasn't the last part, so we have a bogus path request */ @@ -1179,7 +1131,7 @@ struct path *cname(struct vol *vol, struct dir *dir, char **cpath) return NULL; } continue; /* continues while loop */ - case S_IFLNK: + case S_IFLNK: /* 12 */ LOG(log_debug, logtype_afpd, "came('%s'): {link: '%s'}", cfrombstring(dir->d_fullpath), ret.u_name); if (len > 0) { LOG(log_warning, logtype_afpd, "came('%s'): {symlinked dir: '%s'}", cfrombstring(dir->d_fullpath), ret.u_name); @@ -1187,7 +1139,7 @@ struct path *cname(struct vol *vol, struct dir *dir, char **cpath) return NULL; } continue; /* continues while loop */ - case S_IFDIR: + case S_IFDIR: /* 13 */ break; default: LOG(log_info, logtype_afpd, "cname: special file: '%s'", ret.u_name); @@ -1197,10 +1149,10 @@ struct path *cname(struct vol *vol, struct dir *dir, char **cpath) /* Search the cache */ int unamelen = strlen(ret.u_name); - cdir = dircache_search_by_name(vol, dir->d_did, ret.u_name, unamelen); + cdir = dircache_search_by_name(vol, dir, ret.u_name, unamelen); /* 14 */ if (cdir == NULL) { /* Not in cache, create one */ - if ((cdir = dir_add(vol, dir, &ret, unamelen)) == NULL) { + if ((cdir = dir_add(vol, dir, &ret, unamelen)) == NULL) { /* 15 */ LOG(log_error, logtype_afpd, "cname(did:%u, name:'%s', cwd:'%s'): failed to add dir", ntohl(dir->d_did), ret.u_name, getcwdpath()); return NULL; @@ -1209,7 +1161,7 @@ struct path *cname(struct vol *vol, struct dir *dir, char **cpath) } /* if/else cnid==1 */ /* Now chdir to the evaluated dir */ - if (movecwd( vol, cdir ) < 0 ) { + if (movecwd( vol, cdir ) < 0 ) { /* 16 */ LOG(log_debug, logtype_afpd, "cname(cwd:'%s'): failed to chdir to new subdir '%s': %s", cfrombstring(curdir->d_fullpath), cfrombstring(cdir->d_fullpath), strerror(errno)); if (len == 0) @@ -1218,7 +1170,7 @@ struct path *cname(struct vol *vol, struct dir *dir, char **cpath) return NULL; } dir = cdir; - ret.m_name[0] = 0; /* so we later know last token was a dir */ + ret.m_name[0] = 0; /* 17, so we later know last token was a dir */ } /* while (len) */ if (curdir->d_did == DIRDID_ROOT_PARENT) { @@ -1250,12 +1202,12 @@ struct path *cname(struct vol *vol, struct dir *dir, char **cpath) */ int movecwd(const struct vol *vol, struct dir *dir) { - assert(vol); + int ret; - if (dir == NULL) - return -1; + AFP_ASSERT(vol); + AFP_ASSERT(dir); - LOG(log_maxdebug, logtype_afpd, "movecwd(curdir:'%s', cwd:'%s')", + LOG(log_maxdebug, logtype_afpd, "movecwd(curdir:'%s', cwd:'%s')", cfrombstring(curdir->d_fullpath), getcwdpath()); if ( dir == curdir) @@ -1267,8 +1219,21 @@ int movecwd(const struct vol *vol, struct dir *dir) 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; + + if (chdir(vol->v_path ) < 0) { + 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: @@ -1411,6 +1376,8 @@ int getdirparams(const struct vol *vol, case DIRPBIT_PDID : memcpy( data, &pdid, sizeof( pdid )); data += sizeof( pdid ); + LOG(log_debug, logtype_afpd, "metadata('%s'): Parent DID: %u", + s_path->u_name, ntohl(pdid)); break; case DIRPBIT_CDATE : @@ -1467,6 +1434,8 @@ int getdirparams(const struct vol *vol, case DIRPBIT_DID : memcpy( data, &dir->d_did, sizeof( aint )); data += sizeof( aint ); + LOG(log_debug, logtype_afpd, "metadata('%s'): DID: %u", + s_path->u_name, ntohl(dir->d_did)); break; case DIRPBIT_OFFCNT : @@ -2163,8 +2132,12 @@ createdir_done: * dst new unix filename (not a pathname) * newname new mac name * newparent curdir + * dirfd -1 means ignore dirfd (or use AT_FDCWD), otherwise src is relative to dirfd */ -int renamedir(const struct vol *vol, char *src, char *dst, +int renamedir(const struct vol *vol, + int dirfd, + char *src, + char *dst, struct dir *dir, struct dir *newparent, char *newname) @@ -2173,7 +2146,7 @@ int renamedir(const struct vol *vol, char *src, char *dst, 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 ); @@ -2187,11 +2160,11 @@ int renamedir(const struct vol *vol, char *src, char *dst, case EXDEV: /* this needs to copy and delete. bleah. that means we have * to deal with entire directory hierarchies. */ - if ((err = copydir(vol, src, dst)) < 0) { - deletedir(dst); + if ((err = copydir(vol, dirfd, src, dst)) < 0) { + deletedir(-1, dst); return err; } - if ((err = deletedir(src)) < 0) + if ((err = deletedir(dirfd, src)) < 0) return err; break; default : @@ -2199,7 +2172,7 @@ int renamedir(const struct vol *vol, char *src, char *dst, } } - vol->vfs->vfs_renamedir(vol, src, dst); + vol->vfs->vfs_renamedir(vol, dirfd, src, dst); ad_init(&ad, vol->v_adouble, vol->v_ad_options); @@ -2239,7 +2212,7 @@ int deletecurdir(struct vol *vol) if ( ad_metadata( ".", ADFLAGS_DIR, &ad) == 0 ) { ad_getattr(&ad, &ashort); - ad_close( &ad, ADFLAGS_HF ); + ad_close_metadata(&ad); if ((ashort & htons(ATTRBIT_NODELETE))) { return AFPERR_OLOCK; } @@ -2274,7 +2247,7 @@ int deletecurdir(struct vol *vol) goto delete_done; } - 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) { cnid_delete(vol->v_cdb, fdir->d_did); dir_remove( vol, fdir );