FreeBSD/contrib/amd/amd/readdir.c
/*
 * This readdir function which call a special version of it that allows
 * browsing if browsable_dirs=yes was set on the map.
 */
This readdir function which call a special version of it that allows
browsing if browsable_dirs=yes was set on the map.
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;		
  if (mp->am_mnt && mp->am_mnt->mf_mopts) {
    mnt.mnt_opts = mp->am_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);
  }
  if (gen == 0) {
    dlog("amfs_generic_readdir: default search");
    if (count < (2 * (2 * (sizeof(*ep) + sizeof("..") + 4) + sizeof(*dp))))
      return EINVAL;
    xp = next_nonerror_node(mp->am_child);
    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 = (xp ? xp->am_gen : DOT_DOT_COOKIE);
    if (!xp)
      dp->dl_eof = TRUE;	
    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 = 0;
    if (amuDebug(D_READDIR))
      plog(XLOG_DEBUG, "end of readdir eof=TRUE, dl_entries=0\n");
    return 0;
  }
  xp = mp->am_child;
  while (xp && xp->am_gen != gen)
    xp = xp->am_osib;
  if (xp) {
    int nbytes = count / 2;	
    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 = 0;
    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;
}
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 ; if ( mp -> am_mnt && mp -> am_mnt -> mf_mopts ) { mnt . mnt_opts = mp -> am_mnt -> mf_mopts ; if ( amu_hasmntopt ( & mnt , " " ) ) return amfs_readdir_browsable ( mp , cookie , dp , ep , count , TRUE ) ; if ( amu_hasmntopt ( & mnt , " " ) ) return amfs_readdir_browsable ( mp , cookie , dp , ep , count , FALSE ) ; } if ( gen == 0 ) { dlog ( " " ) ; if ( count < ( 2 * ( 2 * ( sizeof ( * ep ) + sizeof ( " " ) + 4 ) + sizeof ( * dp ) ) ) ) return EINVAL ; xp = next_nonerror_node ( mp -> am_child ) ; 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 = ( xp ? xp -> am_gen : DOT_DOT_COOKIE ) ; if ( ! xp ) dp -> dl_eof = TRUE ; 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 , " \" \" " , j ++ , ne -> ne_name , ne -> ne_fileid , cookie ) ; } } return 0 ; } dlog ( " " ) ; if ( gen == DOT_DOT_COOKIE ) { dlog ( " " , mp -> am_path ) ; dp -> dl_eof = TRUE ; dp -> dl_entries = 0 ; if ( amuDebug ( D_READDIR ) ) plog ( XLOG_DEBUG , " \n " ) ; return 0 ; } xp = mp -> am_child ; while ( xp && xp -> am_gen != gen ) xp = xp -> am_osib ; if ( xp ) { int nbytes = count / 2 ; 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 = 0 ; 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 , " \" \" " , j ++ , ne -> ne_name , ne -> ne_fileid , cookie ) ; } } return 0 ; } return ESTALE ; }
This readdir function which call a special version of it that allows
 browsing if browsable_dirs=yes was set on the map.
This readdir function which call a special version of it that allows browsing if browsable_dirs = yes was set on the map .
/* assume readdir not done */ /* check if map is browsable */ /* when gen is 0, we start reading from the beginning of the directory */ /*
     * 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 */ /* construct "." */ /* construct ".." */ /* by default assume readdir done */ /* non-browsable directories code */ /* conservative */