X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=etc%2Fafpd%2Fdirectory.c;h=7b25849114d0d9c1e079ca3f77446d5ade6fce36;hb=4054f4b3c85ecab060dafd46c0d3632cadbb5803;hp=55918eaeb8ed2ef6b8fa8dd0e064d01bc6c0ebbb;hpb=55c0d6d753dc022689616dedf38523e8388d4fd2;p=netatalk.git diff --git a/etc/afpd/directory.c b/etc/afpd/directory.c index 55918eae..7b258491 100644 --- a/etc/afpd/directory.c +++ b/etc/afpd/directory.c @@ -28,6 +28,8 @@ #include #include #include +#include +#include #include "directory.h" #include "dircache.h" @@ -301,7 +303,7 @@ static int cname_mtouname(const struct vol *vol, const struct dir *dir, struct p { static char temp[ MAXPATHLEN + 1]; char *t; - cnid_t fileid; + cnid_t fileid = 0; if (afp_version >= 30) { if (toUTF8) { @@ -429,6 +431,84 @@ int get_afp_errno(const int param) return param; } +/*! + * Resolve struct dir for an absolute path + * + * Given a path like "/Volumes/volume/dir/subdir" in a volume "/Volumes/volume" return + * a pointer to struct dir of "subdir". + * 1. Remove volue path from absolute path + * 2. start path + * 3. loop through all elements of the remaining path from 1. + * 4. we only allow dirs + * 5. search dircache + * 6. if not found in the dircache query the CNID database for the DID + * 7. and use dirlookup to resolve the DID to a it's struct dir * + * + * @param vol (r) volume the path is in, must be known + * @param path (r) absoule path + * + * @returns pointer to struct dir or NULL on error + */ +struct dir *dirlookup_bypath(const struct vol *vol, const char *path) +{ + EC_INIT; + + struct dir *dir = NULL; + cnid_t cnid, did; + bstring rpath = NULL; + bstring statpath = NULL; + struct bstrList *l = NULL; + struct stat st; + + cnid = htonl(2); + dir = vol->v_root; + + EC_NULL(rpath = rel_path_in_vol(path, vol->v_path)); /* 1. */ + EC_NULL(statpath = bfromcstr(vol->v_path)); /* 2. */ + + l = bsplit(rpath, '/'); + for (int i = 0; i < l->qty ; i++) { /* 3. */ + did = cnid; + EC_ZERO(bconcat(statpath, l->entry[i])); + EC_ZERO_LOGSTR(lstat(cfrombstr(statpath), &st), + "lstat(rpath: %s, elem: %s): %s: %s", + cfrombstr(rpath), cfrombstr(l->entry[i]), + cfrombstr(statpath), strerror(errno)); + + if (!(S_ISDIR(st.st_mode))) /* 4. */ + EC_FAIL; + + if ((dir = dircache_search_by_name(vol, /* 5. */ + dir, + cfrombstr(l->entry[i]), + blength(l->entry[i]), + st.st_ctime)) == NULL) { + if ((cnid = cnid_add(vol->v_cdb, /* 6. */ + &st, + did, + cfrombstr(l->entry[i]), + blength(l->entry[i]), + 0)) == CNID_INVALID) { + EC_FAIL; + } + + if ((dir = dirlookup(vol, cnid)) == NULL) /* 7. */ + EC_FAIL; + } + + EC_ZERO(bcatcstr(statpath, "/")); + } + +EC_CLEANUP: + bdestroy(rpath); + bstrListDestroy(l); + bdestroy(statpath); + if (ret != 0) + return NULL; + + return dir; +} + /*! * @brief Resolve a DID * @@ -446,9 +526,6 @@ int get_afp_errno(const int param) * @param did (r) DID to resolve * * @returns pointer to struct dir - * - * @note FIXME: OSX calls it with bogus id, ie file ID not folder ID, - * and we are really bad in this case. */ struct dir *dirlookup(const struct vol *vol, cnid_t did) { @@ -463,24 +540,28 @@ struct dir *dirlookup(const struct vol *vol, cnid_t did) int utf8; int err = 0; - LOG(log_debug, logtype_afpd, "dirlookup(did: %u) {start}", ntohl(did)); + LOG(log_debug, logtype_afpd, "dirlookup(did: %u)", ntohl(did)); /* check for did 0, 1 and 2 */ if (did == 0 || vol == NULL) { /* 1 */ afp_errno = AFPERR_PARAM; - return NULL; + ret = NULL; + goto exit; } else if (did == DIRDID_ROOT_PARENT) { rootParent.d_vid = vol->v_vid; - return (&rootParent); + ret = &rootParent; + goto exit; } else if (did == DIRDID_ROOT) { - return vol->v_root; + ret = vol->v_root; + goto exit; } /* Search the cache */ if ((ret = dircache_search_by_did(vol, did)) != NULL) { /* 2a */ if (ret->d_fullpath == NULL) { /* 2b */ afp_errno = AFPERR_BADTYPE; - return NULL; + ret = NULL; + goto exit; } if (lstat(cfrombstr(ret->d_fullpath), &st) != 0) { LOG(log_debug, logtype_afpd, "dirlookup(did: %u) {lstat: %s}", ntohl(did), strerror(errno)); @@ -491,14 +572,18 @@ struct dir *dirlookup(const struct vol *vol, cnid_t did) LOG(log_debug, logtype_afpd, "dirlookup(did: %u) {calling dir_remove()}", ntohl(did)); dir_remove(vol, ret); afp_errno = AFPERR_NOOBJ; - return NULL; + ret = NULL; + goto exit; default: - return ret; + ret = ret; + goto exit; } /* DEADC0DE */ - return NULL; + ret = NULL; + goto exit; } - return ret; + ret = ret; + goto exit; } utf8 = utf8_encoding(); @@ -506,8 +591,12 @@ struct dir *dirlookup(const struct vol *vol, cnid_t did) /* Get it from the database */ cnid = did; - if ( (upath = cnid_resolve(vol->v_cdb, &cnid, buffer, buflen)) == NULL - || (upath = strdup(upath)) == NULL) { /* 3 */ + if ((upath = cnid_resolve(vol->v_cdb, &cnid, buffer, buflen)) == NULL) { + afp_errno = AFPERR_NOOBJ; + err = 1; + goto exit; + } + if ((upath = strdup(upath)) == NULL) { /* 3 */ afp_errno = AFPERR_NOOBJ; err = 1; goto exit; @@ -519,6 +608,7 @@ struct dir *dirlookup(const struct vol *vol, cnid_t did) * - DIRDID_ROOT is hit * - a cached entry is found */ + LOG(log_debug, logtype_afpd, "dirlookup(did: %u) {recursion for did: %u}", ntohl(pdid)); if ((pdir = dirlookup(vol, pdid)) == NULL) { err = 1; goto exit; @@ -573,14 +663,11 @@ struct dir *dirlookup(const struct vol *vol, cnid_t did) } /* Add it to the cache only if it's a dir */ - if (dircache_add(ret) != 0) { /* 7 */ + if (dircache_add(vol, ret) != 0) { /* 7 */ err = 1; goto exit; } - LOG(log_debug, logtype_afpd, "dirlookup(did: %u) {end: did:%u, path:'%s'}", - ntohl(did), ntohl(pdid), cfrombstr(ret->d_fullpath)); - exit: if (upath) free(upath); if (err) { @@ -593,6 +680,10 @@ exit: ret = NULL; } } + if (ret) + LOG(log_debug, logtype_afpd, "dirlookup(did: %u): pdid: %u, \"%s\"", + ntohl(ret->d_did), ntohl(ret->d_pdid), cfrombstr(ret->d_fullpath)); + return ret; } @@ -817,6 +908,7 @@ struct dir *dir_add(struct vol *vol, const struct dir *dir, struct path *path, i /* Get macname from unixname */ if (path->m_name == NULL) { if ((path->m_name = utompath(vol, path->u_name, id, utf8_encoding())) == NULL) { + LOG(log_error, logtype_afpd, "dir_add(\"%s\"): can't assign macname", path->u_name); err = 2; goto exit; } @@ -837,7 +929,7 @@ struct dir *dir_add(struct vol *vol, const struct dir *dir, struct path *path, i goto exit; } - if ((dircache_add(cdir)) != 0) { /* 4 */ + if ((dircache_add(vol, cdir)) != 0) { /* 4 */ LOG(log_error, logtype_afpd, "dir_add: fatal dircache error: %s", cfrombstr(fullpath)); exit(EXITERR_SYS); } @@ -880,9 +972,9 @@ void dir_free_invalid_q(void) * @brief Remove a dir from a cache and queue it for freeing * * 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. Queue it for removal + * 2. Remove it from the cache + * 3. Queue it for removal + * 4. If it's a request to remove curdir, mark curdir as invalid * 5. Mark it as invalid * * @param (r) pointer to struct vol @@ -896,27 +988,21 @@ int dir_remove(const struct vol *vol, struct dir *dir) if (dir->d_did == DIRDID_ROOT_PARENT || dir->d_did == DIRDID_ROOT) return 0; - if (dir->d_flags & DIRF_CACHELOCK) { /* 1 */ - LOG(log_warning, logtype_afpd, "dir_remove(did:%u,'%s'): dir is locked", - ntohl(dir->d_did), cfrombstr(dir->d_u_name)); - 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), cfrombstr(dir->d_u_name)); - dircache_remove(vol, dir, DIRCACHE | DIDNAME_INDEX | QUEUE_INDEX); /* 3 */ - enqueue(invalid_dircache_entries, dir); /* 4 */ + dircache_remove(vol, dir, DIRCACHE | DIDNAME_INDEX | QUEUE_INDEX); /* 2 */ + enqueue(invalid_dircache_entries, dir); /* 3 */ + + if (curdir == dir) /* 4 */ + curdir = NULL; + dir->d_did = CNID_INVALID; /* 5 */ + return 0; } +#if 0 /* unused */ /*! * @brief Modify a struct dir, adjust cache * @@ -988,13 +1074,14 @@ int dir_modify(const struct vol *vol, dir->d_m_name_ucs2 = NULL; /* Re-add it to the cache */ - if ((dircache_add(dir)) != 0) { + if ((dircache_add(vol, dir)) != 0) { dircache_dump(); AFP_PANIC("dir_modify"); } return ret; } +#endif /*! * @brief Resolve a catalog node name path @@ -1104,7 +1191,7 @@ struct path *cname(struct vol *vol, struct dir *dir, char **cpath) /* 6*/ for ( p = path; *data != 0 && len > 0; len-- ) { *p++ = *data++; - if (p > &path[ MAXPATHLEN]) { + if (p > &path[UTF8FILELEN_EARLY]) { /* FIXME safeguard, limit of early Mac OS X */ afp_errno = AFPERR_PARAM; return NULL; } @@ -1253,21 +1340,19 @@ int movecwd(const struct vol *vol, struct dir *dir) AFP_ASSERT(vol); AFP_ASSERT(dir); - LOG(log_maxdebug, logtype_afpd, "movecwd(curdir:'%s', cwd:'%s')", - cfrombstr(curdir->d_fullpath), getcwdpath()); + LOG(log_maxdebug, logtype_afpd, "movecwd: from: curdir:\"%s\", cwd:\"%s\"", + curdir ? cfrombstr(curdir->d_fullpath) : "INVALID", getcwdpath()); - if ( dir == curdir) - return( 0 ); if (dir->d_did == DIRDID_ROOT_PARENT) { curdir = &rootParent; return 0; } - LOG(log_debug, logtype_afpd, "movecwd(did:%u, '%s')", + LOG(log_debug, logtype_afpd, "movecwd(to: did: %u, \"%s\")", ntohl(dir->d_did), cfrombstr(dir->d_fullpath)); if ((ret = lchdir(cfrombstr(dir->d_fullpath))) != 0 ) { - LOG(log_debug, logtype_afpd, "movecwd('%s'): ret: %u, %s", + LOG(log_debug, logtype_afpd, "movecwd(\"%s\"): ret: %u, %s", cfrombstr(dir->d_fullpath), ret, strerror(errno)); if (ret == 1) { /* p is a symlink or getcwd failed */ @@ -1328,10 +1413,18 @@ int file_access(struct path *path, int mode) struct maccess ma; accessmode(path->u_name, &ma, curdir, &path->st); - if ((mode & OPENACC_WR) && !(ma.ma_user & AR_UWRITE)) + + LOG(log_debug, logtype_afpd, "file_access(\"%s\"): mapped user mode: 0x%02x", + path->u_name, ma.ma_user); + + if ((mode & OPENACC_WR) && !(ma.ma_user & AR_UWRITE)) { + LOG(log_debug, logtype_afpd, "file_access(\"%s\"): write access denied", path->u_name); return -1; - if ((mode & OPENACC_RD) && !(ma.ma_user & AR_UREAD)) + } + if ((mode & OPENACC_RD) && !(ma.ma_user & AR_UREAD)) { + LOG(log_debug, logtype_afpd, "file_access(\"%s\"): read access denied", path->u_name); return -1; + } return 0; } @@ -2160,6 +2253,8 @@ int afp_createdir(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_ ad_setname(&ad, s_path->m_name); ad_setid( &ad, s_path->st.st_dev, s_path->st.st_ino, dir->d_did, did, vol->v_stamp); + fce_register_new_dir(s_path); + ad_flush( &ad); ad_close_metadata( &ad); @@ -2232,13 +2327,13 @@ int deletecurdir(struct vol *vol) { struct dirent *de; struct stat st; - struct dir *fdir; + struct dir *fdir, *pdir; DIR *dp; struct adouble ad; u_int16_t ashort; int err; - if ( dirlookup(vol, curdir->d_pdid) == NULL ) { + if ((pdir = dirlookup(vol, curdir->d_pdid)) == NULL) { return( AFPERR_ACCESS ); } @@ -2256,6 +2351,8 @@ int deletecurdir(struct vol *vol) } err = vol->vfs->vfs_deletecurdir(vol); if (err) { + LOG(log_error, logtype_afpd, "deletecurdir: error deleting .AppleDouble in \"%s\"", + curdir->d_fullpath); return err; } @@ -2268,6 +2365,8 @@ int deletecurdir(struct vol *vol) /* bail if it's not a symlink */ if ((lstat(de->d_name, &st) == 0) && !S_ISLNK(st.st_mode)) { + LOG(log_error, logtype_afpd, "deletecurdir(\"%s\"): not empty", + curdir->d_fullpath); closedir(dp); return AFPERR_DIRNEMPT; } @@ -2279,16 +2378,23 @@ int deletecurdir(struct vol *vol) } } - if ( movecwd(vol, dirlookup(vol, curdir->d_pdid)) < 0 ) { + if (movecwd(vol, pdir) < 0) { err = afp_errno; goto delete_done; } + LOG(log_debug, logtype_afpd, "deletecurdir: moved to \"%s\"", + cfrombstr(curdir->d_fullpath)); + err = netatalk_rmdir_all_errors(-1, cfrombstr(fdir->d_u_name)); if ( err == AFP_OK || err == AFPERR_NOOBJ) { cnid_delete(vol->v_cdb, fdir->d_did); dir_remove( vol, fdir ); + } else { + LOG(log_error, logtype_afpd, "deletecurdir(\"%s\"): netatalk_rmdir_all_errors error", + curdir->d_fullpath); } + delete_done: if (dp) { /* inode is used as key for cnid.