1 /* $OpenBSD: opendir.c,v 1.30 2016/09/21 04:38:56 guenther Exp $ */
2 /*
3 * Copyright (c) 1983, 1993
4 * The Regents of the University of California. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of the University nor the names of its contributors
15 * may be used to endorse or promote products derived from this software
16 * without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 */
30
31 #include <sys/types.h>
32 #include <sys/stat.h>
33
34 #include <dirent.h>
35 #include <errno.h>
36 #include <fcntl.h>
37 #include <stdlib.h>
38 #include <unistd.h>
39
40 #include "telldir.h"
41
42 static DIR *__fdopendir(int fd);
43
44 /*
45 * Open a directory specified by name.
46 */
47 DIR *
opendir(const char * name)48 opendir(const char *name)
49 {
50 DIR *dirp;
51 int fd;
52
53 if ((fd = open(name, O_RDONLY | O_DIRECTORY | O_CLOEXEC)) == -1)
54 return (NULL);
55 dirp = __fdopendir(fd);
56 if (dirp == NULL)
57 close(fd);
58 return (dirp);
59 }
60 DEF_WEAK(opendir);
61
62 /*
63 * Open a directory specified by file descriptor.
64 */
65 DIR *
fdopendir(int fd)66 fdopendir(int fd)
67 {
68 DIR *dirp;
69 int flags;
70
71 if ((flags = fcntl(fd, F_GETFL)) == -1)
72 return (NULL);
73 if ((flags & O_ACCMODE) != O_RDONLY && (flags & O_ACCMODE) != O_RDWR) {
74 errno = EBADF;
75 return (NULL);
76 }
77 dirp = __fdopendir(fd);
78 if (dirp != NULL) {
79 /* Record current offset for immediate telldir() */
80 dirp->dd_bufpos = dirp->dd_curpos = lseek(fd, 0, SEEK_CUR);
81
82 /*
83 * POSIX doesn't require fdopendir() to set
84 * FD_CLOEXEC, so it's okay for this to fail.
85 */
86 (void)fcntl(fd, F_SETFD, FD_CLOEXEC);
87 }
88 return (dirp);
89 }
90 DEF_WEAK(fdopendir);
91
92 static DIR *
__fdopendir(int fd)93 __fdopendir(int fd)
94 {
95 DIR *dirp;
96 struct stat sb;
97 int pageoffset;
98
99 if (fstat(fd, &sb))
100 return (NULL);
101 if (!S_ISDIR(sb.st_mode)) {
102 errno = ENOTDIR;
103 return (NULL);
104 }
105 if ((dirp = malloc(sizeof(DIR))) == NULL)
106 return (NULL);
107
108 pageoffset = getpagesize() - 1;
109 dirp->dd_len = ((int)sb.st_blksize * 4 + pageoffset) & ~pageoffset;
110 dirp->dd_buf = malloc(dirp->dd_len);
111 if (dirp->dd_buf == NULL) {
112 free(dirp);
113 return (NULL);
114 }
115
116 dirp->dd_size = 0;
117 dirp->dd_loc = 0;
118 dirp->dd_fd = fd;
119 dirp->dd_lock = NULL;
120 dirp->dd_curpos = 0;
121 dirp->dd_bufpos = 0;
122
123 return (dirp);
124 }
125