Diff below adds POSIX.1-2008's fdopendir(3) to libc. Specifically:
- Moves the current opendir.c to fdopendir.c with changes as
appropriate (e.g., checking that the fd is open for reading,
and setting FD_CLOEXEC after we've already allocated memory for
the DIR struct). Also removed some unnecessary #includes.
- Reimplemented opendir(3) as a thin wrapper around fdopendir(3).
Also, this uses O_DIRECTORY instead of O_NONBLOCK (tested to make
sure it still returns ENOTDIR on fifos without blocking), and uses
O_CLOEXEC to atomically set the close-on-exec flag.
(It would be possible to change things slightly to avoid the two
fcntl(2) system calls in fdopendir(3) when called from opendir(3), but
I don't think it's worth the complexity.)
This will need a minor bump, but I can hold off on committing this
until the openat(2) syscalls are ready to be exposed in libc too and
let them share a bump.
ok?
Index: include/dirent.h
===================================================================
RCS file: /home/mdempsky/anoncvs/cvs/src/include/dirent.h,v
retrieving revision 1.23
diff -u -p -r1.23 dirent.h
--- include/dirent.h 14 Jul 2011 02:16:00 -0000 1.23
+++ include/dirent.h 14 Jul 2011 03:05:54 -0000
@@ -97,6 +97,9 @@ typedef void * DIR;
#ifndef _KERNEL
__BEGIN_DECLS
DIR *opendir(const char *);
+#if __POSIX_VISIBLE >= 200809
+DIR *fdopendir(int);
+#endif
struct dirent *readdir(DIR *);
void rewinddir(DIR *);
int closedir(DIR *);
Index: lib/libc/gen/Makefile.inc
===================================================================
RCS file: /home/mdempsky/anoncvs/cvs/src/lib/libc/gen/Makefile.inc,v
retrieving revision 1.53
diff -u -p -r1.53 Makefile.inc
--- lib/libc/gen/Makefile.inc 8 Jul 2011 22:58:54 -0000 1.53
+++ lib/libc/gen/Makefile.inc 14 Jul 2011 06:02:38 -0000
@@ -6,7 +6,8 @@
SRCS+= alarm.c assert.c auth_subr.c authenticate.c \
basename.c clock.c closedir.c confstr.c ctermid.c ctype_.c \
daemon.c devname.c dirname.c disklabel.c elf_hash.c err.c \
- errx.c errlist.c errno.c exec.c fnmatch.c fpclassify.c frexp.c \
+ errx.c errlist.c errno.c exec.c fdopendir.c fnmatch.c fpclassify.c \
+ frexp.c \
fstab.c ftok.c fts.c ftw.c getbsize.c getcap.c getcwd.c \
getdomainname.c getgrent.c getgrouplist.c gethostname.c \
getloadavg.c getlogin.c getmntinfo.c getnetgrent.c getpagesize.c \
Index: lib/libc/gen/opendir.c
===================================================================
RCS file: /home/mdempsky/anoncvs/cvs/src/lib/libc/gen/opendir.c,v
retrieving revision 1.21
diff -u -p -r1.21 opendir.c
--- lib/libc/gen/opendir.c 14 Jul 2011 02:16:00 -0000 1.21
+++ lib/libc/gen/opendir.c 14 Jul 2011 06:03:07 -0000
@@ -1,47 +1,24 @@
/* $OpenBSD: opendir.c,v 1.21 2011/07/14 02:16:00 deraadt Exp $ */
/*
- * Copyright (c) 1983, 1993
- * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 2011 Matthew Dempsky <[email protected]>
*
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
*
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#include <sys/param.h>
-#include <sys/mount.h>
-#include <sys/stat.h>
-
#include <dirent.h>
-#include <errno.h>
#include <fcntl.h>
-#include <limits.h>
-#include <stdlib.h>
-#include <string.h>
#include <unistd.h>
-#include "telldir.h"
-
/*
* Open a directory.
*/
@@ -50,56 +27,11 @@ opendir(const char *name)
{
DIR *dirp;
int fd;
- struct stat sb;
- int pageoffset;
- if ((fd = open(name, O_RDONLY | O_NONBLOCK)) == -1)
- return (NULL);
- if (fstat(fd, &sb)) {
- close(fd);
- return (NULL);
- }
- if (!S_ISDIR(sb.st_mode)) {
- close(fd);
- errno = ENOTDIR;
- return (NULL);
- }
- if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1 ||
- (dirp = malloc(sizeof(DIR) + sizeof(struct _telldir))) == NULL) {
- close(fd);
+ if ((fd = open(name, O_RDONLY | O_DIRECTORY | O_CLOEXEC)) == -1)
return (NULL);
- }
-
- dirp->dd_td = (struct _telldir *)((char *)dirp + sizeof(DIR));
- dirp->dd_td->td_locs = NULL;
- dirp->dd_td->td_sz = 0;
- dirp->dd_td->td_loccnt = 0;
- dirp->dd_td->td_last = 0;
-
- /*
- * Use a buffer that is page aligned.
- * Hopefully this can be a big win someday by allowing page trades
- * to user space to be done by getdirentries()
- */
- pageoffset = getpagesize() - 1;
- dirp->dd_len = ((int)sb.st_blksize + pageoffset) & ~pageoffset;
- dirp->dd_buf = malloc((size_t)dirp->dd_len);
- if (dirp->dd_buf == NULL) {
- free(dirp);
+ dirp = fdopendir(fd);
+ if (dirp == NULL)
close(fd);
- return (NULL);
- }
-
- dirp->dd_seek = 0;
- dirp->dd_loc = 0;
- dirp->dd_fd = fd;
- dirp->dd_unused = 0;
- dirp->dd_lock = NULL;
-
- /*
- * Set up seek point for rewinddir.
- */
- dirp->dd_rewind = telldir(dirp);
-
return (dirp);
}
Index: lib/libc/gen/fdopendir.c
===================================================================
RCS file: lib/libc/gen/fdopendir.c
diff -N lib/libc/gen/fdopendir.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ lib/libc/gen/fdopendir.c 14 Jul 2011 03:57:03 -0000
@@ -0,0 +1,111 @@
+/* $OpenBSD: opendir.c,v 1.21 2011/07/14 02:16:00 deraadt Exp $ */
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "telldir.h"
+
+/*
+ * Open a directory.
+ */
+DIR *
+fdopendir(int fd)
+{
+ DIR *dirp;
+ struct stat sb;
+ int pageoffset, flags;
+
+ if ((flags = fcntl(fd, F_GETFL)) == -1)
+ return (NULL);
+ if ((flags & O_ACCMODE) != O_RDONLY && (flags & O_ACCMODE) != O_RDWR) {
+ errno = EBADF;
+ return (NULL);
+ }
+ if (fstat(fd, &sb))
+ return (NULL);
+ if (!S_ISDIR(sb.st_mode)) {
+ errno = ENOTDIR;
+ return (NULL);
+ }
+ if ((dirp = malloc(sizeof(DIR) + sizeof(struct _telldir))) == NULL)
+ return (NULL);
+
+ /*
+ * Use a buffer that is page aligned.
+ * Hopefully this can be a big win someday by allowing page trades
+ * to user space to be done by getdirentries()
+ */
+ pageoffset = getpagesize() - 1;
+ dirp->dd_len = ((int)sb.st_blksize + pageoffset) & ~pageoffset;
+ dirp->dd_buf = malloc((size_t)dirp->dd_len);
+ if (dirp->dd_buf == NULL) {
+ free(dirp);
+ return (NULL);
+ }
+
+ /*
+ * Set FD_CLOEXEC once we know we'll succeed.
+ *
+ * POSIX doesn't require fdopendir() to set FD_CLOEXEC, so we don't
+ * really need to worry if fcntl() fails, but it doesn't hurt to play
+ * safe.
+ */
+ if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) {
+ free(dirp->dd_buf);
+ free(dirp);
+ return (NULL);
+ }
+
+ dirp->dd_td = (struct _telldir *)((char *)dirp + sizeof(DIR));
+ dirp->dd_td->td_locs = NULL;
+ dirp->dd_td->td_sz = 0;
+ dirp->dd_td->td_loccnt = 0;
+ dirp->dd_td->td_last = 0;
+
+ dirp->dd_seek = 0;
+ dirp->dd_loc = 0;
+ dirp->dd_fd = fd;
+ dirp->dd_unused = 0;
+ dirp->dd_lock = NULL;
+
+ /*
+ * Set up seek point for rewinddir.
+ */
+ dirp->dd_rewind = telldir(dirp);
+
+ return (dirp);
+}