summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorMatthew Dempsky <matthew@cvs.openbsd.org>2011-07-18 00:27:16 +0000
committerMatthew Dempsky <matthew@cvs.openbsd.org>2011-07-18 00:27:16 +0000
commitd4690ef70a159b8efc7cccd2e29deac67bddd4d4 (patch)
tree51520b2dc2da575bf757f8ae0407b488172250ba /lib
parent0862cd89c38c47f15c4de07c912b6d9df70294ee (diff)
Implement fdopendir(3) and refactor opendir(3) and fdopendir(3) to use
a common __fdopendir() function. Also, take advantage of the new O_DIRECTORY and O_CLOEXEC flags in opendir(3). (Currently fdopendir(3) is commented out; it will be enabled shortly alongside openat(2) et al.) Tested by naddy@ in a bulk build. tweaks and ok guenther@; stupid POSIX nit pointed out by oga@
Diffstat (limited to 'lib')
-rw-r--r--lib/libc/gen/opendir.c84
1 files changed, 62 insertions, 22 deletions
diff --git a/lib/libc/gen/opendir.c b/lib/libc/gen/opendir.c
index b9401f878f3..481ae11c2e0 100644
--- a/lib/libc/gen/opendir.c
+++ b/lib/libc/gen/opendir.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: opendir.c,v 1.21 2011/07/14 02:16:00 deraadt Exp $ */
+/* $OpenBSD: opendir.c,v 1.22 2011/07/18 00:27:15 matthew Exp $ */
/*
* Copyright (c) 1983, 1993
* The Regents of the University of California. All rights reserved.
@@ -28,53 +28,82 @@
* SUCH DAMAGE.
*/
-#include <sys/param.h>
-#include <sys/mount.h>
+#include <sys/types.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"
+static DIR *__fdopendir(int fd, off_t offset);
+
/*
- * Open a directory.
+ * Open a directory specified by name.
*/
DIR *
opendir(const char *name)
{
DIR *dirp;
int fd;
- struct stat sb;
- int pageoffset;
- if ((fd = open(name, O_RDONLY | O_NONBLOCK)) == -1)
+ if ((fd = open(name, O_RDONLY | O_DIRECTORY | O_CLOEXEC)) == -1)
return (NULL);
- if (fstat(fd, &sb)) {
+ dirp = __fdopendir(fd, 0);
+ if (dirp == NULL)
close(fd);
+ return (dirp);
+}
+
+#if 0
+/*
+ * Open a directory specified by file descriptor.
+ */
+DIR *
+fdopendir(int fd)
+{
+ DIR *dirp;
+ int flags;
+ off_t offset;
+
+ 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 ((offset = lseek(fd, 0, SEEK_CUR)) == -1)
return (NULL);
+ dirp = __fdopendir(fd, offset);
+ if (dirp != NULL) {
+ /*
+ * POSIX doesn't require fdopendir() to set
+ * FD_CLOEXEC, so it's okay for this to fail.
+ */
+ (void)fcntl(fd, F_SETFD, FD_CLOEXEC);
}
+ return (dirp);
+}
+#endif
+
+static DIR *
+__fdopendir(int fd, off_t offset)
+{
+ DIR *dirp;
+ struct stat sb;
+ int pageoffset;
+
+ if (fstat(fd, &sb))
+ 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 ((dirp = malloc(sizeof(DIR) + sizeof(struct _telldir))) == NULL)
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.
@@ -86,10 +115,15 @@ opendir(const char *name)
dirp->dd_buf = malloc((size_t)dirp->dd_len);
if (dirp->dd_buf == NULL) {
free(dirp);
- close(fd);
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;
@@ -101,5 +135,11 @@ opendir(const char *name)
*/
dirp->dd_rewind = telldir(dirp);
+ /*
+ * Store our actual seek offset. Must do this *after* setting
+ * dd_rewind = telldir() so that rewinddir() works correctly.
+ */
+ dirp->dd_seek = offset;
+
return (dirp);
}