X-Git-Url: https://git.saurik.com/apple/libc.git/blobdiff_plain/ad3c9f2af814c84582fdd1649e49ec4f68572c5a..HEAD:/gen/FreeBSD/telldir.c diff --git a/gen/FreeBSD/telldir.c b/gen/FreeBSD/telldir.c index 355ed50..8351dc1 100644 --- a/gen/FreeBSD/telldir.c +++ b/gen/FreeBSD/telldir.c @@ -31,7 +31,7 @@ static char sccsid[] = "@(#)telldir.c 8.1 (Berkeley) 6/4/93"; #endif /* LIBC_SCCS and not lint */ #include -__FBSDID("$FreeBSD: src/lib/libc/gen/telldir.c,v 1.11 2008/05/05 14:05:23 kib Exp $"); +__FBSDID("$FreeBSD$"); #include "namespace.h" #include @@ -45,62 +45,46 @@ __FBSDID("$FreeBSD: src/lib/libc/gen/telldir.c,v 1.11 2008/05/05 14:05:23 kib Ex #include "libc_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. - */ -#if !__DARWIN_UNIX03 -#define SINGLEUSE -#endif /* !__DARWIN_UNIX03 */ - /* * return a pointer into a directory */ long -telldir(dirp) - DIR *dirp; +telldir(DIR *dirp) { struct ddloc *lp; + long idx; -#if __DARWIN_UNIX03 if (__isthreaded) _pthread_mutex_lock(&dirp->dd_lock); LIST_FOREACH(lp, &dirp->dd_td->td_locq, loc_lqe) { - if ( #if __DARWIN_64_BIT_INO_T - (lp->loc_seek == dirp->dd_td->seekoff) + if (lp->loc_seek == dirp->dd_td->seekoff && #else /* !__DARWIN_64_BIT_INO_T */ - (lp->loc_seek == dirp->dd_seek) + if (lp->loc_seek == dirp->dd_seek && #endif /* __DARWIN_64_BIT_INO_T */ - && (lp->loc_loc == dirp->dd_loc)) - goto found; - } - if ((lp = (struct ddloc *)malloc(sizeof(struct ddloc))) == NULL) { - if (__isthreaded) - _pthread_mutex_unlock(&dirp->dd_lock); - return (-1); + lp->loc_loc == dirp->dd_loc) + break; } -#else /* !__DARWIN_UNIX03 */ - if ((lp = (struct ddloc *)malloc(sizeof(struct ddloc))) == NULL) - return (-1); - if (__isthreaded) - _pthread_mutex_lock(&dirp->dd_lock); -#endif /* __DARWIN_UNIX03 */ - lp->loc_index = dirp->dd_td->td_loccnt++; + 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++; #if __DARWIN_64_BIT_INO_T - lp->loc_seek = dirp->dd_td->seekoff; + lp->loc_seek = dirp->dd_td->seekoff; #else /* !__DARWIN_64_BIT_INO_T */ - lp->loc_seek = dirp->dd_seek; + lp->loc_seek = dirp->dd_seek; #endif /* __DARWIN_64_BIT_INO_T */ - lp->loc_loc = dirp->dd_loc; - LIST_INSERT_HEAD(&dirp->dd_td->td_locq, lp, loc_lqe); -#if __DARWIN_UNIX03 -found: -#endif /* __DARWIN_UNIX03 */ + 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); } /* @@ -108,9 +92,7 @@ found: * Only values returned by "telldir" should be passed to seekdir. */ void -_seekdir(dirp, loc) - DIR *dirp; - long loc; +_seekdir(DIR *dirp, long loc) { struct ddloc *lp; struct dirent *dp; @@ -121,14 +103,28 @@ _seekdir(dirp, loc) } if (lp == NULL) return; - if (lp->loc_loc == dirp->dd_loc && #if __DARWIN_64_BIT_INO_T - lp->loc_seek == dirp->dd_td->seekoff + if (lp->loc_loc == dirp->dd_loc && lp->loc_seek == dirp->dd_td->seekoff) #else /* !__DARWIN_64_BIT_INO_T */ - lp->loc_seek == dirp->dd_seek + if (lp->loc_loc == dirp->dd_loc && lp->loc_seek == dirp->dd_seek) #endif /* __DARWIN_64_BIT_INO_T */ - ) - goto found; + return; + + /* If it's within the same chunk of data, don't bother reloading. */ +#if __DARWIN_64_BIT_INO_T + if (lp->loc_seek == dirp->dd_td->seekoff) { +#else /* !__DARWIN_64_BIT_INO_T */ + if (lp->loc_seek == dirp->dd_seek) { +#endif /* __DARWIN_64_BIT_INO_T */ + /* + * If we go back to 0 don't make the next readdir + * trigger a call to getdirentries(). + */ + if (lp->loc_loc == 0) + dirp->dd_flags |= __DTF_SKIPREAD; + dirp->dd_loc = lp->loc_loc; + return; + } (void) lseek(dirp->dd_fd, (off_t)lp->loc_seek, SEEK_SET); #if __DARWIN_64_BIT_INO_T dirp->dd_td->seekoff = lp->loc_seek; @@ -136,16 +132,40 @@ _seekdir(dirp, loc) dirp->dd_seek = lp->loc_seek; #endif /* __DARWIN_64_BIT_INO_T */ dirp->dd_loc = 0; + dirp->dd_flags &= ~(__DTF_SKIPREAD | __DTF_ATEND); /* current contents are invalid */ while (dirp->dd_loc < lp->loc_loc) { dp = _readdir_unlocked(dirp, 0); if (dp == NULL) break; } -found:; -#ifdef SINGLEUSE - LIST_REMOVE(lp, loc_lqe); - free((caddr_t)lp); -#endif +} + +/* + * After readdir returns the last entry in a block, a call to telldir + * returns a location that is after the end of that last entry. + * However, that location doesn't refer to a valid directory entry. + * Ideally, the call to telldir would return a location that refers to + * the first entry in the next block. That location is not known + * until the next block is read, so readdir calls this function after + * fetching a new block to fix any such telldir locations. + */ +void +_fixtelldir(DIR *dirp, long oldseek, long oldloc) +{ + struct ddloc *lp; + + lp = LIST_FIRST(&dirp->dd_td->td_locq); + if (lp != NULL) { + if (lp->loc_loc == oldloc && + lp->loc_seek == oldseek) { +#if __DARWIN_64_BIT_INO_T + lp->loc_seek = dirp->dd_td->seekoff; +#else /* !__DARWIN_64_BIT_INO_T */ + lp->loc_seek = dirp->dd_seek; +#endif /* __DARWIN_64_BIT_INO_T */ + lp->loc_loc = dirp->dd_loc; + } + } } #ifndef BUILDING_VARIANT @@ -153,8 +173,7 @@ found:; * Reclaim memory for telldir cookies which weren't used. */ void -_reclaim_telldir(dirp) - DIR *dirp; +_reclaim_telldir(DIR *dirp) { struct ddloc *lp; struct ddloc *templp; @@ -167,4 +186,4 @@ _reclaim_telldir(dirp) } LIST_INIT(&dirp->dd_td->td_locq); } -#endif /* !BUILDING_VARIANT */ +#endif