Fix bugs in opendir():

- it succeeded on non-directories (see POSIX 5.1.2.4).
- it hung on (non-open) named pipes.
- it leaked memory if the second malloc() failed.
- it didn't preserve errno across errors in close().
This commit is contained in:
Bruce Evans 1995-04-21 15:23:27 +00:00
parent 7332aa0b69
commit 55e2b2c608

View File

@ -36,8 +36,10 @@ static char sccsid[] = "@(#)opendir.c 8.2 (Berkeley) 2/12/94";
#endif /* LIBC_SCCS and not lint */
#include <sys/param.h>
#include <sys/stat.h>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
@ -51,14 +53,21 @@ opendir(name)
{
register DIR *dirp;
register int fd;
int saved_errno;
struct stat sb;
if ((fd = open(name, 0)) == -1)
return NULL;
if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1 ||
(dirp = (DIR *)malloc(sizeof(DIR))) == NULL) {
close (fd);
if ((fd = open(name, O_RDONLY | O_NONBLOCK)) == -1)
return NULL;
dirp = NULL;
if (fstat(fd, &sb) != 0)
goto fail;
if (!S_ISDIR(sb.st_mode)) {
errno = ENOTDIR;
goto fail;
}
if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1 ||
(dirp = malloc(sizeof(DIR))) == NULL)
goto fail;
/*
* If CLBYTES is an exact multiple of DIRBLKSIZ, use a CLBYTES
* buffer that it cluster boundary aligned.
@ -72,10 +81,8 @@ opendir(name)
dirp->dd_buf = malloc(DIRBLKSIZ);
dirp->dd_len = DIRBLKSIZ;
}
if (dirp->dd_buf == NULL) {
close (fd);
return NULL;
}
if (dirp->dd_buf == NULL)
goto fail;
dirp->dd_fd = fd;
dirp->dd_loc = 0;
dirp->dd_seek = 0;
@ -84,4 +91,11 @@ opendir(name)
*/
dirp->dd_rewind = telldir(dirp);
return dirp;
fail:
saved_errno = errno;
free(dirp);
close(fd);
errno = saved_errno;
return NULL;
}