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 27Given a pointer to a string containing a pathname, returns a canonical 28version of the filename. Symlinks will be resolved, and ``.'' and ``..'' 29components 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) 56extern 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 75char * 76lrealpath (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