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
28 #include <sys/param.h>
29 #include <sys/types.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
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
;
54 struct stat
*pst
= NULL
;
56 if (!name
|| !resolved
)
64 /* As per Single Unix Specification V2 we must return an error if
65 the name argument points to an empty string. */
70 if ((buf
=(char *)calloc(PATH_MAX
, sizeof(char)))==NULL
) {
74 if ((extra_buf
=(char *)calloc(PATH_MAX
, sizeof(char)))==NULL
) {
78 if ((pst
=(struct stat
*)calloc(1, sizeof(struct stat
)))==NULL
) {
83 resolved_limit
= resolved
+ PATH_MAX
;
85 /* relative path, the first char is not '/' */
88 if (!getcwd(resolved
, PATH_MAX
))
94 dest
= strchr (resolved
, '\0');
102 /* special case "/" */
111 /* now resolved is the current wd or "/", navigate through the path */
112 for (start
= end
= name
; *start
; start
= end
)
116 /* Skip sequence of multiple path-separators. */
117 while (*start
== '/')
120 /* Find end of path component. */
121 for (end
= start
; *end
&& *end
!= '/'; ++end
);
123 if (end
- start
== 0)
125 else if (end
- start
== 1 && start
[0] == '.')
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] != '/');
138 if (dest
+ (end
- start
) >= resolved_limit
)
140 errno
= ENAMETOOLONG
;
141 if (dest
> resolved_root
)
147 /* copy the component, don't use mempcpy for better portability */
148 dest
= (char*)memcpy(dest
, start
, end
- start
) + (end
- start
);
151 /*check the dir along the path */
152 if (lstat(resolved
, pst
) < 0)
156 /* this is a symbolic link, thus restart the navigation from
157 * the symlink location */
158 if (S_ISLNK (pst
->st_mode
))
162 if (++num_links
> MAXSYMLINKS
)
169 n
= readlink (resolved
, buf
, PATH_MAX
);
176 if ((long) (n
+ len
) >= PATH_MAX
)
178 errno
= ENAMETOOLONG
;
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
);
187 dest
= resolved_root
; /* It's an absolute symlink */
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
))
198 else if (*end
== '/')
200 if (access(resolved
, X_OK
) != 0)
209 if (dest
> resolved
+ 1 && dest
[-1] == '/')
220 if (extra_buf
) free(extra_buf
);