1 /* Return the canonical absolute name of a given file.
2 Copyright (C) 1996-2021 Free Software Foundation, Inc.
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
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.
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
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <https://www.gnu.org/licenses/>. */
18
19 #ifndef _LIBC
20 /* Don't use __attribute__ __nonnull__ in this compilation unit. Otherwise gcc
21 optimizes away the name == NULL test below. */
22 # define _GL_ARG_NONNULL(params)
23
24 # include <libc-config.h>
25 #endif
26
27 /* Specification. */
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 /* When building the relocatable program wrapper, use the system's getcwd
58 function, not the gnulib override, otherwise we would get a link error.
59 */
60 # undef getcwd
61 # endif
62 # if defined VMS && !defined getcwd
63 /* We want the directory in Unix syntax, not in VMS syntax.
64 The gnulib override of 'getcwd' takes 2 arguments; the original VMS
65 'getcwd' takes 3 arguments. */
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 # define __stat stat
78 # if IN_RELOCWRAPPER
79 /* When building the relocatable program wrapper, use the system's memmove
80 function, not the gnulib override, otherwise we would get a link error.
81 */
82 # undef memmove
83 # endif
84 #endif
85
86 /* Suppress bogus GCC -Wmaybe-uninitialized warnings. */
87 #if defined GCC_LINT || defined lint
88 # define IF_LINT(Code) Code
89 #else
90 # define IF_LINT(Code) /* empty */
91 #endif
92
93 #ifndef DOUBLE_SLASH_IS_DISTINCT_ROOT
94 # define DOUBLE_SLASH_IS_DISTINCT_ROOT false
95 #endif
96
97 #if defined _LIBC || !FUNC_REALPATH_WORKS
98
99 /* Return true if FILE's existence can be shown, false (setting errno)
100 otherwise. Follow symbolic links. */
101 static bool
file_accessible(char const * file)102 file_accessible (char const *file)
103 {
104 # if defined _LIBC || HAVE_FACCESSAT
105 return __faccessat (AT_FDCWD, file, F_OK, AT_EACCESS) == 0;
106 # else
107 struct stat st;
108 return __stat (file, &st) == 0 || errno == EOVERFLOW;
109 # endif
110 }
111
112 /* True if concatenating END as a suffix to a file name means that the
113 code needs to check that the file name is that of a searchable
114 directory, since the canonicalize_filename_mode_stk code won't
115 check this later anyway when it checks an ordinary file name
116 component within END. END must either be empty, or start with a
117 slash. */
118
119 static bool _GL_ATTRIBUTE_PURE
suffix_requires_dir_check(char const * end)120 suffix_requires_dir_check (char const *end)
121 {
122 /* If END does not start with a slash, the suffix is OK. */
123 while (ISSLASH (*end))
124 {
125 /* Two or more slashes act like a single slash. */
126 do
127 end++;
128 while (ISSLASH (*end));
129
130 switch (*end++)
131 {
132 default: return false; /* An ordinary file name component is OK. */
133 case '\0': return true; /* Trailing "/" is trouble. */
134 case '.': break; /* Possibly "." or "..". */
135 }
136 /* Trailing "/.", or "/.." even if not trailing, is trouble. */
137 if (!*end || (*end == '.' && (!end[1] || ISSLASH (end[1]))))
138 return true;
139 }
140
141 return false;
142 }
143
144 /* Append this to a file name to test whether it is a searchable directory.
145 On POSIX platforms "/" suffices, but "/./" is sometimes needed on
146 macOS 10.13 <https://bugs.gnu.org/30350>, and should also work on
147 platforms like AIX 7.2 that need at least "/.". */
148
149 # if defined _LIBC || defined LSTAT_FOLLOWS_SLASHED_SYMLINK
150 static char const dir_suffix[] = "/";
151 # else
152 static char const dir_suffix[] = "/./";
153 # endif
154
155 /* Return true if DIR is a searchable dir, false (setting errno) otherwise.
156 DIREND points to the NUL byte at the end of the DIR string.
157 Store garbage into DIREND[0 .. strlen (dir_suffix)]. */
158
159 static bool
dir_check(char * dir,char * dirend)160 dir_check (char *dir, char *dirend)
161 {
162 strcpy (dirend, dir_suffix);
163 return file_accessible (dir);
164 }
165
166 static idx_t
get_path_max(void)167 get_path_max (void)
168 {
169 # ifdef PATH_MAX
170 long int path_max = PATH_MAX;
171 # else
172 /* The caller invoked realpath with a null RESOLVED, even though
173 PATH_MAX is not defined as a constant. The glibc manual says
174 programs should not do this, and POSIX says the behavior is undefined.
175 Historically, glibc here used the result of pathconf, or 1024 if that
176 failed; stay consistent with this (dubious) historical practice. */
177 int err = errno;
178 long int path_max = __pathconf ("/", _PC_PATH_MAX);
179 __set_errno (err);
180 # endif
181 return path_max < 0 ? 1024 : path_max <= IDX_MAX ? path_max : IDX_MAX;
182 }
183
184 /* Act like __realpath (see below), with an additional argument
185 rname_buf that can be used as temporary storage.
186
187 If GCC_LINT is defined, do not inline this function with GCC 10.1
188 and later, to avoid creating a pointer to the stack that GCC
189 -Wreturn-local-addr incorrectly complains about. See:
190 https://gcc.gnu.org/bugzilla/show_bug.cgi?id=93644
191 Although the noinline attribute can hurt performance a bit, no better way
192 to pacify GCC is known; even an explicit #pragma does not pacify GCC.
193 When the GCC bug is fixed this workaround should be limited to the
194 broken GCC versions. */
195 # if __GNUC_PREREQ (10, 1)
196 # if defined GCC_LINT || defined lint
197 __attribute__ ((__noinline__))
198 # elif __OPTIMIZE__ && !__NO_INLINE__
199 # define GCC_BOGUS_WRETURN_LOCAL_ADDR
200 # endif
201 # endif
202 static char *
realpath_stk(const char * name,char * resolved,struct scratch_buffer * rname_buf)203 realpath_stk (const char *name, char *resolved,
204 struct scratch_buffer *rname_buf)
205 {
206 char *dest;
207 char const *start;
208 char const *end;
209 int num_links = 0;
210
211 if (name == NULL)
212 {
213 /* As per Single Unix Specification V2 we must return an error if
214 either parameter is a null pointer. We extend this to allow
215 the RESOLVED parameter to be NULL in case the we are expected to
216 allocate the room for the return value. */
217 __set_errno (EINVAL);
218 return NULL;
219 }
220
221 if (name[0] == '\0')
222 {
223 /* As per Single Unix Specification V2 we must return an error if
224 the name argument points to an empty string. */
225 __set_errno (ENOENT);
226 return NULL;
227 }
228
229 struct scratch_buffer extra_buffer, link_buffer;
230 scratch_buffer_init (&extra_buffer);
231 scratch_buffer_init (&link_buffer);
232 scratch_buffer_init (rname_buf);
233 char *rname_on_stack = rname_buf->data;
234 char *rname = rname_on_stack;
235 bool end_in_extra_buffer = false;
236 bool failed = true;
237
238 /* This is always zero for Posix hosts, but can be 2 for MS-Windows
239 and MS-DOS X:/foo/bar file names. */
240 idx_t prefix_len = FILE_SYSTEM_PREFIX_LEN (name);
241
242 if (!IS_ABSOLUTE_FILE_NAME (name))
243 {
244 while (!__getcwd (rname, rname_buf->length))
245 {
246 if (errno != ERANGE)
247 {
248 dest = rname;
249 goto error;
250 }
251 if (!scratch_buffer_grow (rname_buf))
252 goto error_nomem;
253 rname = rname_buf->data;
254 }
255 dest = __rawmemchr (rname, '\0');
256 start = name;
257 prefix_len = FILE_SYSTEM_PREFIX_LEN (rname);
258 }
259 else
260 {
261 dest = __mempcpy (rname, name, prefix_len);
262 *dest++ = '/';
263 if (DOUBLE_SLASH_IS_DISTINCT_ROOT)
264 {
265 if (prefix_len == 0 /* implies ISSLASH (name[0]) */
266 && ISSLASH (name[1]) && !ISSLASH (name[2]))
267 *dest++ = '/';
268 *dest = '\0';
269 }
270 start = name + prefix_len;
271 }
272
273 for ( ; *start; start = end)
274 {
275 /* Skip sequence of multiple file name separators. */
276 while (ISSLASH (*start))
277 ++start;
278
279 /* Find end of component. */
280 for (end = start; *end && !ISSLASH (*end); ++end)
281 /* Nothing. */;
282
283 /* Length of this file name component; it can be zero if a file
284 name ends in '/'. */
285 idx_t startlen = end - start;
286
287 if (startlen == 0)
288 break;
289 else if (startlen == 1 && start[0] == '.')
290 /* nothing */;
291 else if (startlen == 2 && start[0] == '.' && start[1] == '.')
292 {
293 /* Back up to previous component, ignore if at root already. */
294 if (dest > rname + prefix_len + 1)
295 for (--dest; dest > rname && !ISSLASH (dest[-1]); --dest)
296 continue;
297 if (DOUBLE_SLASH_IS_DISTINCT_ROOT
298 && dest == rname + 1 && !prefix_len
299 && ISSLASH (*dest) && !ISSLASH (dest[1]))
300 dest++;
301 }
302 else
303 {
304 if (!ISSLASH (dest[-1]))
305 *dest++ = '/';
306
307 while (rname + rname_buf->length - dest
308 < startlen + sizeof dir_suffix)
309 {
310 idx_t dest_offset = dest - rname;
311 if (!scratch_buffer_grow_preserve (rname_buf))
312 goto error_nomem;
313 rname = rname_buf->data;
314 dest = rname + dest_offset;
315 }
316
317 dest = __mempcpy (dest, start, startlen);
318 *dest = '\0';
319
320 char *buf;
321 ssize_t n;
322 while (true)
323 {
324 buf = link_buffer.data;
325 idx_t bufsize = link_buffer.length;
326 n = __readlink (rname, buf, bufsize - 1);
327 if (n < bufsize - 1)
328 break;
329 if (!scratch_buffer_grow (&link_buffer))
330 goto error_nomem;
331 }
332 if (0 <= n)
333 {
334 if (++num_links > __eloop_threshold ())
335 {
336 __set_errno (ELOOP);
337 goto error;
338 }
339
340 buf[n] = '\0';
341
342 char *extra_buf = extra_buffer.data;
343 idx_t end_idx IF_LINT (= 0);
344 if (end_in_extra_buffer)
345 end_idx = end - extra_buf;
346 size_t len = strlen (end);
347 if (INT_ADD_OVERFLOW (len, n))
348 {
349 __set_errno (ENOMEM);
350 goto error_nomem;
351 }
352 while (extra_buffer.length <= len + n)
353 {
354 if (!scratch_buffer_grow_preserve (&extra_buffer))
355 goto error_nomem;
356 extra_buf = extra_buffer.data;
357 }
358 if (end_in_extra_buffer)
359 end = extra_buf + end_idx;
360
361 /* Careful here, end may be a pointer into extra_buf... */
362 memmove (&extra_buf[n], end, len + 1);
363 name = end = memcpy (extra_buf, buf, n);
364 end_in_extra_buffer = true;
365
366 if (IS_ABSOLUTE_FILE_NAME (buf))
367 {
368 idx_t pfxlen = FILE_SYSTEM_PREFIX_LEN (buf);
369
370 dest = __mempcpy (rname, buf, pfxlen);
371 *dest++ = '/'; /* It's an absolute symlink */
372 if (DOUBLE_SLASH_IS_DISTINCT_ROOT)
373 {
374 if (ISSLASH (buf[1]) && !ISSLASH (buf[2]) && !pfxlen)
375 *dest++ = '/';
376 *dest = '\0';
377 }
378 /* Install the new prefix to be in effect hereafter. */
379 prefix_len = pfxlen;
380 }
381 else
382 {
383 /* Back up to previous component, ignore if at root
384 already: */
385 if (dest > rname + prefix_len + 1)
386 for (--dest; dest > rname && !ISSLASH (dest[-1]); --dest)
387 continue;
388 if (DOUBLE_SLASH_IS_DISTINCT_ROOT && dest == rname + 1
389 && ISSLASH (*dest) && !ISSLASH (dest[1]) && !prefix_len)
390 dest++;
391 }
392 }
393 else if (! (suffix_requires_dir_check (end)
394 ? dir_check (rname, dest)
395 : errno == EINVAL))
396 goto error;
397 }
398 }
399 if (dest > rname + prefix_len + 1 && ISSLASH (dest[-1]))
400 --dest;
401 if (DOUBLE_SLASH_IS_DISTINCT_ROOT && dest == rname + 1 && !prefix_len
402 && ISSLASH (*dest) && !ISSLASH (dest[1]))
403 dest++;
404 failed = false;
405
406 error:
407 *dest++ = '\0';
408 if (resolved != NULL && dest - rname <= get_path_max ())
409 rname = strcpy (resolved, rname);
410
411 error_nomem:
412 scratch_buffer_free (&extra_buffer);
413 scratch_buffer_free (&link_buffer);
414
415 if (failed || rname == resolved)
416 {
417 scratch_buffer_free (rname_buf);
418 return failed ? NULL : resolved;
419 }
420
421 return scratch_buffer_dupfree (rname_buf, dest - rname);
422 }
423
424 /* Return the canonical absolute name of file NAME. A canonical name
425 does not contain any ".", ".." components nor any repeated file name
426 separators ('/') or symlinks. All file name components must exist. If
427 RESOLVED is null, the result is malloc'd; otherwise, if the
428 canonical name is PATH_MAX chars or more, returns null with 'errno'
429 set to ENAMETOOLONG; if the name fits in fewer than PATH_MAX chars,
430 returns the name in RESOLVED. If the name cannot be resolved and
431 RESOLVED is non-NULL, it contains the name of the first component
432 that cannot be resolved. If the name can be resolved, RESOLVED
433 holds the same value as the value returned. */
434
435 char *
__realpath(const char * name,char * resolved)436 __realpath (const char *name, char *resolved)
437 {
438 #ifdef GCC_BOGUS_WRETURN_LOCAL_ADDR
439 #warning "GCC might issue a bogus -Wreturn-local-addr warning here."
440 #warning "See <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=93644>."
441 #endif
442 struct scratch_buffer rname_buffer;
443 return realpath_stk (name, resolved, &rname_buffer);
444 }
445 libc_hidden_def (__realpath)
446 versioned_symbol (libc, __realpath, realpath, GLIBC_2_3);
447
448 #endif /* defined _LIBC || !FUNC_REALPATH_WORKS */
449
450
451 #if SHLIB_COMPAT(libc, GLIBC_2_0, GLIBC_2_3)
452 char *
453 attribute_compat_text_section
__old_realpath(const char * name,char * resolved)454 __old_realpath (const char *name, char *resolved)
455 {
456 if (resolved == NULL)
457 {
458 __set_errno (EINVAL);
459 return NULL;
460 }
461
462 return __realpath (name, resolved);
463 }
464 compat_symbol (libc, __old_realpath, realpath, GLIBC_2_0);
465 #endif
466
467
468 char *
__canonicalize_file_name(const char * name)469 __canonicalize_file_name (const char *name)
470 {
471 return __realpath (name, NULL);
472 }
473 weak_alias (__canonicalize_file_name, canonicalize_file_name)
474