getcwd.c revision 1.34 1 1.34 simonb /* $NetBSD: getcwd.c,v 1.34 2005/01/06 23:43:32 simonb 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.34 simonb __RCSID("$NetBSD: getcwd.c,v 1.34 2005/01/06 23:43:32 simonb 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.8 perry #include <dirent.h>
50 1.1 cgd #include <errno.h>
51 1.8 perry #include <fcntl.h>
52 1.1 cgd #include <stdio.h>
53 1.1 cgd #include <stdlib.h>
54 1.1 cgd #include <string.h>
55 1.1 cgd #include <unistd.h>
56 1.17 sommerfe
57 1.17 sommerfe #include "extern.h"
58 1.7 jtc
59 1.7 jtc #ifdef __weak_alias
60 1.24 mycroft __weak_alias(getcwd,_getcwd)
61 1.24 mycroft __weak_alias(realpath,_realpath)
62 1.7 jtc #endif
63 1.1 cgd
64 1.1 cgd #define ISDOT(dp) \
65 1.1 cgd (dp->d_name[0] == '.' && (dp->d_name[1] == '\0' || \
66 1.6 christos (dp->d_name[1] == '.' && dp->d_name[2] == '\0')))
67 1.1 cgd
68 1.8 perry
69 1.15 christos #if defined(__SVR4) || defined(__svr4__)
70 1.15 christos #define d_fileno d_ino
71 1.15 christos #endif
72 1.15 christos
73 1.8 perry /*
74 1.8 perry * char *realpath(const char *path, char resolved_path[MAXPATHLEN]);
75 1.8 perry *
76 1.8 perry * Find the real name of path, by removing all ".", ".." and symlink
77 1.8 perry * components. Returns (resolved) on success, or (NULL) on failure,
78 1.8 perry * in which case the path which caused trouble is left in (resolved).
79 1.8 perry */
80 1.8 perry char *
81 1.8 perry realpath(path, resolved)
82 1.8 perry const char *path;
83 1.8 perry char *resolved;
84 1.8 perry {
85 1.8 perry struct stat sb;
86 1.21 fvdl int fd, n, rootd, serrno, nlnk = 0;
87 1.8 perry char *p, *q, wbuf[MAXPATHLEN];
88 1.22 lukem
89 1.22 lukem _DIAGASSERT(path != NULL);
90 1.22 lukem _DIAGASSERT(resolved != NULL);
91 1.8 perry
92 1.8 perry /* Save the starting point. */
93 1.8 perry if ((fd = open(".", O_RDONLY)) < 0) {
94 1.28 itojun (void)strlcpy(resolved, ".", MAXPATHLEN);
95 1.8 perry return (NULL);
96 1.8 perry }
97 1.8 perry
98 1.8 perry /*
99 1.8 perry * Find the dirname and basename from the path to be resolved.
100 1.8 perry * Change directory to the dirname component.
101 1.8 perry * lstat the basename part.
102 1.8 perry * if it is a symlink, read in the value and loop.
103 1.8 perry * if it is a directory, then change to that directory.
104 1.8 perry * get the current directory name and append the basename.
105 1.8 perry */
106 1.31 itojun if (strlcpy(resolved, path, MAXPATHLEN) >= MAXPATHLEN) {
107 1.31 itojun errno = ENAMETOOLONG;
108 1.31 itojun goto err1;
109 1.31 itojun }
110 1.8 perry loop:
111 1.8 perry q = strrchr(resolved, '/');
112 1.8 perry if (q != NULL) {
113 1.8 perry p = q + 1;
114 1.8 perry if (q == resolved)
115 1.8 perry q = "/";
116 1.8 perry else {
117 1.8 perry do {
118 1.8 perry --q;
119 1.8 perry } while (q > resolved && *q == '/');
120 1.8 perry q[1] = '\0';
121 1.8 perry q = resolved;
122 1.8 perry }
123 1.8 perry if (chdir(q) < 0)
124 1.8 perry goto err1;
125 1.8 perry } else
126 1.8 perry p = resolved;
127 1.8 perry
128 1.8 perry /* Deal with the last component. */
129 1.8 perry if (lstat(p, &sb) == 0) {
130 1.8 perry if (S_ISLNK(sb.st_mode)) {
131 1.21 fvdl if (nlnk++ >= MAXSYMLINKS) {
132 1.21 fvdl errno = ELOOP;
133 1.21 fvdl goto err1;
134 1.21 fvdl }
135 1.26 provos n = readlink(p, resolved, MAXPATHLEN-1);
136 1.8 perry if (n < 0)
137 1.8 perry goto err1;
138 1.8 perry resolved[n] = '\0';
139 1.8 perry goto loop;
140 1.8 perry }
141 1.8 perry if (S_ISDIR(sb.st_mode)) {
142 1.8 perry if (chdir(p) < 0)
143 1.8 perry goto err1;
144 1.8 perry p = "";
145 1.8 perry }
146 1.8 perry }
147 1.8 perry
148 1.8 perry /*
149 1.8 perry * Save the last component name and get the full pathname of
150 1.8 perry * the current directory.
151 1.8 perry */
152 1.31 itojun if (strlcpy(wbuf, p, sizeof(wbuf)) >= sizeof(wbuf)) {
153 1.31 itojun errno = ENAMETOOLONG;
154 1.31 itojun goto err1;
155 1.31 itojun }
156 1.8 perry
157 1.8 perry /*
158 1.8 perry * Call the inernal internal version of getcwd which
159 1.8 perry * does a physical search rather than using the $PWD short-cut
160 1.8 perry */
161 1.12 lukem if (getcwd(resolved, MAXPATHLEN) == 0)
162 1.8 perry goto err1;
163 1.8 perry
164 1.8 perry /*
165 1.8 perry * Join the two strings together, ensuring that the right thing
166 1.8 perry * happens if the last component is empty, or the dirname is root.
167 1.8 perry */
168 1.8 perry if (resolved[0] == '/' && resolved[1] == '\0')
169 1.8 perry rootd = 1;
170 1.8 perry else
171 1.8 perry rootd = 0;
172 1.8 perry
173 1.8 perry if (*wbuf) {
174 1.29 itojun if (strlen(resolved) + strlen(wbuf) + (rootd ? 0 : 1) + 1 >
175 1.29 itojun MAXPATHLEN) {
176 1.8 perry errno = ENAMETOOLONG;
177 1.8 perry goto err1;
178 1.8 perry }
179 1.8 perry if (rootd == 0)
180 1.31 itojun if (strlcat(resolved, "/", MAXPATHLEN) >= MAXPATHLEN) {
181 1.31 itojun errno = ENAMETOOLONG;
182 1.31 itojun goto err1;
183 1.31 itojun }
184 1.31 itojun if (strlcat(resolved, wbuf, MAXPATHLEN) >= MAXPATHLEN) {
185 1.31 itojun errno = ENAMETOOLONG;
186 1.31 itojun goto err1;
187 1.31 itojun }
188 1.8 perry }
189 1.8 perry
190 1.8 perry /* Go back to where we came from. */
191 1.8 perry if (fchdir(fd) < 0) {
192 1.8 perry serrno = errno;
193 1.8 perry goto err2;
194 1.8 perry }
195 1.8 perry
196 1.8 perry /* It's okay if the close fails, what's an fd more or less? */
197 1.8 perry (void)close(fd);
198 1.8 perry return (resolved);
199 1.8 perry
200 1.8 perry err1: serrno = errno;
201 1.8 perry (void)fchdir(fd);
202 1.8 perry err2: (void)close(fd);
203 1.8 perry errno = serrno;
204 1.8 perry return (NULL);
205 1.8 perry }
206 1.8 perry
207 1.16 sommerfe char *
208 1.16 sommerfe getcwd(pt, size)
209 1.16 sommerfe char *pt;
210 1.16 sommerfe size_t size;
211 1.16 sommerfe {
212 1.18 christos size_t ptsize, bufsize;
213 1.18 christos int len;
214 1.16 sommerfe
215 1.16 sommerfe /*
216 1.16 sommerfe * If no buffer specified by the user, allocate one as necessary.
217 1.16 sommerfe * If a buffer is specified, the size has to be non-zero. The path
218 1.16 sommerfe * is built from the end of the buffer backwards.
219 1.16 sommerfe */
220 1.16 sommerfe if (pt) {
221 1.16 sommerfe ptsize = 0;
222 1.16 sommerfe if (!size) {
223 1.16 sommerfe errno = EINVAL;
224 1.16 sommerfe return (NULL);
225 1.16 sommerfe }
226 1.16 sommerfe bufsize = size;
227 1.16 sommerfe } else {
228 1.16 sommerfe if ((pt = malloc(ptsize = 1024 - 4)) == NULL)
229 1.16 sommerfe return (NULL);
230 1.16 sommerfe bufsize = ptsize;
231 1.16 sommerfe }
232 1.18 christos for (;;) {
233 1.16 sommerfe len = __getcwd(pt, bufsize);
234 1.16 sommerfe if ((len < 0) && (size == 0) && (errno == ERANGE)) {
235 1.20 sommerfe if (ptsize > (MAXPATHLEN*4))
236 1.20 sommerfe return NULL;
237 1.16 sommerfe if ((pt = realloc(pt, ptsize *= 2)) == NULL)
238 1.16 sommerfe return NULL;
239 1.16 sommerfe bufsize = ptsize;
240 1.16 sommerfe continue;
241 1.16 sommerfe }
242 1.18 christos break;
243 1.18 christos }
244 1.16 sommerfe if (len < 0)
245 1.16 sommerfe return NULL;
246 1.16 sommerfe else
247 1.16 sommerfe return pt;
248 1.16 sommerfe }
249