xref: /netbsd-src/external/gpl3/gcc.old/dist/libiberty/lrealpath.c (revision 8feb0f0b7eaff0608f8350bbfa3098827b4bb91b)
11debfc3dSmrg /* Libiberty realpath.  Like realpath, but more consistent behavior.
21debfc3dSmrg    Based on gdb_realpath from GDB.
31debfc3dSmrg 
4*8feb0f0bSmrg    Copyright (C) 2003-2020 Free Software Foundation, Inc.
51debfc3dSmrg 
61debfc3dSmrg    This file is part of the libiberty library.
71debfc3dSmrg 
81debfc3dSmrg    This program is free software; you can redistribute it and/or modify
91debfc3dSmrg    it under the terms of the GNU General Public License as published by
101debfc3dSmrg    the Free Software Foundation; either version 2 of the License, or
111debfc3dSmrg    (at your option) any later version.
121debfc3dSmrg 
131debfc3dSmrg    This program is distributed in the hope that it will be useful,
141debfc3dSmrg    but WITHOUT ANY WARRANTY; without even the implied warranty of
151debfc3dSmrg    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
161debfc3dSmrg    GNU General Public License for more details.
171debfc3dSmrg 
181debfc3dSmrg    You should have received a copy of the GNU General Public License
191debfc3dSmrg    along with this program; if not, write to the Free Software
201debfc3dSmrg    Foundation, Inc., 51 Franklin Street - Fifth Floor,
211debfc3dSmrg    Boston, MA 02110-1301, USA.  */
221debfc3dSmrg 
231debfc3dSmrg /*
241debfc3dSmrg 
251debfc3dSmrg @deftypefn Replacement {const char*} lrealpath (const char *@var{name})
261debfc3dSmrg 
271debfc3dSmrg Given a pointer to a string containing a pathname, returns a canonical
281debfc3dSmrg version of the filename.  Symlinks will be resolved, and ``.'' and ``..''
291debfc3dSmrg components will be simplified.  The returned value will be allocated using
301debfc3dSmrg @code{malloc}, or @code{NULL} will be returned on a memory allocation error.
311debfc3dSmrg 
321debfc3dSmrg @end deftypefn
331debfc3dSmrg 
341debfc3dSmrg */
351debfc3dSmrg 
361debfc3dSmrg #include "config.h"
371debfc3dSmrg #include "ansidecl.h"
381debfc3dSmrg #include "libiberty.h"
391debfc3dSmrg 
401debfc3dSmrg #ifdef HAVE_LIMITS_H
411debfc3dSmrg #include <limits.h>
421debfc3dSmrg #endif
431debfc3dSmrg #ifdef HAVE_STDLIB_H
441debfc3dSmrg #include <stdlib.h>
451debfc3dSmrg #endif
461debfc3dSmrg #ifdef HAVE_UNISTD_H
471debfc3dSmrg #include <unistd.h>
481debfc3dSmrg #endif
491debfc3dSmrg #ifdef HAVE_STRING_H
501debfc3dSmrg #include <string.h>
511debfc3dSmrg #endif
521debfc3dSmrg 
531debfc3dSmrg /* On GNU libc systems the declaration is only visible with _GNU_SOURCE.  */
541debfc3dSmrg #if defined(HAVE_CANONICALIZE_FILE_NAME) \
551debfc3dSmrg     && defined(NEED_DECLARATION_CANONICALIZE_FILE_NAME)
561debfc3dSmrg extern char *canonicalize_file_name (const char *);
571debfc3dSmrg #endif
581debfc3dSmrg 
591debfc3dSmrg #if defined(HAVE_REALPATH)
601debfc3dSmrg # if defined (PATH_MAX)
611debfc3dSmrg #  define REALPATH_LIMIT PATH_MAX
621debfc3dSmrg # else
631debfc3dSmrg #  if defined (MAXPATHLEN)
641debfc3dSmrg #   define REALPATH_LIMIT MAXPATHLEN
651debfc3dSmrg #  endif
661debfc3dSmrg # endif
671debfc3dSmrg #else
681debfc3dSmrg   /* cygwin has realpath, so it won't get here.  */
691debfc3dSmrg # if defined (_WIN32)
701debfc3dSmrg #  define WIN32_LEAN_AND_MEAN
711debfc3dSmrg #  include <windows.h> /* for GetFullPathName */
721debfc3dSmrg # endif
731debfc3dSmrg #endif
741debfc3dSmrg 
751debfc3dSmrg char *
lrealpath(const char * filename)761debfc3dSmrg lrealpath (const char *filename)
771debfc3dSmrg {
781debfc3dSmrg   /* Method 1: The system has a compile time upper bound on a filename
791debfc3dSmrg      path.  Use that and realpath() to canonicalize the name.  This is
801debfc3dSmrg      the most common case.  Note that, if there isn't a compile time
811debfc3dSmrg      upper bound, you want to avoid realpath() at all costs.  */
821debfc3dSmrg #if defined(REALPATH_LIMIT)
831debfc3dSmrg   {
841debfc3dSmrg     char buf[REALPATH_LIMIT];
851debfc3dSmrg     const char *rp = realpath (filename, buf);
861debfc3dSmrg     if (rp == NULL)
871debfc3dSmrg       rp = filename;
881debfc3dSmrg     return strdup (rp);
891debfc3dSmrg   }
901debfc3dSmrg #endif /* REALPATH_LIMIT */
911debfc3dSmrg 
921debfc3dSmrg   /* Method 2: The host system (i.e., GNU) has the function
931debfc3dSmrg      canonicalize_file_name() which malloc's a chunk of memory and
941debfc3dSmrg      returns that, use that.  */
951debfc3dSmrg #if defined(HAVE_CANONICALIZE_FILE_NAME)
961debfc3dSmrg   {
971debfc3dSmrg     char *rp = canonicalize_file_name (filename);
981debfc3dSmrg     if (rp == NULL)
991debfc3dSmrg       return strdup (filename);
1001debfc3dSmrg     else
1011debfc3dSmrg       return rp;
1021debfc3dSmrg   }
1031debfc3dSmrg #endif
1041debfc3dSmrg 
1051debfc3dSmrg   /* Method 3: Now we're getting desperate!  The system doesn't have a
1061debfc3dSmrg      compile time buffer size and no alternative function.  Query the
1071debfc3dSmrg      OS, using pathconf(), for the buffer limit.  Care is needed
1081debfc3dSmrg      though, some systems do not limit PATH_MAX (return -1 for
1091debfc3dSmrg      pathconf()) making it impossible to pass a correctly sized buffer
1101debfc3dSmrg      to realpath() (it could always overflow).  On those systems, we
1111debfc3dSmrg      skip this.  */
1121debfc3dSmrg #if defined (HAVE_REALPATH) && defined (HAVE_UNISTD_H)
1131debfc3dSmrg   {
1141debfc3dSmrg     /* Find out the max path size.  */
1151debfc3dSmrg     long path_max = pathconf ("/", _PC_PATH_MAX);
1161debfc3dSmrg     if (path_max > 0)
1171debfc3dSmrg       {
1181debfc3dSmrg 	/* PATH_MAX is bounded.  */
1191debfc3dSmrg 	char *buf, *rp, *ret;
1201debfc3dSmrg 	buf = (char *) malloc (path_max);
1211debfc3dSmrg 	if (buf == NULL)
1221debfc3dSmrg 	  return NULL;
1231debfc3dSmrg 	rp = realpath (filename, buf);
1241debfc3dSmrg 	ret = strdup (rp ? rp : filename);
1251debfc3dSmrg 	free (buf);
1261debfc3dSmrg 	return ret;
1271debfc3dSmrg       }
1281debfc3dSmrg   }
1291debfc3dSmrg #endif
1301debfc3dSmrg 
1311debfc3dSmrg   /* The MS Windows method.  If we don't have realpath, we assume we
1321debfc3dSmrg      don't have symlinks and just canonicalize to a Windows absolute
1331debfc3dSmrg      path.  GetFullPath converts ../ and ./ in relative paths to
1341debfc3dSmrg      absolute paths, filling in current drive if one is not given
1351debfc3dSmrg      or using the current directory of a specified drive (eg, "E:foo").
1361debfc3dSmrg      It also converts all forward slashes to back slashes.  */
1371debfc3dSmrg #if defined (_WIN32)
1381debfc3dSmrg   {
1391debfc3dSmrg     char buf[MAX_PATH];
1401debfc3dSmrg     char* basename;
1411debfc3dSmrg     DWORD len = GetFullPathName (filename, MAX_PATH, buf, &basename);
1421debfc3dSmrg     if (len == 0 || len > MAX_PATH - 1)
1431debfc3dSmrg       return strdup (filename);
1441debfc3dSmrg     else
1451debfc3dSmrg       {
1461debfc3dSmrg 	/* The file system is case-preserving but case-insensitive,
1471debfc3dSmrg 	   Canonicalize to lowercase, using the codepage associated
1481debfc3dSmrg 	   with the process locale.  */
1491debfc3dSmrg         CharLowerBuff (buf, len);
1501debfc3dSmrg         return strdup (buf);
1511debfc3dSmrg       }
1521debfc3dSmrg   }
1531debfc3dSmrg #endif
1541debfc3dSmrg 
1551debfc3dSmrg   /* This system is a lost cause, just duplicate the filename.  */
1561debfc3dSmrg   return strdup (filename);
1571debfc3dSmrg }
158