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