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);
+}

Reply via email to