File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / libiconv / srclib / canonicalize-lgpl.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 22:57:48 2012 UTC (12 years, 5 months ago) by misho
Branches: libiconv, MAIN
CVS tags: v1_13_1, HEAD
libiconv

    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>