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

1.1       misho       1: /* Return the canonical absolute name of a given file.
                      2:    Copyright (C) 1996-2003, 2005-2008 Free Software Foundation, Inc.
                      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: 
                     18: #include <config.h>
                     19: 
                     20: /* Avoid a clash of our rpl_realpath() function with the prototype in
                     21:    <stdlib.h> on Solaris 2.5.1.  */
                     22: #undef realpath
                     23: 
                     24: #if !HAVE_CANONICALIZE_FILE_NAME || defined _LIBC
                     25: 
                     26: #include <alloca.h>
                     27: 
                     28: /* Specification.  */
                     29: #include "canonicalize.h"
                     30: 
                     31: #include <stddef.h>
                     32: #include <stdlib.h>
                     33: #include <string.h>
                     34: 
                     35: #if HAVE_UNISTD_H || defined _LIBC
                     36: # include <unistd.h>
                     37: #endif
                     38: 
                     39: #include <limits.h>
                     40: 
                     41: #if HAVE_SYS_PARAM_H || defined _LIBC
                     42: # include <sys/param.h>
                     43: #endif
                     44: #ifndef MAXSYMLINKS
                     45: # define MAXSYMLINKS 20
                     46: #endif
                     47: 
                     48: #include <sys/stat.h>
                     49: 
                     50: #include <errno.h>
                     51: #ifndef _LIBC
                     52: # define __set_errno(e) errno = (e)
                     53: # ifndef ENAMETOOLONG
                     54: #  define ENAMETOOLONG EINVAL
                     55: # endif
                     56: #endif
                     57: 
                     58: #ifdef _LIBC
                     59: # include <shlib-compat.h>
                     60: #else
                     61: # define SHLIB_COMPAT(lib, introduced, obsoleted) 0
                     62: # define versioned_symbol(lib, local, symbol, version)
                     63: # define compat_symbol(lib, local, symbol, version)
                     64: # define weak_alias(local, symbol)
                     65: # define __canonicalize_file_name canonicalize_file_name
                     66: # define __realpath rpl_realpath
                     67: # include "pathmax.h"
                     68: # include "malloca.h"
                     69: # if HAVE_GETCWD
                     70: #  ifdef VMS
                     71:     /* We want the directory in Unix syntax, not in VMS syntax.  */
                     72: #   define __getcwd(buf, max) getcwd (buf, max, 0)
                     73: #  else
                     74: #   define __getcwd getcwd
                     75: #  endif
                     76: # else
                     77: #  define __getcwd(buf, max) getwd (buf)
                     78: # endif
                     79: # define __readlink readlink
                     80:   /* On systems without symbolic links, call stat() instead of lstat().  */
                     81: # if !defined S_ISLNK && !HAVE_READLINK
                     82: #  define lstat stat
                     83: # endif
                     84: #endif
                     85: 
                     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: #if HAVE_READLINK
                    104:   int num_links = 0;
                    105: #endif
                    106: 
                    107:   if (name == NULL)
                    108:     {
                    109:       /* As per Single Unix Specification V2 we must return an error if
                    110:         either parameter is a null pointer.  We extend this to allow
                    111:         the RESOLVED parameter to be NULL in case the we are expected to
                    112:         allocate the room for the return value.  */
                    113:       __set_errno (EINVAL);
                    114:       return NULL;
                    115:     }
                    116: 
                    117:   if (name[0] == '\0')
                    118:     {
                    119:       /* As per Single Unix Specification V2 we must return an error if
                    120:         the name argument points to an empty string.  */
                    121:       __set_errno (ENOENT);
                    122:       return NULL;
                    123:     }
                    124: 
                    125: #ifdef PATH_MAX
                    126:   path_max = PATH_MAX;
                    127: #else
                    128:   path_max = pathconf (name, _PC_PATH_MAX);
                    129:   if (path_max <= 0)
                    130:     path_max = 1024;
                    131: #endif
                    132: 
                    133:   if (resolved == NULL)
                    134:     {
                    135:       rpath = malloc (path_max);
                    136:       if (rpath == NULL)
                    137:        {
                    138:          /* It's easier to set errno to ENOMEM than to rely on the
                    139:             'malloc-posix' gnulib module.  */
                    140:          errno = ENOMEM;
                    141:          return NULL;
                    142:        }
                    143:     }
                    144:   else
                    145:     rpath = resolved;
                    146:   rpath_limit = rpath + path_max;
                    147: 
                    148:   if (name[0] != '/')
                    149:     {
                    150:       if (!__getcwd (rpath, path_max))
                    151:        {
                    152:          rpath[0] = '\0';
                    153:          goto error;
                    154:        }
                    155:       dest = strchr (rpath, '\0');
                    156:     }
                    157:   else
                    158:     {
                    159:       rpath[0] = '/';
                    160:       dest = rpath + 1;
                    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
                    170: 
                    171:       /* Skip sequence of multiple path-separators.  */
                    172:       while (*start == '/')
                    173:        ++start;
                    174: 
                    175:       /* Find end of path component.  */
                    176:       for (end = start; *end && *end != '/'; ++end)
                    177:        /* Nothing.  */;
                    178: 
                    179:       if (end - start == 0)
                    180:        break;
                    181:       else if (end - start == 1 && start[0] == '.')
                    182:        /* nothing */;
                    183:       else if (end - start == 2 && start[0] == '.' && start[1] == '.')
                    184:        {
                    185:          /* Back up to previous component, ignore if at root already.  */
                    186:          if (dest > rpath + 1)
                    187:            while ((--dest)[-1] != '/');
                    188:        }
                    189:       else
                    190:        {
                    191:          size_t new_size;
                    192: 
                    193:          if (dest[-1] != '/')
                    194:            *dest++ = '/';
                    195: 
                    196:          if (dest + (end - start) >= rpath_limit)
                    197:            {
                    198:              ptrdiff_t dest_offset = dest - rpath;
                    199:              char *new_rpath;
                    200: 
                    201:              if (resolved)
                    202:                {
                    203:                  __set_errno (ENAMETOOLONG);
                    204:                  if (dest > rpath + 1)
                    205:                    dest--;
                    206:                  *dest = '\0';
                    207:                  goto error;
                    208:                }
                    209:              new_size = rpath_limit - rpath;
                    210:              if (end - start + 1 > path_max)
                    211:                new_size += end - start + 1;
                    212:              else
                    213:                new_size += path_max;
                    214:              new_rpath = (char *) realloc (rpath, new_size);
                    215:              if (new_rpath == NULL)
                    216:                {
                    217:                  /* It's easier to set errno to ENOMEM than to rely on the
                    218:                     'realloc-posix' gnulib module.  */
                    219:                  errno = ENOMEM;
                    220:                  goto error;
                    221:                }
                    222:              rpath = new_rpath;
                    223:              rpath_limit = rpath + new_size;
                    224: 
                    225:              dest = rpath + dest_offset;
                    226:            }
                    227: 
                    228: #ifdef _LIBC
                    229:          dest = __mempcpy (dest, start, end - start);
                    230: #else
                    231:          memcpy (dest, start, end - start);
                    232:          dest += end - start;
                    233: #endif
                    234:          *dest = '\0';
                    235: 
                    236: #ifdef _LIBC
                    237:          if (__lxstat64 (_STAT_VER, rpath, &st) < 0)
                    238: #else
                    239:          if (lstat (rpath, &st) < 0)
                    240: #endif
                    241:            goto error;
                    242: 
                    243: #if HAVE_READLINK
                    244:          if (S_ISLNK (st.st_mode))
                    245:            {
                    246:              char *buf;
                    247:              size_t len;
                    248:              int n;
                    249: 
                    250:              if (++num_links > MAXSYMLINKS)
                    251:                {
                    252:                  __set_errno (ELOOP);
                    253:                  goto error;
                    254:                }
                    255: 
                    256:              buf = malloca (path_max);
                    257:              if (!buf)
                    258:                {
                    259:                  errno = ENOMEM;
                    260:                  goto error;
                    261:                }
                    262: 
                    263:              n = __readlink (rpath, buf, path_max - 1);
                    264:              if (n < 0)
                    265:                {
                    266:                  int saved_errno = errno;
                    267:                  freea (buf);
                    268:                  errno = saved_errno;
                    269:                  goto error;
                    270:                }
                    271:              buf[n] = '\0';
                    272: 
                    273:              if (!extra_buf)
                    274:                {
                    275:                  extra_buf = malloca (path_max);
                    276:                  if (!extra_buf)
                    277:                    {
                    278:                      freea (buf);
                    279:                      errno = ENOMEM;
                    280:                      goto error;
                    281:                    }
                    282:                }
                    283: 
                    284:              len = strlen (end);
                    285:              if ((long int) (n + len) >= path_max)
                    286:                {
                    287:                  freea (buf);
                    288:                  __set_errno (ENAMETOOLONG);
                    289:                  goto error;
                    290:                }
                    291: 
                    292:              /* Careful here, end may be a pointer into extra_buf... */
                    293:              memmove (&extra_buf[n], end, len + 1);
                    294:              name = end = memcpy (extra_buf, buf, n);
                    295: 
                    296:              if (buf[0] == '/')
                    297:                dest = rpath + 1;       /* It's an absolute symlink */
                    298:              else
                    299:                /* Back up to previous component, ignore if at root already: */
                    300:                if (dest > rpath + 1)
                    301:                  while ((--dest)[-1] != '/');
                    302:            }
                    303: #endif
                    304:        }
                    305:     }
                    306:   if (dest > rpath + 1 && dest[-1] == '/')
                    307:     --dest;
                    308:   *dest = '\0';
                    309: 
                    310:   if (extra_buf)
                    311:     freea (extra_buf);
                    312: 
                    313:   return resolved ? memcpy (resolved, rpath, dest - rpath + 1) : rpath;
                    314: 
                    315: error:
                    316:   {
                    317:     int saved_errno = errno;
                    318:     if (extra_buf)
                    319:       freea (extra_buf);
                    320:     if (resolved)
                    321:       strcpy (resolved, rpath);
                    322:     else
                    323:       free (rpath);
                    324:     errno = saved_errno;
                    325:   }
                    326:   return NULL;
                    327: }
                    328: #ifdef _LIBC
                    329: versioned_symbol (libc, __realpath, realpath, GLIBC_2_3);
                    330: #endif
                    331: 
                    332: 
                    333: #if SHLIB_COMPAT(libc, GLIBC_2_0, GLIBC_2_3)
                    334: char *
                    335: __old_realpath (const char *name, char *resolved)
                    336: {
                    337:   if (resolved == NULL)
                    338:     {
                    339:       __set_errno (EINVAL);
                    340:       return NULL;
                    341:     }
                    342: 
                    343:   return __realpath (name, resolved);
                    344: }
                    345: compat_symbol (libc, __old_realpath, realpath, GLIBC_2_0);
                    346: #endif
                    347: 
                    348: 
                    349: char *
                    350: __canonicalize_file_name (const char *name)
                    351: {
                    352:   return __realpath (name, NULL);
                    353: }
                    354: weak_alias (__canonicalize_file_name, canonicalize_file_name)
                    355: 
                    356: #else
                    357: 
                    358: /* This declaration is solely to ensure that after preprocessing
                    359:    this file is never empty.  */
                    360: typedef int dummy;
                    361: 
                    362: #endif

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