gerbv  2.10.1-dev~93f1b5
lrealpath.c
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 "lrealpath.h"
38 
39 #ifdef HAVE_LIMITS_H
40 #include <limits.h>
41 #endif
42 #ifdef HAVE_STDLIB_H
43 #include <stdlib.h>
44 #endif
45 #ifdef HAVE_UNISTD_H
46 #include <unistd.h>
47 #endif
48 #ifdef HAVE_STRING_H
49 #include <string.h>
50 #endif
51 
52 /* On GNU libc systems the declaration is only visible with _GNU_SOURCE. */
53 #if defined(HAVE_CANONICALIZE_FILE_NAME) && defined(NEED_DECLARATION_CANONICALIZE_FILE_NAME)
54 extern char* canonicalize_file_name(const char*);
55 #endif
56 
57 #if defined(HAVE_REALPATH)
58 #if defined(PATH_MAX)
59 #define REALPATH_LIMIT PATH_MAX
60 #else
61 #if defined(MAXPATHLEN)
62 #define REALPATH_LIMIT MAXPATHLEN
63 #endif
64 #endif
65 #else
66 /* cygwin has realpath, so it won't get here. */
67 #if defined(_WIN32)
68 #define WIN32_LEAN_AND_MEAN
69 #include <windows.h> /* for GetFullPathName */
70 #endif
71 #endif
72 
73 char*
74 lrealpath(const char* filename) {
75  /* Method 1: The system has a compile time upper bound on a filename
76  path. Use that and realpath() to canonicalize the name. This is
77  the most common case. Note that, if there isn't a compile time
78  upper bound, you want to avoid realpath() at all costs. */
79 #if defined(REALPATH_LIMIT)
80  {
81  char buf[REALPATH_LIMIT];
82  const char* rp = realpath(filename, buf);
83  if (rp == NULL)
84  rp = filename;
85  return strdup(rp);
86  }
87  /* REALPATH_LIMIT */
88 
89  /* Method 2: The host system (i.e., GNU) has the function
90  canonicalize_file_name() which malloc's a chunk of memory and
91  returns that, use that. */
92 #elif defined(HAVE_CANONICALIZE_FILE_NAME)
93  {
94  char* rp = canonicalize_file_name(filename);
95  if (rp == NULL)
96  return strdup(filename);
97  else
98  return rp;
99  }
100  /* HAVE_CANONICALIZE_FILE_NAME */
101 
102  /* Method 3: Now we're getting desperate! The system doesn't have a
103  compile time buffer size and no alternative function. Query the
104  OS, using pathconf(), for the buffer limit. Care is needed
105  though, some systems do not limit PATH_MAX (return -1 for
106  pathconf()) making it impossible to pass a correctly sized buffer
107  to realpath() (it could always overflow). On those systems, we
108  skip this. */
109 #elif defined(HAVE_REALPATH) && defined(HAVE_UNISTD_H)
110  {
111  /* Find out the max path size. */
112  long path_max = pathconf("/", _PC_PATH_MAX);
113  if (path_max > 0) {
114  /* PATH_MAX is bounded. */
115  char *buf, *rp, *ret;
116  buf = (char*)malloc(path_max);
117  if (buf == NULL)
118  return NULL;
119  rp = realpath(filename, buf);
120  ret = strdup(rp ? rp : filename);
121  free(buf);
122  return ret;
123  } else {
124  return NULL;
125  }
126  }
127  /* HAVE_REALPATH && HAVE_UNISTD_H */
128 
129  /* The MS Windows method. If we don't have realpath, we assume we
130  don't have symlinks and just canonicalize to a Windows absolute
131  path. GetFullPath converts ../ and ./ in relative paths to
132  absolute paths, filling in current drive if one is not given
133  or using the current directory of a specified drive (eg, "E:foo").
134  It also converts all forward slashes to back slashes. */
135 #elif defined(_WIN32)
136  {
137  char buf[MAX_PATH];
138  char* basename;
139  DWORD len = GetFullPathName(filename, MAX_PATH, buf, &basename);
140  if (len == 0 || len > MAX_PATH - 1)
141  return strdup(filename);
142  else {
143  /* The file system is case-preserving but case-insensitive,
144  Canonicalize to lowercase, using the codepage associated
145  with the process locale. */
146  CharLowerBuff(buf, len);
147  return strdup(buf);
148  }
149  }
150 #else
151 
152  /* This system is a lost cause, just duplicate the filename. */
153  return strdup(filename);
154 #endif
155 }