diff options
author | Ted Unangst <tedu@cvs.openbsd.org> | 2004-03-05 04:11:52 +0000 |
---|---|---|
committer | Ted Unangst <tedu@cvs.openbsd.org> | 2004-03-05 04:11:52 +0000 |
commit | f27b58730fc040b378fef8693bbfc5023b7df0e1 (patch) | |
tree | e8d5299819388f20319cea6f14db65f2681daec5 /lib/libc/gen | |
parent | 93d6d80307a0cffa73d6b8a221dd479cf08604bf (diff) |
don't leak memory. free and netbsd via Patrick Latifi
Diffstat (limited to 'lib/libc/gen')
-rw-r--r-- | lib/libc/gen/scandir.c | 66 |
1 files changed, 37 insertions, 29 deletions
diff --git a/lib/libc/gen/scandir.c b/lib/libc/gen/scandir.c index 8b51e0c7e3a..c29bb18ffb6 100644 --- a/lib/libc/gen/scandir.c +++ b/lib/libc/gen/scandir.c @@ -28,7 +28,7 @@ */ #if defined(LIBC_SCCS) && !defined(lint) -static char rcsid[] = "$OpenBSD: scandir.c,v 1.7 2003/06/02 20:18:34 millert Exp $"; +static char rcsid[] = "$OpenBSD: scandir.c,v 1.8 2004/03/05 04:11:51 tedu Exp $"; #endif /* LIBC_SCCS and not lint */ /* @@ -64,16 +64,16 @@ scandir(dirname, namelist, select, dcomp) int (*select)(struct dirent *); int (*dcomp)(const void *, const void *); { - register struct dirent *d, *p, **names; - register size_t nitems; + struct dirent *d, *p, **names = NULL; + size_t nitems = 0; struct stat stb; long arraysz; DIR *dirp; if ((dirp = opendir(dirname)) == NULL) - return(-1); + return (-1); if (fstat(dirp->dd_fd, &stb) < 0) - return(-1); + goto fail; /* * estimate the array size by taking the size of the directory file @@ -82,53 +82,61 @@ scandir(dirname, namelist, select, dcomp) arraysz = (stb.st_size / 24); if (arraysz > SIZE_T_MAX / sizeof(struct dirent *)) { errno = ENOMEM; - return(-1); + goto fail; } names = (struct dirent **)malloc(arraysz * sizeof(struct dirent *)); if (names == NULL) - return(-1); + goto fail; - nitems = 0; while ((d = readdir(dirp)) != NULL) { if (select != NULL && !(*select)(d)) continue; /* just selected names */ - /* - * Make a minimum size copy of the data - */ - p = (struct dirent *)malloc(DIRSIZ(d)); - if (p == NULL) - return(-1); - p->d_ino = d->d_ino; - p->d_type = d->d_type; - p->d_reclen = d->d_reclen; - p->d_namlen = d->d_namlen; - bcopy(d->d_name, p->d_name, p->d_namlen + 1); + /* * Check to make sure the array has space left and * realloc the maximum size. */ - if (++nitems >= arraysz) { - register struct dirent **nnames; + if (nitems >= arraysz) { + struct dirent **nnames; if (fstat(dirp->dd_fd, &stb) < 0) - return(-1); /* just might have grown */ + goto fail; + arraysz = stb.st_size / 12; nnames = (struct dirent **)realloc((char *)names, arraysz * sizeof(struct dirent *)); - if (nnames == NULL) { - if (names) - free(names); - return(-1); - } + if (nnames == NULL) + goto fail; + names = nnames; } - names[nitems-1] = p; + + /* + * Make a minimum size copy of the data + */ + p = (struct dirent *)malloc(DIRSIZ(d)); + if (p == NULL) + goto fail; + + p->d_ino = d->d_ino; + p->d_type = d->d_type; + p->d_reclen = d->d_reclen; + p->d_namlen = d->d_namlen; + bcopy(d->d_name, p->d_name, p->d_namlen + 1); + names[nitems++] = p; } closedir(dirp); if (nitems && dcomp != NULL) qsort(names, nitems, sizeof(struct dirent *), dcomp); *namelist = names; - return(nitems); + return (nitems); + +fail: + while (nitems > 0) + free(names[--nitems]); + free(names); + closedir(dirp); + return (-1); } /* |