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