summaryrefslogtreecommitdiffstats
path: root/lib/libc/gen/opendir.c
diff options
context:
space:
mode:
authorbde <bde@FreeBSD.org>1995-04-21 15:23:27 +0000
committerbde <bde@FreeBSD.org>1995-04-21 15:23:27 +0000
commit135036b6248d06c5fe8f6e6f2d90dbe9d871d582 (patch)
tree6cc61941ffdb793694d99f0ff4adf4767816cac8 /lib/libc/gen/opendir.c
parent20f32e409c6096d1040d9f0f2f46e1b5a234b4d8 (diff)
downloadFreeBSD-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/libc/gen/opendir.c')
-rw-r--r--lib/libc/gen/opendir.c32
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;
}
OpenPOWER on IntegriCloud