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