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