FreeBSD/contrib/amd/amd/readdir.c
/* This one is called only if map is browsable */
This one is called only if map is browsable
This one is called only if map is browsable
static int
amfs_readdir_browsable(am_node *mp, nfscookie cookie, nfsdirlist *dp, nfsentry *ep, u_int count, int fully_browsable)
{
  u_int gen = *(u_int *) cookie;
  int chain_length, i;
  static nfsentry *te, *te_next;
  static int j;
  dp->dl_eof = FALSE;		
  if (amuDebug(D_READDIR))
    plog(XLOG_DEBUG, "amfs_readdir_browsable gen=%u, count=%d",
	 gen, count);
  if (gen == 0) {
    dlog("amfs_readdir_browsable: default search");
    if (count < (2 * (2 * (sizeof(*ep) + sizeof("..") + 4) + sizeof(*dp))))
      return EINVAL;
    chain_length = count / 128;
    te = te_next = NULL;
    dp->dl_entries = ep;
    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));
    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 = 0;
    *(u_int *) ep[1].ne_cookie = DOT_DOT_COOKIE;
    te = make_entry_chain(mp, dp->dl_entries, fully_browsable);
    if (!te)
      return 0;
    if (amuDebug(D_READDIR)) {
      nfsentry *ne;
      for (j = 0, ne = te; ne; ne = ne->ne_nextentry)
	plog(XLOG_DEBUG, "gen1 key %4d \"%s\"", j++, ne->ne_name);
    }
    te_next = te;
    for (i=1; i<chain_length; ++i) {
      te_next = te_next->ne_nextentry;
      if (!te_next)
	break;
    }
    if (te_next) {
      nfsentry *te_saved = te_next->ne_nextentry;
      te_next->ne_nextentry = NULL; 
      te_next = te_saved;	
      dp->dl_eof = FALSE;	
    } else {
      dp->dl_eof = TRUE;	
    }
    ep[1].ne_nextentry = te;	
    if (amuDebug(D_READDIR)) {
      nfsentry *ne;
      for (j = 0, ne = te; ne; ne = ne->ne_nextentry)
	plog(XLOG_DEBUG, "gen2 key %4d \"%s\"", j++, ne->ne_name);
      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);
      }
      plog(XLOG_DEBUG, "EOF is %d", dp->dl_eof);
    }
    return 0;
  } 
  dlog("amfs_readdir_browsable: real child");
  if (gen == DOT_DOT_COOKIE) {
    dlog("amfs_readdir_browsable: End of readdir in %s", mp->am_path);
    dp->dl_eof = TRUE;
    dp->dl_entries = 0;
    return 0;
  }
  dp->dl_eof = TRUE;
  dp->dl_entries = ep;
  te = te_next;			
  if (!te) {			
    dp->dl_entries = 0;
    return 0;
  }
  chain_length = count / 128;
  for (i = 1; i < chain_length; ++i) {
    te_next = te_next->ne_nextentry;
    if (!te_next)
      break;
  }
  if (te_next) {
    nfsentry *te_saved = te_next->ne_nextentry;
    te_next->ne_nextentry = NULL; 
    te_next = te_saved;		
    dp->dl_eof = FALSE;		
  }
  ep = te;			
  dp->dl_entries = ep;
  if (amuDebug(D_READDIR)) {
    nfsentry *ne;
    plog(XLOG_DEBUG, "dl_entries=%p, te_next=%p, dl_eof=%d",
	 dp->dl_entries, te_next, dp->dl_eof);
    for (ne = te; ne; ne = ne->ne_nextentry)
      plog(XLOG_DEBUG, "gen3 key %4d \"%s\"", j++, ne->ne_name);
  }
  return 0;
}
static int amfs_readdir_browsable ( am_node * mp , nfscookie cookie , nfsdirlist * dp , nfsentry * ep , u_int count , int fully_browsable ) { u_int gen = * ( u_int * ) cookie ; int chain_length , i ; static nfsentry * te , * te_next ; static int j ; dp -> dl_eof = FALSE ; if ( amuDebug ( D_READDIR ) ) plog ( XLOG_DEBUG , " " , gen , count ) ; if ( gen == 0 ) { dlog ( " " ) ; if ( count < ( 2 * ( 2 * ( sizeof ( * ep ) + sizeof ( " " ) + 4 ) + sizeof ( * dp ) ) ) ) return EINVAL ; chain_length = count / 128 ; te = te_next = NULL ; dp -> dl_entries = ep ; 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 ) ) ; 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 = 0 ; * ( u_int * ) ep [ 1 ] . ne_cookie = DOT_DOT_COOKIE ; te = make_entry_chain ( mp , dp -> dl_entries , fully_browsable ) ; if ( ! te ) return 0 ; if ( amuDebug ( D_READDIR ) ) { nfsentry * ne ; for ( j = 0 , ne = te ; ne ; ne = ne -> ne_nextentry ) plog ( XLOG_DEBUG , " \" \" " , j ++ , ne -> ne_name ) ; } te_next = te ; for ( i = 1 ; i < chain_length ; ++ i ) { te_next = te_next -> ne_nextentry ; if ( ! te_next ) break ; } if ( te_next ) { nfsentry * te_saved = te_next -> ne_nextentry ; te_next -> ne_nextentry = NULL ; te_next = te_saved ; dp -> dl_eof = FALSE ; } else { dp -> dl_eof = TRUE ; } ep [ 1 ] . ne_nextentry = te ; if ( amuDebug ( D_READDIR ) ) { nfsentry * ne ; for ( j = 0 , ne = te ; ne ; ne = ne -> ne_nextentry ) plog ( XLOG_DEBUG , " \" \" " , j ++ , ne -> ne_name ) ; for ( j = 0 , ne = ep ; ne ; ne = ne -> ne_nextentry ) { u_int cookie ; ( void ) memcpy ( & cookie , ne -> ne_cookie , sizeof ( cookie ) ) ; plog ( XLOG_DEBUG , " \" \" " , j ++ , ne -> ne_name , ne -> ne_fileid , cookie ) ; } plog ( XLOG_DEBUG , " " , dp -> dl_eof ) ; } return 0 ; } dlog ( " " ) ; if ( gen == DOT_DOT_COOKIE ) { dlog ( " " , mp -> am_path ) ; dp -> dl_eof = TRUE ; dp -> dl_entries = 0 ; return 0 ; } dp -> dl_eof = TRUE ; dp -> dl_entries = ep ; te = te_next ; if ( ! te ) { dp -> dl_entries = 0 ; return 0 ; } chain_length = count / 128 ; for ( i = 1 ; i < chain_length ; ++ i ) { te_next = te_next -> ne_nextentry ; if ( ! te_next ) break ; } if ( te_next ) { nfsentry * te_saved = te_next -> ne_nextentry ; te_next -> ne_nextentry = NULL ; te_next = te_saved ; dp -> dl_eof = FALSE ; } ep = te ; dp -> dl_entries = ep ; if ( amuDebug ( D_READDIR ) ) { nfsentry * ne ; plog ( XLOG_DEBUG , " " , dp -> dl_entries , te_next , dp -> dl_eof ) ; for ( ne = te ; ne ; ne = ne -> ne_nextentry ) plog ( XLOG_DEBUG , " \" \" " , j ++ , ne -> ne_name ) ; } return 0 ; }
This one is called only if map is browsable
This one is called only if map is browsable
/* assume readdir not done */ /*
     * 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.
     */ /*
     * 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 */ /*
     * compute # of entries to send in this chain.
     * heuristics: 128 bytes per entry.
     * This is too much probably, but it seems to work better because
     * of the re-entrant nature of nfs_readdir, and esp. on systems
     * like OpenBSD 2.2.
     */ /* reset static state counters */ /* construct "." */ /* construct ".." */ /*
     * If map is browsable, call a function make_entry_chain() to construct
     * a linked list of unmounted keys, and return it.  Then link the chain
     * to the regular list.  Get the chain only once, but return
     * chunks of it each time.
     */ /* return only "chain_length" entries */ /* terminate "te" chain */ /* save rest of "te" for next iteration */ /* tell readdir there's more */ /* tell readdir that's it */ /* append this chunk of "te" chain */ /* end of "if (gen == 0)" statement */ /*
   * If browsable directories, then continue serving readdir() with another
   * chunk of entries, starting from where we left off (when gen was equal
   * to 0).  Once again, assume last chunk served to readdir.
   */ /* reset 'te' from last saved te_next */ /* another indicator of end of readdir */ /*
   * compute # of entries to send in this chain.
   * heuristics: 128 bytes per entry.
   */ /* return only "chain_length" entries */ /* terminate "te" chain */ /* save rest of "te" for next iteration */ /* tell readdir there's more */ /* send next chunk of "te" chain */