getcwd.c revision 1.50.10.1 1 1.50.10.1 bouyer /* $NetBSD: getcwd.c,v 1.50.10.1 2013/04/20 10:11:43 bouyer Exp $ */
2 1.4 cgd
3 1.1 cgd /*
4 1.8 perry * Copyright (c) 1989, 1991, 1993, 1995
5 1.4 cgd * The Regents of the University of California. All rights reserved.
6 1.1 cgd *
7 1.8 perry * This code is derived from software contributed to Berkeley by
8 1.8 perry * Jan-Simon Pendry.
9 1.8 perry *
10 1.1 cgd * Redistribution and use in source and binary forms, with or without
11 1.1 cgd * modification, are permitted provided that the following conditions
12 1.1 cgd * are met:
13 1.1 cgd * 1. Redistributions of source code must retain the above copyright
14 1.1 cgd * notice, this list of conditions and the following disclaimer.
15 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright
16 1.1 cgd * notice, this list of conditions and the following disclaimer in the
17 1.1 cgd * documentation and/or other materials provided with the distribution.
18 1.32 agc * 3. Neither the name of the University nor the names of its contributors
19 1.1 cgd * may be used to endorse or promote products derived from this software
20 1.1 cgd * without specific prior written permission.
21 1.1 cgd *
22 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 1.1 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 1.1 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 1.1 cgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 1.1 cgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 1.1 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 1.1 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 1.1 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 1.1 cgd * SUCH DAMAGE.
33 1.1 cgd */
34 1.1 cgd
35 1.6 christos #include <sys/cdefs.h>
36 1.1 cgd #if defined(LIBC_SCCS) && !defined(lint)
37 1.4 cgd #if 0
38 1.8 perry static char sccsid[] = "@(#)getcwd.c 8.5 (Berkeley) 2/7/95";
39 1.4 cgd #else
40 1.50.10.1 bouyer __RCSID("$NetBSD: getcwd.c,v 1.50.10.1 2013/04/20 10:11:43 bouyer Exp $");
41 1.4 cgd #endif
42 1.1 cgd #endif /* LIBC_SCCS and not lint */
43 1.1 cgd
44 1.7 jtc #include "namespace.h"
45 1.1 cgd #include <sys/param.h>
46 1.1 cgd #include <sys/stat.h>
47 1.8 perry
48 1.22 lukem #include <assert.h>
49 1.1 cgd #include <errno.h>
50 1.1 cgd #include <stdlib.h>
51 1.1 cgd #include <string.h>
52 1.1 cgd #include <unistd.h>
53 1.50 joerg #include <ssp/ssp.h>
54 1.17 sommerfe
55 1.17 sommerfe #include "extern.h"
56 1.7 jtc
57 1.7 jtc #ifdef __weak_alias
58 1.50 joerg __weak_alias(getcwd,_getcwd)
59 1.50 joerg __weak_alias(_sys_getcwd,_getcwd)
60 1.24 mycroft __weak_alias(realpath,_realpath)
61 1.49 tron #endif
62 1.1 cgd
63 1.8 perry /*
64 1.50.10.1 bouyer * char *realpath(const char *path, char *resolved);
65 1.8 perry *
66 1.8 perry * Find the real name of path, by removing all ".", ".." and symlink
67 1.8 perry * components. Returns (resolved) on success, or (NULL) on failure,
68 1.8 perry * in which case the path which caused trouble is left in (resolved).
69 1.8 perry */
70 1.8 perry char *
71 1.50.10.1 bouyer realpath(const char * __restrict path, char * __restrict resolved)
72 1.8 perry {
73 1.8 perry struct stat sb;
74 1.40 elad int idx = 0, n, nlnk = 0;
75 1.36 enami const char *q;
76 1.50.10.1 bouyer char *p, wbuf[2][MAXPATHLEN], *fres;
77 1.36 enami size_t len;
78 1.22 lukem
79 1.46 dholland /* POSIX sez we must test for this */
80 1.46 dholland if (path == NULL) {
81 1.46 dholland errno = EINVAL;
82 1.46 dholland return NULL;
83 1.46 dholland }
84 1.46 dholland
85 1.50.10.1 bouyer if (resolved == NULL) {
86 1.50.10.1 bouyer fres = resolved = malloc(MAXPATHLEN);
87 1.50.10.1 bouyer if (resolved == NULL)
88 1.50.10.1 bouyer return NULL;
89 1.50.10.1 bouyer } else
90 1.50.10.1 bouyer fres = NULL;
91 1.50.10.1 bouyer
92 1.50.10.1 bouyer
93 1.36 enami /*
94 1.36 enami * Build real path one by one with paying an attention to .,
95 1.36 enami * .. and symbolic link.
96 1.36 enami */
97 1.36 enami
98 1.36 enami /*
99 1.36 enami * `p' is where we'll put a new component with prepending
100 1.36 enami * a delimiter.
101 1.36 enami */
102 1.36 enami p = resolved;
103 1.36 enami
104 1.50.10.1 bouyer if (*path == '\0') {
105 1.50.10.1 bouyer *p = '\0';
106 1.36 enami errno = ENOENT;
107 1.50.10.1 bouyer goto out;
108 1.8 perry }
109 1.8 perry
110 1.36 enami /* If relative path, start from current working directory. */
111 1.36 enami if (*path != '/') {
112 1.43 christos /* check for resolved pointer to appease coverity */
113 1.43 christos if (resolved && getcwd(resolved, MAXPATHLEN) == NULL) {
114 1.36 enami p[0] = '.';
115 1.50.10.1 bouyer p[1] = '\0';
116 1.50.10.1 bouyer goto out;
117 1.36 enami }
118 1.36 enami len = strlen(resolved);
119 1.36 enami if (len > 1)
120 1.36 enami p += len;
121 1.31 itojun }
122 1.36 enami
123 1.8 perry loop:
124 1.36 enami /* Skip any slash. */
125 1.36 enami while (*path == '/')
126 1.36 enami path++;
127 1.36 enami
128 1.50.10.1 bouyer if (*path == '\0') {
129 1.36 enami if (p == resolved)
130 1.36 enami *p++ = '/';
131 1.50.10.1 bouyer *p = '\0';
132 1.50.10.1 bouyer return resolved;
133 1.36 enami }
134 1.36 enami
135 1.36 enami /* Find the end of this component. */
136 1.36 enami q = path;
137 1.36 enami do
138 1.36 enami q++;
139 1.50.10.1 bouyer while (*q != '/' && *q != '\0');
140 1.36 enami
141 1.36 enami /* Test . or .. */
142 1.36 enami if (path[0] == '.') {
143 1.36 enami if (q - path == 1) {
144 1.36 enami path = q;
145 1.8 perry goto loop;
146 1.8 perry }
147 1.36 enami if (path[1] == '.' && q - path == 2) {
148 1.36 enami /* Trim the last component. */
149 1.36 enami if (p != resolved)
150 1.36 enami while (*--p != '/')
151 1.50.10.1 bouyer continue;
152 1.36 enami path = q;
153 1.36 enami goto loop;
154 1.8 perry }
155 1.8 perry }
156 1.8 perry
157 1.36 enami /* Append this component. */
158 1.36 enami if (p - resolved + 1 + q - path + 1 > MAXPATHLEN) {
159 1.31 itojun errno = ENAMETOOLONG;
160 1.36 enami if (p == resolved)
161 1.36 enami *p++ = '/';
162 1.50.10.1 bouyer *p = '\0';
163 1.50.10.1 bouyer goto out;
164 1.31 itojun }
165 1.36 enami p[0] = '/';
166 1.36 enami memcpy(&p[1], path,
167 1.36 enami /* LINTED We know q > path. */
168 1.36 enami q - path);
169 1.50.10.1 bouyer p[1 + q - path] = '\0';
170 1.8 perry
171 1.8 perry /*
172 1.36 enami * If this component is a symlink, toss it and prepend link
173 1.36 enami * target to unresolved path.
174 1.36 enami */
175 1.50.10.1 bouyer if (lstat(resolved, &sb) == -1)
176 1.50.10.1 bouyer goto out;
177 1.50.10.1 bouyer
178 1.36 enami if (S_ISLNK(sb.st_mode)) {
179 1.36 enami if (nlnk++ >= MAXSYMLINKS) {
180 1.36 enami errno = ELOOP;
181 1.50.10.1 bouyer goto out;
182 1.36 enami }
183 1.36 enami n = readlink(resolved, wbuf[idx], sizeof(wbuf[0]) - 1);
184 1.36 enami if (n < 0)
185 1.36 enami return (NULL);
186 1.36 enami if (n == 0) {
187 1.36 enami errno = ENOENT;
188 1.50.10.1 bouyer goto out;
189 1.36 enami }
190 1.8 perry
191 1.36 enami /* Append unresolved path to link target and switch to it. */
192 1.36 enami if (n + (len = strlen(q)) + 1 > sizeof(wbuf[0])) {
193 1.8 perry errno = ENAMETOOLONG;
194 1.50.10.1 bouyer goto out;
195 1.31 itojun }
196 1.36 enami memcpy(&wbuf[idx][n], q, len + 1);
197 1.36 enami path = wbuf[idx];
198 1.36 enami idx ^= 1;
199 1.36 enami
200 1.36 enami /* If absolute symlink, start from root. */
201 1.36 enami if (*path == '/')
202 1.36 enami p = resolved;
203 1.36 enami goto loop;
204 1.8 perry }
205 1.38 enami if (*q == '/' && !S_ISDIR(sb.st_mode)) {
206 1.38 enami errno = ENOTDIR;
207 1.50.10.1 bouyer goto out;
208 1.38 enami }
209 1.8 perry
210 1.36 enami /* Advance both resolved and unresolved path. */
211 1.36 enami p += 1 + q - path;
212 1.36 enami path = q;
213 1.36 enami goto loop;
214 1.50.10.1 bouyer out:
215 1.50.10.1 bouyer free(fres);
216 1.50.10.1 bouyer return NULL;
217 1.8 perry }
218 1.8 perry
219 1.16 sommerfe char *
220 1.50 joerg __ssp_real(getcwd)(char *pt, size_t size)
221 1.16 sommerfe {
222 1.35 enami char *npt;
223 1.35 enami
224 1.16 sommerfe /*
225 1.35 enami * If a buffer is specified, the size has to be non-zero.
226 1.16 sommerfe */
227 1.35 enami if (pt != NULL) {
228 1.35 enami if (size == 0) {
229 1.35 enami /* __getcwd(pt, 0) results ERANGE. */
230 1.16 sommerfe errno = EINVAL;
231 1.16 sommerfe return (NULL);
232 1.16 sommerfe }
233 1.35 enami if (__getcwd(pt, size) >= 0)
234 1.35 enami return (pt);
235 1.35 enami return (NULL);
236 1.16 sommerfe }
237 1.35 enami
238 1.35 enami /*
239 1.35 enami * If no buffer specified by the user, allocate one as necessary.
240 1.35 enami */
241 1.35 enami size = 1024 >> 1;
242 1.35 enami do {
243 1.35 enami if ((npt = realloc(pt, size <<= 1)) == NULL)
244 1.35 enami break;
245 1.35 enami pt = npt;
246 1.35 enami if (__getcwd(pt, size) >= 0)
247 1.35 enami return (pt);
248 1.35 enami } while (size <= MAXPATHLEN * 4 && errno == ERANGE);
249 1.35 enami
250 1.35 enami free(pt);
251 1.35 enami return (NULL);
252 1.16 sommerfe }
253