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