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 General Public
7    License as published by the Free Software Foundation; either
8    version 3 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    General Public License for more details.
14 
15    You should have received a copy of the GNU 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.  */
96 static bool
file_accessible(char const * file)97 file_accessible (char const *file)
98 {
99 # if defined _LIBC || HAVE_FACCESSAT
100   return __faccessat (AT_FDCWD, 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 
114 static bool _GL_ATTRIBUTE_PURE
suffix_requires_dir_check(char const * end)115 suffix_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
145 static char const dir_suffix[] = "/";
146 #else
147 static 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 
154 static bool
dir_check(char * dir,char * dirend)155 dir_check (char *dir, char *dirend)
156 {
157   strcpy (dirend, dir_suffix);
158   return file_accessible (dir);
159 }
160 
161 static idx_t
get_path_max(void)162 get_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
197 static char *
realpath_stk(const char * name,char * resolved,struct scratch_buffer * rname_buf)198 realpath_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 (&extra_buffer);
226   scratch_buffer_init (&link_buffer);
227   scratch_buffer_init (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 (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 (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 (rname, buf, bufsize - 1);
322               if (n < bufsize - 1)
323                 break;
324               if (!scratch_buffer_grow (&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 (&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 (rname, 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 
401 error:
402   *dest++ = '\0';
403   if (resolved != NULL && dest - rname <= get_path_max ())
404     rname = strcpy (resolved, rname);
405 
406 error_nomem:
407   scratch_buffer_free (&extra_buffer);
408   scratch_buffer_free (&link_buffer);
409 
410   if (failed || rname == resolved)
411     {
412       scratch_buffer_free (rname_buf);
413       return failed ? NULL : resolved;
414     }
415 
416   return scratch_buffer_dupfree (rname_buf, dest - rname);
417 }
418 
419 /* Return the canonical absolute name of file NAME.  A canonical name
420    does not contain any ".", ".." components nor any repeated file name
421    separators ('/') or symlinks.  All file name components must exist.  If
422    RESOLVED is null, the result is malloc'd; otherwise, if the
423    canonical name is PATH_MAX chars or more, returns null with 'errno'
424    set to ENAMETOOLONG; if the name fits in fewer than PATH_MAX chars,
425    returns the name in RESOLVED.  If the name cannot be resolved and
426    RESOLVED is non-NULL, it contains the name of the first component
427    that cannot be resolved.  If the name can be resolved, RESOLVED
428    holds the same value as the value returned.  */
429 
430 char *
__realpath(const char * name,char * resolved)431 __realpath (const char *name, char *resolved)
432 {
433   #ifdef GCC_BOGUS_WRETURN_LOCAL_ADDR
434    #warning "GCC might issue a bogus -Wreturn-local-addr warning here."
435    #warning "See <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=93644>."
436   #endif
437   struct scratch_buffer rname_buffer;
438   return realpath_stk (name, resolved, &rname_buffer);
439 }
440 libc_hidden_def (__realpath)
441 versioned_symbol (libc, __realpath, realpath, GLIBC_2_3);
442 #endif /* !FUNC_REALPATH_WORKS || defined _LIBC */
443 
444 
445 #if SHLIB_COMPAT(libc, GLIBC_2_0, GLIBC_2_3)
446 char *
447 attribute_compat_text_section
__old_realpath(const char * name,char * resolved)448 __old_realpath (const char *name, char *resolved)
449 {
450   if (resolved == NULL)
451     {
452       __set_errno (EINVAL);
453       return NULL;
454     }
455 
456   return __realpath (name, resolved);
457 }
458 compat_symbol (libc, __old_realpath, realpath, GLIBC_2_0);
459 #endif
460 
461 
462 char *
__canonicalize_file_name(const char * name)463 __canonicalize_file_name (const char *name)
464 {
465   return __realpath (name, NULL);
466 }
467 weak_alias (__canonicalize_file_name, canonicalize_file_name)
468