1130561Sobrien/* Libiberty realpath. Like realpath, but more consistent behavior. 2130561Sobrien Based on gdb_realpath from GDB. 3130561Sobrien 4130561Sobrien Copyright 2003 Free Software Foundation, Inc. 5130561Sobrien 6130561Sobrien This file is part of the libiberty library. 7130561Sobrien 8130561Sobrien This program is free software; you can redistribute it and/or modify 9130561Sobrien it under the terms of the GNU General Public License as published by 10130561Sobrien the Free Software Foundation; either version 2 of the License, or 11130561Sobrien (at your option) any later version. 12130561Sobrien 13130561Sobrien This program is distributed in the hope that it will be useful, 14130561Sobrien but WITHOUT ANY WARRANTY; without even the implied warranty of 15130561Sobrien MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16130561Sobrien GNU General Public License for more details. 17130561Sobrien 18130561Sobrien You should have received a copy of the GNU General Public License 19130561Sobrien along with this program; if not, write to the Free Software 20218822Sdim Foundation, Inc., 51 Franklin Street - Fifth Floor, 21218822Sdim Boston, MA 02110-1301, USA. */ 22130561Sobrien 23130561Sobrien/* 24130561Sobrien 25130561Sobrien@deftypefn Replacement {const char*} lrealpath (const char *@var{name}) 26130561Sobrien 27130561SobrienGiven a pointer to a string containing a pathname, returns a canonical 28130561Sobrienversion of the filename. Symlinks will be resolved, and ``.'' and ``..'' 29130561Sobriencomponents will be simplified. The returned value will be allocated using 30130561Sobrien@code{malloc}, or @code{NULL} will be returned on a memory allocation error. 31130561Sobrien 32130561Sobrien@end deftypefn 33130561Sobrien 34130561Sobrien*/ 35130561Sobrien 36130561Sobrien#include "config.h" 37130561Sobrien#include "ansidecl.h" 38130561Sobrien#include "libiberty.h" 39130561Sobrien 40130561Sobrien#ifdef HAVE_LIMITS_H 41130561Sobrien#include <limits.h> 42130561Sobrien#endif 43130561Sobrien#ifdef HAVE_STDLIB_H 44130561Sobrien#include <stdlib.h> 45130561Sobrien#endif 46130561Sobrien#ifdef HAVE_UNISTD_H 47130561Sobrien#include <unistd.h> 48130561Sobrien#endif 49130561Sobrien#ifdef HAVE_STRING_H 50130561Sobrien#include <string.h> 51130561Sobrien#endif 52130561Sobrien 53130561Sobrien/* On GNU libc systems the declaration is only visible with _GNU_SOURCE. */ 54130561Sobrien#if defined(HAVE_CANONICALIZE_FILE_NAME) \ 55130561Sobrien && defined(NEED_DECLARATION_CANONICALIZE_FILE_NAME) 56130561Sobrienextern char *canonicalize_file_name (const char *); 57130561Sobrien#endif 58130561Sobrien 59130561Sobrien#if defined(HAVE_REALPATH) 60130561Sobrien# if defined (PATH_MAX) 61130561Sobrien# define REALPATH_LIMIT PATH_MAX 62130561Sobrien# else 63130561Sobrien# if defined (MAXPATHLEN) 64130561Sobrien# define REALPATH_LIMIT MAXPATHLEN 65130561Sobrien# endif 66130561Sobrien# endif 67218822Sdim#else 68218822Sdim /* cygwin has realpath, so it won't get here. */ 69218822Sdim# if defined (_WIN32) 70218822Sdim# define WIN32_LEAN_AND_MEAN 71218822Sdim# include <windows.h> /* for GetFullPathName */ 72218822Sdim# endif 73130561Sobrien#endif 74130561Sobrien 75130561Sobrienchar * 76218822Sdimlrealpath (const char *filename) 77130561Sobrien{ 78130561Sobrien /* Method 1: The system has a compile time upper bound on a filename 79130561Sobrien path. Use that and realpath() to canonicalize the name. This is 80130561Sobrien the most common case. Note that, if there isn't a compile time 81130561Sobrien upper bound, you want to avoid realpath() at all costs. */ 82130561Sobrien#if defined(REALPATH_LIMIT) 83130561Sobrien { 84130561Sobrien char buf[REALPATH_LIMIT]; 85130561Sobrien const char *rp = realpath (filename, buf); 86130561Sobrien if (rp == NULL) 87130561Sobrien rp = filename; 88130561Sobrien return strdup (rp); 89130561Sobrien } 90130561Sobrien#endif /* REALPATH_LIMIT */ 91130561Sobrien 92130561Sobrien /* Method 2: The host system (i.e., GNU) has the function 93130561Sobrien canonicalize_file_name() which malloc's a chunk of memory and 94130561Sobrien returns that, use that. */ 95130561Sobrien#if defined(HAVE_CANONICALIZE_FILE_NAME) 96130561Sobrien { 97130561Sobrien char *rp = canonicalize_file_name (filename); 98130561Sobrien if (rp == NULL) 99130561Sobrien return strdup (filename); 100130561Sobrien else 101130561Sobrien return rp; 102130561Sobrien } 103130561Sobrien#endif 104130561Sobrien 105130561Sobrien /* Method 3: Now we're getting desperate! The system doesn't have a 106130561Sobrien compile time buffer size and no alternative function. Query the 107130561Sobrien OS, using pathconf(), for the buffer limit. Care is needed 108130561Sobrien though, some systems do not limit PATH_MAX (return -1 for 109130561Sobrien pathconf()) making it impossible to pass a correctly sized buffer 110130561Sobrien to realpath() (it could always overflow). On those systems, we 111130561Sobrien skip this. */ 112130561Sobrien#if defined (HAVE_REALPATH) && defined (HAVE_UNISTD_H) 113130561Sobrien { 114130561Sobrien /* Find out the max path size. */ 115130561Sobrien long path_max = pathconf ("/", _PC_PATH_MAX); 116130561Sobrien if (path_max > 0) 117130561Sobrien { 118130561Sobrien /* PATH_MAX is bounded. */ 119130561Sobrien char *buf, *rp, *ret; 120218822Sdim buf = (char *) malloc (path_max); 121130561Sobrien if (buf == NULL) 122130561Sobrien return NULL; 123130561Sobrien rp = realpath (filename, buf); 124130561Sobrien ret = strdup (rp ? rp : filename); 125130561Sobrien free (buf); 126130561Sobrien return ret; 127130561Sobrien } 128130561Sobrien } 129130561Sobrien#endif 130130561Sobrien 131218822Sdim /* The MS Windows method. If we don't have realpath, we assume we 132218822Sdim don't have symlinks and just canonicalize to a Windows absolute 133218822Sdim path. GetFullPath converts ../ and ./ in relative paths to 134218822Sdim absolute paths, filling in current drive if one is not given 135218822Sdim or using the current directory of a specified drive (eg, "E:foo"). 136218822Sdim It also converts all forward slashes to back slashes. */ 137218822Sdim#if defined (_WIN32) 138218822Sdim { 139218822Sdim char buf[MAX_PATH]; 140218822Sdim char* basename; 141218822Sdim DWORD len = GetFullPathName (filename, MAX_PATH, buf, &basename); 142218822Sdim if (len == 0 || len > MAX_PATH - 1) 143218822Sdim return strdup (filename); 144218822Sdim else 145218822Sdim { 146218822Sdim /* The file system is case-preserving but case-insensitive, 147218822Sdim Canonicalize to lowercase, using the codepage associated 148218822Sdim with the process locale. */ 149218822Sdim CharLowerBuff (buf, len); 150218822Sdim return strdup (buf); 151218822Sdim } 152218822Sdim } 153218822Sdim#endif 154218822Sdim 155130561Sobrien /* This system is a lost cause, just duplicate the filename. */ 156130561Sobrien return strdup (filename); 157130561Sobrien} 158