Home | History | Annotate | Download | only in libiberty
      1 /* Libiberty realpath.  Like realpath, but more consistent behavior.
      2    Based on gdb_realpath from GDB.
      3 
      4    Copyright 2003 Free Software Foundation, Inc.
      5 
      6    This file is part of the libiberty library.
      7 
      8    This program is free software; you can redistribute it and/or modify
      9    it under the terms of the GNU General Public License as published by
     10    the Free Software Foundation; either version 2 of the License, or
     11    (at your option) any later version.
     12 
     13    This program is distributed in the hope that it will be useful,
     14    but WITHOUT ANY WARRANTY; without even the implied warranty of
     15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     16    GNU General Public License for more details.
     17 
     18    You should have received a copy of the GNU General Public License
     19    along with this program; if not, write to the Free Software
     20    Foundation, Inc., 51 Franklin Street - Fifth Floor,
     21    Boston, MA 02110-1301, USA.  */
     22 
     23 /*
     24 
     25 @deftypefn Replacement {const char*} lrealpath (const char *@var{name})
     26 
     27 Given a pointer to a string containing a pathname, returns a canonical
     28 version of the filename.  Symlinks will be resolved, and ``.'' and ``..''
     29 components will be simplified.  The returned value will be allocated using
     30 @code{malloc}, or @code{NULL} will be returned on a memory allocation error.
     31 
     32 @end deftypefn
     33 
     34 */
     35 
     36 #include "config.h"
     37 #include "ansidecl.h"
     38 #include "libiberty.h"
     39 
     40 #ifdef HAVE_LIMITS_H
     41 #include <limits.h>
     42 #endif
     43 #ifdef HAVE_STDLIB_H
     44 #include <stdlib.h>
     45 #endif
     46 #ifdef HAVE_UNISTD_H
     47 #include <unistd.h>
     48 #endif
     49 #ifdef HAVE_STRING_H
     50 #include <string.h>
     51 #endif
     52 
     53 /* On GNU libc systems the declaration is only visible with _GNU_SOURCE.  */
     54 #if defined(HAVE_CANONICALIZE_FILE_NAME) \
     55     && defined(NEED_DECLARATION_CANONICALIZE_FILE_NAME)
     56 extern char *canonicalize_file_name (const char *);
     57 #endif
     58 
     59 #if defined(HAVE_REALPATH)
     60 # if defined (PATH_MAX)
     61 #  define REALPATH_LIMIT PATH_MAX
     62 # else
     63 #  if defined (MAXPATHLEN)
     64 #   define REALPATH_LIMIT MAXPATHLEN
     65 #  endif
     66 # endif
     67 #else
     68   /* cygwin has realpath, so it won't get here.  */
     69 # if defined (_WIN32)
     70 #  define WIN32_LEAN_AND_MEAN
     71 #  include <windows.h> /* for GetFullPathName */
     72 # endif
     73 #endif
     74 
     75 char *
     76 lrealpath (const char *filename)
     77 {
     78   /* Method 1: The system has a compile time upper bound on a filename
     79      path.  Use that and realpath() to canonicalize the name.  This is
     80      the most common case.  Note that, if there isn't a compile time
     81      upper bound, you want to avoid realpath() at all costs.  */
     82 #if defined(REALPATH_LIMIT)
     83   {
     84     char buf[REALPATH_LIMIT];
     85     const char *rp = realpath (filename, buf);
     86     if (rp == NULL)
     87       rp = filename;
     88     return strdup (rp);
     89   }
     90 #endif /* REALPATH_LIMIT */
     91 
     92   /* Method 2: The host system (i.e., GNU) has the function
     93      canonicalize_file_name() which malloc's a chunk of memory and
     94      returns that, use that.  */
     95 #if defined(HAVE_CANONICALIZE_FILE_NAME)
     96   {
     97     char *rp = canonicalize_file_name (filename);
     98     if (rp == NULL)
     99       return strdup (filename);
    100     else
    101       return rp;
    102   }
    103 #endif
    104 
    105   /* Method 3: Now we're getting desperate!  The system doesn't have a
    106      compile time buffer size and no alternative function.  Query the
    107      OS, using pathconf(), for the buffer limit.  Care is needed
    108      though, some systems do not limit PATH_MAX (return -1 for
    109      pathconf()) making it impossible to pass a correctly sized buffer
    110      to realpath() (it could always overflow).  On those systems, we
    111      skip this.  */
    112 #if defined (HAVE_REALPATH) && defined (HAVE_UNISTD_H)
    113   {
    114     /* Find out the max path size.  */
    115     long path_max = pathconf ("/", _PC_PATH_MAX);
    116     if (path_max > 0)
    117       {
    118 	/* PATH_MAX is bounded.  */
    119 	char *buf, *rp, *ret;
    120 	buf = (char *) malloc (path_max);
    121 	if (buf == NULL)
    122 	  return NULL;
    123 	rp = realpath (filename, buf);
    124 	ret = strdup (rp ? rp : filename);
    125 	free (buf);
    126 	return ret;
    127       }
    128   }
    129 #endif
    130 
    131   /* The MS Windows method.  If we don't have realpath, we assume we
    132      don't have symlinks and just canonicalize to a Windows absolute
    133      path.  GetFullPath converts ../ and ./ in relative paths to
    134      absolute paths, filling in current drive if one is not given
    135      or using the current directory of a specified drive (eg, "E:foo").
    136      It also converts all forward slashes to back slashes.  */
    137 #if defined (_WIN32)
    138   {
    139     char buf[MAX_PATH];
    140     char* basename;
    141     DWORD len = GetFullPathName (filename, MAX_PATH, buf, &basename);
    142     if (len == 0 || len > MAX_PATH - 1)
    143       return strdup (filename);
    144     else
    145       {
    146 	/* The file system is case-preserving but case-insensitive,
    147 	   Canonicalize to lowercase, using the codepage associated
    148 	   with the process locale.  */
    149         CharLowerBuff (buf, len);
    150         return strdup (buf);
    151       }
    152   }
    153 #endif
    154 
    155   /* This system is a lost cause, just duplicate the filename.  */
    156   return strdup (filename);
    157 }
    158