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