diff options
| author | christos <christos@NetBSD.org> | 2006-05-17 20:36:50 +0000 |
|---|---|---|
| committer | christos <christos@NetBSD.org> | 2006-05-17 20:36:50 +0000 |
| commit | cfd3aebca47c5c3ef947e99fa964389716bb250f (patch) | |
| tree | 97f9c83b91b118ac7f22dbaa5e51945f1e994a82 | |
| parent | 54595e994676fcb788ae71a4165ca5ca4c65f595 (diff) | |
PR/24324: Arne H Juul: Re-implement seekdir/telldir using a pointer of
locations per directory instead of a global hash table to avoid memory
leak issues, and incorrect results.
| -rw-r--r-- | lib/libc/gen/closedir.c | 21 | ||||
| -rw-r--r-- | lib/libc/gen/directory.3 | 6 | ||||
| -rw-r--r-- | lib/libc/gen/dirent_private.h | 22 | ||||
| -rw-r--r-- | lib/libc/gen/opendir.c | 16 | ||||
| -rw-r--r-- | lib/libc/gen/readdir.c | 6 | ||||
| -rw-r--r-- | lib/libc/gen/rewinddir.c | 20 | ||||
| -rw-r--r-- | lib/libc/gen/seekdir.c | 10 | ||||
| -rw-r--r-- | lib/libc/gen/telldir.c | 98 | ||||
| -rw-r--r-- | lib/libc/include/extern.h | 10 |
9 files changed, 102 insertions, 107 deletions
diff --git a/lib/libc/gen/closedir.c b/lib/libc/gen/closedir.c index d169b2ae2de..5ba009b113e 100644 --- a/lib/libc/gen/closedir.c +++ b/lib/libc/gen/closedir.c @@ -1,4 +1,4 @@ -/* $NetBSD: closedir.c,v 1.14 2006/01/24 19:33:10 christos Exp $ */ +/* $NetBSD: closedir.c,v 1.15 2006/05/17 20:36:50 christos Exp $ */ /* * Copyright (c) 1983, 1993 @@ -34,7 +34,7 @@ #if 0 static char sccsid[] = "@(#)closedir.c 8.1 (Berkeley) 6/10/93"; #else -__RCSID("$NetBSD: closedir.c,v 1.14 2006/01/24 19:33:10 christos Exp $"); +__RCSID("$NetBSD: closedir.c,v 1.15 2006/05/17 20:36:50 christos Exp $"); #endif #endif /* LIBC_SCCS and not lint */ @@ -49,6 +49,8 @@ __RCSID("$NetBSD: closedir.c,v 1.14 2006/01/24 19:33:10 christos Exp $"); #include <stdlib.h> #include <unistd.h> +#include "dirent_private.h" + #ifdef __weak_alias __weak_alias(closedir,_closedir) #endif @@ -57,10 +59,10 @@ __weak_alias(closedir,_closedir) * close a directory. */ int -closedir(dirp) - DIR *dirp; +closedir(DIR *dirp) { int fd; + struct dirpos *poslist; _DIAGASSERT(dirp != NULL); @@ -68,11 +70,18 @@ closedir(dirp) if (__isthreaded) mutex_lock((mutex_t *)dirp->dd_lock); #endif - _seekdir_unlocked(dirp, dirp->dd_rewind);/* free seekdir storage */ fd = dirp->dd_fd; dirp->dd_fd = -1; dirp->dd_loc = 0; - free((void *)dirp->dd_buf); + free(dirp->dd_buf); + + /* free seekdir/telldir storage */ + for (poslist = dirp->dd_internal; poslist; ) { + struct dirpos *nextpos = poslist->dp_next; + free(poslist); + poslist = nextpos; + } + #ifdef _REENTRANT if (__isthreaded) { mutex_unlock((mutex_t *)dirp->dd_lock); diff --git a/lib/libc/gen/directory.3 b/lib/libc/gen/directory.3 index 005f32b1117..a962aa5d2df 100644 --- a/lib/libc/gen/directory.3 +++ b/lib/libc/gen/directory.3 @@ -1,4 +1,4 @@ -.\" $NetBSD: directory.3,v 1.24 2003/08/07 16:42:47 agc Exp $ +.\" $NetBSD: directory.3,v 1.25 2006/05/17 20:36:50 christos Exp $ .\" .\" Copyright (c) 1983, 1991, 1993 .\" The Regents of the University of California. All rights reserved. @@ -29,7 +29,7 @@ .\" .\" @(#)directory.3 8.1 (Berkeley) 6/4/93 .\" -.Dd May 28, 2003 +.Dd May 16, 2006 .Dt DIRECTORY 3 .Os .Sh NAME @@ -53,7 +53,7 @@ .Ft int .Fn readdir_r "DIR * restrict dirp" "struct dirent * restrict entry" "struct dirent ** restrict result" .Ft long -.Fn telldir "const DIR *dirp" +.Fn telldir "DIR *dirp" .Ft void .Fn seekdir "DIR *dirp" "long loc" .Ft void diff --git a/lib/libc/gen/dirent_private.h b/lib/libc/gen/dirent_private.h new file mode 100644 index 00000000000..bb76f31c043 --- /dev/null +++ b/lib/libc/gen/dirent_private.h @@ -0,0 +1,22 @@ +/* $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 *); +#ifndef __LIBC12_SOURCE__ +struct dirent; +struct dirent *_readdir_unlocked(struct _dirdesc *) + __RENAME(___readdir_unlocked30); +#endif diff --git a/lib/libc/gen/opendir.c b/lib/libc/gen/opendir.c index c6fa5ae5752..d4785fcbf15 100644 --- a/lib/libc/gen/opendir.c +++ b/lib/libc/gen/opendir.c @@ -1,4 +1,4 @@ -/* $NetBSD: opendir.c,v 1.30 2006/01/24 19:33:10 christos Exp $ */ +/* $NetBSD: opendir.c,v 1.31 2006/05/17 20:36:50 christos Exp $ */ /* * Copyright (c) 1983, 1993 @@ -34,7 +34,7 @@ #if 0 static char sccsid[] = "@(#)opendir.c 8.7 (Berkeley) 12/10/94"; #else -__RCSID("$NetBSD: opendir.c,v 1.30 2006/01/24 19:33:10 christos Exp $"); +__RCSID("$NetBSD: opendir.c,v 1.31 2006/05/17 20:36:50 christos Exp $"); #endif #endif /* LIBC_SCCS and not lint */ @@ -53,12 +53,13 @@ __RCSID("$NetBSD: opendir.c,v 1.30 2006/01/24 19:33:10 christos Exp $"); #include <string.h> #include <unistd.h> +#include "dirent_private.h" + /* * Open a directory. */ DIR * -opendir(name) - const char *name; +opendir(const char *name) { _DIAGASSERT(name != NULL); @@ -67,9 +68,7 @@ opendir(name) } DIR * -__opendir2(name, flags) - const char *name; - int flags; +__opendir2(const char *name, int flags) { DIR *dirp = NULL; int fd; @@ -304,7 +303,8 @@ retry: mutex_init((mutex_t *)dirp->dd_lock, NULL); } #endif - dirp->dd_rewind = _telldir_unlocked(dirp); + dirp->dd_internal = NULL; + (void)_telldir_unlocked(dirp); return (dirp); error: serrno = errno; diff --git a/lib/libc/gen/readdir.c b/lib/libc/gen/readdir.c index 8bbb1b4abd8..2b94543a4a7 100644 --- a/lib/libc/gen/readdir.c +++ b/lib/libc/gen/readdir.c @@ -1,4 +1,4 @@ -/* $NetBSD: readdir.c,v 1.22 2006/01/24 19:33:10 christos Exp $ */ +/* $NetBSD: readdir.c,v 1.23 2006/05/17 20:36:50 christos Exp $ */ /* * Copyright (c) 1983, 1993 @@ -34,7 +34,7 @@ #if 0 static char sccsid[] = "@(#)readdir.c 8.3 (Berkeley) 9/29/94"; #else -__RCSID("$NetBSD: readdir.c,v 1.22 2006/01/24 19:33:10 christos Exp $"); +__RCSID("$NetBSD: readdir.c,v 1.23 2006/05/17 20:36:50 christos Exp $"); #endif #endif /* LIBC_SCCS and not lint */ @@ -48,6 +48,8 @@ __RCSID("$NetBSD: readdir.c,v 1.22 2006/01/24 19:33:10 christos Exp $"); #include <string.h> #include <unistd.h> +#include "dirent_private.h" + /* * get next entry in a directory. */ diff --git a/lib/libc/gen/rewinddir.c b/lib/libc/gen/rewinddir.c index cb15edc453d..e52f0e2d158 100644 --- a/lib/libc/gen/rewinddir.c +++ b/lib/libc/gen/rewinddir.c @@ -1,4 +1,4 @@ -/* $NetBSD: rewinddir.c,v 1.11 2006/01/24 19:33:10 christos Exp $ */ +/* $NetBSD: rewinddir.c,v 1.12 2006/05/17 20:36:50 christos Exp $ */ /*- * Copyright (c) 1990, 1993 @@ -34,7 +34,7 @@ #if 0 static char sccsid[] = "@(#)rewinddir.c 8.1 (Berkeley) 6/8/93"; #else -__RCSID("$NetBSD: rewinddir.c,v 1.11 2006/01/24 19:33:10 christos Exp $"); +__RCSID("$NetBSD: rewinddir.c,v 1.12 2006/05/17 20:36:50 christos Exp $"); #endif #endif /* LIBC_SCCS and not lint */ @@ -45,25 +45,27 @@ __RCSID("$NetBSD: rewinddir.c,v 1.11 2006/01/24 19:33:10 christos Exp $"); #include <dirent.h> +#include "dirent_private.h" + #ifdef __weak_alias __weak_alias(rewinddir,_rewinddir) #endif void -rewinddir(dirp) - DIR *dirp; +rewinddir(DIR *dirp) { + struct dirpos *dp = dirp->dd_internal; + + while (dp->dp_next) + dp = dp->dp_next; #ifdef _REENTRANT if (__isthreaded) { mutex_lock((mutex_t *)dirp->dd_lock); - _seekdir_unlocked(dirp, dirp->dd_rewind); - dirp->dd_rewind = _telldir_unlocked(dirp); + _seekdir_unlocked(dirp, (long)(intptr_t)dp); mutex_unlock((mutex_t *)dirp->dd_lock); return; } #endif - _seekdir_unlocked(dirp, dirp->dd_rewind); - dirp->dd_rewind = _telldir_unlocked(dirp); - + _seekdir_unlocked(dirp, (long)(intptr_t)dp); } diff --git a/lib/libc/gen/seekdir.c b/lib/libc/gen/seekdir.c index 09ea5484220..e70eba635e4 100644 --- a/lib/libc/gen/seekdir.c +++ b/lib/libc/gen/seekdir.c @@ -1,4 +1,4 @@ -/* $NetBSD: seekdir.c,v 1.13 2006/01/24 19:33:10 christos Exp $ */ +/* $NetBSD: seekdir.c,v 1.14 2006/05/17 20:36:50 christos Exp $ */ /* * Copyright (c) 1983, 1993 @@ -34,7 +34,7 @@ #if 0 static char sccsid[] = "@(#)seekdir.c 8.1 (Berkeley) 6/4/93"; #else -__RCSID("$NetBSD: seekdir.c,v 1.13 2006/01/24 19:33:10 christos Exp $"); +__RCSID("$NetBSD: seekdir.c,v 1.14 2006/05/17 20:36:50 christos Exp $"); #endif #endif /* LIBC_SCCS and not lint */ @@ -45,6 +45,8 @@ __RCSID("$NetBSD: seekdir.c,v 1.13 2006/01/24 19:33:10 christos Exp $"); #include <dirent.h> +#include "dirent_private.h" + #ifdef __weak_alias __weak_alias(seekdir,_seekdir) #endif @@ -54,9 +56,7 @@ __weak_alias(seekdir,_seekdir) * _seekdir_unlocked is in telldir.c so that it can share opaque data structures. */ void -seekdir(dirp, loc) - DIR *dirp; - long loc; +seekdir(DIR *dirp, long loc) { #ifdef _REENTRANT diff --git a/lib/libc/gen/telldir.c b/lib/libc/gen/telldir.c index 85d64e8a0d5..a25083f88a2 100644 --- a/lib/libc/gen/telldir.c +++ b/lib/libc/gen/telldir.c @@ -1,4 +1,4 @@ -/* $NetBSD: telldir.c,v 1.17 2006/01/24 19:33:10 christos Exp $ */ +/* $NetBSD: telldir.c,v 1.18 2006/05/17 20:36:50 christos Exp $ */ /* * Copyright (c) 1983, 1993 @@ -34,7 +34,7 @@ #if 0 static char sccsid[] = "@(#)telldir.c 8.1 (Berkeley) 6/4/93"; #else -__RCSID("$NetBSD: telldir.c,v 1.17 2006/01/24 19:33:10 christos Exp $"); +__RCSID("$NetBSD: telldir.c,v 1.18 2006/05/17 20:36:50 christos Exp $"); #endif #endif /* LIBC_SCCS and not lint */ @@ -48,48 +48,24 @@ __RCSID("$NetBSD: telldir.c,v 1.17 2006/01/24 19:33:10 christos Exp $"); #include <stdlib.h> #include <unistd.h> +#include "dirent_private.h" + #ifdef __weak_alias __weak_alias(telldir,_telldir) #endif -/* - * 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 */ -}; - -#define NDIRHASH 32 /* Num of hash lists, must be a power of 2 */ -#define LOCHASH(i) (((int)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 */ - long -telldir(const DIR *dirp) +telldir(DIR *dirp) { long rv; #ifdef _REENTRANT if (__isthreaded) { mutex_lock((mutex_t *)dirp->dd_lock); - rv = _telldir_unlocked(dirp); + rv = (intptr_t)_telldir_unlocked(dirp); mutex_unlock((mutex_t *)dirp->dd_lock); } else #endif - rv = _telldir_unlocked(dirp); + rv = (intptr_t)_telldir_unlocked(dirp); return rv; } @@ -97,20 +73,24 @@ telldir(const DIR *dirp) * return a pointer into a directory */ long -_telldir_unlocked(const DIR *dirp) +_telldir_unlocked(DIR *dirp) { - long idx; - struct ddloc *lp; + struct dirpos *lp; - if ((lp = (struct ddloc *)malloc(sizeof(struct ddloc))) == NULL) + 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); - idx = dd_loccnt++; - lp->loc_index = idx; - lp->loc_seek = dirp->dd_seek; - lp->loc_loc = dirp->dd_loc; - lp->loc_next = dd_hash[LOCHASH(idx)]; - dd_hash[LOCHASH(idx)] = lp; - return (idx); + + 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; } /* @@ -120,35 +100,23 @@ _telldir_unlocked(const DIR *dirp) void _seekdir_unlocked(DIR *dirp, long loc) { - struct ddloc *lp; - struct ddloc **prevlp; - struct dirent *dp; + struct dirpos *lp; _DIAGASSERT(dirp != NULL); - prevlp = &dd_hash[LOCHASH(loc)]; - lp = *prevlp; - while (lp != NULL) { - if (lp->loc_index == loc) + for (lp = dirp->dd_internal; lp; lp = lp->dp_next) + if ((intptr_t)lp == 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; - (void) lseek(dirp->dd_fd, (off_t)lp->loc_seek, SEEK_SET); - dirp->dd_seek = lp->loc_seek; + + 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->loc_loc) { - dp = _readdir_unlocked(dirp); - if (dp == NULL) + while (dirp->dd_loc < lp->dp_loc) + if (_readdir_unlocked(dirp) == NULL) break; - } -found: -#ifdef SINGLEUSE - *prevlp = lp->loc_next; - free(lp); -#endif } diff --git a/lib/libc/include/extern.h b/lib/libc/include/extern.h index 9a8e3550190..e5b52614622 100644 --- a/lib/libc/include/extern.h +++ b/lib/libc/include/extern.h @@ -1,4 +1,4 @@ -/* $NetBSD: extern.h,v 1.12 2006/02/24 19:33:09 drochner Exp $ */ +/* $NetBSD: extern.h,v 1.13 2006/05/17 20:36:50 christos Exp $ */ /* * Copyright (c) 1997 Christos Zoulas. All rights reserved. @@ -46,14 +46,6 @@ struct sigaction; int __sigaction_sigtramp __P((int, const struct sigaction *, struct sigaction *, const void *, int)); -struct _dirdesc; -void _seekdir_unlocked(struct _dirdesc *, long); -long _telldir_unlocked(const struct _dirdesc *); -#ifndef __LIBC12_SOURCE__ -struct dirent; -struct dirent *_readdir_unlocked(struct _dirdesc *) __RENAME(___readdir_unlocked30); -#endif - #ifdef WIDE_DOUBLE char *__hdtoa(double, const char *, int, int *, int *, char **); char *__hldtoa(long double, const char *, int, int *, int *, char **); |
