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