]> git.ipfire.org Git - thirdparty/glibc.git/blame - sysdeps/posix/opendir.c
Update copyright notices with scripts/update-copyrights.
[thirdparty/glibc.git] / sysdeps / posix / opendir.c
CommitLineData
568035b7 1/* Copyright (C) 1991-2013 Free Software Foundation, Inc.
01c901a5
UD
2 This file is part of the GNU C Library.
3
4 The GNU C Library is free software; you can redistribute it and/or
41bdb6e2
AJ
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
01c901a5
UD
8
9 The GNU C Library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
41bdb6e2 12 Lesser General Public License for more details.
01c901a5 13
41bdb6e2 14 You should have received a copy of the GNU Lesser General Public
59ba27a6
PE
15 License along with the GNU C Library; if not, see
16 <http://www.gnu.org/licenses/>. */
28f540f4 17
c55fbd1e 18#include <assert.h>
28f540f4
RM
19#include <errno.h>
20#include <limits.h>
21#include <stddef.h>
22#include <stdlib.h>
23#include <dirent.h>
24#include <fcntl.h>
25#include <sys/types.h>
26#include <sys/stat.h>
27#include <unistd.h>
28#include <stdio.h>
39358e8b 29#include <string.h>
28f540f4 30
92777700 31#include <dirstream.h>
73299943 32#include <not-cancel.h>
cbf0489b 33#include <kernel-features.h>
73299943 34
172a631a
FW
35/* The st_blksize value of the directory is used as a hint for the
36 size of the buffer which receives struct dirent values from the
37 kernel. st_blksize is limited to MAX_DIR_BUFFER_SIZE, in case the
38 file system provides a bogus value. */
39#define MAX_DIR_BUFFER_SIZE 1048576U
28f540f4 40
8b7fb588
UD
41/* opendir() must not accidentally open something other than a directory.
42 Some OS's have kernel support for that, some don't. In the worst
43 case we have to stat() before the open() AND fstat() after.
44
45 We have to test at runtime for kernel support since libc may have
46 been compiled with different headers to the kernel it's running on.
47 This test can't be done reliably in the general case. We'll use
48 /dev/null, which if it's not a device lots of stuff will break, as
49 a guinea pig. It may be missing in chroot environments, so we
50 make sure to fail safe. */
413bb8ca 51#ifdef O_DIRECTORY
675e4015
UD
52# ifdef O_DIRECTORY_WORKS
53# define o_directory_works 1
54# define tryopen_o_directory() while (1) /* This must not be called. */
55# else
8b7fb588 56static int o_directory_works;
413bb8ca
UD
57
58static void
8b7fb588
UD
59tryopen_o_directory (void)
60{
61 int serrno = errno;
73299943 62 int x = open_not_cancel_2 ("/dev/null", O_RDONLY|O_NDELAY|O_DIRECTORY);
8b7fb588
UD
63
64 if (x >= 0)
65 {
73299943 66 close_not_cancel_no_status (x);
8b7fb588
UD
67 o_directory_works = -1;
68 }
69 else if (errno != ENOTDIR)
70 o_directory_works = -1;
71 else
72 o_directory_works = 1;
73
74 __set_errno (serrno);
75}
675e4015 76# endif
413bb8ca
UD
77# define EXTRA_FLAGS O_DIRECTORY
78#else
79# define EXTRA_FLAGS 0
9ffbb612
UD
80#endif
81
82
28f540f4 83DIR *
c55fbd1e
UD
84internal_function
85__opendirat (int dfd, const char *name)
28f540f4 86{
8edf6e0d 87 struct stat64 statbuf;
62f63c47 88 struct stat64 *statp = NULL;
28f540f4 89
726b7b0f 90 if (__builtin_expect (name[0], '\1') == '\0')
28f540f4
RM
91 {
92 /* POSIX.1-1990 says an empty name gets ENOENT;
93 but `open' might like it fine. */
c4029823 94 __set_errno (ENOENT);
28f540f4
RM
95 return NULL;
96 }
97
413bb8ca
UD
98#ifdef O_DIRECTORY
99 /* Test whether O_DIRECTORY works. */
8b7fb588 100 if (o_directory_works == 0)
413bb8ca
UD
101 tryopen_o_directory ();
102
103 /* We can skip the expensive `stat' call if O_DIRECTORY works. */
8b7fb588 104 if (o_directory_works < 0)
413bb8ca 105#endif
99e46354 106 {
413bb8ca
UD
107 /* We first have to check whether the name is for a directory. We
108 cannot do this after the open() call since the open/close operation
109 performed on, say, a tape device might have undesirable effects. */
726b7b0f 110 if (__builtin_expect (__xstat64 (_STAT_VER, name, &statbuf), 0) < 0)
413bb8ca 111 return NULL;
726b7b0f 112 if (__builtin_expect (! S_ISDIR (statbuf.st_mode), 0))
413bb8ca
UD
113 {
114 __set_errno (ENOTDIR);
115 return NULL;
116 }
99e46354
UD
117 }
118
cbf0489b
UD
119 int flags = O_RDONLY|O_NDELAY|EXTRA_FLAGS|O_LARGEFILE;
120#ifdef O_CLOEXEC
121 flags |= O_CLOEXEC;
122#endif
c55fbd1e
UD
123 int fd;
124#ifdef IS_IN_rtld
125 assert (dfd == AT_FDCWD);
126 fd = open_not_cancel_2 (name, flags);
127#else
128 fd = openat_not_cancel_3 (dfd, name, flags);
129#endif
726b7b0f 130 if (__builtin_expect (fd, 0) < 0)
4bd8be48
UD
131 return NULL;
132
256ba888
UD
133#ifdef O_DIRECTORY
134 if (o_directory_works <= 0)
135#endif
4bd8be48 136 {
62f63c47
UD
137 /* Now make sure this really is a directory and nothing changed since
138 the `stat' call. */
139 if (__builtin_expect (__fxstat64 (_STAT_VER, fd, &statbuf), 0) < 0)
140 goto lose;
256ba888
UD
141 if (__builtin_expect (! S_ISDIR (statbuf.st_mode), 0))
142 {
1812d50b
UD
143 __set_errno (ENOTDIR);
144 lose:
145 close_not_cancel_no_status (fd);
146 return NULL;
256ba888 147 }
62f63c47 148 statp = &statbuf;
4bd8be48 149 }
28f540f4 150
28377d1b 151 return __alloc_dir (fd, true, 0, statp);
1812d50b 152}
c55fbd1e
UD
153
154
155/* Open a directory stream on NAME. */
156DIR *
157__opendir (const char *name)
158{
159 return __opendirat (AT_FDCWD, name);
160}
1812d50b
UD
161weak_alias (__opendir, opendir)
162
163
cbf0489b
UD
164#ifdef __ASSUME_O_CLOEXEC
165# define check_have_o_cloexec(fd) 1
166#else
167static int
168check_have_o_cloexec (int fd)
169{
170 if (__have_o_cloexec == 0)
171 __have_o_cloexec = (__fcntl (fd, F_GETFD, 0) & FD_CLOEXEC) == 0 ? -1 : 1;
172 return __have_o_cloexec > 0;
173}
174#endif
175
176
1812d50b
UD
177DIR *
178internal_function
28377d1b 179__alloc_dir (int fd, bool close_fd, int flags, const struct stat64 *statp)
1812d50b 180{
cbf0489b
UD
181 /* We always have to set the close-on-exit flag if the user provided
182 the file descriptor. Otherwise only if we have no working
183 O_CLOEXEC support. */
184#ifdef O_CLOEXEC
28377d1b
UD
185 if ((! close_fd && (flags & O_CLOEXEC) == 0)
186 || ! check_have_o_cloexec (fd))
cbf0489b
UD
187#endif
188 {
189 if (__builtin_expect (__fcntl (fd, F_SETFD, FD_CLOEXEC), 0) < 0)
190 goto lose;
191 }
28f540f4 192
62f63c47
UD
193 const size_t default_allocation = (4 * BUFSIZ < sizeof (struct dirent64)
194 ? sizeof (struct dirent64) : 4 * BUFSIZ);
195 const size_t small_allocation = (BUFSIZ < sizeof (struct dirent64)
196 ? sizeof (struct dirent64) : BUFSIZ);
197 size_t allocation = default_allocation;
28f540f4 198#ifdef _STATBUF_ST_BLKSIZE
172a631a
FW
199 /* Increase allocation if requested, but not if the value appears to
200 be bogus. */
201 if (statp != NULL)
202 allocation = MIN (MAX ((size_t) statp->st_blksize, default_allocation),
203 MAX_DIR_BUFFER_SIZE);
28f540f4 204#endif
9eecb5e8 205
fa39685d 206 DIR *dirp = (DIR *) malloc (sizeof (DIR) + allocation);
9eecb5e8 207 if (dirp == NULL)
28f540f4 208 {
62f63c47
UD
209 allocation = small_allocation;
210 dirp = (DIR *) malloc (sizeof (DIR) + allocation);
211
221e5230 212 if (dirp == NULL)
221e5230
UD
213 lose:
214 {
215 if (close_fd)
216 {
217 int save_errno = errno;
218 close_not_cancel_no_status (fd);
219 __set_errno (save_errno);
220 }
221 return NULL;
18b8e054 222 }
28f540f4 223 }
c1509239 224
c8ccd8e3 225 dirp->fd = fd;
858ee15d 226#ifndef NOT_IN_libc
0d204b0a 227 __libc_lock_init (dirp->lock);
858ee15d 228#endif
c8ccd8e3 229 dirp->allocation = allocation;
fa39685d
UD
230 dirp->size = 0;
231 dirp->offset = 0;
232 dirp->filepos = 0;
c1509239 233
28f540f4
RM
234 return dirp;
235}