Diff for /embedaddon/libiconv/srclib/canonicalize-lgpl.c between versions 1.1.1.1 and 1.1.1.3

version 1.1.1.1, 2012/02/21 22:57:48 version 1.1.1.3, 2021/03/17 13:38:46
Line 1 Line 1
 /* Return the canonical absolute name of a given file.  /* Return the canonical absolute name of a given file.
   Copyright (C) 1996-2003, 2005-2008 Free Software Foundation, Inc.   Copyright (C) 1996-2019 Free Software Foundation, Inc.
    This file is part of the GNU C Library.     This file is part of the GNU C Library.
   
    This program is free software: you can redistribute it and/or modify     This program is free software: you can redistribute it and/or modify
Line 13 Line 13
    GNU General Public License for more details.     GNU General Public License for more details.
   
    You should have received a copy of the GNU General Public License     You should have received a copy of the GNU General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
   
#include <config.h>#ifndef _LIBC
 /* Don't use __attribute__ __nonnull__ in this compilation unit.  Otherwise gcc
    optimizes away the name == NULL test below.  */
 # define _GL_ARG_NONNULL(params)
   
/* Avoid a clash of our rpl_realpath() function with the prototype in# define _GL_USE_STDLIB_ALLOC 1
   <stdlib.h> on Solaris 2.5.1.  */# include <config.h>
#undef realpath#endif
   
#if !HAVE_CANONICALIZE_FILE_NAME || defined _LIBC#if !HAVE_CANONICALIZE_FILE_NAME || !FUNC_REALPATH_WORKS || defined _LIBC
   
 #include <alloca.h>  
   
 /* Specification.  */  /* Specification.  */
 #include "canonicalize.h"  
   
 #include <stddef.h>  
 #include <stdlib.h>  #include <stdlib.h>
 #include <string.h>  
   
#if HAVE_UNISTD_H || defined _LIBC#include <alloca.h>
# include <unistd.h>#include <string.h>
#endif#include <unistd.h>
 
 #include <limits.h>  #include <limits.h>
   
 #if HAVE_SYS_PARAM_H || defined _LIBC  #if HAVE_SYS_PARAM_H || defined _LIBC
 # include <sys/param.h>  # include <sys/param.h>
 #endif  #endif
 #ifndef MAXSYMLINKS  
 # define MAXSYMLINKS 20  
 #endif  
   
 #include <sys/stat.h>  #include <sys/stat.h>
   
 #include <errno.h>  #include <errno.h>
#ifndef _LIBC#include <stddef.h>
# define __set_errno(e) errno = (e) 
# ifndef ENAMETOOLONG 
#  define ENAMETOOLONG EINVAL 
# endif 
#endif 
   
 #ifdef _LIBC  #ifdef _LIBC
 # include <shlib-compat.h>  # include <shlib-compat.h>
 #else  #else
 # define SHLIB_COMPAT(lib, introduced, obsoleted) 0  # define SHLIB_COMPAT(lib, introduced, obsoleted) 0
# define versioned_symbol(lib, local, symbol, version)# define versioned_symbol(lib, local, symbol, version) extern int dummy
 # define compat_symbol(lib, local, symbol, version)  # define compat_symbol(lib, local, symbol, version)
 # define weak_alias(local, symbol)  # define weak_alias(local, symbol)
 # define __canonicalize_file_name canonicalize_file_name  # define __canonicalize_file_name canonicalize_file_name
# define __realpath rpl_realpath# define __realpath realpath
 # include "pathmax.h"  # include "pathmax.h"
 # include "malloca.h"  # include "malloca.h"
   # include "dosname.h"
 # if HAVE_GETCWD  # if HAVE_GETCWD
#  ifdef VMS#  if IN_RELOCWRAPPER
    /* We want the directory in Unix syntax, not in VMS syntax.  */    /* When building the relocatable program wrapper, use the system's getcwd
        function, not the gnulib override, otherwise we would get a link error.
      */
 #   undef getcwd
 #  endif
 #  if defined VMS && !defined getcwd
     /* We want the directory in Unix syntax, not in VMS syntax.
        The gnulib override of 'getcwd' takes 2 arguments; the original VMS
        'getcwd' takes 3 arguments.  */
 #   define __getcwd(buf, max) getcwd (buf, max, 0)  #   define __getcwd(buf, max) getcwd (buf, max, 0)
 #  else  #  else
 #   define __getcwd getcwd  #   define __getcwd getcwd
