X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=etc%2Fafpd%2Fdirectory.c;h=7b25849114d0d9c1e079ca3f77446d5ade6fce36;hb=4054f4b3c85ecab060dafd46c0d3632cadbb5803;hp=467bc62d89e936c2cf69988db42f66b27ea3fe36;hpb=4178967bf281a63438b3c076db90057ff2195f98;p=netatalk.git diff --git a/etc/afpd/directory.c b/etc/afpd/directory.c index 467bc62d..7b258491 100644 --- a/etc/afpd/directory.c +++ b/etc/afpd/directory.c @@ -1,6 +1,4 @@ /* - * $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. */ @@ -30,6 +28,8 @@ #include #include #include +#include +#include #include "directory.h" #include "dircache.h" @@ -43,10 +43,6 @@ #include "mangle.h" #include "hash.h" -#ifdef HAVE_NFSv4_ACLS -extern void addir_inherit_acl(const struct vol *vol); -#endif - /* * FIXMEs, loose ends after the dircache rewrite: * o merge dircache_search_by_name and dir_add ?? @@ -59,9 +55,10 @@ extern void addir_inherit_acl(const struct vol *vol); ******************************************************************************************/ int afp_errno; +/* As long as directory.c hasn't got its own init call, this get initialized in dircache_init */ 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 */ + NULL, 0, 0, /* qidx_node, ctime, d_flags */ 0, 0, 0, 0 /* pdid, did, offcnt, d_vid */ }; struct dir *curdir = &rootParent; @@ -76,6 +73,17 @@ struct path Cur_Path = { {0} /* struct stat */ }; +/* + * dir_remove queues struct dirs to be freed here. We can't just delete them immeidately + * eg in dircache_search_by_id, because a caller somewhere up the stack might be + * referencing it. + * So instead: + * - we mark it as invalid by setting d_did to CNID_INVALID (ie 0) + * - queue it in "invalid_dircache_entries" queue + * - which is finally freed at the end of every AFP func in afp_dsi.c. + */ +q_t *invalid_dircache_entries; + /******************************************************************************************* * Locals @@ -85,9 +93,24 @@ struct path Cur_Path = { /* ------------------------- appledouble mkdir afp error code. */ -static int netatalk_mkdir(const char *name) +static int netatalk_mkdir(const struct vol *vol, const char *name) { - if (ad_mkdir(name, DIRBITS | 0777) < 0) { + int ret; + struct stat st; + + if (vol->v_flags & AFPVOL_UNIX_PRIV) { + if (lstat(".", &st) < 0) + return AFPERR_MISC; + int mode = (DIRBITS & (~S_ISGID & st.st_mode)) | (0777 & ~vol->v_umask); + LOG(log_maxdebug, logtype_afpd, "netatalk_mkdir(\"%s\") {parent mode: %04o, vol umask: %04o}", + name, st.st_mode, vol->v_umask); + + ret = mkdir(name, mode); + } else { + ret = ad_mkdir(name, DIRBITS | 0777); + } + + if (ret < 0) { switch ( errno ) { case ENOENT : return( AFPERR_NOOBJ ); @@ -178,7 +201,7 @@ static int copydir(const struct vol *vol, int dirfd, char *src, char *dst) return AFPERR_PARAM; /* try to create the destination directory */ - if (AFP_OK != (err = netatalk_mkdir(dst)) ) { + if (AFP_OK != (err = netatalk_mkdir(vol, dst)) ) { closedir(dp); return err; } @@ -280,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) { @@ -355,19 +378,19 @@ static struct path *path_from_dir(struct vol *vol, struct dir *dir, struct path 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); /* 3 */ + memcpy(ret->m_name, cfrombstr(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 { ret->u_name = ret->m_name + blength(dir->d_m_name) + 1; - memcpy(ret->u_name, cfrombstring(dir->d_u_name), blength(dir->d_u_name) + 1); + memcpy(ret->u_name, cfrombstr(dir->d_u_name), blength(dir->d_u_name) + 1); } ret->d_dir = dir; LOG(log_debug, logtype_afpd, "cname('%s') {path-from-dir: AFPERR_ACCESS. curdir:'%s', path:'%s'}", - cfrombstring(dir->d_fullpath), - cfrombstring(curdir->d_fullpath), + cfrombstr(dir->d_fullpath), + cfrombstr(curdir->d_fullpath), ret->u_name); return ret; @@ -376,12 +399,12 @@ static struct path *path_from_dir(struct vol *vol, struct dir *dir, struct path 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, cfrombstr(dir->d_m_name), blength(dir->d_m_name) + 1); if (dir->d_m_name == dir->d_u_name) { ret->u_name = ret->m_name; } else { ret->u_name = ret->m_name + blength(dir->d_m_name) + 1; - memcpy(ret->u_name, cfrombstring(dir->d_u_name), blength(dir->d_u_name) + 1); + memcpy(ret->u_name, cfrombstr(dir->d_u_name), blength(dir->d_u_name) + 1); } ret->d_dir = NULL; /* 4 */ @@ -408,12 +431,91 @@ 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 * * Resolve a DID, allocate a struct dir for it * 1. Check for special CNIDs 0 (invalid), 1 and 2. - * 2. Check if the DID is in the cache. + * 2a. Check if the DID is in the cache. + * 2b. Check if it's really a dir (d_fullpath != NULL) because we cache files too. * 3. If it's not in the cache resolve it via the database. * 4. Build complete server-side path to the dir. * 5. Check if it exists and is a directory. @@ -424,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) { @@ -441,22 +540,30 @@ 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) { /* 2 */ - if (lstat(cfrombstring(ret->d_fullpath), &st) != 0) { + if ((ret = dircache_search_by_did(vol, did)) != NULL) { /* 2a */ + if (ret->d_fullpath == NULL) { /* 2b */ + afp_errno = AFPERR_BADTYPE; + 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)); switch (errno) { case ENOENT: @@ -465,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(); @@ -480,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; @@ -493,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; @@ -507,9 +623,9 @@ struct dir *dirlookup(const struct vol *vol, cnid_t did) } /* stat it and check if it's a dir */ - LOG(log_debug, logtype_afpd, "dirlookup: {stating %s}", cfrombstring(fullpath)); + LOG(log_debug, logtype_afpd, "dirlookup: {stating %s}", cfrombstr(fullpath)); - if (stat(cfrombstring(fullpath), &st) != 0) { /* 5a */ + if (stat(cfrombstr(fullpath), &st) != 0) { /* 5a */ switch (errno) { case ENOENT: afp_errno = AFPERR_NOOBJ; @@ -540,26 +656,23 @@ struct dir *dirlookup(const struct vol *vol, cnid_t did) } /* Create struct dir */ - if ((ret = dir_new(mpath, upath, vol, pdid, did, fullpath)) == NULL) { /* 6 */ + if ((ret = dir_new(mpath, upath, vol, pdid, did, fullpath, st.st_ctime)) == NULL) { /* 6 */ LOG(log_error, logtype_afpd, "dirlookup(did: %u) {%s, %s}: %s", ntohl(did), mpath, upath, strerror(errno)); err = 1; goto exit; } - + /* 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), cfrombstring(ret->d_fullpath)); - exit: + if (upath) free(upath); 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) { @@ -567,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; } @@ -662,7 +779,8 @@ int caseenumerate(const struct vol *vol, struct path *path, struct dir *dir) * @param vol (r) pointer to struct vol * @param pdid (r) Parent CNID * @param did (r) CNID - * @param fullpath (r) Full unix path to dir + * @param path (r) Full unix path to dir or NULL for files + * @param ctime (r) st_ctime from stat * * @returns pointer to new struct dir or NULL on error * @@ -673,7 +791,8 @@ struct dir *dir_new(const char *m_name, const struct vol *vol, cnid_t pdid, cnid_t did, - bstring path) + bstring path, + time_t ctime) { struct dir *dir; @@ -707,6 +826,7 @@ struct dir *dir_new(const char *m_name, dir->d_pdid = pdid; dir->d_vid = vol->v_vid; dir->d_fullpath = path; + dir->ctime_dircache = ctime; return dir; } @@ -731,14 +851,13 @@ void dir_free(struct dir *dir) * @brief Create struct dir from struct path * * 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 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. * 4. Add it to the cache. * - * @param vol (r) pointer to struct vol + * @param vol (r) pointer to struct vol, possibly modified in callee * @param dir (r) pointer to parrent directory * @param path (rw) pointer to struct path with valid path->u_name * @param len (r) strlen of path->u_name @@ -747,7 +866,7 @@ void dir_free(struct dir *dir) * * @note Function also assigns path->m_name from path->u_name. */ -struct dir *dir_add(const struct vol *vol, const struct dir *dir, struct path *path, int len) +struct dir *dir_add(struct vol *vol, const struct dir *dir, struct path *path, int len) { int err = 0; struct dir *cdir = NULL; @@ -761,14 +880,14 @@ struct dir *dir_add(const struct vol *vol, const struct dir *dir, struct path *p AFP_ASSERT(path); AFP_ASSERT(len > 0); - if ((cdir = dircache_search_by_name(vol, dir, path->u_name, strlen(path->u_name))) != NULL) { + if ((cdir = dircache_search_by_name(vol, dir, path->u_name, strlen(path->u_name), path->st.st_ctime)) != 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, - ntohl(cdir->d_did), cfrombstring(dir->d_fullpath)); + ntohl(dir->d_did), cfrombstr(dir->d_fullpath), path->u_name, + ntohl(cdir->d_did), cfrombstr(dir->d_fullpath)); if (dir_remove(vol, cdir) != 0) { dircache_dump(); - exit(EXITERR_SYS); + AFP_PANIC("dir_add"); } } @@ -789,6 +908,7 @@ struct dir *dir_add(const struct vol *vol, const struct dir *dir, struct path *p /* 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; } @@ -804,20 +924,20 @@ struct dir *dir_add(const struct vol *vol, const struct dir *dir, struct path *p } /* Allocate and initialize struct dir */ - if ((cdir = dir_new( path->m_name, path->u_name, vol, dir->d_did, id, fullpath)) == NULL) { /* 3 */ + if ((cdir = dir_new( path->m_name, path->u_name, vol, dir->d_did, id, fullpath, path->st.st_ctime)) == NULL) { /* 3 */ err = 4; goto exit; } - if ((dircache_add(cdir)) != 0) { /* 4 */ - LOG(log_error, logtype_afpd, "dir_add: fatal dircache error: %s", cfrombstring(fullpath)); + if ((dircache_add(vol, cdir)) != 0) { /* 4 */ + LOG(log_error, logtype_afpd, "dir_add: fatal dircache error: %s", cfrombstr(fullpath)); exit(EXITERR_SYS); } exit: if (err != 0) { LOG(log_debug, logtype_afpd, "dir_add('%s/%s'): error: %u", - cfrombstring(dir->d_u_name), path->u_name, err); + cfrombstr(dir->d_u_name), path->u_name, err); if (adp) ad_close_metadata(adp); @@ -829,20 +949,33 @@ exit: } else { /* no error */ LOG(log_debug, logtype_afpd, "dir_add(did:%u,'%s/%s'): {cached: %u,'%s'}", - ntohl(dir->d_did), cfrombstring(dir->d_fullpath), path->u_name, - ntohl(cdir->d_did), cfrombstring(cdir->d_fullpath)); + ntohl(dir->d_did), cfrombstr(dir->d_fullpath), path->u_name, + ntohl(cdir->d_did), cfrombstr(cdir->d_fullpath)); } return(cdir); } /*! - * @brief Remove a dir from a cache and free it and any ressources with it + * Free the queue with invalid struct dirs + * + * This gets called at the end of every AFP func. + */ +void dir_free_invalid_q(void) +{ + struct dir *dir; + while (dir = (struct dir *)dequeue(invalid_dircache_entries)) + dir_free(dir); +} + +/*! + * @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. Remove the dir plus any allocated resources it references + * 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 * @param (rw) pointer to struct dir @@ -855,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 || 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; - } + LOG(log_debug, logtype_afpd, "dir_remove(did:%u,'%s'): {removing}", + ntohl(dir->d_did), cfrombstr(dir->d_u_name)); - 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); - } - } + dircache_remove(vol, dir, DIRCACHE | DIDNAME_INDEX | QUEUE_INDEX); /* 2 */ + enqueue(invalid_dircache_entries, dir); /* 3 */ - LOG(log_debug, logtype_afpd, "dir_remove(did:%u,'%s'): {removing}", - ntohl(dir->d_did), cfrombstring(dir->d_fullpath)); + if (curdir == dir) /* 4 */ + curdir = NULL; - dircache_remove(vol, dir, DIRCACHE | DIDNAME_INDEX | QUEUE_INDEX); /* 3 */ - dir_free(dir); /* 4 */ + dir->d_did = CNID_INVALID; /* 5 */ return 0; } +#if 0 /* unused */ /*! * @brief Modify a struct dir, adjust cache * @@ -888,6 +1015,7 @@ int dir_remove(const struct vol *vol, struct dir *dir) * @param did (r) new DID * @param new_mname (r) new mac-name * @param new_uname (r) new unix-name + * @param pdir_fullpath (r) new fullpath of parent dir */ int dir_modify(const struct vol *vol, struct dir *dir, @@ -925,7 +1053,7 @@ int dir_modify(const struct vol *vol, dir->d_u_name = dir->d_m_name; } else { if ((dir->d_u_name = bfromcstr(new_uname)) == NULL) { - LOG(log_error, logtype_afpd, "renamedir: bassigncstr: %s", strerror(errno) ); + LOG(log_error, logtype_afpd, "dir_modify: bassigncstr: %s", strerror(errno) ); return -1; } } @@ -946,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(); - exit(EXITERR_SYS); + AFP_PANIC("dir_modify"); } return ret; } +#endif /*! * @brief Resolve a catalog node name path @@ -993,7 +1122,7 @@ struct path *cname(struct vol *vol, struct dir *dir, char **cpath) int size = 0; int toUTF8 = 0; - LOG(log_maxdebug, logtype_afpd, "came('%s'): {start}", cfrombstring(dir->d_fullpath)); + LOG(log_maxdebug, logtype_afpd, "came('%s'): {start}", cfrombstr(dir->d_fullpath)); data = *cpath; afp_errno = AFPERR_NOOBJ; @@ -1034,7 +1163,7 @@ struct path *cname(struct vol *vol, struct dir *dir, char **cpath) if (movecwd(vol, dir) < 0 ) { LOG(log_debug, logtype_afpd, "cname(did:%u): failed to chdir to '%s'", - ntohl(dir->d_did), cfrombstring(dir->d_fullpath)); + ntohl(dir->d_did), cfrombstr(dir->d_fullpath)); if (len == 0) return path_from_dir(vol, dir, &ret); else @@ -1062,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; } @@ -1075,7 +1204,7 @@ struct path *cname(struct vol *vol, struct dir *dir, char **cpath) return NULL; } - LOG(log_maxdebug, logtype_afpd, "came('%s'): {node: '%s}", cfrombstring(dir->d_fullpath), ret.u_name); + LOG(log_maxdebug, logtype_afpd, "came('%s'): {node: '%s}", cfrombstr(dir->d_fullpath), ret.u_name); /* Prevent access to our special folders like .AppleDouble */ if (check_name(vol, ret.u_name)) { @@ -1091,7 +1220,7 @@ struct path *cname(struct vol *vol, struct dir *dir, char **cpath) * root parent (did 1) has one child: the volume. Requests for did=1 with * some must check against the volume name. */ - if ((strcmp(cfrombstring(vol->v_root->d_m_name), ret.m_name)) == 0) + if ((strcmp(cfrombstr(vol->v_root->d_m_name), ret.m_name)) == 0) cdir = vol->v_root; else return NULL; @@ -1118,13 +1247,15 @@ struct path *cname(struct vol *vol, struct dir *dir, char **cpath) * this will terminate clean in while (1) because len == 0, * 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); + LOG(log_maxdebug, logtype_afpd, "came('%s'): {leave-cnode ENOENT (possile create request): '%s'}", + cfrombstr(dir->d_fullpath), ret.u_name); continue; /* 10 */ } switch (ret.st.st_mode & S_IFMT) { case S_IFREG: /* 11 */ - LOG(log_debug, logtype_afpd, "came('%s'): {file: '%s'}", cfrombstring(dir->d_fullpath), ret.u_name); + LOG(log_debug, logtype_afpd, "came('%s'): {file: '%s'}", + cfrombstr(dir->d_fullpath), ret.u_name); if (len > 0) { /* it wasn't the last part, so we have a bogus path request */ afp_errno = AFPERR_PARAM; @@ -1132,9 +1263,11 @@ struct path *cname(struct vol *vol, struct dir *dir, char **cpath) } continue; /* continues while loop */ case S_IFLNK: /* 12 */ - LOG(log_debug, logtype_afpd, "came('%s'): {link: '%s'}", cfrombstring(dir->d_fullpath), ret.u_name); + LOG(log_debug, logtype_afpd, "came('%s'): {link: '%s'}", + cfrombstr(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); + LOG(log_warning, logtype_afpd, "came('%s'): {symlinked dir: '%s'}", + cfrombstr(dir->d_fullpath), ret.u_name); afp_errno = AFPERR_PARAM; return NULL; } @@ -1149,7 +1282,7 @@ 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, ret.u_name, unamelen); /* 14 */ + cdir = dircache_search_by_name(vol, dir, ret.u_name, unamelen, ret.st.st_ctime); /* 14 */ if (cdir == NULL) { /* Not in cache, create one */ if ((cdir = dir_add(vol, dir, &ret, unamelen)) == NULL) { /* 15 */ @@ -1163,7 +1296,7 @@ struct path *cname(struct vol *vol, struct dir *dir, char **cpath) /* Now chdir to the evaluated dir */ 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)); + cfrombstr(curdir->d_fullpath), cfrombstr(cdir->d_fullpath), strerror(errno)); if (len == 0) return path_from_dir(vol, cdir, &ret); else @@ -1185,8 +1318,8 @@ struct path *cname(struct vol *vol, struct dir *dir, char **cpath) } LOG(log_debug, logtype_afpd, "came('%s') {end: curdir:'%s', path:'%s'}", - cfrombstring(dir->d_fullpath), - cfrombstring(curdir->d_fullpath), + cfrombstr(dir->d_fullpath), + cfrombstr(curdir->d_fullpath), ret.u_name); return &ret; @@ -1207,21 +1340,20 @@ 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')", - cfrombstring(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')", ntohl(dir->d_did), cfrombstring(dir->d_fullpath)); + LOG(log_debug, logtype_afpd, "movecwd(to: did: %u, \"%s\")", + ntohl(dir->d_did), cfrombstr(dir->d_fullpath)); - 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 = lchdir(cfrombstr(dir->d_fullpath))) != 0 ) { + 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 */ afp_errno = AFPERR_BADTYPE; @@ -1281,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; } @@ -1364,7 +1504,7 @@ int getdirparams(const struct vol *vol, case DIRPBIT_ATTR : if ( isad ) { ad_getattr(&ad, &ashort); - } else if (invisible_dots(vol, cfrombstring(dir->d_u_name))) { + } else if (invisible_dots(vol, cfrombstr(dir->d_u_name))) { ashort = htons(ATTRBIT_INVISIBLE); } else ashort = 0; @@ -1410,7 +1550,7 @@ int getdirparams(const struct vol *vol, memcpy(data + FINDERINFO_FRVIEWOFF, &ashort, sizeof(ashort)); /* dot files are by default visible */ - if (invisible_dots(vol, cfrombstring(dir->d_u_name))) { + if (invisible_dots(vol, cfrombstr(dir->d_u_name))) { ashort = htons(FINDERINFO_INVISIBLE); memcpy(data + FINDERINFO_FRFLAGOFF, &ashort, sizeof(ashort)); } @@ -1533,12 +1673,12 @@ int getdirparams(const struct vol *vol, if ( l_nameoff ) { ashort = htons( data - buf ); memcpy( l_nameoff, &ashort, sizeof( ashort )); - data = set_name(vol, data, pdid, cfrombstring(dir->d_m_name), dir->d_did, 0); + data = set_name(vol, data, pdid, cfrombstr(dir->d_m_name), dir->d_did, 0); } if ( utf_nameoff ) { ashort = htons( data - buf ); memcpy( utf_nameoff, &ashort, sizeof( ashort )); - data = set_name(vol, data, pdid, cfrombstring(dir->d_m_name), dir->d_did, utf8); + data = set_name(vol, data, pdid, cfrombstr(dir->d_m_name), dir->d_did, utf8); } if ( isad ) { ad_close_metadata( &ad ); @@ -1775,7 +1915,7 @@ int setdirparams(struct vol *vol, struct path *path, u_int16_t d_bitmap, char *b * to set our name, etc. */ if ( (ad_get_HF_flags( &ad ) & O_CREAT)) { - ad_setname(&ad, cfrombstring(curdir->d_m_name)); + ad_setname(&ad, cfrombstr(curdir->d_m_name)); } } @@ -2037,7 +2177,7 @@ int afp_syncdir(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, if ( fsync(dfd) < 0 ) LOG(log_error, logtype_afpd, "afp_syncdir(%s): %s", - vol->ad_path(cfrombstring(dir->d_u_name), ADFLAGS_DIR), strerror(errno) ); + vol->ad_path(cfrombstr(dir->d_u_name), ADFLAGS_DIR), strerror(errno) ); close(dfd); } @@ -2086,7 +2226,7 @@ int afp_createdir(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_ upath = s_path->u_name; - if (AFP_OK != (err = netatalk_mkdir( upath))) { + if (AFP_OK != (err = netatalk_mkdir(vol, upath))) { return err; } @@ -2113,15 +2253,12 @@ 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); createdir_done: -#ifdef HAVE_NFSv4_ACLS - /* FIXME: are we really inside the created dir? */ - addir_inherit_acl(vol); -#endif - memcpy( rbuf, &dir->d_did, sizeof( u_int32_t )); *rbuflen = sizeof( u_int32_t ); setvoltime(obj, vol ); @@ -2182,11 +2319,6 @@ int renamedir(const struct vol *vol, ad_close_metadata( &ad); } - if (dir_modify(vol, dir, curdir->d_did, 0, newname, dst, curdir->d_fullpath) != 0) { - LOG(log_error, logtype_afpd, "renamedir: fatal error from dir_modify: %s -> %s", src, dst); - return AFPERR_MISC; - } - return( AFP_OK ); } @@ -2195,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 ); } @@ -2219,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; } @@ -2231,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; } @@ -2242,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; } - err = netatalk_rmdir_all_errors(-1, cfrombstring(fdir->d_u_name)); + 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. @@ -2276,7 +2419,6 @@ int afp_mapid(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *r sfunc = (unsigned char) *ibuf++; *rbuflen = 0; - if (sfunc >= 3 && sfunc <= 6) { if (afp_version < 30) { return( AFPERR_PARAM ); @@ -2315,17 +2457,18 @@ int afp_mapid(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *r name = NULL; } break; -#ifdef HAVE_NFSv4_ACLS + case 5 : /* UUID -> username */ case 6 : /* UUID -> groupname */ if ((afp_version < 32) || !(obj->options.flags & OPTION_UUID )) return AFPERR_PARAM; LOG(log_debug, logtype_afpd, "afp_mapid: valid UUID request"); uuidtype_t type; - len = getnamefromuuid( ibuf, &name, &type); + len = getnamefromuuid((unsigned char*) ibuf, &name, &type); if (len != 0) /* its a error code, not len */ return AFPERR_NOITEM; - if (type == UUID_USER) { + switch (type) { + case UUID_USER: if (( pw = getpwnam( name )) == NULL ) return( AFPERR_NOITEM ); LOG(log_debug, logtype_afpd, "afp_mapid: name:%s -> uid:%d", name, pw->pw_uid); @@ -2336,7 +2479,8 @@ int afp_mapid(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *r memcpy( rbuf, &id, sizeof( id )); rbuf += sizeof( id ); *rbuflen = 2 * sizeof( id ); - } else { /* type == UUID_GROUP */ + break; + case UUID_GROUP: if (( gr = getgrnam( name )) == NULL ) return( AFPERR_NOITEM ); LOG(log_debug, logtype_afpd, "afp_mapid: group:%s -> gid:%d", name, gr->gr_gid); @@ -2347,9 +2491,15 @@ int afp_mapid(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *r memcpy( rbuf, &id, sizeof( id )); rbuf += sizeof( id ); *rbuflen = 2 * sizeof( id ); + break; + case UUID_LOCAL: + free(name); + return (AFPERR_NOITEM); + default: + return AFPERR_MISC; } break; -#endif + default : return( AFPERR_PARAM ); } @@ -2403,7 +2553,6 @@ int afp_mapname(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, siz case 4 : len = (unsigned char) *ibuf++; break; -#ifdef HAVE_NFSv4_ACLS case 5 : /* username -> UUID */ case 6 : /* groupname -> UUID */ if ((afp_version < 32) || !(obj->options.flags & OPTION_UUID )) @@ -2412,7 +2561,6 @@ int afp_mapname(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, siz len = ntohs(ulen); ibuf += 2; break; -#endif default : return( AFPERR_PARAM ); } @@ -2446,20 +2594,18 @@ int afp_mapname(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, siz memcpy( rbuf, &id, sizeof( id )); *rbuflen = sizeof( id ); break; -#ifdef HAVE_NFSv4_ACLS case 5 : /* username -> UUID */ LOG(log_debug, logtype_afpd, "afp_mapname: name: %s",ibuf); - if (0 != getuuidfromname(ibuf, UUID_USER, rbuf)) + if (0 != getuuidfromname(ibuf, UUID_USER, (unsigned char *)rbuf)) return AFPERR_NOITEM; *rbuflen = UUID_BINSIZE; break; case 6 : /* groupname -> UUID */ LOG(log_debug, logtype_afpd, "afp_mapname: name: %s",ibuf); - if (0 != getuuidfromname(ibuf, UUID_GROUP, rbuf)) + if (0 != getuuidfromname(ibuf, UUID_GROUP, (unsigned char *)rbuf)) return AFPERR_NOITEM; *rbuflen = UUID_BINSIZE; break; -#endif } } return( AFP_OK );