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:
jhb 2014-07-29 00:16:33 +00:00
parent 0cc7234e3b
commit 3fdccc4e7a
2 changed files with 26 additions and 28 deletions

View File

@ -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

View File

@ -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
}
/*