root/lib/canonicalize-lgpl.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. file_accessible
  2. suffix_requires_dir_check
  3. dir_check
  4. get_path_max
  5. realpath_stk
  6. __realpath
  7. libc_hidden_def
  8. __canonicalize_file_name

     1 /* Return the canonical absolute name of a given file.
     2    Copyright (C) 1996-2023 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 <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     /* 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 # if IN_RELOCWRAPPER
    78     /* When building the relocatable program wrapper, use the system's memmove
    79        function, not the gnulib override, otherwise we would get a link error.
    80      */
    81 #  undef memmove
    82 # endif
    83 #endif
    84 
    85 /* Suppress bogus GCC -Wmaybe-uninitialized warnings.  */
    86 #if defined GCC_LINT || defined lint
    87 # define IF_LINT(Code) Code
    88 #else
    89 # define IF_LINT(Code) /* empty */
    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 /* Return true if FILE's existence can be shown, false (setting errno)
    99    otherwise.  Follow symbolic links.  */
   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 /* True if concatenating END as a suffix to a file name means that the
   112    code needs to check that the file name is that of a searchable
   113    directory, since the canonicalize_filename_mode_stk code won't
   114    check this later anyway when it checks an ordinary file name
   115    component within END.  END must either be empty, or start with a
   116    slash.  */
   117 
   118 static bool _GL_ATTRIBUTE_PURE
   119 suffix_requires_dir_check (char const *end)
   120 {
   121   /* If END does not start with a slash, the suffix is OK.  */
   122   while (ISSLASH (*end))
   123     {
   124       /* Two or more slashes act like a single slash.  */
   125       do
   126         end++;
   127       while (ISSLASH (*end));
   128 
   129       switch (*end++)
   130         {
   131         default: return false;  /* An ordinary file name component is OK.  */
   132         case '\0': return true; /* Trailing "/" is trouble.  */
   133         case '.': break;        /* Possibly "." or "..".  */
   134         }
   135       /* Trailing "/.", or "/.." even if not trailing, is trouble.  */
   136       if (!*end || (*end == '.' && (!end[1] || ISSLASH (end[1]))))
   137         return true;
   138     }
   139 
   140   return false;
   141 }
   142 
   143 /* Append this to a file name to test whether it is a searchable directory.
   144    On POSIX platforms "/" suffices, but "/./" is sometimes needed on
   145    macOS 10.13 <https://bugs.gnu.org/30350>, and should also work on
   146    platforms like AIX 7.2 that need at least "/.".  */
   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 /* Return true if DIR is a searchable dir, false (setting errno) otherwise.
   155    DIREND points to the NUL byte at the end of the DIR string.
   156    Store garbage into DIREND[0 .. strlen (dir_suffix)].  */
   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   /* The caller invoked realpath with a null RESOLVED, even though
   172      PATH_MAX is not defined as a constant.  The glibc manual says
   173      programs should not do this, and POSIX says the behavior is undefined.
   174      Historically, glibc here used the result of pathconf, or 1024 if that
   175      failed; stay consistent with this (dubious) historical practice.  */
   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 /* Scratch buffers used by realpath_stk and managed by __realpath.  */
   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       /* As per Single Unix Specification V2 we must return an error if
   202          either parameter is a null pointer.  We extend this to allow
   203          the RESOLVED parameter to be NULL in case the we are expected to
   204          allocate the room for the return value.  */
   205       __set_errno (EINVAL);
   206       return NULL;
   207     }
   208 
   209   if (name[0] == '\0')
   210     {
   211       /* As per Single Unix Specification V2 we must return an error if
   212          the name argument points to an empty string.  */
   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   /* This is always zero for Posix hosts, but can be 2 for MS-Windows
   222      and MS-DOS X:/foo/bar file names.  */
   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 /* implies ISSLASH (name[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       /* Skip sequence of multiple file name separators.  */
   259       while (ISSLASH (*start))
   260         ++start;
   261 
   262       /* Find end of component.  */
   263       for (end = start; *end && !ISSLASH (*end); ++end)
   264         /* Nothing.  */;
   265 
   266       /* Length of this file name component; it can be zero if a file
   267          name ends in '/'.  */
   268       idx_t startlen = end - start;
   269 
   270       if (startlen == 0)
   271         break;
   272       else if (startlen == 1 && start[0] == '.')
   273         /* nothing */;
   274       else if (startlen == 2 && start[0] == '.' && start[1] == '.')
   275         {
   276           /* Back up to previous component, ignore if at root already.  */
   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               /* Careful here, end may be a pointer into extra_buf... */
   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++ = '/'; /* It's an absolute symlink */
   355                   if (DOUBLE_SLASH_IS_DISTINCT_ROOT)
   356                     {
   357                       if (ISSLASH (buf[1]) && !ISSLASH (buf[2]) && !pfxlen)
   358                         *dest++ = '/';
   359                       *dest = '\0';
   360                     }
   361                   /* Install the new prefix to be in effect hereafter.  */
   362                   prefix_len = pfxlen;
   363                 }
   364               else
   365                 {
   366                   /* Back up to previous component, ignore if at root
   367                      already: */
   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       /* Copy the full result on success or partial result if failure was due
   394          to the path not existing or not being accessible.  */
   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 /* Return the canonical absolute name of file NAME.  A canonical name
   418    does not contain any ".", ".." components nor any repeated file name
   419    separators ('/') or symlinks.  All file name components must exist.  If
   420    RESOLVED is null, the result is malloc'd; otherwise, if the
   421    canonical name is PATH_MAX chars or more, returns null with 'errno'
   422    set to ENAMETOOLONG; if the name fits in fewer than PATH_MAX chars,
   423    returns the name in RESOLVED.  If the name cannot be resolved and
   424    RESOLVED is non-NULL, it contains the name of the first component
   425    that cannot be resolved.  If the name can be resolved, RESOLVED
   426    holds the same value as the value returned.  */
   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 /* defined _LIBC || !FUNC_REALPATH_WORKS */
   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)

/* [<][>][^][v][top][bottom][index][help] */