public inbox for newlib-cvs@sourceware.org
help / color / mirror / Atom feed
* [newlib-cygwin] scandir(3) previously used st_size
@ 2019-02-01 9:39 Sebastian Huber
0 siblings, 0 replies; only message in thread
From: Sebastian Huber @ 2019-02-01 9:39 UTC (permalink / raw)
To: newlib-cvs
https://sourceware.org/git/gitweb.cgi?p=newlib-cygwin.git;h=2d3c2f4697481dc6df76528c9addabd4c80d3652
commit 2d3c2f4697481dc6df76528c9addabd4c80d3652
Author: das <das@FreeBSD.org>
Date: Sun Mar 16 19:08:53 2008 +0000
scandir(3) previously used st_size
to obtain an initial estimate of the array length needed to store all
the directory entries. Although BSD has historically guaranteed that
st_size is the size of the directory file, POSIX does not, and more to
the point, some recent filesystems such as ZFS use st_size to mean
something else.
The fix is to not stat the directory at all, set the initial
array size to 32 entries, and realloc it in powers of 2 if that
proves insufficient.
PR: 113668
Diff:
---
newlib/libc/posix/scandir.c | 84 +++++++++++++++++----------------------------
1 file changed, 31 insertions(+), 53 deletions(-)
diff --git a/newlib/libc/posix/scandir.c b/newlib/libc/posix/scandir.c
index 95be977..56de1b9 100644
--- a/newlib/libc/posix/scandir.c
+++ b/newlib/libc/posix/scandir.c
@@ -42,8 +42,6 @@ __FBSDID("$FreeBSD$");
* struct dirent (through namelist). Returns -1 if there were any errors.
*/
-#include <sys/types.h>
-#include <sys/stat.h>
#include <stddef.h>
#include <dirent.h>
#include <stdlib.h>
@@ -71,41 +69,22 @@ scandir(const char *dirname, struct dirent ***namelist,
int (*select)(const struct dirent *), int (*dcomp)(const struct dirent **,
const struct dirent **))
{
- register struct dirent *d, *p, **names;
- register size_t nitems;
- struct stat stb;
- long arraysz;
+ register struct dirent *d, *p, **names = NULL;
+ register size_t arraysz, numitems;
DIR *dirp;
- int successful = 0;
- int rc = 0;
-
- dirp = NULL;
- names = NULL;
if ((dirp = opendir(dirname)) == NULL)
return(-1);
#ifdef HAVE_DD_LOCK
__lock_acquire_recursive(dirp->dd_lock);
#endif
- if (fstat(dirp->dd_fd, &stb) < 0)
- goto cleanup;
-
- /*
- * If there were no directory entries, then bail.
- */
- if (stb.st_size == 0)
- goto cleanup;
- /*
- * estimate the array size by taking the size of the directory file
- * and dividing it by a multiple of the minimum size entry.
- */
- arraysz = (stb.st_size / 24);
+ numitems = 0;
+ arraysz = 32; /* initial estimate of the array size */
names = (struct dirent **)malloc(arraysz * sizeof(struct dirent *));
if (names == NULL)
- goto cleanup;
+ goto fail;
- nitems = 0;
while ((d = readdir(dirp)) != NULL) {
if (select != NULL && !(*select)(d))
continue; /* just selected names */
@@ -114,7 +93,7 @@ scandir(const char *dirname, struct dirent ***namelist,
*/
p = (struct dirent *)malloc(DIRSIZ(d));
if (p == NULL)
- goto cleanup;
+ goto fail;
p->d_ino = d->d_ino;
p->d_reclen = d->d_reclen;
#ifdef _DIRENT_HAVE_D_NAMLEN
@@ -127,39 +106,38 @@ scandir(const char *dirname, struct dirent ***namelist,
* Check to make sure the array has space left and
* realloc the maximum size.
*/
- if (++nitems >= arraysz) {
- if (fstat(dirp->dd_fd, &stb) < 0)
- goto cleanup;
- arraysz = stb.st_size / 12;
- names = (struct dirent **)reallocf((char *)names,
- arraysz * sizeof(struct dirent *));
- if (names == NULL)
- goto cleanup;
+ if (numitems >= arraysz) {
+ struct dirent **names2;
+
+ names2 = reallocarray(names, arraysz,
+ 2 * sizeof(struct dirent *));
+ if (names2 == NULL) {
+ free(p);
+ goto fail;
+ }
+ names = names2;
+ arraysz *= 2;
}
- names[nitems-1] = p;
+ names[numitems++] = p;
}
- successful = 1;
-cleanup:
closedir(dirp);
- if (successful) {
- if (nitems && dcomp != NULL)
- qsort(names, nitems, sizeof(struct dirent *), (void *)dcomp);
- *namelist = names;
- rc = nitems;
- } else { /* We were unsuccessful, clean up storage and return -1. */
- if ( names ) {
- int i;
- for (i=0; i < nitems; i++ )
- free( names[i] );
- free( names );
- }
- rc = -1;
- }
+ if (numitems && dcomp != NULL)
+ qsort(names, numitems, sizeof(struct dirent *), (void *)dcomp);
+ *namelist = names;
+#ifdef HAVE_DD_LOCK
+ __lock_release_recursive(dirp->dd_lock);
+#endif
+ return (numitems);
+fail:
+ while (numitems > 0)
+ free(names[--numitems]);
+ free(names);
+ closedir(dirp);
#ifdef HAVE_DD_LOCK
__lock_release_recursive(dirp->dd_lock);
#endif
- return(rc);
+ return (-1);
}
/*
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2019-02-01 9:39 UTC | newest]
Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-02-01 9:39 [newlib-cygwin] scandir(3) previously used st_size Sebastian Huber
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).