Annotation of embedaddon/libiconv/srclib/canonicalize-lgpl.c, revision 1.1.1.1
1.1 misho 1: /* Return the canonical absolute name of a given file.
2: Copyright (C) 1996-2003, 2005-2008 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: #include <config.h>
19:
20: /* Avoid a clash of our rpl_realpath() function with the prototype in
21: <stdlib.h> on Solaris 2.5.1. */
22: #undef realpath
23:
24: #if !HAVE_CANONICALIZE_FILE_NAME || defined _LIBC
25:
26: #include <alloca.h>
27:
28: /* Specification. */
29: #include "canonicalize.h"
30:
31: #include <stddef.h>
32: #include <stdlib.h>
33: #include <string.h>
34:
35: #if HAVE_UNISTD_H || defined _LIBC
36: # include <unistd.h>
37: #endif
38:
39: #include <limits.h>
40:
41: #if HAVE_SYS_PARAM_H || defined _LIBC
42: # include <sys/param.h>
43: #endif
44: #ifndef MAXSYMLINKS
45: # define MAXSYMLINKS 20
46: #endif
47:
48: #include <sys/stat.h>
49:
50: #include <errno.h>
51: #ifndef _LIBC
52: # define __set_errno(e) errno = (e)
53: # ifndef ENAMETOOLONG
54: # define ENAMETOOLONG EINVAL
55: # endif
56: #endif
57:
58: #ifdef _LIBC
59: # include <shlib-compat.h>
60: #else
61: # define SHLIB_COMPAT(lib, introduced, obsoleted) 0
62: # define versioned_symbol(lib, local, symbol, version)
63: # define compat_symbol(lib, local, symbol, version)
64: # define weak_alias(local, symbol)
65: # define __canonicalize_file_name canonicalize_file_name
66: # define __realpath rpl_realpath
67: # include "pathmax.h"
68: # include "malloca.h"
69: # if HAVE_GETCWD
70: # ifdef VMS
71: /* We want the directory in Unix syntax, not in VMS syntax. */
72: # define __getcwd(buf, max) getcwd (buf, max, 0)
73: # else
74: # define __getcwd getcwd
75: # endif
76: # else
77: # define __getcwd(buf, max) getwd (buf)
78: # endif
79: # define __readlink readlink
80: /* On systems without symbolic links, call stat() instead of lstat(). */
81: # if !defined S_ISLNK && !HAVE_READLINK
82: # define lstat stat
83: # endif
84: #endif
85:
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: #if HAVE_READLINK
104: int num_links = 0;
105: #endif
106:
107: if (name == NULL)
108: {
109: /* As per Single Unix Specification V2 we must return an error if
110: either parameter is a null pointer. We extend this to allow
111: the RESOLVED parameter to be NULL in case the we are expected to
112: allocate the room for the return value. */
113: __set_errno (EINVAL);
114: return NULL;
115: }
116:
117: if (name[0] == '\0')
118: {
119: /* As per Single Unix Specification V2 we must return an error if
120: the name argument points to an empty string. */
121: __set_errno (ENOENT);
122: return NULL;
123: }
124:
125: #ifdef PATH_MAX
126: path_max = PATH_MAX;
127: #else
128: path_max = pathconf (name, _PC_PATH_MAX);
129: if (path_max <= 0)
130: path_max = 1024;
131: #endif
132:
133: if (resolved == NULL)
134: {
135: rpath = malloc (path_max);
136: if (rpath == NULL)
137: {
138: /* It's easier to set errno to ENOMEM than to rely on the
139: 'malloc-posix' gnulib module. */
140: errno = ENOMEM;
141: return NULL;
142: }
143: }
144: else
145: rpath = resolved;
146: rpath_limit = rpath + path_max;
147:
148: if (name[0] != '/')
149: {
150: if (!__getcwd (rpath, path_max))
151: {
152: rpath[0] = '\0';
153: goto error;
154: }
155: dest = strchr (rpath, '\0');
156: }
157: else
158: {
159: rpath[0] = '/';
160: dest = rpath + 1;
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:
171: /* Skip sequence of multiple path-separators. */
172: while (*start == '/')
173: ++start;
174:
175: /* Find end of path component. */
176: for (end = start; *end && *end != '/'; ++end)
177: /* Nothing. */;
178:
179: if (end - start == 0)
180: break;
181: else if (end - start == 1 && start[0] == '.')
182: /* nothing */;
183: else if (end - start == 2 && start[0] == '.' && start[1] == '.')
184: {
185: /* Back up to previous component, ignore if at root already. */
186: if (dest > rpath + 1)
187: while ((--dest)[-1] != '/');
188: }
189: else
190: {
191: size_t new_size;
192:
193: if (dest[-1] != '/')
194: *dest++ = '/';
195:
196: if (dest + (end - start) >= rpath_limit)
197: {
198: ptrdiff_t dest_offset = dest - rpath;
199: char *new_rpath;
200:
201: if (resolved)
202: {
203: __set_errno (ENAMETOOLONG);
204: if (dest > rpath + 1)
205: dest--;
206: *dest = '\0';
207: goto error;
208: }
209: new_size = rpath_limit - rpath;
210: if (end - start + 1 > path_max)
211: new_size += end - start + 1;
212: else
213: new_size += path_max;
214: new_rpath = (char *) realloc (rpath, new_size);
215: if (new_rpath == NULL)
216: {
217: /* It's easier to set errno to ENOMEM than to rely on the
218: 'realloc-posix' gnulib module. */
219: errno = ENOMEM;
220: goto error;
221: }
222: rpath = new_rpath;
223: rpath_limit = rpath + new_size;
224:
225: dest = rpath + dest_offset;
226: }
227:
228: #ifdef _LIBC
229: dest = __mempcpy (dest, start, end - start);
230: #else
231: memcpy (dest, start, end - start);
232: dest += end - start;
233: #endif
234: *dest = '\0';
235:
236: #ifdef _LIBC
237: if (__lxstat64 (_STAT_VER, rpath, &st) < 0)
238: #else
239: if (lstat (rpath, &st) < 0)
240: #endif
241: goto error;
242:
243: #if HAVE_READLINK
244: if (S_ISLNK (st.st_mode))
245: {
246: char *buf;
247: size_t len;
248: int n;
249:
250: if (++num_links > MAXSYMLINKS)
251: {
252: __set_errno (ELOOP);
253: goto error;
254: }
255:
256: buf = malloca (path_max);
257: if (!buf)
258: {
259: errno = ENOMEM;
260: goto error;
261: }
262:
263: n = __readlink (rpath, buf, path_max - 1);
264: if (n < 0)
265: {
266: int saved_errno = errno;
267: freea (buf);
268: errno = saved_errno;
269: goto error;
270: }
271: buf[n] = '\0';
272:
273: if (!extra_buf)
274: {
275: extra_buf = malloca (path_max);
276: if (!extra_buf)
277: {
278: freea (buf);
279: errno = ENOMEM;
280: goto error;
281: }
282: }
283:
284: len = strlen (end);
285: if ((long int) (n + len) >= path_max)
286: {
287: freea (buf);
288: __set_errno (ENAMETOOLONG);
289: goto error;
290: }
291:
292: /* Careful here, end may be a pointer into extra_buf... */
293: memmove (&extra_buf[n], end, len + 1);
294: name = end = memcpy (extra_buf, buf, n);
295:
296: if (buf[0] == '/')
297: dest = rpath + 1; /* It's an absolute symlink */
298: else
299: /* Back up to previous component, ignore if at root already: */
300: if (dest > rpath + 1)
301: while ((--dest)[-1] != '/');
302: }
303: #endif
304: }
305: }
306: if (dest > rpath + 1 && dest[-1] == '/')
307: --dest;
308: *dest = '\0';
309:
310: if (extra_buf)
311: freea (extra_buf);
312:
313: return resolved ? memcpy (resolved, rpath, dest - rpath + 1) : rpath;
314:
315: error:
316: {
317: int saved_errno = errno;
318: if (extra_buf)
319: freea (extra_buf);
320: if (resolved)
321: strcpy (resolved, rpath);
322: else
323: free (rpath);
324: errno = saved_errno;
325: }
326: return NULL;
327: }
328: #ifdef _LIBC
329: versioned_symbol (libc, __realpath, realpath, GLIBC_2_3);
330: #endif
331:
332:
333: #if SHLIB_COMPAT(libc, GLIBC_2_0, GLIBC_2_3)
334: char *
335: __old_realpath (const char *name, char *resolved)
336: {
337: if (resolved == NULL)
338: {
339: __set_errno (EINVAL);
340: return NULL;
341: }
342:
343: return __realpath (name, resolved);
344: }
345: compat_symbol (libc, __old_realpath, realpath, GLIBC_2_0);
346: #endif
347:
348:
349: char *
350: __canonicalize_file_name (const char *name)
351: {
352: return __realpath (name, NULL);
353: }
354: weak_alias (__canonicalize_file_name, canonicalize_file_name)
355:
356: #else
357:
358: /* This declaration is solely to ensure that after preprocessing
359: this file is never empty. */
360: typedef int dummy;
361:
362: #endif
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>