Annotation of embedaddon/libiconv/srclib/canonicalize-lgpl.c, revision 1.1.1.2

1.1       misho       1: /* Return the canonical absolute name of a given file.
1.1.1.2 ! misho       2:    Copyright (C) 1996-2011 Free Software Foundation, Inc.
1.1       misho       3:    This file is part of the GNU C Library.
                      4: 
                      5:    This program is free software: you can redistribute it and/or modify
                      6:    it under the terms of the GNU General Public License as published by
                      7:    the Free Software Foundation; either version 3 of the License, or
                      8:    (at your option) any later version.
                      9: 
                     10:    This program 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
                     13:    GNU General Public License for more details.
                     14: 
                     15:    You should have received a copy of the GNU General Public License
                     16:    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
                     17: 
1.1.1.2 ! misho      18: #ifndef _LIBC
        !            19: # define _GL_USE_STDLIB_ALLOC 1
        !            20: # include <config.h>
        !            21: #endif
1.1       misho      22: 
1.1.1.2 ! misho      23: #if !HAVE_CANONICALIZE_FILE_NAME || !FUNC_REALPATH_WORKS || defined _LIBC
1.1       misho      24: 
1.1.1.2 ! misho      25: /* Don't use __attribute__ __nonnull__ in this compilation unit.  Otherwise gcc
        !            26:    optimizes away the name == NULL test below.  */
        !            27: #define _GL_ARG_NONNULL(params)
1.1       misho      28: 
                     29: /* Specification.  */
                     30: #include <stdlib.h>
                     31: 
1.1.1.2 ! misho      32: #include <alloca.h>
        !            33: #include <string.h>
        !            34: #include <unistd.h>
1.1       misho      35: #include <limits.h>
                     36: #if HAVE_SYS_PARAM_H || defined _LIBC
                     37: # include <sys/param.h>
                     38: #endif
                     39: #include <sys/stat.h>
                     40: #include <errno.h>
1.1.1.2 ! misho      41: #include <stddef.h>
1.1       misho      42: 
                     43: #ifdef _LIBC
                     44: # include <shlib-compat.h>
                     45: #else
                     46: # define SHLIB_COMPAT(lib, introduced, obsoleted) 0
1.1.1.2 ! misho      47: # define versioned_symbol(lib, local, symbol, version) extern int dummy
1.1       misho      48: # define compat_symbol(lib, local, symbol, version)
                     49: # define weak_alias(local, symbol)
                     50: # define __canonicalize_file_name canonicalize_file_name
1.1.1.2 ! misho      51: # define __realpath realpath
1.1       misho      52: # include "pathmax.h"
                     53: # include "malloca.h"
                     54: # if HAVE_GETCWD
1.1.1.2 ! misho      55: #  if IN_RELOCWRAPPER
        !            56:     /* When building the relocatable program wrapper, use the system's getcwd
        !            57:        function, not the gnulib override, otherwise we would get a link error.
        !            58:      */
        !            59: #   undef getcwd
        !            60: #  endif
1.1       misho      61: #  ifdef VMS
                     62:     /* We want the directory in Unix syntax, not in VMS syntax.  */
                     63: #   define __getcwd(buf, max) getcwd (buf, max, 0)
                     64: #  else
                     65: #   define __getcwd getcwd
                     66: #  endif
                     67: # else
                     68: #  define __getcwd(buf, max) getwd (buf)
                     69: # endif
                     70: # define __readlink readlink
1.1.1.2 ! misho      71: # define __set_errno(e) errno = (e)
        !            72: # ifndef MAXSYMLINKS
        !            73: #  ifdef SYMLOOP_MAX
        !            74: #   define MAXSYMLINKS SYMLOOP_MAX
        !            75: #  else
        !            76: #   define MAXSYMLINKS 20
        !            77: #  endif
1.1       misho      78: # endif
                     79: #endif
                     80: 
1.1.1.2 ! misho      81: #ifndef DOUBLE_SLASH_IS_DISTINCT_ROOT
        !            82: # define DOUBLE_SLASH_IS_DISTINCT_ROOT 0
        !            83: #endif
        !            84: 
        !            85: #if !FUNC_REALPATH_WORKS || defined _LIBC
