readdir.c revision 174295
1192873Sweongyo/* 2192873Sweongyo * Copyright (c) 1997-2006 Erez Zadok 3192873Sweongyo * Copyright (c) 1990 Jan-Simon Pendry 4192873Sweongyo * Copyright (c) 1990 Imperial College of Science, Technology & Medicine 5192873Sweongyo * Copyright (c) 1990 The Regents of the University of California. 6192873Sweongyo * All rights reserved. 7192873Sweongyo * 8192873Sweongyo * This code is derived from software contributed to Berkeley by 9192873Sweongyo * Jan-Simon Pendry at Imperial College, London. 10192873Sweongyo * 11192873Sweongyo * Redistribution and use in source and binary forms, with or without 12192873Sweongyo * modification, are permitted provided that the following conditions 13192873Sweongyo * are met: 14192873Sweongyo * 1. Redistributions of source code must retain the above copyright 15192873Sweongyo * notice, this list of conditions and the following disclaimer. 16192873Sweongyo * 2. Redistributions in binary form must reproduce the above copyright 17192873Sweongyo * notice, this list of conditions and the following disclaimer in the 18192873Sweongyo * documentation and/or other materials provided with the distribution. 19192873Sweongyo * 3. All advertising materials mentioning features or use of this software 20192873Sweongyo * must display the following acknowledgment: 21192873Sweongyo * This product includes software developed by the University of 22192873Sweongyo * California, Berkeley and its contributors. 23192873Sweongyo * 4. Neither the name of the University nor the names of its contributors 24192873Sweongyo * may be used to endorse or promote products derived from this software 25192873Sweongyo * without specific prior written permission. 26192873Sweongyo * 27192873Sweongyo * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 28192873Sweongyo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 29192873Sweongyo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 30192873Sweongyo * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 31192873Sweongyo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 32192873Sweongyo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 33192873Sweongyo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 34192873Sweongyo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 35192873Sweongyo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 36192873Sweongyo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 37192873Sweongyo * SUCH DAMAGE. 38192873Sweongyo * 39192873Sweongyo * 40192873Sweongyo * File: am-utils/amd/readdir.c 41192873Sweongyo * 42192873Sweongyo */ 43192873Sweongyo 44192873Sweongyo 45192873Sweongyo#ifdef HAVE_CONFIG_H 46192873Sweongyo# include <config.h> 47192873Sweongyo#endif /* HAVE_CONFIG_H */ 48192873Sweongyo#include <am_defs.h> 49192873Sweongyo#include <amd.h> 50192873Sweongyo 51192873Sweongyo 52192873Sweongyo/**************************************************************************** 53192873Sweongyo *** MACROS *** 54194677Sthompsa ****************************************************************************/ 55192873Sweongyo#define DOT_DOT_COOKIE (u_int) 1 56192873Sweongyo#define MAX_CHAIN 2048 57192873Sweongyo 58192873Sweongyo 59192873Sweongyo/**************************************************************************** 60227309Sed *** FORWARD DEFINITIONS *** 61192873Sweongyo ****************************************************************************/ 62192873Sweongyostatic int key_already_in_chain(char *keyname, const nfsentry *chain); 63242126Shselaskystatic nfsentry *make_entry_chain(am_node *mp, const nfsentry *current_chain, int fully_browsable); 64192873Sweongyostatic int amfs_readdir_browsable(am_node *mp, nfscookie cookie, nfsdirlist *dp, nfsentry *ep, u_int count, int fully_browsable); 65192873Sweongyo 66192873Sweongyo 67192873Sweongyo/**************************************************************************** 68192873Sweongyo *** FUNCTIONS *** 69192873Sweongyo ****************************************************************************/ 70192873Sweongyo/* 71192873Sweongyo * Was: NEW_TOPLVL_READDIR 72192873Sweongyo * Search a chain for an entry with some name. 73192873Sweongyo * -Erez Zadok <ezk@cs.columbia.edu> 74192873Sweongyo */ 75198194Sweongyostatic int 76192873Sweongyokey_already_in_chain(char *keyname, const nfsentry *chain) 77192873Sweongyo{ 78192873Sweongyo const nfsentry *tmpchain = chain; 79192873Sweongyo 80192873Sweongyo while (tmpchain) { 81192873Sweongyo if (keyname && tmpchain->ne_name && STREQ(keyname, tmpchain->ne_name)) 82192873Sweongyo return 1; 83192873Sweongyo tmpchain = tmpchain->ne_nextentry; 84192873Sweongyo } 85192873Sweongyo 86192873Sweongyo return 0; 87194099Sthompsa} 88242126Shselasky 89192873Sweongyo 90192873Sweongyo/* 91192873Sweongyo * Create a chain of entries which are not linked. 92192873Sweongyo * -Erez Zadok <ezk@cs.columbia.edu> 93192873Sweongyo */ 94192873Sweongyostatic nfsentry * 95192873Sweongyomake_entry_chain(am_node *mp, const nfsentry *current_chain, int fully_browsable) 96192873Sweongyo{ 97192873Sweongyo static u_int last_cookie = (u_int) 2; /* monotonically increasing */ 98192873Sweongyo static nfsentry chain[MAX_CHAIN]; 99192873Sweongyo static int max_entries = MAX_CHAIN; 100192873Sweongyo char *key; 101223486Shselasky int num_entries = 0, i; 102197761Sweongyo u_int preflen = 0; 103197761Sweongyo nfsentry *retval = (nfsentry *) NULL; 104197761Sweongyo mntfs *mf; 105197761Sweongyo mnt_map *mmp; 106197761Sweongyo 107197761Sweongyo if (!mp) { 108197761Sweongyo plog(XLOG_DEBUG, "make_entry_chain: mp is (NULL)"); 109197761Sweongyo return retval; 110197761Sweongyo } 111197761Sweongyo mf = mp->am_mnt; 112197761Sweongyo if (!mf) { 113197761Sweongyo plog(XLOG_DEBUG, "make_entry_chain: mp->am_mnt is (NULL)"); 114223446Sgavin return retval; 115192873Sweongyo } 116192873Sweongyo mmp = (mnt_map *) mf->mf_private; 117192873Sweongyo if (!mmp) { 118192873Sweongyo plog(XLOG_DEBUG, "make_entry_chain: mp->am_mnt->mf_private is (NULL)"); 119192873Sweongyo return retval; 120192873Sweongyo } 121192873Sweongyo 122192873Sweongyo if (mp->am_pref) 123192873Sweongyo preflen = strlen(mp->am_pref); 124192873Sweongyo 125192873Sweongyo /* iterate over keys */ 126192873Sweongyo for (i = 0; i < NKVHASH; i++) { 127192873Sweongyo kv *k; 128192873Sweongyo for (k = mmp->kvhash[i]; k ; k = k->next) { 129192873Sweongyo 130192873Sweongyo /* 131192873Sweongyo * Skip unwanted entries which are either not real entries or 132192873Sweongyo * very difficult to interpret (wildcards...) This test needs 133192873Sweongyo * lots of improvement. Any takers? 134192873Sweongyo */ 135192873Sweongyo key = k->key; 136192873Sweongyo if (!key) 137192873Sweongyo continue; 138192873Sweongyo 139192873Sweongyo /* Skip '/defaults' */ 140192873Sweongyo if (STREQ(key, "/defaults")) 141192873Sweongyo continue; 142192873Sweongyo 143192873Sweongyo /* Skip '*' */ 144192873Sweongyo if (!fully_browsable && strchr(key, '*')) 145192873Sweongyo continue; 146192873Sweongyo 147192873Sweongyo /* 148192873Sweongyo * If the map has a prefix-string then check if the key starts with 149192873Sweongyo * this string, and if it does, skip over this prefix. If it has a 150192873Sweongyo * prefix and it doesn't match the start of the key, skip it. 151192873Sweongyo */ 152192873Sweongyo if (preflen) { 153192873Sweongyo if (preflen > strlen(key)) 154192873Sweongyo continue; 155192873Sweongyo if (!NSTREQ(key, mp->am_pref, preflen)) 156192873Sweongyo continue; 157192873Sweongyo key += preflen; 158192873Sweongyo } 159192873Sweongyo 160192873Sweongyo /* no more '/' are allowed, unless browsable_dirs=full was used */ 161192873Sweongyo if (!fully_browsable && strchr(key, '/')) 162192873Sweongyo continue; 163192873Sweongyo 164192873Sweongyo /* no duplicates allowed */ 165192873Sweongyo if (key_already_in_chain(key, current_chain)) 166192873Sweongyo continue; 167192873Sweongyo 168192873Sweongyo /* fill in a cell and link the entry */ 169192873Sweongyo if (num_entries >= max_entries) { 170192873Sweongyo /* out of space */ 171192873Sweongyo plog(XLOG_DEBUG, "make_entry_chain: no more space in chain"); 172192873Sweongyo if (num_entries > 0) { 173192873Sweongyo chain[num_entries - 1].ne_nextentry = 0; 174192873Sweongyo retval = &chain[0]; 175192873Sweongyo } 176192873Sweongyo return retval; 177192873Sweongyo } 178192873Sweongyo 179192873Sweongyo /* we have space. put entry in next cell */ 180192873Sweongyo ++last_cookie; 181192873Sweongyo chain[num_entries].ne_fileid = (u_int) last_cookie; 182192873Sweongyo *(u_int *) chain[num_entries].ne_cookie = (u_int) last_cookie; 183192873Sweongyo chain[num_entries].ne_name = key; 184192873Sweongyo if (num_entries < max_entries - 1) { /* link to next one */ 185192873Sweongyo chain[num_entries].ne_nextentry = &chain[num_entries + 1]; 186192873Sweongyo } 187192873Sweongyo ++num_entries; 188192873Sweongyo } /* end of "while (k)" */ 189192873Sweongyo } /* end of "for (i ... NKVHASH ..." */ 190192873Sweongyo 191196970Sphk /* terminate chain */ 192196970Sphk if (num_entries > 0) { 193196970Sphk chain[num_entries - 1].ne_nextentry = 0; 194196970Sphk retval = &chain[0]; 195196970Sphk } 196196970Sphk 197196970Sphk return retval; 198196970Sphk} 199196970Sphk 200196970Sphk 201196970Sphk 202196970Sphk/* This one is called only if map is browsable */ 203196970Sphkstatic int 204196970Sphkamfs_readdir_browsable(am_node *mp, nfscookie cookie, nfsdirlist *dp, nfsentry *ep, u_int count, int fully_browsable) 205196970Sphk{ 206192873Sweongyo u_int gen = *(u_int *) cookie; 207192873Sweongyo int chain_length, i; 208192873Sweongyo static nfsentry *te, *te_next; 209192873Sweongyo static int j; 210192873Sweongyo 211192873Sweongyo dp->dl_eof = FALSE; /* assume readdir not done */ 212192873Sweongyo 213192873Sweongyo if (amuDebug(D_READDIR)) 214192873Sweongyo plog(XLOG_DEBUG, "amfs_readdir_browsable gen=%u, count=%d", 215192873Sweongyo gen, count); 216192873Sweongyo 217192873Sweongyo if (gen == 0) { 218192873Sweongyo /* 219192873Sweongyo * In the default instance (which is used to start a search) we return 220192873Sweongyo * "." and "..". 221192873Sweongyo * 222192873Sweongyo * This assumes that the count is big enough to allow both "." and ".." 223192873Sweongyo * to be returned in a single packet. If it isn't (which would be 224192873Sweongyo * fairly unbelievable) then tough. 225192873Sweongyo */ 226192873Sweongyo dlog("amfs_readdir_browsable: default search"); 227192873Sweongyo /* 228192873Sweongyo * Check for enough room. This is extremely approximate but is more 229192873Sweongyo * than enough space. Really need 2 times: 230192873Sweongyo * 4byte fileid 231192873Sweongyo * 4byte cookie 232192873Sweongyo * 4byte name length 233192873Sweongyo * 4byte name 234192873Sweongyo * plus the dirlist structure */ 235192873Sweongyo if (count < (2 * (2 * (sizeof(*ep) + sizeof("..") + 4) + sizeof(*dp)))) 236192873Sweongyo return EINVAL; 237192873Sweongyo 238196970Sphk /* 239192873Sweongyo * compute # of entries to send in this chain. 240192873Sweongyo * heuristics: 128 bytes per entry. 241192873Sweongyo * This is too much probably, but it seems to work better because 242192873Sweongyo * of the re-entrant nature of nfs_readdir, and esp. on systems 243192873Sweongyo * like OpenBSD 2.2. 244192873Sweongyo */ 245192873Sweongyo chain_length = count / 128; 246192873Sweongyo 247192873Sweongyo /* reset static state counters */ 248192873Sweongyo te = te_next = NULL; 249192873Sweongyo 250192873Sweongyo dp->dl_entries = ep; 251192873Sweongyo 252192873Sweongyo /* construct "." */ 253192873Sweongyo ep[0].ne_fileid = mp->am_gen; 254192873Sweongyo ep[0].ne_name = "."; 255192873Sweongyo ep[0].ne_nextentry = &ep[1]; 256192873Sweongyo *(u_int *) ep[0].ne_cookie = 0; 257192873Sweongyo 258192873Sweongyo /* construct ".." */ 259192873Sweongyo if (mp->am_parent) 260192873Sweongyo ep[1].ne_fileid = mp->am_parent->am_gen; 261192873Sweongyo else 262192873Sweongyo ep[1].ne_fileid = mp->am_gen; 263192873Sweongyo 264192873Sweongyo ep[1].ne_name = ".."; 265192873Sweongyo ep[1].ne_nextentry = 0; 266192873Sweongyo *(u_int *) ep[1].ne_cookie = DOT_DOT_COOKIE; 267192873Sweongyo 268192873Sweongyo /* 269192873Sweongyo * If map is browsable, call a function make_entry_chain() to construct 270192873Sweongyo * a linked list of unmounted keys, and return it. Then link the chain 271192873Sweongyo * to the regular list. Get the chain only once, but return 272192873Sweongyo * chunks of it each time. 273192873Sweongyo */ 274192873Sweongyo te = make_entry_chain(mp, dp->dl_entries, fully_browsable); 275192873Sweongyo if (!te) 276192873Sweongyo return 0; 277192873Sweongyo if (amuDebug(D_READDIR)) { 278192873Sweongyo nfsentry *ne; 279192873Sweongyo for (j = 0, ne = te; ne; ne = ne->ne_nextentry) 280196970Sphk plog(XLOG_DEBUG, "gen1 key %4d \"%s\"", j++, ne->ne_name); 281192873Sweongyo } 282192873Sweongyo 283192873Sweongyo /* return only "chain_length" entries */ 284192873Sweongyo te_next = te; 285192873Sweongyo for (i=1; i<chain_length; ++i) { 286192873Sweongyo te_next = te_next->ne_nextentry; 287192873Sweongyo if (!te_next) 288192873Sweongyo break; 289192873Sweongyo } 290192873Sweongyo if (te_next) { 291192873Sweongyo nfsentry *te_saved = te_next->ne_nextentry; 292192873Sweongyo te_next->ne_nextentry = NULL; /* terminate "te" chain */ 293192873Sweongyo te_next = te_saved; /* save rest of "te" for next iteration */ 294192873Sweongyo dp->dl_eof = FALSE; /* tell readdir there's more */ 295192873Sweongyo } else { 296192873Sweongyo dp->dl_eof = TRUE; /* tell readdir that's it */ 297192873Sweongyo } 298192873Sweongyo ep[1].ne_nextentry = te; /* append this chunk of "te" chain */ 299192873Sweongyo if (amuDebug(D_READDIR)) { 300192873Sweongyo nfsentry *ne; 301192873Sweongyo for (j = 0, ne = te; ne; ne = ne->ne_nextentry) 302192873Sweongyo plog(XLOG_DEBUG, "gen2 key %4d \"%s\"", j++, ne->ne_name); 303192873Sweongyo for (j = 0, ne = ep; ne; ne = ne->ne_nextentry) 304192873Sweongyo plog(XLOG_DEBUG, "gen2+ key %4d \"%s\" fi=%d ck=%d", 305196970Sphk j++, ne->ne_name, ne->ne_fileid, *(u_int *)ne->ne_cookie); 306192873Sweongyo plog(XLOG_DEBUG, "EOF is %d", dp->dl_eof); 307192873Sweongyo } 308192873Sweongyo return 0; 309192873Sweongyo } /* end of "if (gen == 0)" statement */ 310192873Sweongyo 311192873Sweongyo dlog("amfs_readdir_browsable: real child"); 312192873Sweongyo 313192873Sweongyo if (gen == DOT_DOT_COOKIE) { 314192873Sweongyo dlog("amfs_readdir_browsable: End of readdir in %s", mp->am_path); 315192873Sweongyo dp->dl_eof = TRUE; 316192873Sweongyo dp->dl_entries = 0; 317192873Sweongyo return 0; 318192873Sweongyo } 319192873Sweongyo 320192873Sweongyo /* 321192873Sweongyo * If browsable directories, then continue serving readdir() with another 322192873Sweongyo * chunk of entries, starting from where we left off (when gen was equal 323192873Sweongyo * to 0). Once again, assume last chunk served to readdir. 324192873Sweongyo */ 325192873Sweongyo dp->dl_eof = TRUE; 326198194Sweongyo dp->dl_entries = ep; 327192873Sweongyo 328192873Sweongyo te = te_next; /* reset 'te' from last saved te_next */ 329192873Sweongyo if (!te) { /* another indicator of end of readdir */ 330192873Sweongyo dp->dl_entries = 0; 331192873Sweongyo return 0; 332192873Sweongyo } 333198194Sweongyo /* 334198194Sweongyo * compute # of entries to send in this chain. 335198194Sweongyo * heuristics: 128 bytes per entry. 336198194Sweongyo */ 337198194Sweongyo chain_length = count / 128; 338198194Sweongyo 339198194Sweongyo /* return only "chain_length" entries */ 340198194Sweongyo for (i = 1; i < chain_length; ++i) { 341198194Sweongyo te_next = te_next->ne_nextentry; 342198194Sweongyo if (!te_next) 343198194Sweongyo break; 344198194Sweongyo } 345198194Sweongyo if (te_next) { 346198194Sweongyo nfsentry *te_saved = te_next->ne_nextentry; 347198194Sweongyo te_next->ne_nextentry = NULL; /* terminate "te" chain */ 348198194Sweongyo te_next = te_saved; /* save rest of "te" for next iteration */ 349198194Sweongyo dp->dl_eof = FALSE; /* tell readdir there's more */ 350198194Sweongyo } 351198194Sweongyo ep = te; /* send next chunk of "te" chain */ 352198194Sweongyo dp->dl_entries = ep; 353198194Sweongyo if (amuDebug(D_READDIR)) { 354198194Sweongyo nfsentry *ne; 355198194Sweongyo plog(XLOG_DEBUG, "dl_entries=%p, te_next=%p, dl_eof=%d", 356198194Sweongyo dp->dl_entries, te_next, dp->dl_eof); 357198194Sweongyo for (ne = te; ne; ne = ne->ne_nextentry) 358198194Sweongyo plog(XLOG_DEBUG, "gen3 key %4d \"%s\"", j++, ne->ne_name); 359198194Sweongyo } 360198194Sweongyo return 0; 361198194Sweongyo} 362198194Sweongyo 363198194Sweongyo 364198194Sweongyo/* 365198194Sweongyo * This readdir function which call a special version of it that allows 366198194Sweongyo * browsing if browsable_dirs=yes was set on the map. 367192873Sweongyo */ 368192873Sweongyoint 369192873Sweongyoamfs_generic_readdir(am_node *mp, nfscookie cookie, nfsdirlist *dp, nfsentry *ep, u_int count) 370192873Sweongyo{ 371192873Sweongyo u_int gen = *(u_int *) cookie; 372192873Sweongyo am_node *xp; 373192873Sweongyo mntent_t mnt; 374192873Sweongyo 375192873Sweongyo dp->dl_eof = FALSE; /* assume readdir not done */ 376192873Sweongyo 377192873Sweongyo /* check if map is browsable */ 378192873Sweongyo if (mp->am_mnt && mp->am_mnt->mf_mopts) { 379192873Sweongyo mnt.mnt_opts = mp->am_mnt->mf_mopts; 380192873Sweongyo if (amu_hasmntopt(&mnt, "fullybrowsable")) 381192873Sweongyo return amfs_readdir_browsable(mp, cookie, dp, ep, count, TRUE); 382192873Sweongyo if (amu_hasmntopt(&mnt, "browsable")) 383192873Sweongyo return amfs_readdir_browsable(mp, cookie, dp, ep, count, FALSE); 384192873Sweongyo } 385192873Sweongyo 386192873Sweongyo /* when gen is 0, we start reading from the beginning of the directory */ 387192873Sweongyo if (gen == 0) { 388192873Sweongyo /* 389192873Sweongyo * In the default instance (which is used to start a search) we return 390192873Sweongyo * "." and "..". 391192873Sweongyo * 392192873Sweongyo * This assumes that the count is big enough to allow both "." and ".." 393192873Sweongyo * to be returned in a single packet. If it isn't (which would be 394192873Sweongyo * fairly unbelievable) then tough. 395192873Sweongyo */ 396192873Sweongyo dlog("amfs_generic_readdir: default search"); 397192873Sweongyo /* 398192873Sweongyo * Check for enough room. This is extremely approximate but is more 399192873Sweongyo * than enough space. Really need 2 times: 400192873Sweongyo * 4byte fileid 401192873Sweongyo * 4byte cookie 402192873Sweongyo * 4byte name length 403192873Sweongyo * 4byte name 404192873Sweongyo * plus the dirlist structure */ 405192873Sweongyo if (count < (2 * (2 * (sizeof(*ep) + sizeof("..") + 4) + sizeof(*dp)))) 406192873Sweongyo return EINVAL; 407192873Sweongyo 408192873Sweongyo xp = next_nonerror_node(mp->am_child); 409192873Sweongyo dp->dl_entries = ep; 410192873Sweongyo 411192873Sweongyo /* construct "." */ 412192873Sweongyo ep[0].ne_fileid = mp->am_gen; 413192873Sweongyo ep[0].ne_name = "."; 414192873Sweongyo ep[0].ne_nextentry = &ep[1]; 415192873Sweongyo *(u_int *) ep[0].ne_cookie = 0; 416192873Sweongyo 417192873Sweongyo /* construct ".." */ 418192873Sweongyo if (mp->am_parent) 419192873Sweongyo ep[1].ne_fileid = mp->am_parent->am_gen; 420192873Sweongyo else 421192873Sweongyo ep[1].ne_fileid = mp->am_gen; 422192873Sweongyo ep[1].ne_name = ".."; 423192873Sweongyo ep[1].ne_nextentry = 0; 424192873Sweongyo *(u_int *) ep[1].ne_cookie = (xp ? xp->am_gen : DOT_DOT_COOKIE); 425192873Sweongyo 426192873Sweongyo if (!xp) 427192873Sweongyo dp->dl_eof = TRUE; /* by default assume readdir done */ 428192873Sweongyo 429192873Sweongyo if (amuDebug(D_READDIR)) { 430192873Sweongyo nfsentry *ne; 431192873Sweongyo int j; 432192873Sweongyo for (j = 0, ne = ep; ne; ne = ne->ne_nextentry) 433192873Sweongyo plog(XLOG_DEBUG, "gen1 key %4d \"%s\" fi=%d ck=%d", 434192873Sweongyo j++, ne->ne_name, ne->ne_fileid, *(u_int *)ne->ne_cookie); 435192873Sweongyo } 436192873Sweongyo return 0; 437192873Sweongyo } 438192873Sweongyo dlog("amfs_generic_readdir: real child"); 439192873Sweongyo 440192873Sweongyo if (gen == DOT_DOT_COOKIE) { 441192873Sweongyo dlog("amfs_generic_readdir: End of readdir in %s", mp->am_path); 442192873Sweongyo dp->dl_eof = TRUE; 443192873Sweongyo dp->dl_entries = 0; 444192873Sweongyo if (amuDebug(D_READDIR)) 445196970Sphk plog(XLOG_DEBUG, "end of readdir eof=TRUE, dl_entries=0\n"); 446192873Sweongyo return 0; 447192873Sweongyo } 448196970Sphk 449196970Sphk /* non-browsable directories code */ 450196970Sphk xp = mp->am_child; 451196970Sphk while (xp && xp->am_gen != gen) 452192873Sweongyo xp = xp->am_osib; 453192873Sweongyo 454192873Sweongyo if (xp) { 455192873Sweongyo int nbytes = count / 2; /* conservative */ 456192873Sweongyo int todo = MAX_READDIR_ENTRIES; 457192873Sweongyo 458192873Sweongyo dp->dl_entries = ep; 459192873Sweongyo do { 460192873Sweongyo am_node *xp_next = next_nonerror_node(xp->am_osib); 461192873Sweongyo 462192873Sweongyo if (xp_next) { 463192873Sweongyo *(u_int *) ep->ne_cookie = xp_next->am_gen; 464192873Sweongyo } else { 465192873Sweongyo *(u_int *) ep->ne_cookie = DOT_DOT_COOKIE; 466192873Sweongyo dp->dl_eof = TRUE; 467192873Sweongyo } 468192873Sweongyo 469192873Sweongyo ep->ne_fileid = xp->am_gen; 470192873Sweongyo ep->ne_name = xp->am_name; 471192873Sweongyo nbytes -= sizeof(*ep) + 1; 472192873Sweongyo if (xp->am_name) 473192873Sweongyo nbytes -= strlen(xp->am_name); 474192873Sweongyo 475192873Sweongyo xp = xp_next; 476260284Sdim 477196970Sphk if (nbytes > 0 && !dp->dl_eof && todo > 1) { 478196970Sphk ep->ne_nextentry = ep + 1; 479196970Sphk ep++; 480196970Sphk --todo; 481196970Sphk } else { 482196970Sphk todo = 0; 483196970Sphk } 484196970Sphk } while (todo > 0); 485196970Sphk 486196970Sphk ep->ne_nextentry = 0; 487196970Sphk 488196970Sphk if (amuDebug(D_READDIR)) { 489196970Sphk nfsentry *ne; 490196970Sphk int j; 491196970Sphk for (j=0,ne=ep; ne; ne=ne->ne_nextentry) 492196970Sphk plog(XLOG_DEBUG, "gen2 key %4d \"%s\" fi=%d ck=%d", 493196970Sphk j++, ne->ne_name, ne->ne_fileid, *(u_int *)ne->ne_cookie); 494196970Sphk } 495196970Sphk return 0; 496196970Sphk } 497196970Sphk return ESTALE; 498196970Sphk} 499196970Sphk