diff -u -r -p -N ../../src.old/lib/libc/gen/closedir.c libc/gen/closedir.c --- lib/libc/gen/closedir.c 2005-04-26 10:04:59.000000000 -0500 +++ lib/libc/gen/closedir.c 2008-04-16 20:38:41.000000000 -0500 @@ -44,6 +44,7 @@ #include "un-namespace.h" #include "libc_private.h" +#include "dirent_private.h" /* * close a directory. @@ -55,12 +56,19 @@ closedir(DIR *dirp) if (__isthreaded) _pthread_mutex_lock((pthread_mutex_t *)&dirp->dd_lock); - _seekdir(dirp, dirp->dd_rewind); /* free seekdir storage */ + fd = dirp->dd_fd; dirp->dd_fd = -1; dirp->dd_loc = 0; - free(dirp->dd_buf); - _reclaim_telldir(dirp); + free(dirp->dd_buf); + + /* free seekdir/telldir storage */ + for (poslist = dirp->dd_internal; poslist; ) { + struct dirpos *nextpos = poslist->dp_next; + free(poslist); + poslist = nextpos; + } + if (__isthreaded) { _pthread_mutex_unlock((pthread_mutex_t *)&dirp->dd_lock); _pthread_mutex_destroy((pthread_mutex_t *)&dirp->dd_lock); diff -u -r -p -N ../../src.old/lib/libc/gen/dirent_private.h libc/gen/dirent_private.h --- /dev/null 1969-12-31 18:00:00.000000000 -0600 +++ lib/libc/gen/dirent_private.h 2008-04-16 20:39:14.000000000 -0500 @@ -0,0 +1,20 @@ + +/* $NetBSD: dirent_private.h,v 1.1 2006/05/17 20:36:50 christos Exp $ */ + +/* + * One struct _dirpos is malloced to describe the current directory + * position each time telldir is called. It records the current magic + * cookie returned by getdirentries and the offset within the buffer + * associated with that return value. + */ +struct dirpos { + struct dirpos *dp_next; /* next structure in list */ + off_t dp_seek; /* magic cookie returned by getdirentries */ + long dp_loc; /* offset of entry in buffer */ +}; + +struct _dirdesc; +void _seekdir_unlocked(struct _dirdesc *, long); +long _telldir_unlocked(struct _dirdesc *); + + diff -u -r -p -N ../../src.old/lib/libc/gen/opendir.c libc/gen/opendir.c --- lib/libc/gen/opendir.c 2005-11-12 18:07:42.000000000 -0600 +++ lib/libc/gen/opendir.c 2008-04-16 20:42:41.000000000 -0500 @@ -47,6 +47,7 @@ #include #include #include "un-namespace.h" +#include "dirent_private.h" /* * Open a directory. @@ -113,7 +114,8 @@ __opendir2(const char *name, int flags) /* * Set up seek point for rewinddir. */ - dirp->dd_rewind = telldir(dirp); + dirp->dd_internal = NULL; + (void)telldir(dirp); return (dirp); diff -u -r -p -N ../../src.old/lib/libc/gen/rewinddir.c libc/gen/rewinddir.c --- lib/libc/gen/rewinddir.c 2005-04-26 03:48:19.000000000 -0500 +++ lib/libc/gen/rewinddir.c 2008-04-16 20:43:18.000000000 -0500 @@ -37,10 +37,16 @@ */ #include +#include "dirent_private.h" void rewinddir(DIR *dirp) { - _seekdir(dirp, dirp->dd_rewind); - dirp->dd_rewind = telldir(dirp); + struct dirpos *dp = dirp->dd_internal; + + while (dp->dp_next) + dp = dp->dp_next; + + _seekdir(dirp, (long)(intptr_t)dp); + } diff -u -r -p -N ../../src.old/lib/libc/gen/seekdir.c libc/gen/seekdir.c --- lib/libc/gen/seekdir.c 2005-11-19 16:32:53.000000000 -0600 +++ lib/libc/gen/seekdir.c 2008-04-16 20:43:54.000000000 -0500 @@ -43,6 +43,7 @@ #include "un-namespace.h" #include "libc_private.h" +#include "dirent_private.h" /* * Seek to an entry in a directory. diff -u -r -p -N lib/libc/gen/telldir.c libc/gen/telldir.c --- lib/libc/gen/telldir.c 2007-11-20 23:48:31.000000000 -0600 +++ lib/libc/gen/telldir.c 2008-04-16 20:53:06.000000000 -0500 @@ -45,57 +45,30 @@ #include "un-namespace.h" #include "libc_private.h" - -/* - * The option SINGLEUSE may be defined to say that a telldir - * cookie may be used only once before it is freed. This option - * is used to avoid having memory usage grow without bound. - */ -#define SINGLEUSE - -/* - * One of these structures is malloced to describe the current directory - * position each time telldir is called. It records the current magic - * cookie returned by getdirentries and the offset within the buffer - * associated with that return value. - */ -struct ddloc { - struct ddloc *loc_next;/* next structure in list */ - long loc_index; /* key associated with structure */ - off_t loc_seek; /* magic cookie returned by getdirentries */ - long loc_loc; /* offset of entry in buffer */ - const DIR* loc_dirp; /* directory which used this entry */ -}; - -#define NDIRHASH 32 /* Num of hash lists, must be a power of 2 */ -#define LOCHASH(i) ((i)&(NDIRHASH-1)) - -static long dd_loccnt; /* Index of entry for sequential readdir's */ -static struct ddloc *dd_hash[NDIRHASH]; /* Hash list heads for ddlocs */ +#include "dirent_private.h" /* * return a pointer into a directory */ long -telldir(const DIR *dirp) +telldir(DIR *dirp) { - int index; - struct ddloc *lp; + struct dirpos *lp; - if ((lp = (struct ddloc *)malloc(sizeof(struct ddloc))) == NULL) - return (-1); - if (__isthreaded) - _pthread_mutex_lock((pthread_mutex_t *)&dirp->dd_lock); - index = dd_loccnt++; - lp->loc_index = index; - lp->loc_seek = dirp->dd_seek; - lp->loc_loc = dirp->dd_loc; - lp->loc_dirp = dirp; - lp->loc_next = dd_hash[LOCHASH(index)]; - dd_hash[LOCHASH(index)] = lp; - if (__isthreaded) - _pthread_mutex_unlock((pthread_mutex_t *)&dirp->dd_lock); - return (index); + for (lp = dirp->dd_internal; lp; lp = lp->dp_next) + if (lp->dp_seek == dirp->dd_seek && + lp->dp_loc == dirp->dd_loc) + return (intptr_t)lp; + if ((lp = malloc(sizeof(*lp))) == NULL) + return (-1); + + lp->dp_seek = dirp->dd_seek; + lp->dp_loc = dirp->dd_loc; + lp->dp_next = dirp->dd_internal; + dirp->dd_internal = lp; + + return (intptr_t)lp; + } /* @@ -105,59 +78,21 @@ telldir(const DIR *dirp) void _seekdir(DIR *dirp, long loc) { - struct ddloc *lp; - struct ddloc **prevlp; - struct dirent *dp; - - prevlp = &dd_hash[LOCHASH(loc)]; - lp = *prevlp; - while (lp != NULL) { - if (lp->loc_index == loc) - break; - prevlp = &lp->loc_next; - lp = lp->loc_next; - } - if (lp == NULL) - return; - if (lp->loc_loc == dirp->dd_loc && lp->loc_seek == dirp->dd_seek) - goto found; - lseek(dirp->dd_fd, lp->loc_seek, SEEK_SET); - dirp->dd_seek = lp->loc_seek; - dirp->dd_loc = 0; - while (dirp->dd_loc < lp->loc_loc) { - dp = _readdir_unlocked(dirp); - if (dp == NULL) - break; - } -found: -#ifdef SINGLEUSE - *prevlp = lp->loc_next; - free((caddr_t)lp); -#endif -} + struct dirpos *lp; + for (lp = dirp->dd_internal; lp; lp = lp->dp_next) + if ((intptr_t)lp == loc) + break; + + if (lp == NULL) + return; + + if (lp->dp_loc == dirp->dd_loc && lp->dp_seek == dirp->dd_seek) + return; + + dirp->dd_seek = lseek(dirp->dd_fd, lp->dp_seek, SEEK_SET); + dirp->dd_loc = 0; + while (dirp->dd_loc < lp->dp_loc) + if (_readdir_unlocked(dirp) == NULL) + break; -/* - * Reclaim memory for telldir cookies which weren't used. - */ -void -_reclaim_telldir(DIR *dirp) -{ - struct ddloc *lp; - struct ddloc **prevlp; - int i; - - for (i = 0; i < NDIRHASH; i++) { - prevlp = &dd_hash[i]; - lp = *prevlp; - while (lp != NULL) { - if (lp->loc_dirp == dirp) { - *prevlp = lp->loc_next; - free((caddr_t)lp); - lp = *prevlp; - continue; - } - prevlp = &lp->loc_next; - lp = lp->loc_next; - } - } } --- include/dirent.h 2007-11-20 15:03:43.000000000 -0600 +++ include/dirent.h 2008-03-12 11:17:12.000000000 -0500 @@ -59,7 +59,7 @@ char *dd_buf; /* data buffer */ int dd_len; /* size of data buffer */ long dd_unused01; /* old magic cookie returned by getdirentries */ - long dd_rewind; /* magic cookie for rewinding */ + void *dd_internal; /* state for seekdir/telldir */ int dd_flags; /* flags for readdir */ void *dd_lock; /* hack to avoid include */ off_t dd_seek; /* new magic cookie returned by getdirentries */ @@ -90,7 +90,7 @@ int closedir (DIR *); #ifndef _POSIX_SOURCE DIR *__opendir2 (const char *, int); -long telldir (const DIR *); +long telldir (DIR *); struct dirent *_readdir_unlocked(DIR *); void seekdir(DIR *, long); void _reclaim_telldir(DIR *);