4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
22 #pragma ident "%Z%%M% %I% %E% SMI"
25 * Copyright (c) 1987 by Sun Microsystems, Inc.
29 #include <sys/param.h>
37 * Input name in raw, canonicalized pathname output to canon. If dosymlinks
38 * is nonzero, resolves all symbolic links encountered during canonicalization
39 * into an equivalent symlink-free form. Returns 0 on success, -1 on failure.
40 * The routine fails if the current working directory can't be obtained or if
41 * either of the arguments is NULL.
43 * Sets errno on failure.
46 pathcanon(raw
, canon
, dosymlinks
)
53 register char *limit
= canon
+ MAXPATHLEN
;
58 * Do a bit of sanity checking.
60 if (raw
== NULL
|| canon
== NULL
) {
66 * If the path in raw is not already absolute, convert it to that form.
67 * In any case, initialize canon with the absolute form of raw. Make
68 * sure that none of the operations overflow the corresponding buffers.
69 * The code below does the copy operations by hand so that it can easily
70 * keep track of whether overflow is about to occur.
75 /* Relative; prepend the working directory. */
76 if (getwd(d
) == NULL
) {
77 /* Use whatever errno value getwd may have left around. */
81 /* Add slash to separate working directory from relative part. */
87 while (d
< limit
&& *s
)
90 /* Add a trailing slash to simplify the code below. */
92 while (d
< limit
&& (*d
++ = *s
++))
97 * Canonicalize the path. The strategy is to update in place, with
98 * d pointing to the end of the canonicalized portion and s to the
99 * current spot from which we're copying. This works because
100 * canonicalization doesn't increase path length, except as discussed
101 * below. Note also that the path has had a slash added at its end.
102 * This greatly simplifies the treatment of boundary conditions.
105 while (d
< limit
&& *s
) {
106 if ((*d
++ = *s
++) == '/' && d
> canon
+ 1) {
107 register char *t
= d
- 2;
111 /* Found // in the name. */
117 /* Found /./ in the name. */
122 /* Found /../ in the name. */
123 while (t
> canon
&& *--t
!= '/')
136 * We're at the end of a component. If dosymlinks is set
137 * see whether the component is a symbolic link. If so,
138 * replace it by its contents.
141 char link
[MAXPATHLEN
+ 1];
145 * See whether it's a symlink by trying to read it.
147 * Start by isolating it.
150 if ((llen
= readlink(canon
, link
, sizeof link
)) >= 0) {
151 /* Make sure that there are no circular links. */
153 if (nlink
> MAXSYMLINKS
) {
158 * The component is a symlink. Since its value can be
159 * of arbitrary size, we can't continue copying in place.
160 * Instead, form the new path suffix in the link buffer
161 * and then copy it back to its proper spot in canon.
166 * Copy the remaining unresolved portion to the end
167 * of the symlink. If the sum of the unresolved part and
168 * the readlink exceeds MAXPATHLEN, the extra bytes
169 * will be dropped off. Too bad!
171 (void) strncpy(t
, s
, sizeof link
- llen
- 1);
172 link
[sizeof link
- 1] = '\0';
174 * If the link's contents are absolute, copy it back
175 * to the start of canon, otherwise to the beginning of
176 * the link's position in the path.
178 if (link
[0] == '/') {
180 (void) strcpy(canon
, link
);
185 * Relative: find beginning of component and copy.
188 while (d
> canon
&& *--d
!= '/')
192 * If the sum of the resolved part, the readlink
193 * and the remaining unresolved part exceeds
194 * MAXPATHLEN, the extra bytes will be dropped off.
196 if (strlen(link
) >= (limit
- s
)) {
197 (void) strncpy(s
, link
, limit
- s
);
200 (void) strcpy(s
, link
);
206 * readlink call failed. It can be because it was
207 * not a link (i.e. a file, dir etc.) or because the
208 * the call actually failed.
212 *(d
- 1) = '/'; /* Restore it */
214 } /* if (dosymlinks) */
218 /* Remove the trailing slash that was added above. */
219 if (*(d
- 1) == '/' && d
> canon
+ 1)
226 * Canonicalize the path given in raw, resolving away all symbolic link
227 * components. Store the result into the buffer named by canon, which
228 * must be long enough (MAXPATHLEN bytes will suffice). Returns NULL
229 * on failure and canon on success.
231 * The routine indirectly invokes the readlink() system call and getwd()
232 * so it inherits the possibility of hanging due to inaccessible file
240 return (pathcanon(raw
, canon
, 1) < 0 ? NULL
: canon
);