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