Tue Apr 14 05:21:26 2015 UTC ()
Pull up following revision(s) (requested by christos in ticket #691):
	lib/libc/gen/opendir.c: revision 1.39
- Use O_DIRECTORY to open the file, so that we don't need to stat() after
  that.
- Move the stat() call to fdopendir() and change it's error handling so that
  it does not hide errors.
- According to POSIX, fdopendir() transfers ownership of the fd only on
  success, so don't close it on failure. XXX: We still make it non-blocking
  on failure, but that's nitpicking.


(snj)
diff -r1.38 -r1.38.20.1 src/lib/libc/gen/opendir.c

cvs diff -r1.38 -r1.38.20.1 src/lib/libc/gen/opendir.c (expand / switch to context diff)
--- src/lib/libc/gen/opendir.c 2011/10/15 23:00:01 1.38
+++ src/lib/libc/gen/opendir.c 2015/04/14 05:21:26 1.38.20.1
@@ -1,4 +1,4 @@
-/*	$NetBSD: opendir.c,v 1.38 2011/10/15 23:00:01 christos Exp $	*/
+/*	$NetBSD: opendir.c,v 1.38.20.1 2015/04/14 05:21:26 snj Exp $	*/
 
 /*
  * Copyright (c) 1983, 1993
@@ -34,7 +34,7 @@
 #if 0
 static char sccsid[] = "@(#)opendir.c	8.7 (Berkeley) 12/10/94";
 #else
-__RCSID("$NetBSD: opendir.c,v 1.38 2011/10/15 23:00:01 christos Exp $");
+__RCSID("$NetBSD: opendir.c,v 1.38.20.1 2015/04/14 05:21:26 snj Exp $");
 #endif
 #endif /* LIBC_SCCS and not lint */
 
@@ -75,17 +75,36 @@
 DIR *
 __opendir2(const char *name, int flags)
 {
+	DIR *dirp;
 	int fd;
 
-	if ((fd = open(name, O_RDONLY | O_NONBLOCK | O_CLOEXEC)) == -1)
+	if ((fd = open(name, O_RDONLY|O_DIRECTORY|O_NONBLOCK|O_CLOEXEC)) == -1)
 		return NULL;
-	return __opendir_common(fd, name, flags);
+
+	dirp = __opendir_common(fd, name, flags);
+	if (dirp == NULL) {
+		int serrno = errno;
+		(void)close(fd);
+		errno = serrno;
+	}
+	return dirp;
 }
 
 #ifndef __LIBC12_SOURCE__
 DIR *
 _fdopendir(int fd)
 {
+	struct stat sb;
+
+	if (fstat(fd, &sb) == -1)
+		return NULL;
+
+	if (!S_ISDIR(sb.st_mode)) {
+		errno = ENOTDIR;
+		return NULL;
+	}
+
+	/* This is optional according to POSIX, but a good measure */
 	if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1)
 		return NULL;
 
@@ -96,16 +115,11 @@
 static DIR *
 __opendir_common(int fd, const char *name, int flags)
 {
-	DIR *dirp = NULL;
+	DIR *dirp;
 	int serrno;
-	struct stat sb;
 	struct statvfs sfb;
 	int error;
 
-	if (fstat(fd, &sb) || !S_ISDIR(sb.st_mode)) {
-		errno = ENOTDIR;
-		goto error;
-	}
 	if ((dirp = malloc(sizeof(*dirp))) == NULL)
 		goto error;
 	dirp->dd_buf = NULL;
@@ -157,8 +171,6 @@
 		free(dirp->dd_buf);
 	}
 	free(dirp);
-	if (fd != -1)
-		(void)close(fd);
 	errno = serrno;
 	return NULL;
 }