Line 77 Line 71
 #  define __getcwd(buf, max) getwd (buf)  #  define __getcwd(buf, max) getwd (buf)
 # endif  # endif
 # define __readlink readlink  # define __readlink readlink
  /* On systems without symbolic links, call stat() instead of lstat().  */# define __set_errno(e) errno = (e)
# if !defined S_ISLNK && !HAVE_READLINK# ifndef MAXSYMLINKS
#  define lstat stat#  ifdef SYMLOOP_MAX
 #   define MAXSYMLINKS SYMLOOP_MAX
 #  else
 #   define MAXSYMLINKS 20
 #  endif
 # endif  # endif
 #endif  #endif
   
   #ifndef DOUBLE_SLASH_IS_DISTINCT_ROOT
   # define DOUBLE_SLASH_IS_DISTINCT_ROOT 0
   #endif
   
   /* Define this independently so that stdint.h is not a prerequisite.  */
   #ifndef SIZE_MAX
   # define SIZE_MAX ((size_t) -1)
   #endif
   
   #if !FUNC_REALPATH_WORKS || defined _LIBC
   
   static void
   alloc_failed (void)
   {
   #if defined _WIN32 && ! defined __CYGWIN__
     /* Avoid errno problem without using the malloc or realloc modules; see:
        https://lists.gnu.org/r/bug-gnulib/2016-08/msg00025.html  */
     errno = ENOMEM;
   #endif
   }
   
 /* Return the canonical absolute name of file NAME.  A canonical name  /* Return the canonical absolute name of file NAME.  A canonical name
   does not contain any `.', `..' components nor any repeated path   does not contain any ".", ".." components nor any repeated path
    separators ('/') or symlinks.  All path components must exist.  If     separators ('/') or symlinks.  All path components must exist.  If
    RESOLVED is null, the result is malloc'd; otherwise, if the     RESOLVED is null, the result is malloc'd; otherwise, if the
   canonical name is PATH_MAX chars or more, returns null with `errno'   canonical name is PATH_MAX chars or more, returns null with 'errno'
    set to ENAMETOOLONG; if the name fits in fewer than PATH_MAX chars,     set to ENAMETOOLONG; if the name fits in fewer than PATH_MAX chars,
    returns the name in RESOLVED.  If the name cannot be resolved and     returns the name in RESOLVED.  If the name cannot be resolved and
    RESOLVED is non-NULL, it contains the path of the first component     RESOLVED is non-NULL, it contains the path of the first component
Line 100  __realpath (const char *name, char *resolved) Line 119  __realpath (const char *name, char *resolved)
   char *rpath, *dest, *extra_buf = NULL;    char *rpath, *dest, *extra_buf = NULL;
   const char *start, *end, *rpath_limit;    const char *start, *end, *rpath_limit;
   long int path_max;    long int path_max;
 #if HAVE_READLINK  
   int num_links = 0;    int num_links = 0;
#endif  size_t prefix_len;
   
   if (name == NULL)    if (name == NULL)
     {      {
       /* As per Single Unix Specification V2 we must return an error if        /* As per Single Unix Specification V2 we must return an error if
         either parameter is a null pointer.  We extend this to allow         either parameter is a null pointer.  We extend this to allow
         the RESOLVED parameter to be NULL in case the we are expected to         the RESOLVED parameter to be NULL in case the we are expected to
         allocate the room for the return value.  */         allocate the room for the return value.  */
       __set_errno (EINVAL);        __set_errno (EINVAL);
       return NULL;        return NULL;
     }      }
Line 117  __realpath (const char *name, char *resolved) Line 135  __realpath (const char *name, char *resolved)
   if (name[0] == '\0')    if (name[0] == '\0')
     {      {
       /* As per Single Unix Specification V2 we must return an error if        /* As per Single Unix Specification V2 we must return an error if
         the name argument points to an empty string.  */         the name argument points to an empty string.  */
       __set_errno (ENOENT);        __set_errno (ENOENT);
       return NULL;        return NULL;
     }      }
