summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorchristos <christos@NetBSD.org>2006-05-17 20:36:50 +0000
committerchristos <christos@NetBSD.org>2006-05-17 20:36:50 +0000
commitcfd3aebca47c5c3ef947e99fa964389716bb250f (patch)
tree97f9c83b91b118ac7f22dbaa5e51945f1e994a82
parent54595e994676fcb788ae71a4165ca5ca4c65f595 (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.c21
-rw-r--r--lib/libc/gen/directory.36
-rw-r--r--lib/libc/gen/dirent_private.h22
-rw-r--r--lib/libc/gen/opendir.c16
-rw-r--r--lib/libc/gen/readdir.c6
-rw-r--r--lib/libc/gen/rewinddir.c20
-rw-r--r--lib/libc/gen/seekdir.c10
-rw-r--r--lib/libc/gen/telldir.c98
-rw-r--r--lib/libc/include/extern.h10
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 **);