Use Gnulib's `inet_ntop' and `inet_pton' modules.
[bpt/guile.git] / lib / canonicalize-lgpl.c
CommitLineData
ffca4c22 1/* Return the canonical absolute name of a given file.
8912421c 2 Copyright (C) 1996-2009 Free Software Foundation, Inc.
ffca4c22
AW
3 This file is part of the GNU C Library.
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>. */
17
8912421c
LC
18#ifndef _LIBC
19# include <config.h>
20#endif
ffca4c22 21
8912421c 22#if !HAVE_CANONICALIZE_FILE_NAME || !FUNC_REALPATH_WORKS || defined _LIBC
ffca4c22
AW
23
24/* Specification. */
ffca4c22 25#include <stdlib.h>
ffca4c22 26
8912421c
LC
27#include <alloca.h>
28#include <string.h>
29#include <unistd.h>
ffca4c22 30#include <limits.h>
ffca4c22
AW
31#if HAVE_SYS_PARAM_H || defined _LIBC
32# include <sys/param.h>
33#endif
ffca4c22 34#include <sys/stat.h>
ffca4c22 35#include <errno.h>
8912421c 36#include <stddef.h>
ffca4c22
AW
37
38#ifdef _LIBC
39# include <shlib-compat.h>
40#else
41# define SHLIB_COMPAT(lib, introduced, obsoleted) 0
42# define versioned_symbol(lib, local, symbol, version)
43# define compat_symbol(lib, local, symbol, version)
44# define weak_alias(local, symbol)
45# define __canonicalize_file_name canonicalize_file_name
8912421c 46# define __realpath realpath
ffca4c22
AW
47# include "pathmax.h"
48# include "malloca.h"
49# if HAVE_GETCWD
50# ifdef VMS
51 /* We want the directory in Unix syntax, not in VMS syntax. */
52# define __getcwd(buf, max) getcwd (buf, max, 0)
53# else
54# define __getcwd getcwd
55# endif
56# else
57# define __getcwd(buf, max) getwd (buf)
58# endif
59# define __readlink readlink
8912421c
LC
60# define __set_errno(e) errno = (e)
61# ifndef MAXSYMLINKS
62# ifdef SYMLOOP_MAX
63# define MAXSYMLINKS SYMLOOP_MAX
64# else
65# define MAXSYMLINKS 20
66# endif
ffca4c22
AW
67# endif
68#endif
69
8912421c
LC
70#ifndef DOUBLE_SLASH_IS_DISTINCT_ROOT
71# define DOUBLE_SLASH_IS_DISTINCT_ROOT 0
72#endif
73
74#if !FUNC_REALPATH_WORKS || defined _LIBC
ffca4c22
AW
75/* Return the canonical absolute name of file NAME. A canonical name
76 does not contain any `.', `..' components nor any repeated path
77 separators ('/') or symlinks. All path components must exist. If
78 RESOLVED is null, the result is malloc'd; otherwise, if the
79 canonical name is PATH_MAX chars or more, returns null with `errno'
80 set to ENAMETOOLONG; if the name fits in fewer than PATH_MAX chars,
81 returns the name in RESOLVED. If the name cannot be resolved and
82 RESOLVED is non-NULL, it contains the path of the first component
83 that cannot be resolved. If the path can be resolved, RESOLVED
84 holds the same value as the value returned. */
85
86char *
87__realpath (const char *name, char *resolved)
88{
89 char *rpath, *dest, *extra_buf = NULL;
90 const char *start, *end, *rpath_limit;
91 long int path_max;
ffca4c22 92 int num_links = 0;
ffca4c22
AW
93
94 if (name == NULL)
95 {
96 /* As per Single Unix Specification V2 we must return an error if
97 either parameter is a null pointer. We extend this to allow
98 the RESOLVED parameter to be NULL in case the we are expected to
99 allocate the room for the return value. */
100 __set_errno (EINVAL);
101 return NULL;
102 }
103
104 if (name[0] == '\0')
105 {
106 /* As per Single Unix Specification V2 we must return an error if
107 the name argument points to an empty string. */
108 __set_errno (ENOENT);
109 return NULL;
110 }
111
112#ifdef PATH_MAX
113 path_max = PATH_MAX;
114#else
115 path_max = pathconf (name, _PC_PATH_MAX);
116 if (path_max <= 0)
117 path_max = 1024;
118#endif
119
120 if (resolved == NULL)
121 {
122 rpath = malloc (path_max);
123 if (rpath == NULL)
124 {
125 /* It's easier to set errno to ENOMEM than to rely on the
126 'malloc-posix' gnulib module. */
127 errno = ENOMEM;
128 return NULL;
129 }
130 }
131 else
132 rpath = resolved;
133 rpath_limit = rpath + path_max;
134
135 if (name[0] != '/')
136 {
137 if (!__getcwd (rpath, path_max))
138 {
139 rpath[0] = '\0';
140 goto error;
141 }
142 dest = strchr (rpath, '\0');
143 }
144 else
145 {
146 rpath[0] = '/';
147 dest = rpath + 1;
8912421c
LC
148 if (DOUBLE_SLASH_IS_DISTINCT_ROOT && name[1] == '/')
149 *dest++ = '/';
ffca4c22
AW
150 }
151
152 for (start = end = name; *start; start = end)
153 {
154#ifdef _LIBC
155 struct stat64 st;
156#else
157 struct stat st;
158#endif
8912421c 159 int n;
ffca4c22
AW
160
161 /* Skip sequence of multiple path-separators. */
162 while (*start == '/')
163 ++start;
164
165 /* Find end of path component. */
166 for (end = start; *end && *end != '/'; ++end)
167 /* Nothing. */;
168
169 if (end - start == 0)
170 break;
171 else if (end - start == 1 && start[0] == '.')
172 /* nothing */;
173 else if (end - start == 2 && start[0] == '.' && start[1] == '.')
174 {
175 /* Back up to previous component, ignore if at root already. */
176 if (dest > rpath + 1)
177 while ((--dest)[-1] != '/');
8912421c
LC
178 if (DOUBLE_SLASH_IS_DISTINCT_ROOT && dest == rpath + 1
179 && *dest == '/')
180 dest++;
ffca4c22
AW
181 }
182 else
183 {
184 size_t new_size;
185
186 if (dest[-1] != '/')
187 *dest++ = '/';
188
189 if (dest + (end - start) >= rpath_limit)
190 {
191 ptrdiff_t dest_offset = dest - rpath;
192 char *new_rpath;
193
194 if (resolved)
195 {
196 __set_errno (ENAMETOOLONG);
197 if (dest > rpath + 1)
198 dest--;
199 *dest = '\0';
200 goto error;
201 }
202 new_size = rpath_limit - rpath;
203 if (end - start + 1 > path_max)
204 new_size += end - start + 1;
205 else
206 new_size += path_max;
207 new_rpath = (char *) realloc (rpath, new_size);
208 if (new_rpath == NULL)
209 {
210 /* It's easier to set errno to ENOMEM than to rely on the
211 'realloc-posix' gnulib module. */
212 errno = ENOMEM;
213 goto error;
214 }
215 rpath = new_rpath;
216 rpath_limit = rpath + new_size;
217
218 dest = rpath + dest_offset;
219 }
220
221#ifdef _LIBC
222 dest = __mempcpy (dest, start, end - start);
223#else
224 memcpy (dest, start, end - start);
225 dest += end - start;
226#endif
227 *dest = '\0';
228
229#ifdef _LIBC
230 if (__lxstat64 (_STAT_VER, rpath, &st) < 0)
231#else
232 if (lstat (rpath, &st) < 0)
233#endif
234 goto error;
235
ffca4c22
AW
236 if (S_ISLNK (st.st_mode))
237 {
238 char *buf;
239 size_t len;
ffca4c22
AW
240
241 if (++num_links > MAXSYMLINKS)
242 {
243 __set_errno (ELOOP);
244 goto error;
245 }
246
247 buf = malloca (path_max);
248 if (!buf)
249 {
250 errno = ENOMEM;
251 goto error;
252 }
253
254 n = __readlink (rpath, buf, path_max - 1);
255 if (n < 0)
256 {
257 int saved_errno = errno;
258 freea (buf);
259 errno = saved_errno;
260 goto error;
261 }
262 buf[n] = '\0';
263
264 if (!extra_buf)
265 {
266 extra_buf = malloca (path_max);
267 if (!extra_buf)
268 {
269 freea (buf);
270 errno = ENOMEM;
271 goto error;
272 }
273 }
274
275 len = strlen (end);
276 if ((long int) (n + len) >= path_max)
277 {
278 freea (buf);
279 __set_errno (ENAMETOOLONG);
280 goto error;
281 }
282
283 /* Careful here, end may be a pointer into extra_buf... */
284 memmove (&extra_buf[n], end, len + 1);
285 name = end = memcpy (extra_buf, buf, n);
286
287 if (buf[0] == '/')
8912421c
LC
288 {
289 dest = rpath + 1; /* It's an absolute symlink */
290 if (DOUBLE_SLASH_IS_DISTINCT_ROOT && buf[1] == '/')
291 *dest++ = '/';
292 }
ffca4c22 293 else
8912421c
LC
294 {
295 /* Back up to previous component, ignore if at root
296 already: */
297 if (dest > rpath + 1)
298 while ((--dest)[-1] != '/');
299 if (DOUBLE_SLASH_IS_DISTINCT_ROOT && dest == rpath + 1
300 && *dest == '/')
301 dest++;
302 }
303 }
304 else if (!S_ISDIR (st.st_mode) && *end != '\0')
305 {
306 __set_errno (ENOTDIR);
307 goto error;
ffca4c22 308 }
ffca4c22
AW
309 }
310 }
311 if (dest > rpath + 1 && dest[-1] == '/')
312 --dest;
8912421c
LC
313 if (DOUBLE_SLASH_IS_DISTINCT_ROOT && dest == rpath + 1 && *dest == '/')
314 dest++;
ffca4c22
AW
315 *dest = '\0';
316
317 if (extra_buf)
318 freea (extra_buf);
319
8912421c 320 return rpath;
ffca4c22
AW
321
322error:
323 {
324 int saved_errno = errno;
325 if (extra_buf)
326 freea (extra_buf);
8912421c 327 if (resolved == NULL)
ffca4c22
AW
328 free (rpath);
329 errno = saved_errno;
330 }
331 return NULL;
332}
ffca4c22 333versioned_symbol (libc, __realpath, realpath, GLIBC_2_3);
8912421c 334#endif /* !FUNC_REALPATH_WORKS || defined _LIBC */
ffca4c22
AW
335
336
337#if SHLIB_COMPAT(libc, GLIBC_2_0, GLIBC_2_3)
338char *
8912421c 339attribute_compat_text_section
ffca4c22
AW
340__old_realpath (const char *name, char *resolved)
341{
342 if (resolved == NULL)
343 {
344 __set_errno (EINVAL);
345 return NULL;
346 }
347
348 return __realpath (name, resolved);
349}
350compat_symbol (libc, __old_realpath, realpath, GLIBC_2_0);
351#endif
352
353
354char *
355__canonicalize_file_name (const char *name)
356{
357 return __realpath (name, NULL);
358}
359weak_alias (__canonicalize_file_name, canonicalize_file_name)
360
361#else
362
363/* This declaration is solely to ensure that after preprocessing
364 this file is never empty. */
365typedef int dummy;
366
367#endif