Line 127  __realpath (const char *name, char *resolved) Line 145  __realpath (const char *name, char *resolved)
 #else  #else
   path_max = pathconf (name, _PC_PATH_MAX);    path_max = pathconf (name, _PC_PATH_MAX);
   if (path_max <= 0)    if (path_max <= 0)
    path_max = 1024;    path_max = 8192;
 #endif  #endif
   
   if (resolved == NULL)    if (resolved == NULL)
     {      {
       rpath = malloc (path_max);        rpath = malloc (path_max);
       if (rpath == NULL)        if (rpath == NULL)
        {        {
          /* It's easier to set errno to ENOMEM than to rely on the          alloc_failed ();
             'malloc-posix' gnulib module.  */          return NULL;
          errno = ENOMEM;        }
          return NULL; 
        } 
     }      }
   else    else
     rpath = resolved;      rpath = resolved;
   rpath_limit = rpath + path_max;    rpath_limit = rpath + path_max;
   
  if (name[0] != '/')  /* This is always zero for Posix hosts, but can be 2 for MS-Windows
      and MS-DOS X:/foo/bar file names.  */
   prefix_len = FILE_SYSTEM_PREFIX_LEN (name);
 
   if (!IS_ABSOLUTE_FILE_NAME (name))
     {      {
       if (!__getcwd (rpath, path_max))        if (!__getcwd (rpath, path_max))
        {        {
          rpath[0] = '\0';          rpath[0] = '\0';
          goto error;          goto error;
        }        }
       dest = strchr (rpath, '\0');        dest = strchr (rpath, '\0');
         start = name;
         prefix_len = FILE_SYSTEM_PREFIX_LEN (rpath);
     }      }
   else    else
     {      {
      rpath[0] = '/';      dest = rpath;
      dest = rpath + 1;      if (prefix_len)
         {
           memcpy (rpath, name, prefix_len);
           dest += prefix_len;
         }
       *dest++ = '/';
       if (DOUBLE_SLASH_IS_DISTINCT_ROOT)
         {
           if (ISSLASH (name[1]) && !ISSLASH (name[2]) && !prefix_len)
             *dest++ = '/';
           *dest = '\0';
         }
       start = name + prefix_len;
     }      }
   
  for (start = end = name; *start; start = end)  for (end = start; *start; start = end)
     {      {
 #ifdef _LIBC  #ifdef _LIBC
       struct stat64 st;        struct stat64 st;
Line 169  __realpath (const char *name, char *resolved) Line 203  __realpath (const char *name, char *resolved)
 #endif  #endif
   
       /* Skip sequence of multiple path-separators.  */        /* Skip sequence of multiple path-separators.  */
      while (*start == '/')      while (ISSLASH (*start))
        ++start;        ++start;
   
       /* Find end of path component.  */        /* Find end of path component.  */
      for (end = start; *end && *end != '/'; ++end)      for (end = start; *end && !ISSLASH (*end); ++end)
        /* Nothing.  */;        /* Nothing.  */;
   
       if (end - start == 0)        if (end - start == 0)
        break;        break;
       else if (end - start == 1 && start[0] == '.')        else if (end - start == 1 && start[0] == '.')
        /* nothing */;        /* nothing */;
       else if (end - start == 2 && start[0] == '.' && start[1] == '.')        else if (end - start == 2 && start[0] == '.' && start[1] == '.')
        {        {
          /* Back up to previous component, ignore if at root already.  */          /* Back up to previous component, ignore if at root already.  */
          if (dest > rpath + 1)          if (dest > rpath + prefix_len + 1)
            while ((--dest)[-1] != '/');            for (--dest; dest > rpath && !ISSLASH (dest[-1]); --dest)
        }              continue;
           if (DOUBLE_SLASH_IS_DISTINCT_ROOT
               && dest == rpath + 1 && !prefix_len
               && ISSLASH (*dest) && !ISSLASH (dest[1]))
             dest++;
         }
       else        else
        {        {
          size_t new_size;          size_t new_size;
   
          if (dest[-1] != '/')          if (!ISSLASH (dest[-1]))
            *dest++ = '/';            *dest++ = '/';
   
          if (dest + (end - start) >= rpath_limit)          if (dest + (end - start) >= rpath_limit)
            {            {
              ptrdiff_t dest_offset = dest - rpath;              ptrdiff_t dest_offset = dest - rpath;
              char *new_rpath;              char *new_rpath;
   
              if (resolved)              if (resolved)
                {                {
                  __set_errno (ENAMETOOLONG);                  __set_errno (ENAMETOOLONG);
                  if (dest > rpath + 1)                  if (dest > rpath + prefix_len + 1)
                    dest--;                    dest--;
                  *dest = '\0';                  *dest = '\0';
                  goto error;                  goto error;
                }                }
              new_size = rpath_limit - rpath;              new_size = rpath_limit - rpath;
              if (end - start + 1 > path_max)              if (end - start + 1 > path_max)
                new_size += end - start + 1;                new_size += end - start + 1;
              else              else
                new_size += path_max;                new_size += path_max;
              new_rpath = (char *) realloc (rpath, new_size);              new_rpath = (char *) realloc (rpath, new_size);
              if (new_rpath == NULL)              if (new_rpath == NULL)
                {                {
                  /* It's easier to set errno to ENOMEM than to rely on the                  alloc_failed ();
                     'realloc-posix' gnulib module.  */                  goto error;
                  errno = ENOMEM;                }
                  goto error;              rpath = new_rpath;
                }              rpath_limit = rpath + new_size;
              rpath = new_rpath; 
              rpath_limit = rpath + new_size; 
   
              dest = rpath + dest_offset;              dest = rpath + dest_offset;
            }            }
   
 #ifdef _LIBC  #ifdef _LIBC
          dest = __mempcpy (dest, start, end - start);          dest = __mempcpy (dest, start, end - start);
 #else  #else
          memcpy (dest, start, end - start);          memcpy (dest, start, end - start);
          dest += end - start;          dest += end - start;
 #endif  #endif
          *dest = '\0';          *dest = '\0';
   
             /* FIXME: if lstat fails with errno == EOVERFLOW,
                the entry exists.  */
 #ifdef _LIBC  #ifdef _LIBC
          if (__lxstat64 (_STAT_VER, rpath, &st) < 0)          if (__lxstat64 (_STAT_VER, rpath, &st) < 0)
 #else  #else
          if (lstat (rpath, &st) < 0)          if (lstat (rpath, &st) < 0)
 #endif  #endif
            goto error;            goto error;
   
#if HAVE_READLINK          if (S_ISLNK (st.st_mode))
          if (S_ISLNK (st.st_mode))            {
            {              char *buf;
              char *buf;              size_t len;
              size_t len;              ssize_t n;
              int n; 
   
              if (++num_links > MAXSYMLINKS)              if (++num_links > MAXSYMLINKS)
                {                {
                  __set_errno (ELOOP);                  __set_errno (ELOOP);
                  goto error;                  goto error;
                }                }
   
              buf = malloca (path_max);              buf = malloca (path_max);
              if (!buf)              if (!buf)
                {                {
                  errno = ENOMEM;                  __set_errno (ENOMEM);
                  goto error;                  goto error;
                }                }
   
              n = __readlink (rpath, buf, path_max - 1);              n = __readlink (rpath, buf, path_max - 1);
              if (n < 0)              if (n < 0)
                {                {
                  int saved_errno = errno;                  int saved_errno = errno;
                  freea (buf);                  freea (buf);
                  errno = saved_errno;                  __set_errno (saved_errno);
                  goto error;                  goto error;
                }                }
              buf[n] = '\0';              buf[n] = '\0';
   
              if (!extra_buf)              if (!extra_buf)
                {                {
                  extra_buf = malloca (path_max);                  extra_buf = malloca (path_max);
                  if (!extra_buf)                  if (!extra_buf)
                    {                    {
                      freea (buf);                      freea (buf);
                      errno = ENOMEM;                      __set_errno (ENOMEM);
                      goto error;                      goto error;
                    }                    }
                }                }
   
              len = strlen (end);              len = strlen (end);
              if ((long int) (n + len) >= path_max)              /* Check that n + len + 1 doesn't overflow and is <= path_max. */
                {              if (n >= SIZE_MAX - len || n + len >= path_max)
                  freea (buf);                {
                  __set_errno (ENAMETOOLONG);                  freea (buf);
                  goto error;                  __set_errno (ENAMETOOLONG);
                }                  goto error;
                 }
   
              /* Careful here, end may be a pointer into extra_buf... */              /* Careful here, end may be a pointer into extra_buf... */
              memmove (&extra_buf[n], end, len + 1);              memmove (&extra_buf[n], end, len + 1);
              name = end = memcpy (extra_buf, buf, n);              name = end = memcpy (extra_buf, buf, n);
   
              if (buf[0] == '/')              if (IS_ABSOLUTE_FILE_NAME (buf))
                dest = rpath + 1;        /* It's an absolute symlink */                {
              else                  size_t pfxlen = FILE_SYSTEM_PREFIX_LEN (buf);
                /* Back up to previous component, ignore if at root already: */
                if (dest > rpath + 1)                  if (pfxlen)
                  while ((--dest)[-1] != '/');                    memcpy (rpath, buf, pfxlen);
            }                  dest = rpath + pfxlen;
#endif                  *dest++ = '/'; /* It's an absolute symlink */
        }                  if (DOUBLE_SLASH_IS_DISTINCT_ROOT)
                     {
                       if (ISSLASH (buf[1]) && !ISSLASH (buf[2]) && !pfxlen)
                         *dest++ = '/';
                       *dest = '\0';
                     }
                   /* Install the new prefix to be in effect hereafter.  */
                   prefix_len = pfxlen;
                 }
               else
                 {
                   /* Back up to previous component, ignore if at root
                      already: */
                   if (dest > rpath + prefix_len + 1)
                     for (--dest; dest > rpath && !ISSLASH (dest[-1]); --dest)
                       continue;
                   if (DOUBLE_SLASH_IS_DISTINCT_ROOT && dest == rpath + 1
                       && ISSLASH (*dest) && !ISSLASH (dest[1]) && !prefix_len)
                     dest++;
                 }
             }
           else if (!S_ISDIR (st.st_mode) && *end != '\0')
             {
               __set_errno (ENOTDIR);
               goto error;
             }
         }
     }      }
  if (dest > rpath + 1 && dest[-1] == '/')  if (dest > rpath + prefix_len + 1 && ISSLASH (dest[-1]))
     --dest;      --dest;
     if (DOUBLE_SLASH_IS_DISTINCT_ROOT && dest == rpath + 1 && !prefix_len
         && ISSLASH (*dest) && !ISSLASH (dest[1]))
       dest++;
   *dest = '\0';    *dest = '\0';
   
   if (extra_buf)    if (extra_buf)
     freea (extra_buf);      freea (extra_buf);
   
  return resolved ? memcpy (resolved, rpath, dest - rpath + 1) : rpath;  return rpath;
   
 error:  error:
   {    {
     int saved_errno = errno;      int saved_errno = errno;
     if (extra_buf)      if (extra_buf)
       freea (extra_buf);        freea (extra_buf);
    if (resolved)    if (resolved == NULL)
      strcpy (resolved, rpath); 
    else 
       free (rpath);        free (rpath);
    errno = saved_errno;    __set_errno (saved_errno);
   }    }
   return NULL;    return NULL;
 }  }
 #ifdef _LIBC  
 versioned_symbol (libc, __realpath, realpath, GLIBC_2_3);  versioned_symbol (libc, __realpath, realpath, GLIBC_2_3);
#endif#endif /* !FUNC_REALPATH_WORKS || defined _LIBC */
   
   
 #if SHLIB_COMPAT(libc, GLIBC_2_0, GLIBC_2_3)  #if SHLIB_COMPAT(libc, GLIBC_2_0, GLIBC_2_3)
 char *  char *
   attribute_compat_text_section
 __old_realpath (const char *name, char *resolved)  __old_realpath (const char *name, char *resolved)
 {  {
   if (resolved == NULL)    if (resolved == NULL)

Removed from v.1.1.1.1  
changed lines
  Added in v.1.1.1.3


FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>