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.
This commit is contained in:
parent
54595e9946
commit
cfd3aebca4
@ -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);
|
||||
|
@ -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
|
||||
|
22
lib/libc/gen/dirent_private.h
Normal file
22
lib/libc/gen/dirent_private.h
Normal file
@ -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
|
@ -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;
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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 **);
|
||||
|
Loading…
Reference in New Issue
Block a user