Subject: Re: PR/36464 CVS commit: src/lib/libc/gen
To: None <gnats-bugs@NetBSD.org>
From: Ed Ravin <eravin@panix.com>
List: netbsd-bugs
Date: 06/12/2007 00:29:07
--rwEMma7ioTxnRzrJ
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
On Sun, Jun 10, 2007 at 01:20:03AM +0000, Christos Zoulas wrote:
> The following reply was made to PR lib/36464; it has been noted by GNATS.
>
> From: christos@zoulas.com (Christos Zoulas)
> To: Ed Ravin <eravin@panix.com>, gnats-bugs@NetBSD.org
> Cc: lib-bug-people@netbsd.org, gnats-admin@netbsd.org,
> netbsd-bugs@netbsd.org
> Subject: Re: PR/36464 CVS commit: src/lib/libc/gen
> Date: Sat, 9 Jun 2007 21:17:57 -0400
>
> On Jun 9, 9:00pm, eravin@panix.com (Ed Ravin) wrote:
> -- Subject: Re: PR/36464 CVS commit: src/lib/libc/gen
>
> | Christos - thanks for the quick fix, I will test it out later this
> | week.
>
> Great, thanks. If you send me a patch I will request a formal pullup.
See attached for a patch against 3.1. It seems to work for the two apps
I tried that use scandir() (Pine, Midnight Commander).
I got lazy and left the "divide by 24" bit in there, but otherwise
I think it matches what you did with the current tree.
--rwEMma7ioTxnRzrJ
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="scandir.c.diff"
--- scandir.c 2007/06/11 23:17:07 1.1
+++ scandir.c 2007/06/12 04:25:56
@@ -60,6 +60,34 @@
__weak_alias(alphasort,_alphasort)
#endif
+
+/*
+ * Compute an estimate of the number of entries in a directory based on
+ * the file size. Returns the estimated number of entries or 0 on failure.
+ */
+static size_t
+dirsize(int fd, size_t olen)
+{
+ struct stat stb;
+ size_t nlen;
+
+ if (fstat(fd, &stb) == -1)
+ return 0;
+ /*
+ * Estimate the array size by taking the size of the directory file
+ * and dividing it by a multiple of the minimum size entry.
+ */
+ nlen = (size_t)(stb.st_size / 24 /*_DIRENT_MINSIZE((struct dirent *)0)*/ );
+ /*
+ * If the size turns up 0, switch to an alternate strategy and use the
+ * file size as the number of entries like ZFS returns. If that turns
+ * out to be 0 too return a minimum of 10 entries, plus the old length.
+ */
+ if (nlen == 0)
+ nlen = (size_t)(stb.st_size ? stb.st_size : 10);
+ return olen + nlen;
+}
+
/*
* The DIRSIZ macro is the minimum record length which will hold the directory
* entry. This requires the amount of space in struct dirent without the
@@ -80,7 +108,6 @@
{
struct dirent *d, *p, **names, **newnames;
size_t nitems, arraysz;
- struct stat stb;
DIR *dirp;
_DIAGASSERT(dirname != NULL);
@@ -88,14 +115,10 @@
if ((dirp = opendir(dirname)) == NULL)
return (-1);
- if (fstat(dirp->dd_fd, &stb) < 0)
+
+ if ((arraysz = dirsize(dirp->dd_fd, 0)) == 0)
goto bad;
- /*
- * estimate the array size by taking the size of the directory file
- * and dividing it by a multiple of the minimum size entry.
- */
- arraysz = (size_t)(stb.st_size / 24);
names = malloc(arraysz * sizeof(struct dirent *));
if (names == NULL)
goto bad;
@@ -110,9 +133,8 @@
* realloc the maximum size.
*/
if (nitems >= arraysz) {
- if (fstat(dirp->dd_fd, &stb) < 0)
- goto bad2; /* just might have grown */
- arraysz = (size_t)(stb.st_size / 12);
+ if ((arraysz = dirsize(dirp->dd_fd, arraysz)) == 0)
+ goto bad2;
newnames = realloc(names,
arraysz * sizeof(struct dirent *));
if (newnames == NULL)
--rwEMma7ioTxnRzrJ--