static am_node * amfs_direct_readlink(am_node *mp, int *error_return) { am_node *xp; int rc = 0; xp = next_nonerror_node(mp->am_child); if (!xp) { if (!mp->am_al->al_mnt->mf_private) amfs_mkcacheref(mp->am_al->al_mnt); xp = amfs_generic_lookup_child(mp, mp->am_path + 1, &rc, VLOOK_CREATE); if (xp && rc < 0) xp = amfs_generic_mount_child(xp, &rc); } if (xp) { new_ttl(xp); /* (7/12/89) from Rein Tollevik */ return xp; } if (amd_state == Finishing) rc = ENOENT; *error_return = rc; return 0; }
/* * This readdir function which call a special version of it that allows * browsing if browsable_dirs=yes was set on the map. */ int amfs_generic_readdir(am_node *mp, nfscookie cookie, nfsdirlist *dp, nfsentry *ep, u_int count) { u_int gen = *(u_int *) cookie; am_node *xp; mntent_t mnt; dp->dl_eof = FALSE; /* assume readdir not done */ /* check if map is browsable */ if (mp->am_al->al_mnt && mp->am_al->al_mnt->mf_mopts) { mnt.mnt_opts = mp->am_al->al_mnt->mf_mopts; if (amu_hasmntopt(&mnt, "fullybrowsable")) return amfs_readdir_browsable(mp, cookie, dp, ep, count, TRUE); if (amu_hasmntopt(&mnt, "browsable")) return amfs_readdir_browsable(mp, cookie, dp, ep, count, FALSE); } /* when gen is 0, we start reading from the beginning of the directory */ if (gen == 0) { /* * In the default instance (which is used to start a search) we return * "." and "..". * * This assumes that the count is big enough to allow both "." and ".." * to be returned in a single packet. If it isn't (which would be * fairly unbelievable) then tough. */ dlog("amfs_generic_readdir: default search"); /* * Check for enough room. This is extremely approximate but is more * than enough space. Really need 2 times: * 4byte fileid * 4byte cookie * 4byte name length * 4byte name * plus the dirlist structure */ if (count < (2 * (2 * (sizeof(*ep) + sizeof("..") + 4) + sizeof(*dp)))) return EINVAL; xp = next_nonerror_node(mp->am_child); dp->dl_entries = ep; /* construct "." */ ep[0].ne_fileid = mp->am_gen; ep[0].ne_name = "."; ep[0].ne_nextentry = &ep[1]; (void)memset(ep[0].ne_cookie, 0, sizeof(u_int)); /* construct ".." */ if (mp->am_parent) ep[1].ne_fileid = mp->am_parent->am_gen; else ep[1].ne_fileid = mp->am_gen; ep[1].ne_name = ".."; ep[1].ne_nextentry = NULL; (void)memcpy(ep[1].ne_cookie, (xp ? &xp->am_gen : &dotdotcookie), sizeof(dotdotcookie)); if (!xp) dp->dl_eof = TRUE; /* by default assume readdir done */ if (amuDebug(D_READDIR)) { nfsentry *ne; int j; for (j = 0, ne = ep; ne; ne = ne->ne_nextentry) { u_int cookie; (void)memcpy(&cookie, ne->ne_cookie, sizeof(cookie)); plog(XLOG_DEBUG, "gen1 key %4d \"%s\" fi=%d ck=%d", j++, ne->ne_name, ne->ne_fileid, cookie); } } return 0; } dlog("amfs_generic_readdir: real child"); if (gen == DOT_DOT_COOKIE) { dlog("amfs_generic_readdir: End of readdir in %s", mp->am_path); dp->dl_eof = TRUE; dp->dl_entries = NULL; if (amuDebug(D_READDIR)) plog(XLOG_DEBUG, "end of readdir eof=TRUE, dl_entries=0\n"); return 0; } /* non-browsable directories code */ xp = mp->am_child; while (xp && xp->am_gen != gen) xp = xp->am_osib; if (xp) { int nbytes = count / 2; /* conservative */ int todo = MAX_READDIR_ENTRIES; dp->dl_entries = ep; do { am_node *xp_next = next_nonerror_node(xp->am_osib); if (xp_next) { (void)memcpy(ep->ne_cookie, &xp_next->am_gen, sizeof(xp_next->am_gen)); } else { (void)memcpy(ep->ne_cookie, &dotdotcookie, sizeof(dotdotcookie)); dp->dl_eof = TRUE; } ep->ne_fileid = xp->am_gen; ep->ne_name = xp->am_name; nbytes -= sizeof(*ep) + 1; if (xp->am_name) nbytes -= strlen(xp->am_name); xp = xp_next; if (nbytes > 0 && !dp->dl_eof && todo > 1) { ep->ne_nextentry = ep + 1; ep++; --todo; } else { todo = 0; } } while (todo > 0); ep->ne_nextentry = NULL; if (amuDebug(D_READDIR)) { nfsentry *ne; int j; for (j=0,ne=ep; ne; ne=ne->ne_nextentry) { u_int cookie; (void)memcpy(&cookie, ne->ne_cookie, sizeof(cookie)); plog(XLOG_DEBUG, "gen2 key %4d \"%s\" fi=%d ck=%d", j++, ne->ne_name, ne->ne_fileid, cookie); } } return 0; } return ESTALE; }
static int amfs_readdir3(am_node *mp, am_cookie3 cookie, am_dirlist3 *dp, am_entry3 *ep, u_int count) { uint64 gen = *(uint64 *) (uintptr_t) cookie; am_node *xp; if (amuDebug(D_READDIR)) plog(XLOG_DEBUG, "amfs_readdir3 gen=%lu, count=%d", (long unsigned) gen, count); dp->eof = FALSE; /* assume readdir not done */ /* when gen is 0, we start reading from the beginning of the directory */ if (gen == 0) { size_t needed = needroom3(); /* * In the default instance (which is used to start a search) we return * "." and "..". * * This assumes that the count is big enough to allow both "." and ".." * to be returned in a single packet. If it isn't (which would be * fairly unbelievable) then tough. */ dlog("%s: default search", __func__); if (count < needed) { dlog("%s: not enough room %u < %zu", __func__, count, needed); return EINVAL; } xp = next_nonerror_node(mp->am_child); dp->entries = ep; /* construct "." */ ep[0].fileid = mp->am_gen; ep[0].name = "."; ep[0].cookie = 0; ep[0].nextentry = &ep[1]; /* construct ".." */ if (mp->am_parent) ep[1].fileid = mp->am_parent->am_gen; else ep[1].fileid = mp->am_gen; ep[1].name = ".."; ep[1].nextentry = NULL; ep[1].cookie = (xp ? xp->am_gen : dotdotcookie); if (!xp) dp->eof = TRUE; /* by default assume readdir done */ if (amuDebug(D_READDIR)) { am_entry3 *ne; int j; for (j = 0, ne = ep; ne; ne = ne->nextentry) { plog(XLOG_DEBUG, "gen1 key %4d \"%s\" fi=%lu ck=%lu", j++, ne->name, (long unsigned) ne->fileid, (long unsigned) ne->cookie); } } return 0; } dlog("%s: real child", __func__); if (gen == (uint64) DOT_DOT_COOKIE) { dlog("%s: End of readdir in %s", __func__, mp->am_path); dp->eof = TRUE; dp->entries = NULL; if (amuDebug(D_READDIR)) plog(XLOG_DEBUG, "end of readdir eof=TRUE, dl_entries=0\n"); return 0; } /* non-browsable directories code */ xp = mp->am_child; while (xp && xp->am_gen != gen) xp = xp->am_osib; if (xp) { int nbytes = count / 2; /* conservative */ int todo = MAX_READDIR_ENTRIES; dp->entries = ep; do { am_node *xp_next = next_nonerror_node(xp->am_osib); if (xp_next) { ep->cookie = xp_next->am_gen; } else { ep->cookie = (uint64) dotdotcookie; dp->eof = TRUE; } ep->fileid = xp->am_gen; ep->name = xp->am_name; nbytes -= sizeof(*ep) + 1; if (xp->am_name) nbytes -= strlen(xp->am_name); xp = xp_next; if (nbytes > 0 && !dp->dl_eof && todo > 1) { ep->nextentry = ep + 1; ep++; --todo; } else { todo = 0; } } while (todo > 0); ep->nextentry = NULL; if (amuDebug(D_READDIR)) { am_entry3 *ne; int j; for (j = 0, ne = ep; ne; ne = ne->nextentry) { plog(XLOG_DEBUG, "gen2 key %4d \"%s\" fi=%lu ck=%lu", j++, ne->name, (long unsigned) ne->fileid, (long unsigned) ne->cookie); } } return 0; } return ESTALE; }