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

source code of glibc/stdlib/canonicalize.c