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 <string.h>
34 #include <sys/stat.h>
35 #include <unistd.h>
36
37 #include <eloop-threshold.h>
38 #include <filename.h>
39 #include <idx.h>
40 #include <intprops.h>
41 #include <scratch_buffer.h>
42
43 #ifdef _LIBC
44 # include <shlib-compat.h>
45 # define GCC_LINT 1
46 # define _GL_ATTRIBUTE_PURE __attribute__ ((__pure__))
47 #else
48 # define __canonicalize_file_name canonicalize_file_name
49 # define __realpath realpath
50 # define __strdup strdup
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 struct realpath_bufs
185 {
186 struct scratch_buffer rname;
187 struct scratch_buffer extra;
188 struct scratch_buffer link;
189 };
190
191 static char *
192 realpath_stk (const char *name, char *resolved, struct realpath_bufs *bufs)
193 {
194 char *dest;
195 char const *start;
196 char const *end;
197 int num_links = 0;
198
199 if (name == NULL)
200 {
201
202
203
204
205 __set_errno (EINVAL);
206 return NULL;
207 }
208
209 if (name[0] == '\0')
210 {
211
212
213 __set_errno (ENOENT);
214 return NULL;
215 }
216
217 char *rname = bufs->rname.data;
218 bool end_in_extra_buffer = false;
219 bool failed = true;
220
221
222
223 idx_t prefix_len = FILE_SYSTEM_PREFIX_LEN (name);
224
225 if (!IS_ABSOLUTE_FILE_NAME (name))
226 {
227 while (!__getcwd (bufs->rname.data, bufs->rname.length))
228 {
229 if (errno != ERANGE)
230 {
231 dest = rname;
232 goto error;
233 }
234 if (!scratch_buffer_grow (&bufs->rname))
235 return NULL;
236 rname = bufs->rname.data;
237 }
238 dest = __rawmemchr (rname, '\0');
239 start = name;
240 prefix_len = FILE_SYSTEM_PREFIX_LEN (rname);
241 }
242 else
243 {
244 dest = __mempcpy (rname, name, prefix_len);
245 *dest++ = '/';
246 if (DOUBLE_SLASH_IS_DISTINCT_ROOT)
247 {
248 if (prefix_len == 0
249 && ISSLASH (name[1]) && !ISSLASH (name[2]))
250 *dest++ = '/';
251 *dest = '\0';
252 }
253 start = name + prefix_len;
254 }
255
256 for ( ; *start; start = end)
257 {
258
259 while (ISSLASH (*start))
260 ++start;
261
262
263 for (end = start; *end && !ISSLASH (*end); ++end)
264 ;
265
266
267
268 idx_t startlen = end - start;
269
270 if (startlen == 0)
271 break;
272 else if (startlen == 1 && start[0] == '.')
273 ;
274 else if (startlen == 2 && start[0] == '.' && start[1] == '.')
275 {
276
277 if (dest > rname + prefix_len + 1)
278 for (--dest; dest > rname && !ISSLASH (dest[-1]); --dest)
279 continue;
280 if (DOUBLE_SLASH_IS_DISTINCT_ROOT
281 && dest == rname + 1 && !prefix_len
282 && ISSLASH (*dest) && !ISSLASH (dest[1]))
283 dest++;
284 }
285 else
286 {
287 if (!ISSLASH (dest[-1]))
288 *dest++ = '/';
289
290 while (rname + bufs->rname.length - dest
291 < startlen + sizeof dir_suffix)
292 {
293 idx_t dest_offset = dest - rname;
294 if (!scratch_buffer_grow_preserve (&bufs->rname))
295 return NULL;
296 rname = bufs->rname.data;
297 dest = rname + dest_offset;
298 }
299
300 dest = __mempcpy (dest, start, startlen);
301 *dest = '\0';
302
303 char *buf;
304 ssize_t n;
305 while (true)
306 {
307 buf = bufs->link.data;
308 idx_t bufsize = bufs->link.length;
309 n = __readlink (rname, buf, bufsize - 1);
310 if (n < bufsize - 1)
311 break;
312 if (!scratch_buffer_grow (&bufs->link))
313 return NULL;
314 }
315 if (0 <= n)
316 {
317 if (++num_links > __eloop_threshold ())
318 {
319 __set_errno (ELOOP);
320 goto error;
321 }
322
323 buf[n] = '\0';
324
325 char *extra_buf = bufs->extra.data;
326 idx_t end_idx IF_LINT (= 0);
327 if (end_in_extra_buffer)
328 end_idx = end - extra_buf;
329 size_t len = strlen (end);
330 if (INT_ADD_OVERFLOW (len, n))
331 {
332 __set_errno (ENOMEM);
333 return NULL;
334 }
335 while (bufs->extra.length <= len + n)
336 {
337 if (!scratch_buffer_grow_preserve (&bufs->extra))
338 return NULL;
339 extra_buf = bufs->extra.data;
340 }
341 if (end_in_extra_buffer)
342 end = extra_buf + end_idx;
343
344
345 memmove (&extra_buf[n], end, len + 1);
346 name = end = memcpy (extra_buf, buf, n);
347 end_in_extra_buffer = true;
348
349 if (IS_ABSOLUTE_FILE_NAME (buf))
350 {
351 idx_t pfxlen = FILE_SYSTEM_PREFIX_LEN (buf);
352
353 dest = __mempcpy (rname, buf, pfxlen);
354 *dest++ = '/';
355 if (DOUBLE_SLASH_IS_DISTINCT_ROOT)
356 {
357 if (ISSLASH (buf[1]) && !ISSLASH (buf[2]) && !pfxlen)
358 *dest++ = '/';
359 *dest = '\0';
360 }
361
362 prefix_len = pfxlen;
363 }
364 else
365 {
366
367
368 if (dest > rname + prefix_len + 1)
369 for (--dest; dest > rname && !ISSLASH (dest[-1]); --dest)
370 continue;
371 if (DOUBLE_SLASH_IS_DISTINCT_ROOT && dest == rname + 1
372 && ISSLASH (*dest) && !ISSLASH (dest[1]) && !prefix_len)
373 dest++;
374 }
375 }
376 else if (! (suffix_requires_dir_check (end)
377 ? dir_check (rname, dest)
378 : errno == EINVAL))
379 goto error;
380 }
381 }
382 if (dest > rname + prefix_len + 1 && ISSLASH (dest[-1]))
383 --dest;
384 if (DOUBLE_SLASH_IS_DISTINCT_ROOT && dest == rname + 1 && !prefix_len
385 && ISSLASH (*dest) && !ISSLASH (dest[1]))
386 dest++;
387 failed = false;
388
389 error:
390 *dest++ = '\0';
391 if (resolved != NULL)
392 {
393
394
395 if ((!failed || errno == ENOENT || errno == EACCES)
396 && dest - rname <= get_path_max ())
397 {
398 strcpy (resolved, rname);
399 if (failed)
400 return NULL;
401 else
402 return resolved;
403 }
404 if (!failed)
405 __set_errno (ENAMETOOLONG);
406 return NULL;
407 }
408 else
409 {
410 if (failed)
411 return NULL;
412 else
413 return __strdup (bufs->rname.data);
414 }
415 }
416
417
418
419
420
421
422
423
424
425
426
427
428 char *
429 __realpath (const char *name, char *resolved)
430 {
431 struct realpath_bufs bufs;
432 scratch_buffer_init (&bufs.rname);
433 scratch_buffer_init (&bufs.extra);
434 scratch_buffer_init (&bufs.link);
435 char *result = realpath_stk (name, resolved, &bufs);
436 scratch_buffer_free (&bufs.link);
437 scratch_buffer_free (&bufs.extra);
438 scratch_buffer_free (&bufs.rname);
439 return result;
440 }
441 libc_hidden_def (__realpath)
442 versioned_symbol (libc, __realpath, realpath, GLIBC_2_3);
443
444 #endif
445
446
447 #if SHLIB_COMPAT(libc, GLIBC_2_0, GLIBC_2_3)
448 char *
449 attribute_compat_text_section
450 __old_realpath (const char *name, char *resolved)
451 {
452 if (resolved == NULL)
453 {
454 __set_errno (EINVAL);
455 return NULL;
456 }
457
458 return __realpath (name, resolved);
459 }
460 compat_symbol (libc, __old_realpath, realpath, GLIBC_2_0);
461 #endif
462
463
464 char *
465 __canonicalize_file_name (const char *name)
466 {
467 return __realpath (name, NULL);
468 }
469 weak_alias (__canonicalize_file_name, canonicalize_file_name)