This source file includes following definitions.
- file_accessible
- suffix_requires_dir_check
- dir_check
- get_path_max
- realpath_stk
- __realpath
- libc_hidden_def
- __canonicalize_file_name
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 #ifndef _LIBC
20
21
22 # define _GL_ARG_NONNULL(params)
23
24 # include <libc-config.h>
25 #endif
26
27
28 #include <stdlib.h>
29
30 #include <errno.h>
31 #include <fcntl.h>
32 #include <limits.h>
33 #include <stdbool.h>
34 #include <string.h>
35 #include <sys/stat.h>
36 #include <unistd.h>
37
38 #include <eloop-threshold.h>
39 #include <filename.h>
40 #include <idx.h>
41 #include <intprops.h>
42 #include <scratch_buffer.h>
43
44 #ifdef _LIBC
45 # include <shlib-compat.h>
46 # define GCC_LINT 1
47 # define _GL_ATTRIBUTE_PURE __attribute__ ((__pure__))
48 #else
49 # define __canonicalize_file_name canonicalize_file_name
50 # define __realpath realpath
51 # include "pathmax.h"
52 # define __faccessat faccessat
53 # if defined _WIN32 && !defined __CYGWIN__
54 # define __getcwd _getcwd
55 # elif HAVE_GETCWD
56 # if IN_RELOCWRAPPER
57
58
59
60 # undef getcwd
61 # endif
62 # if defined VMS && !defined getcwd
63
64
65
66 # define __getcwd(buf, max) getcwd (buf, max, 0)
67 # else
68 # define __getcwd getcwd
69 # endif
70 # else
71 # define __getcwd(buf, max) getwd (buf)
72 # endif
73 # define __mempcpy mempcpy
74 # define __pathconf pathconf
75 # define __rawmemchr rawmemchr
76 # define __readlink readlink
77 # if IN_RELOCWRAPPER
78
79
80
81 # undef memmove
82 # endif
83 #endif
84
85
86 #if defined GCC_LINT || defined lint
87 # define IF_LINT(Code) Code
88 #else
89 # define IF_LINT(Code)
90 #endif
91
92 #ifndef DOUBLE_SLASH_IS_DISTINCT_ROOT
93 # define DOUBLE_SLASH_IS_DISTINCT_ROOT false
94 #endif
95
96 #if defined _LIBC || !FUNC_REALPATH_WORKS
97
98
99
100 static bool
101 file_accessible (char const *file)
102 {
103 # if defined _LIBC || HAVE_FACCESSAT
104 return __faccessat (AT_FDCWD, file, F_OK, AT_EACCESS) == 0;
105 # else
106 struct stat st;
107 return stat (file, &st) == 0 || errno == EOVERFLOW;
108 # endif
109 }
110
111
112
113
114
115
116
117
118 static bool _GL_ATTRIBUTE_PURE
119 suffix_requires_dir_check (char const *end)
120 {
121
122 while (ISSLASH (*end))
123 {
124
125 do
126 end++;
127 while (ISSLASH (*end));
128
129 switch (*end++)
130 {
131 default: return false;
132 case '\0': return true;
133 case '.': break;
134 }
135
136 if (!*end || (*end == '.' && (!end[1] || ISSLASH (end[1]))))
137 return true;
138 }
139
140 return false;
141 }
142
143
144
145
146
147
148 # if defined _LIBC || defined LSTAT_FOLLOWS_SLASHED_SYMLINK
149 static char const dir_suffix[] = "/";
150 # else
151 static char const dir_suffix[] = "/./";
152 # endif
153
154
155
156
157
158 static bool
159 dir_check (char *dir, char *dirend)
160 {
161 strcpy (dirend, dir_suffix);
162 return file_accessible (dir);
163 }
164
165 static idx_t
166 get_path_max (void)
167 {
168 # ifdef PATH_MAX
169 long int path_max = PATH_MAX;
170 # else
171
172
173
174
175
176 int err = errno;
177 long int path_max = __pathconf ("/", _PC_PATH_MAX);
178 __set_errno (err);
179 # endif
180 return path_max < 0 ? 1024 : path_max <= IDX_MAX ? path_max : IDX_MAX;
181 }
182
183
184
185
186
187
188
189
190
191
192
193
194 # if __GNUC_PREREQ (10, 1)
195 # if defined GCC_LINT || defined lint
196 __attribute__ ((__noinline__))
197 # elif __OPTIMIZE__ && !__NO_INLINE__
198 # define GCC_BOGUS_WRETURN_LOCAL_ADDR
199 # endif
200 # endif
201 static char *
202 realpath_stk (const char *name, char *resolved,
203 struct scratch_buffer *rname_buf)
204 {
205 char *dest;
206 char const *start;
207 char const *end;
208 int num_links = 0;
209
210 if (name == NULL)
211 {
212
213
214
215
216 __set_errno (EINVAL);
217 return NULL;
218 }
219
220 if (name[0] == '\0')
221 {
222
223
224 __set_errno (ENOENT);
225 return NULL;
226 }
227
228 struct scratch_buffer extra_buffer, link_buffer;
229 scratch_buffer_init (&extra_buffer);
230 scratch_buffer_init (&link_buffer);
231 scratch_buffer_init (rname_buf);
232 char *rname_on_stack = rname_buf->data;
233 char *rname = rname_on_stack;
234 bool end_in_extra_buffer = false;
235 bool failed = true;
236
237
238
239 idx_t prefix_len = FILE_SYSTEM_PREFIX_LEN (name);
240
241 if (!IS_ABSOLUTE_FILE_NAME (name))
242 {
243 while (!__getcwd (rname, rname_buf->length))
244 {
245 if (errno != ERANGE)
246 {
247 dest = rname;
248 goto error;
249 }
250 if (!scratch_buffer_grow (rname_buf))
251 goto error_nomem;
252 rname = rname_buf->data;
253 }
254 dest = __rawmemchr (rname, '\0');
255 start = name;
256 prefix_len = FILE_SYSTEM_PREFIX_LEN (rname);
257 }
258 else
259 {
260 dest = __mempcpy (rname, name, prefix_len);
261 *dest++ = '/';
262 if (DOUBLE_SLASH_IS_DISTINCT_ROOT)
263 {
264 if (prefix_len == 0
265 && ISSLASH (name[1]) && !ISSLASH (name[2]))
266 *dest++ = '/';
267 *dest = '\0';
268 }
269 start = name + prefix_len;
270 }
271
272 for ( ; *start; start = end)
273 {
274
275 while (ISSLASH (*start))
276 ++start;
277
278
279 for (end = start; *end && !ISSLASH (*end); ++end)
280 ;
281
282
283
284 idx_t startlen = end - start;
285
286 if (startlen == 0)
287 break;
288 else if (startlen == 1 && start[0] == '.')
289 ;
290 else if (startlen == 2 && start[0] == '.' && start[1] == '.')
291 {
292
293 if (dest > rname + prefix_len + 1)
294 for (--dest; dest > rname && !ISSLASH (dest[-1]); --dest)
295 continue;
296 if (DOUBLE_SLASH_IS_DISTINCT_ROOT
297 && dest == rname + 1 && !prefix_len
298 && ISSLASH (*dest) && !ISSLASH (dest[1]))
299 dest++;
300 }
301 else
302 {
303 if (!ISSLASH (dest[-1]))
304 *dest++ = '/';
305
306 while (rname + rname_buf->length - dest
307 < startlen + sizeof dir_suffix)
308 {
309 idx_t dest_offset = dest - rname;
310 if (!scratch_buffer_grow_preserve (rname_buf))
311 goto error_nomem;
312 rname = rname_buf->data;
313 dest = rname + dest_offset;
314 }
315
316 dest = __mempcpy (dest, start, startlen);
317 *dest = '\0';
318
319 char *buf;
320 ssize_t n;
321 while (true)
322 {
323 buf = link_buffer.data;
324 idx_t bufsize = link_buffer.length;
325 n = __readlink (rname, buf, bufsize - 1);
326 if (n < bufsize - 1)
327 break;
328 if (!scratch_buffer_grow (&link_buffer))
329 goto error_nomem;
330 }
331 if (0 <= n)
332 {
333 if (++num_links > __eloop_threshold ())
334 {
335 __set_errno (ELOOP);
336 goto error;
337 }
338
339 buf[n] = '\0';
340
341 char *extra_buf = extra_buffer.data;
342 idx_t end_idx IF_LINT (= 0);
343 if (end_in_extra_buffer)
344 end_idx = end - extra_buf;
345 size_t len = strlen (end);
346 if (INT_ADD_OVERFLOW (len, n))
347 {
348 __set_errno (ENOMEM);
349 goto error_nomem;
350 }
351 while (extra_buffer.length <= len + n)
352 {
353 if (!scratch_buffer_grow_preserve (&extra_buffer))
354 goto error_nomem;
355 extra_buf = extra_buffer.data;
356 }
357 if (end_in_extra_buffer)
358 end = extra_buf + end_idx;
359
360
361 memmove (&extra_buf[n], end, len + 1);
362 name = end = memcpy (extra_buf, buf, n);
363 end_in_extra_buffer = true;
364
365 if (IS_ABSOLUTE_FILE_NAME (buf))
366 {
367 idx_t pfxlen = FILE_SYSTEM_PREFIX_LEN (buf);
368
369 dest = __mempcpy (rname, buf, pfxlen);
370 *dest++ = '/';
371 if (DOUBLE_SLASH_IS_DISTINCT_ROOT)
372 {
373 if (ISSLASH (buf[1]) && !ISSLASH (buf[2]) && !pfxlen)
374 *dest++ = '/';
375 *dest = '\0';
376 }
377
378 prefix_len = pfxlen;
379 }
380 else
381 {
382
383
384 if (dest > rname + prefix_len + 1)
385 for (--dest; dest > rname && !ISSLASH (dest[-1]); --dest)
386 continue;
387 if (DOUBLE_SLASH_IS_DISTINCT_ROOT && dest == rname + 1
388 && ISSLASH (*dest) && !ISSLASH (dest[1]) && !prefix_len)
389 dest++;
390 }
391 }
392 else if (! (suffix_requires_dir_check (end)
393 ? dir_check (rname, dest)
394 : errno == EINVAL))
395 goto error;
396 }
397 }
398 if (dest > rname + prefix_len + 1 && ISSLASH (dest[-1]))
399 --dest;
400 if (DOUBLE_SLASH_IS_DISTINCT_ROOT && dest == rname + 1 && !prefix_len
401 && ISSLASH (*dest) && !ISSLASH (dest[1]))
402 dest++;
403 failed = false;
404
405 error:
406 *dest++ = '\0';
407 if (resolved != NULL && dest - rname <= get_path_max ())
408 rname = strcpy (resolved, rname);
409
410 error_nomem:
411 scratch_buffer_free (&extra_buffer);
412 scratch_buffer_free (&link_buffer);
413
414 if (failed || rname == resolved)
415 {
416 scratch_buffer_free (rname_buf);
417 return failed ? NULL : resolved;
418 }
419
420 return scratch_buffer_dupfree (rname_buf, dest - rname);
421 }
422
423
424
425
426
427
428
429
430
431
432
433
434 char *
435 __realpath (const char *name, char *resolved)
436 {
437 #ifdef GCC_BOGUS_WRETURN_LOCAL_ADDR
438 #warning "GCC might issue a bogus -Wreturn-local-addr warning here."
439 #warning "See <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=93644>."
440 #endif
441 struct scratch_buffer rname_buffer;
442 return realpath_stk (name, resolved, &rname_buffer);
443 }
444 libc_hidden_def (__realpath)
445 versioned_symbol (libc, __realpath, realpath, GLIBC_2_3);
446
447 #endif
448
449
450 #if SHLIB_COMPAT(libc, GLIBC_2_0, GLIBC_2_3)
451 char *
452 attribute_compat_text_section
453 __old_realpath (const char *name, char *resolved)
454 {
455 if (resolved == NULL)
456 {
457 __set_errno (EINVAL);
458 return NULL;
459 }
460
461 return __realpath (name, resolved);
462 }
463 compat_symbol (libc, __old_realpath, realpath, GLIBC_2_0);
464 #endif
465
466
467 char *
468 __canonicalize_file_name (const char *name)
469 {
470 return __realpath (name, NULL);
471 }
472 weak_alias (__canonicalize_file_name, canonicalize_file_name)