diff options
author | bde <bde@FreeBSD.org> | 1995-04-21 15:23:27 +0000 |
---|---|---|
committer | bde <bde@FreeBSD.org> | 1995-04-21 15:23:27 +0000 |
commit | 135036b6248d06c5fe8f6e6f2d90dbe9d871d582 (patch) | |
tree | 6cc61941ffdb793694d99f0ff4adf4767816cac8 /lib | |
parent | 20f32e409c6096d1040d9f0f2f46e1b5a234b4d8 (diff) | |
download | FreeBSD-src-135036b6248d06c5fe8f6e6f2d90dbe9d871d582.zip FreeBSD-src-135036b6248d06c5fe8f6e6f2d90dbe9d871d582.tar.gz |
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().
Diffstat (limited to 'lib')
-rw-r--r-- | lib/libc/gen/opendir.c | 32 |
1 files changed, 23 insertions, 9 deletions
diff --git a/lib/libc/gen/opendir.c b/lib/libc/gen/opendir.c index 83e041d..b3c0e09 100644 --- a/lib/libc/gen/opendir.c +++ b/lib/libc/gen/opendir.c @@ -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; } |