This source file includes following definitions.
- orig_openat
- rpl_openat
- openat
- openat_permissive
- openat_needs_fchdir
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 #define __need_system_fcntl_h
23 #include <config.h>
24
25
26 #include <fcntl.h>
27 #include <sys/types.h>
28 #undef __need_system_fcntl_h
29
30 #if HAVE_OPENAT
31 static int
32 orig_openat (int fd, char const *filename, int flags, mode_t mode)
33 {
34 return openat (fd, filename, flags, mode);
35 }
36 #endif
37
38
39
40 #include "fcntl.h"
41
42 #include "openat.h"
43
44 #include "cloexec.h"
45
46 #include <stdarg.h>
47 #include <stdbool.h>
48 #include <stddef.h>
49 #include <stdlib.h>
50 #include <string.h>
51 #include <sys/stat.h>
52 #include <errno.h>
53
54 #if HAVE_OPENAT
55
56
57
58 int
59 rpl_openat (int dfd, char const *filename, int flags, ...)
60 {
61
62 #if GNULIB_defined_O_CLOEXEC
63 int have_cloexec = -1;
64 #else
65 static int have_cloexec;
66 #endif
67
68 mode_t mode;
69 int fd;
70
71 mode = 0;
72 if (flags & O_CREAT)
73 {
74 va_list arg;
75 va_start (arg, flags);
76
77
78
79 mode = va_arg (arg, PROMOTED_MODE_T);
80
81 va_end (arg);
82 }
83
84 # if OPEN_TRAILING_SLASH_BUG
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103 if ((flags & O_CREAT)
104 || (flags & O_ACCMODE) == O_RDWR
105 || (flags & O_ACCMODE) == O_WRONLY)
106 {
107 size_t len = strlen (filename);
108 if (len > 0 && filename[len - 1] == '/')
109 {
110 errno = EISDIR;
111 return -1;
112 }
113 }
114 # endif
115
116 fd = orig_openat (dfd, filename,
117 flags & ~(have_cloexec < 0 ? O_CLOEXEC : 0), mode);
118
119 if (flags & O_CLOEXEC)
120 {
121 if (! have_cloexec)
122 {
123 if (0 <= fd)
124 have_cloexec = 1;
125 else if (errno == EINVAL)
126 {
127 fd = orig_openat (dfd, filename, flags & ~O_CLOEXEC, mode);
128 have_cloexec = -1;
129 }
130 }
131 if (have_cloexec < 0 && 0 <= fd)
132 set_cloexec_flag (fd, true);
133 }
134
135
136 # if OPEN_TRAILING_SLASH_BUG
137
138
139
140
141
142
143
144
145
146
147 if (fd >= 0)
148 {
149
150 size_t len = strlen (filename);
151 if (filename[len - 1] == '/')
152 {
153 struct stat statbuf;
154
155 if (fstat (fd, &statbuf) >= 0 && !S_ISDIR (statbuf.st_mode))
156 {
157 close (fd);
158 errno = ENOTDIR;
159 return -1;
160 }
161 }
162 }
163 # endif
164
165 return fd;
166 }
167
168 #else
169
170 # include "filename.h"
171 # include "openat-priv.h"
172 # include "save-cwd.h"
173
174
175
176
177
178
179
180
181
182 int
183 openat (int fd, char const *file, int flags, ...)
184 {
185 mode_t mode = 0;
186
187 if (flags & O_CREAT)
188 {
189 va_list arg;
190 va_start (arg, flags);
191
192
193
194 mode = va_arg (arg, PROMOTED_MODE_T);
195
196 va_end (arg);
197 }
198
199 return openat_permissive (fd, file, flags, mode, NULL);
200 }
201
202
203
204
205
206
207
208
209
210
211
212
213 int
214 openat_permissive (int fd, char const *file, int flags, mode_t mode,
215 int *cwd_errno)
216 {
217 struct saved_cwd saved_cwd;
218 int saved_errno;
219 int err;
220 bool save_ok;
221
222 if (fd == AT_FDCWD || IS_ABSOLUTE_FILE_NAME (file))
223 return open (file, flags, mode);
224
225 {
226 char buf[OPENAT_BUFFER_SIZE];
227 char *proc_file = openat_proc_name (buf, fd, file);
228 if (proc_file)
229 {
230 int open_result = open (proc_file, flags, mode);
231 int open_errno = errno;
232 if (proc_file != buf)
233 free (proc_file);
234
235
236
237 if (0 <= open_result || ! EXPECTED_ERRNO (open_errno))
238 {
239 errno = open_errno;
240 return open_result;
241 }
242 }
243 }
244
245 save_ok = (save_cwd (&saved_cwd) == 0);
246 if (! save_ok)
247 {
248 if (! cwd_errno)
249 openat_save_fail (errno);
250 *cwd_errno = errno;
251 }
252 if (0 <= fd && fd == saved_cwd.desc)
253 {
254
255
256
257 free_cwd (&saved_cwd);
258 errno = EBADF;
259 return -1;
260 }
261
262 err = fchdir (fd);
263 saved_errno = errno;
264
265 if (! err)
266 {
267 err = open (file, flags, mode);
268 saved_errno = errno;
269 if (save_ok && restore_cwd (&saved_cwd) != 0)
270 {
271 if (! cwd_errno)
272 {
273
274 saved_errno = errno;
275 if (err == STDERR_FILENO)
276 close (err);
277 openat_restore_fail (saved_errno);
278 }
279 *cwd_errno = errno;
280 }
281 }
282
283 free_cwd (&saved_cwd);
284 errno = saved_errno;
285 return err;
286 }
287
288
289
290 bool
291 openat_needs_fchdir (void)
292 {
293 bool needs_fchdir = true;
294 int fd = open ("/", O_SEARCH | O_CLOEXEC);
295
296 if (0 <= fd)
297 {
298 char buf[OPENAT_BUFFER_SIZE];
299 char *proc_file = openat_proc_name (buf, fd, ".");
300 if (proc_file)
301 {
302 needs_fchdir = false;
303 if (proc_file != buf)
304 free (proc_file);
305 }
306 close (fd);
307 }
308
309 return needs_fchdir;
310 }
311
312 #endif