This source file includes following definitions.
- getcwd_nothrow
- __getcwd_generic
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 #if !_LIBC
18 # include <config.h>
19 # include <unistd.h>
20 # include "pathmax.h"
21 #else
22 # define HAVE_OPENAT 1
23 # define D_INO_IN_DIRENT 1
24 # define HAVE_MSVC_INVALID_PARAMETER_HANDLER 0
25 # define HAVE_MINIMALLY_WORKING_GETCWD 0
26 #endif
27
28 #include <errno.h>
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <stdbool.h>
32 #include <stddef.h>
33
34 #include <fcntl.h>
35
36
37
38
39 #if defined HAVE_OPENAT || (defined GNULIB_OPENAT && defined HAVE_FDOPENDIR)
40 # define HAVE_OPENAT_SUPPORT 1
41 #else
42 # define HAVE_OPENAT_SUPPORT 0
43 #endif
44
45 #ifndef __set_errno
46 # define __set_errno(val) (errno = (val))
47 #endif
48
49 #include <dirent.h>
50 #ifndef _D_EXACT_NAMLEN
51 # define _D_EXACT_NAMLEN(d) strlen ((d)->d_name)
52 #endif
53 #ifndef _D_ALLOC_NAMLEN
54 # define _D_ALLOC_NAMLEN(d) (_D_EXACT_NAMLEN (d) + 1)
55 #endif
56
57 #include <unistd.h>
58 #include <stdlib.h>
59 #include <string.h>
60
61 #if _LIBC
62 # ifndef mempcpy
63 # define mempcpy __mempcpy
64 # endif
65 #endif
66
67 #ifndef MAX
68 # define MAX(a, b) ((a) < (b) ? (b) : (a))
69 #endif
70 #ifndef MIN
71 # define MIN(a, b) ((a) < (b) ? (a) : (b))
72 #endif
73
74
75
76 #ifndef PATH_MAX
77 # define PATH_MAX 8192
78 #endif
79
80 #if D_INO_IN_DIRENT
81 # define MATCHING_INO(dp, ino) ((dp)->d_ino == (ino))
82 #else
83 # define MATCHING_INO(dp, ino) true
84 #endif
85
86 #if HAVE_MSVC_INVALID_PARAMETER_HANDLER
87 # include "msvc-inval.h"
88 #endif
89
90 #if !_LIBC
91 # define GETCWD_RETURN_TYPE char *
92 # define __close_nocancel_nostatus close
93 # define __getcwd_generic rpl_getcwd
94 # undef stat64
95 # define stat64 stat
96 # define __fstat64 fstat
97 # define __fstatat64 fstatat
98 # define __lstat64 lstat
99 # define __closedir closedir
100 # define __opendir opendir
101 # define __readdir64 readdir
102 # define __fdopendir fdopendir
103 # define __openat openat
104 # define __rewinddir rewinddir
105 # define __openat64 openat
106 # define dirent64 dirent
107 #else
108 # include <not-cancel.h>
109 #endif
110
111
112
113
114
115
116
117 #ifdef GNULIB_defined_opendir
118 # undef opendir
119 #endif
120 #ifdef GNULIB_defined_closedir
121 # undef closedir
122 #endif
123
124 #if defined _WIN32 && !defined __CYGWIN__
125 # if HAVE_MSVC_INVALID_PARAMETER_HANDLER
126 static char *
127 getcwd_nothrow (char *buf, size_t size)
128 {
129 char *result;
130
131 TRY_MSVC_INVAL
132 {
133 result = _getcwd (buf, size);
134 }
135 CATCH_MSVC_INVAL
136 {
137 result = NULL;
138 errno = ERANGE;
139 }
140 DONE_MSVC_INVAL;
141
142 return result;
143 }
144 # else
145 # define getcwd_nothrow _getcwd
146 # endif
147 # define getcwd_system getcwd_nothrow
148 #else
149 # define getcwd_system getcwd
150 #endif
151
152
153
154
155
156
157
158 GETCWD_RETURN_TYPE
159 __getcwd_generic (char *buf, size_t size)
160 {
161
162
163
164
165
166 enum
167 {
168 BIG_FILE_NAME_COMPONENT_LENGTH = 255,
169 BIG_FILE_NAME_LENGTH = MIN (4095, PATH_MAX - 1),
170 DEEP_NESTING = 100
171 };
172
173 #if HAVE_OPENAT_SUPPORT
174 int fd = AT_FDCWD;
175 bool fd_needs_closing = false;
176 #else
177 char dots[DEEP_NESTING * sizeof ".." + BIG_FILE_NAME_COMPONENT_LENGTH + 1];
178 char *dotlist = dots;
179 size_t dotsize = sizeof dots;
180 size_t dotlen = 0;
181 #endif
182 DIR *dirstream = NULL;
183 dev_t rootdev, thisdev;
184 ino_t rootino, thisino;
185 char *dir;
186 register char *dirp;
187 struct stat64 st;
188 size_t allocated = size;
189 size_t used;
190
191 #if HAVE_MINIMALLY_WORKING_GETCWD
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206 # undef getcwd
207 dir = getcwd_system (buf, size);
208 if (dir || (size && errno == ERANGE))
209 return dir;
210
211
212
213
214
215 if (errno == EINVAL && buf == NULL && size == 0)
216 {
217 char big_buffer[BIG_FILE_NAME_LENGTH + 1];
218 dir = getcwd_system (big_buffer, sizeof big_buffer);
219 if (dir)
220 return strdup (dir);
221 }
222
223 # if HAVE_PARTLY_WORKING_GETCWD
224
225
226 if (errno != ERANGE && errno != ENAMETOOLONG && errno != ENOENT)
227 return NULL;
228 # endif
229 #endif
230 if (size == 0)
231 {
232 if (buf != NULL)
233 {
234 __set_errno (EINVAL);
235 return NULL;
236 }
237
238 allocated = BIG_FILE_NAME_LENGTH + 1;
239 }
240
241 if (buf == NULL)
242 {
243 dir = malloc (allocated);
244 if (dir == NULL)
245 return NULL;
246 }
247 else
248 dir = buf;
249
250 dirp = dir + allocated;
251 *--dirp = '\0';
252
253 if (__lstat64 (".", &st) < 0)
254 goto lose;
255 thisdev = st.st_dev;
256 thisino = st.st_ino;
257
258 if (__lstat64 ("/", &st) < 0)
259 goto lose;
260 rootdev = st.st_dev;
261 rootino = st.st_ino;
262
263 while (!(thisdev == rootdev && thisino == rootino))
264 {
265 struct dirent64 *d;
266 dev_t dotdev;
267 ino_t dotino;
268 bool mount_point;
269 int parent_status;
270 size_t dirroom;
271 size_t namlen;
272 bool use_d_ino = true;
273
274
275 #if HAVE_OPENAT_SUPPORT
276 fd = __openat64 (fd, "..", O_RDONLY);
277 if (fd < 0)
278 goto lose;
279 fd_needs_closing = true;
280 parent_status = __fstat64 (fd, &st);
281 #else
282 dotlist[dotlen++] = '.';
283 dotlist[dotlen++] = '.';
284 dotlist[dotlen] = '\0';
285 parent_status = __lstat64 (dotlist, &st);
286 #endif
287 if (parent_status != 0)
288 goto lose;
289
290 if (dirstream && __closedir (dirstream) != 0)
291 {
292 dirstream = NULL;
293 goto lose;
294 }
295
296
297 dotdev = st.st_dev;
298 dotino = st.st_ino;
299 mount_point = dotdev != thisdev;
300
301
302 #if HAVE_OPENAT_SUPPORT
303 dirstream = __fdopendir (fd);
304 if (dirstream == NULL)
305 goto lose;
306 fd_needs_closing = false;
307 #else
308 dirstream = __opendir (dotlist);
309 if (dirstream == NULL)
310 goto lose;
311 dotlist[dotlen++] = '/';
312 #endif
313 for (;;)
314 {
315
316
317 __set_errno (0);
318 d = __readdir64 (dirstream);
319
320
321
322
323
324
325
326
327 if (d == NULL && errno == 0 && use_d_ino)
328 {
329 use_d_ino = false;
330 __rewinddir (dirstream);
331 d = __readdir64 (dirstream);
332 }
333
334 if (d == NULL)
335 {
336 if (errno == 0)
337
338
339 __set_errno (ENOENT);
340 goto lose;
341 }
342 if (d->d_name[0] == '.' &&
343 (d->d_name[1] == '\0' ||
344 (d->d_name[1] == '.' && d->d_name[2] == '\0')))
345 continue;
346
347 if (use_d_ino)
348 {
349 bool match = (MATCHING_INO (d, thisino) || mount_point);
350 if (! match)
351 continue;
352 }
353
354 {
355 int entry_status;
356 #if HAVE_OPENAT_SUPPORT
357 entry_status = __fstatat64 (fd, d->d_name, &st, AT_SYMLINK_NOFOLLOW);
358 #else
359
360
361
362
363 size_t name_alloc = _D_ALLOC_NAMLEN (d);
364 size_t filesize = dotlen + MAX (sizeof "..", name_alloc);
365
366 if (filesize < dotlen)
367 goto memory_exhausted;
368
369 if (dotsize < filesize)
370 {
371
372 size_t newsize = MAX (filesize, dotsize * 2);
373 size_t i;
374 if (newsize < dotsize)
375 goto memory_exhausted;
376 if (dotlist != dots)
377 free (dotlist);
378 dotlist = malloc (newsize);
379 if (dotlist == NULL)
380 goto lose;
381 dotsize = newsize;
382
383 i = 0;
384 do
385 {
386 dotlist[i++] = '.';
387 dotlist[i++] = '.';
388 dotlist[i++] = '/';
389 }
390 while (i < dotlen);
391 }
392
393 memcpy (dotlist + dotlen, d->d_name, _D_ALLOC_NAMLEN (d));
394 entry_status = __lstat64 (dotlist, &st);
395 #endif
396
397
398
399
400
401 if (entry_status == 0 && S_ISDIR (st.st_mode)
402 && st.st_dev == thisdev && st.st_ino == thisino)
403 break;
404 }
405 }
406
407 dirroom = dirp - dir;
408 namlen = _D_EXACT_NAMLEN (d);
409
410 if (dirroom <= namlen)
411 {
412 if (size != 0)
413 {
414 __set_errno (ERANGE);
415 goto lose;
416 }
417 else
418 {
419 char *tmp;
420 size_t oldsize = allocated;
421
422 allocated += MAX (allocated, namlen);
423 if (allocated < oldsize
424 || ! (tmp = realloc (dir, allocated)))
425 goto memory_exhausted;
426
427
428
429 dirp = memcpy (tmp + allocated - (oldsize - dirroom),
430 tmp + dirroom,
431 oldsize - dirroom);
432 dir = tmp;
433 }
434 }
435 dirp -= namlen;
436 memcpy (dirp, d->d_name, namlen);
437 *--dirp = '/';
438
439 thisdev = dotdev;
440 thisino = dotino;
441 }
442
443 if (dirstream && __closedir (dirstream) != 0)
444 {
445 dirstream = NULL;
446 goto lose;
447 }
448
449 if (dirp == &dir[allocated - 1])
450 *--dirp = '/';
451
452 #if ! HAVE_OPENAT_SUPPORT
453 if (dotlist != dots)
454 free (dotlist);
455 #endif
456
457 used = dir + allocated - dirp;
458 memmove (dir, dirp, used);
459
460 if (size == 0)
461
462 buf = (used < allocated ? realloc (dir, used) : dir);
463
464 if (buf == NULL)
465
466
467 buf = dir;
468
469 return buf;
470
471 memory_exhausted:
472 __set_errno (ENOMEM);
473 lose:
474 {
475 int save = errno;
476 if (dirstream)
477 __closedir (dirstream);
478 #if HAVE_OPENAT_SUPPORT
479 if (fd_needs_closing)
480 __close_nocancel_nostatus (fd);
481 #else
482 if (dotlist != dots)
483 free (dotlist);
484 #endif
485 if (buf == NULL)
486 free (dir);
487 __set_errno (save);
488 }
489 return NULL;
490 }
491
492 #if defined _LIBC && !defined GETCWD_RETURN_TYPE
493 libc_hidden_def (__getcwd)
494 weak_alias (__getcwd, getcwd)
495 #endif