If telldir() is called immediately after a call to seekdir(), POSIX
requires the return value of telldir() to equal the value passed to seekdir(). The current seekdir code with SINGLEUSE enabled breaks this case as each call to telldir() allocates a new cookie. Instead, remove the SINGLEUSE code and change telldir() to look for an existing cookie for the directory's current location rather than always creating a new cookie. CR: https://phabric.freebsd.org/D490 PR: 121656 Reviewed by: jilles MFC after: 1 week
This commit is contained in:
parent
0cc7234e3b
commit
3fdccc4e7a
@ -28,7 +28,7 @@
|
||||
.\" @(#)directory.3 8.1 (Berkeley) 6/4/93
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd August 18, 2013
|
||||
.Dd July 28, 2014
|
||||
.Dt DIRECTORY 3
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -169,6 +169,10 @@ If the directory is closed and then
|
||||
reopened, prior values returned by
|
||||
.Fn telldir
|
||||
will no longer be valid.
|
||||
Values returned by
|
||||
.Fn telldir
|
||||
are also invalidated by a call to
|
||||
.Fn rewinddir .
|
||||
.Pp
|
||||
The
|
||||
.Fn seekdir
|
||||
@ -182,13 +186,6 @@ The new position reverts to the one associated with the
|
||||
when the
|
||||
.Fn telldir
|
||||
operation was performed.
|
||||
State associated with the token returned by
|
||||
.Fn telldir is freed when it is passed to
|
||||
.Fn seekdir .
|
||||
If you wish return to the same location again,
|
||||
then you must create a new token with another
|
||||
.Fn telldir
|
||||
call.
|
||||
.Pp
|
||||
The
|
||||
.Fn rewinddir
|
||||
|
@ -46,13 +46,6 @@ __FBSDID("$FreeBSD$");
|
||||
#include "gen-private.h"
|
||||
#include "telldir.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
|
||||
|
||||
/*
|
||||
* return a pointer into a directory
|
||||
*/
|
||||
@ -61,18 +54,31 @@ telldir(dirp)
|
||||
DIR *dirp;
|
||||
{
|
||||
struct ddloc *lp;
|
||||
long idx;
|
||||
|
||||
if ((lp = (struct ddloc *)malloc(sizeof(struct ddloc))) == NULL)
|
||||
return (-1);
|
||||
if (__isthreaded)
|
||||
_pthread_mutex_lock(&dirp->dd_lock);
|
||||
lp->loc_index = dirp->dd_td->td_loccnt++;
|
||||
lp->loc_seek = dirp->dd_seek;
|
||||
lp->loc_loc = dirp->dd_loc;
|
||||
LIST_INSERT_HEAD(&dirp->dd_td->td_locq, lp, loc_lqe);
|
||||
LIST_FOREACH(lp, &dirp->dd_td->td_locq, loc_lqe) {
|
||||
if (lp->loc_seek == dirp->dd_seek &&
|
||||
lp->loc_loc == dirp->dd_loc)
|
||||
break;
|
||||
}
|
||||
if (lp == NULL) {
|
||||
lp = malloc(sizeof(struct ddloc));
|
||||
if (lp == NULL) {
|
||||
if (__isthreaded)
|
||||
_pthread_mutex_unlock(&dirp->dd_lock);
|
||||
return (-1);
|
||||
}
|
||||
lp->loc_index = dirp->dd_td->td_loccnt++;
|
||||
lp->loc_seek = dirp->dd_seek;
|
||||
lp->loc_loc = dirp->dd_loc;
|
||||
LIST_INSERT_HEAD(&dirp->dd_td->td_locq, lp, loc_lqe);
|
||||
}
|
||||
idx = lp->loc_index;
|
||||
if (__isthreaded)
|
||||
_pthread_mutex_unlock(&dirp->dd_lock);
|
||||
return (lp->loc_index);
|
||||
return (idx);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -94,7 +100,7 @@ _seekdir(dirp, loc)
|
||||
if (lp == NULL)
|
||||
return;
|
||||
if (lp->loc_loc == dirp->dd_loc && lp->loc_seek == dirp->dd_seek)
|
||||
goto found;
|
||||
return;
|
||||
(void) lseek(dirp->dd_fd, (off_t)lp->loc_seek, SEEK_SET);
|
||||
dirp->dd_seek = lp->loc_seek;
|
||||
dirp->dd_loc = 0;
|
||||
@ -103,11 +109,6 @@ _seekdir(dirp, loc)
|
||||
if (dp == NULL)
|
||||
break;
|
||||
}
|
||||
found:
|
||||
#ifdef SINGLEUSE
|
||||
LIST_REMOVE(lp, loc_lqe);
|
||||
free((caddr_t)lp);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
|
Loading…
Reference in New Issue
Block a user