From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 111566 invoked by alias); 1 Feb 2019 09:39:52 -0000 Mailing-List: contact newlib-cvs-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: newlib-cvs-owner@sourceware.org Received: (qmail 111547 invoked by uid 10080); 1 Feb 2019 09:39:52 -0000 Date: Fri, 01 Feb 2019 09:39:00 -0000 Message-ID: <20190201093952.111545.qmail@sourceware.org> Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: Sebastian Huber To: newlib-cvs@sourceware.org Subject: [newlib-cygwin] scandir(3) previously used st_size X-Act-Checkin: newlib-cygwin X-Git-Author: das X-Git-Refname: refs/heads/master X-Git-Oldrev: d785551a46a786ed08db6b5efd2e1032d513f234 X-Git-Newrev: 2d3c2f4697481dc6df76528c9addabd4c80d3652 X-SW-Source: 2019-q1/txt/msg00020.txt.bz2 https://sourceware.org/git/gitweb.cgi?p=newlib-cygwin.git;h=2d3c2f4697481dc6df76528c9addabd4c80d3652 commit 2d3c2f4697481dc6df76528c9addabd4c80d3652 Author: das 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 -#include #include #include #include @@ -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); } /*