1.1       misho      86: /* Return the canonical absolute name of file NAME.  A canonical name
                     87:    does not contain any `.', `..' components nor any repeated path
                     88:    separators ('/') or symlinks.  All path components must exist.  If
                     89:    RESOLVED is null, the result is malloc'd; otherwise, if the
                     90:    canonical name is PATH_MAX chars or more, returns null with `errno'
                     91:    set to ENAMETOOLONG; if the name fits in fewer than PATH_MAX chars,
                     92:    returns the name in RESOLVED.  If the name cannot be resolved and
                     93:    RESOLVED is non-NULL, it contains the path of the first component
                     94:    that cannot be resolved.  If the path can be resolved, RESOLVED
                     95:    holds the same value as the value returned.  */
                     96: 
                     97: char *
                     98: __realpath (const char *name, char *resolved)
                     99: {
                    100:   char *rpath, *dest, *extra_buf = NULL;
                    101:   const char *start, *end, *rpath_limit;
                    102:   long int path_max;
                    103:   int num_links = 0;
                    104: 
                    105:   if (name == NULL)
                    106:     {
                    107:       /* As per Single Unix Specification V2 we must return an error if
1.1.1.2 ! misho     108:          either parameter is a null pointer.  We extend this to allow
        !           109:          the RESOLVED parameter to be NULL in case the we are expected to
        !           110:          allocate the room for the return value.  */
1.1       misho     111:       __set_errno (EINVAL);
                    112:       return NULL;
                    113:     }
                    114: 
                    115:   if (name[0] == '\0')
                    116:     {
                    117:       /* As per Single Unix Specification V2 we must return an error if
1.1.1.2 ! misho     118:          the name argument points to an empty string.  */
1.1       misho     119:       __set_errno (ENOENT);
                    120:       return NULL;
                    121:     }
                    122: 
                    123: #ifdef PATH_MAX
                    124:   path_max = PATH_MAX;
                    125: #else
                    126:   path_max = pathconf (name, _PC_PATH_MAX);
                    127:   if (path_max <= 0)
1.1.1.2 ! misho     128:     path_max = 8192;
1.1       misho     129: #endif
                    130: 
                    131:   if (resolved == NULL)
                    132:     {
                    133:       rpath = malloc (path_max);
                    134:       if (rpath == NULL)
1.1.1.2 ! misho     135:         {
        !           136:           /* It's easier to set errno to ENOMEM than to rely on the
        !           137:              'malloc-posix' gnulib module.  */
        !           138:           errno = ENOMEM;
        !           139:           return NULL;
        !           140:         }
1.1       misho     141:     }
                    142:   else
                    143:     rpath = resolved;
                    144:   rpath_limit = rpath + path_max;
                    145: 
                    146:   if (name[0] != '/')
                    147:     {
                    148:       if (!__getcwd (rpath, path_max))
1.1.1.2 ! misho     149:         {
        !           150:           rpath[0] = '\0';
        !           151:           goto error;
        !           152:         }
1.1       misho     153:       dest = strchr (rpath, '\0');
                    154:     }
                    155:   else
                    156:     {
                    157:       rpath[0] = '/';
                    158:       dest = rpath + 1;
1.1.1.2 ! misho     159:       if (DOUBLE_SLASH_IS_DISTINCT_ROOT && name[1] == '/')
        !           160:         *dest++ = '/';
1.1       misho     161:     }
                    162: 
                    163:   for (start = end = name; *start; start = end)
                    164:     {
                    165: #ifdef _LIBC
                    166:       struct stat64 st;
                    167: #else
                    168:       struct stat st;
                    169: #endif
1.1.1.2 ! misho     170:       int n;
1.1       misho     171: 
                    172:       /* Skip sequence of multiple path-separators.  */
                    173:       while (*start == '/')
1.1.1.2 ! misho     174:         ++start;
1.1       misho     175: 
                    176:       /* Find end of path component.  */
                    177:       for (end = start; *end && *end != '/'; ++end)
1.1.1.2 ! misho     178:         /* Nothing.  */;
1.1       misho     179: 
                    180:       if (end - start == 0)
1.1.1.2 ! misho     181:         break;
1.1       misho     182:       else if (end - start == 1 && start[0] == '.')
1.1.1.2 ! misho     183:         /* nothing */;
1.1       misho     184:       else if (end - start == 2 && start[0] == '.' && start[1] == '.')
1.1.1.2 ! misho     185:         {
        !           186:           /* Back up to previous component, ignore if at root already.  */
        !           187:           if (dest > rpath + 1)
        !           188:             while ((--dest)[-1] != '/');
        !           189:           if (DOUBLE_SLASH_IS_DISTINCT_ROOT && dest == rpath + 1
        !           190:               && *dest == '/')
        !           191:             dest++;
        !           192:         }
1.1       misho     193:       else
1.1.1.2 ! misho     194:         {
        !           195:           size_t new_size;
1.1       misho     196: 
1.1.1.2 ! misho     197:           if (dest[-1] != '/')
        !           198:             *dest++ = '/';
1.1       misho     199: 
1.1.1.2 ! misho     200:           if (dest + (end - start) >= rpath_limit)
        !           201:             {
        !           202:               ptrdiff_t dest_offset = dest - rpath;
        !           203:               char *new_rpath;
        !           204: 
        !           205:               if (resolved)
        !           206:                 {
        !           207:                   __set_errno (ENAMETOOLONG);
        !           208:                   if (dest > rpath + 1)
        !           209:                     dest--;
        !           210:                   *dest = '\0';
        !           211:                   goto error;
        !           212:                 }
        !           213:               new_size = rpath_limit - rpath;
        !           214:               if (end - start + 1 > path_max)
        !           215:                 new_size += end - start + 1;
        !           216:               else
        !           217:                 new_size += path_max;
        !           218:               new_rpath = (char *) realloc (rpath, new_size);
        !           219:               if (new_rpath == NULL)
        !           220:                 {
        !           221:                   /* It's easier to set errno to ENOMEM than to rely on the
        !           222:                      'realloc-posix' gnulib module.  */
        !           223:                   errno = ENOMEM;
        !           224:                   goto error;
        !           225:                 }
        !           226:               rpath = new_rpath;
        !           227:               rpath_limit = rpath + new_size;
1.1       misho     228: 
1.1.1.2 ! misho     229:               dest = rpath + dest_offset;
        !           230:             }
1.1       misho     231: 
                    232: #ifdef _LIBC
1.1.1.2 ! misho     233:           dest = __mempcpy (dest, start, end - start);
1.1       misho     234: #else
1.1.1.2 ! misho     235:           memcpy (dest, start, end - start);
        !           236:           dest += end - start;
1.1       misho     237: #endif
1.1.1.2 ! misho     238:           *dest = '\0';
1.1       misho     239: 
                    240: #ifdef _LIBC
1.1.1.2 ! misho     241:           if (__lxstat64 (_STAT_VER, rpath, &st) < 0)
1.1       misho     242: #else
1.1.1.2 ! misho     243:           if (lstat (rpath, &st) < 0)
1.1       misho     244: #endif
1.1.1.2 ! misho     245:             goto error;
1.1       misho     246: 
1.1.1.2 ! misho     247:           if (S_ISLNK (st.st_mode))
        !           248:             {
        !           249:               char *buf;
        !           250:               size_t len;
        !           251: 
        !           252:               if (++num_links > MAXSYMLINKS)
        !           253:                 {
        !           254:                   __set_errno (ELOOP);
        !           255:                   goto error;
        !           256:                 }
        !           257: 
        !           258:               buf = malloca (path_max);
        !           259:               if (!buf)
        !           260:                 {
        !           261:                   errno = ENOMEM;
        !           262:                   goto error;
        !           263:                 }
        !           264: 
        !           265:               n = __readlink (rpath, buf, path_max - 1);
        !           266:               if (n < 0)
        !           267:                 {
        !           268:                   int saved_errno = errno;
        !           269:                   freea (buf);
        !           270:                   errno = saved_errno;
        !           271:                   goto error;
        !           272:                 }
        !           273:               buf[n] = '\0';
        !           274: 
        !           275:               if (!extra_buf)
        !           276:                 {
        !           277:                   extra_buf = malloca (path_max);
        !           278:                   if (!extra_buf)
        !           279:                     {
        !           280:                       freea (buf);
        !           281:                       errno = ENOMEM;
        !           282:                       goto error;
        !           283:                     }
        !           284:                 }
        !           285: 
        !           286:               len = strlen (end);
        !           287:               if ((long int) (n + len) >= path_max)
        !           288:                 {
        !           289:                   freea (buf);
        !           290:                   __set_errno (ENAMETOOLONG);
        !           291:                   goto error;
        !           292:                 }
        !           293: 
        !           294:               /* Careful here, end may be a pointer into extra_buf... */
        !           295:               memmove (&extra_buf[n], end, len + 1);
        !           296:               name = end = memcpy (extra_buf, buf, n);
        !           297: 
        !           298:               if (buf[0] == '/')
        !           299:                 {
        !           300:                   dest = rpath + 1;     /* It's an absolute symlink */
        !           301:                   if (DOUBLE_SLASH_IS_DISTINCT_ROOT && buf[1] == '/')
        !           302:                     *dest++ = '/';
        !           303:                 }
        !           304:               else
        !           305:                 {
        !           306:                   /* Back up to previous component, ignore if at root
        !           307:                      already: */
        !           308:                   if (dest > rpath + 1)
        !           309:                     while ((--dest)[-1] != '/');
        !           310:                   if (DOUBLE_SLASH_IS_DISTINCT_ROOT && dest == rpath + 1
        !           311:                       && *dest == '/')
        !           312:                     dest++;
        !           313:                 }
        !           314:             }
        !           315:           else if (!S_ISDIR (st.st_mode) && *end != '\0')
        !           316:             {
        !           317:               __set_errno (ENOTDIR);
        !           318:               goto error;
        !           319:             }
        !           320:         }
1.1       misho     321:     }
                    322:   if (dest > rpath + 1 && dest[-1] == '/')
                    323:     --dest;
1.1.1.2 ! misho     324:   if (DOUBLE_SLASH_IS_DISTINCT_ROOT && dest == rpath + 1 && *dest == '/')
        !           325:     dest++;
1.1       misho     326:   *dest = '\0';
                    327: 
                    328:   if (extra_buf)
                    329:     freea (extra_buf);
                    330: 
1.1.1.2 ! misho     331:   return rpath;
1.1       misho     332: 
                    333: error:
                    334:   {
                    335:     int saved_errno = errno;
                    336:     if (extra_buf)
                    337:       freea (extra_buf);
1.1.1.2 ! misho     338:     if (resolved == NULL)
1.1       misho     339:       free (rpath);
                    340:     errno = saved_errno;
                    341:   }
                    342:   return NULL;
                    343: }
                    344: versioned_symbol (libc, __realpath, realpath, GLIBC_2_3);
1.1.1.2 ! misho     345: #endif /* !FUNC_REALPATH_WORKS || defined _LIBC */
1.1       misho     346: 
                    347: 
                    348: #if SHLIB_COMPAT(libc, GLIBC_2_0, GLIBC_2_3)
                    349: char *
1.1.1.2 ! misho     350: attribute_compat_text_section
1.1       misho     351: __old_realpath (const char *name, char *resolved)
                    352: {
                    353:   if (resolved == NULL)
                    354:     {
                    355:       __set_errno (EINVAL);
                    356:       return NULL;
                    357:     }
                    358: 
                    359:   return __realpath (name, resolved);
                    360: }
                    361: compat_symbol (libc, __old_realpath, realpath, GLIBC_2_0);
                    362: #endif
                    363: 
                    364: 
                    365: char *
                    366: __canonicalize_file_name (const char *name)
                    367: {
                    368:   return __realpath (name, NULL);
                    369: }
                    370: weak_alias (__canonicalize_file_name, canonicalize_file_name)
                    371: 
                    372: #else
                    373: 
                    374: /* This declaration is solely to ensure that after preprocessing
                    375:    this file is never empty.  */
                    376: typedef int dummy;
                    377: 
                    378: #endif

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