Clean up unused variables.
[vde.git] / vde-2 / src / common / canonicalize.c
blob13d0e5e0a756557564acc1ce69de6e776b59515c
1 /*
2 * Return the canonical absolute name of a given file.
3 * Copyright (C) 1996-2001, 2002 Free Software Foundation, Inc.
4 * This file is part of the GNU C Library.
5 * Modified for um-viewos (C) Renzo Davoli 2005-2006
6 * Simplified for VDE (c) Ludovico Gardenghi 2008
8 * The GNU C Library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * The GNU C Library 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 GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with the GNU C Library; if not, write to the Free
20 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
21 * 02110-1301 USA.
24 #include <stdlib.h>
25 #include <string.h>
26 #include <unistd.h>
27 #include <limits.h>
28 #include <sys/param.h>
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <errno.h>
32 #include <stddef.h>
33 #include <config.h>
36 * Return the canonical absolute name of file NAME. A canonical name does not
37 * contain any `.', `..' components nor any repeated path separators ('/') or
38 * symlinks. All path components must exist. ; otherwise, if the canonical
39 * name is PATH_MAX chars or more, returns null with `errno' set to
40 * ENAMETOOLONG; if the name fits in fewer than PATH_MAX chars, returns the
41 * name in RESOLVED. If the name cannot be resolved and RESOLVED is non-NULL,
42 * it contains the path of the first component that cannot be resolved. If
43 * the path can be resolved, RESOLVED holds the same value as the value
44 * returned.
47 char *vde_realpath(const char *name, char *resolved)
49 char *dest, *buf=NULL, *extra_buf=NULL;
50 const char *start, *end, *resolved_limit;
51 char *resolved_root = resolved + 1;
52 char *ret_path = NULL;
53 int num_links = 0;
54 struct stat *pst = NULL;
56 if (!name || !resolved)
58 errno = EINVAL;
59 goto abort;
62 if (name[0] == '\0')
64 /* As per Single Unix Specification V2 we must return an error if
65 the name argument points to an empty string. */
66 errno = ENOENT;
67 goto abort;
70 if ((buf=(char *)calloc(PATH_MAX, sizeof(char)))==NULL) {
71 errno = ENOMEM;
72 goto abort;
74 if ((extra_buf=(char *)calloc(PATH_MAX, sizeof(char)))==NULL) {
75 errno = ENOMEM;
76 goto abort;
78 if ((pst=(struct stat *)calloc(1, sizeof(struct stat)))==NULL) {
79 errno = ENOMEM;
80 goto abort;
83 resolved_limit = resolved + PATH_MAX;
85 /* relative path, the first char is not '/' */
86 if (name[0] != '/')
88 if (!getcwd(resolved, PATH_MAX))
90 resolved[0] = '\0';
91 goto abort;
94 dest = strchr (resolved, '\0');
96 else
98 /* absolute path */
99 dest = resolved_root;
100 resolved[0] = '/';
102 /* special case "/" */
103 if (name[1] == 0)
105 *dest = '\0';
106 ret_path = resolved;
107 goto cleanup;
111 /* now resolved is the current wd or "/", navigate through the path */
112 for (start = end = name; *start; start = end)
114 int n;
116 /* Skip sequence of multiple path-separators. */
117 while (*start == '/')
118 ++start;
120 /* Find end of path component. */
121 for (end = start; *end && *end != '/'; ++end);
123 if (end - start == 0)
124 break;
125 else if (end - start == 1 && start[0] == '.')
126 /* nothing */;
127 else if (end - start == 2 && start[0] == '.' && start[1] == '.')
129 /* Back up to previous component, ignore if at root already. */
130 if (dest > resolved_root)
131 while ((--dest)[-1] != '/');
133 else
135 if (dest[-1] != '/')
136 *dest++ = '/';
138 if (dest + (end - start) >= resolved_limit)
140 errno = ENAMETOOLONG;
141 if (dest > resolved_root)
142 dest--;
143 *dest = '\0';
144 goto abort;
147 /* copy the component, don't use mempcpy for better portability */
148 dest = (char*)memcpy(dest, start, end - start) + (end - start);
149 *dest = '\0';
151 /*check the dir along the path */
152 if (lstat(resolved, pst) < 0)
153 goto abort;
154 else
156 /* this is a symbolic link, thus restart the navigation from
157 * the symlink location */
158 if (S_ISLNK (pst->st_mode))
160 size_t len;
162 if (++num_links > MAXSYMLINKS)
164 errno = ELOOP;
165 goto abort;
168 /* symlink! */
169 n = readlink (resolved, buf, PATH_MAX);
170 if (n < 0)
171 goto abort;
173 buf[n] = '\0';
175 len = strlen (end);
176 if ((long) (n + len) >= PATH_MAX)
178 errno = ENAMETOOLONG;
179 goto abort;
182 /* Careful here, end may be a pointer into extra_buf... */
183 memmove (&extra_buf[n], end, len + 1);
184 name = end = memcpy (extra_buf, buf, n);
186 if (buf[0] == '/')
187 dest = resolved_root; /* It's an absolute symlink */
188 else
189 /* Back up to previous component, ignore if at root already: */
190 if (dest > resolved + 1)
191 while ((--dest)[-1] != '/');
193 else if (*end == '/' && !S_ISDIR(pst->st_mode))
195 errno = ENOTDIR;
196 goto abort;
198 else if (*end == '/')
200 if (access(resolved, X_OK) != 0)
202 errno = EACCES;
203 goto abort;
209 if (dest > resolved + 1 && dest[-1] == '/')
210 --dest;
211 *dest = '\0';
213 ret_path = resolved;
214 goto cleanup;
216 abort:
217 ret_path = NULL;
218 cleanup:
219 if (buf) free(buf);
220 if (extra_buf) free(extra_buf);
221 if (pst) free(pst);
222 return ret_path;