Annotation of src/lib/libc/gen/getcwd.c, Revision 1.33
1.33 ! christos 1: /* $NetBSD: getcwd.c,v 1.32 2003/08/07 16:42:49 agc Exp $ */
1.4 cgd 2:
1.1 cgd 3: /*
1.8 perry 4: * Copyright (c) 1989, 1991, 1993, 1995
1.4 cgd 5: * The Regents of the University of California. All rights reserved.
1.1 cgd 6: *
1.8 perry 7: * This code is derived from software contributed to Berkeley by
8: * Jan-Simon Pendry.
9: *
1.1 cgd 10: * Redistribution and use in source and binary forms, with or without
11: * modification, are permitted provided that the following conditions
12: * are met:
13: * 1. Redistributions of source code must retain the above copyright
14: * notice, this list of conditions and the following disclaimer.
15: * 2. Redistributions in binary form must reproduce the above copyright
16: * notice, this list of conditions and the following disclaimer in the
17: * documentation and/or other materials provided with the distribution.
1.32 agc 18: * 3. Neither the name of the University nor the names of its contributors
1.1 cgd 19: * may be used to endorse or promote products derived from this software
20: * without specific prior written permission.
21: *
22: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32: * SUCH DAMAGE.
33: */
34:
1.6 christos 35: #include <sys/cdefs.h>
1.1 cgd 36: #if defined(LIBC_SCCS) && !defined(lint)
1.4 cgd 37: #if 0
1.8 perry 38: static char sccsid[] = "@(#)getcwd.c 8.5 (Berkeley) 2/7/95";
1.4 cgd 39: #else
1.33 ! christos 40: __RCSID("$NetBSD: getcwd.c,v 1.32 2003/08/07 16:42:49 agc Exp $");
1.4 cgd 41: #endif
1.1 cgd 42: #endif /* LIBC_SCCS and not lint */
43:
1.7 jtc 44: #include "namespace.h"
1.1 cgd 45: #include <sys/param.h>
46: #include <sys/stat.h>
1.8 perry 47:
1.22 lukem 48: #include <assert.h>
1.8 perry 49: #include <dirent.h>
1.1 cgd 50: #include <errno.h>
1.8 perry 51: #include <fcntl.h>
1.1 cgd 52: #include <stdio.h>
53: #include <stdlib.h>
54: #include <string.h>
55: #include <unistd.h>
1.17 sommerfe 56:
57: #include "extern.h"
1.7 jtc 58:
59: #ifdef __weak_alias
1.24 mycroft 60: __weak_alias(getcwd,_getcwd)
61: __weak_alias(realpath,_realpath)
1.7 jtc 62: #endif
1.1 cgd 63:
64: #define ISDOT(dp) \
65: (dp->d_name[0] == '.' && (dp->d_name[1] == '\0' || \
1.6 christos 66: (dp->d_name[1] == '.' && dp->d_name[2] == '\0')))
1.1 cgd 67:
1.8 perry 68:
1.15 christos 69: #if defined(__SVR4) || defined(__svr4__)
70: #define d_fileno d_ino
71: #endif
72:
1.8 perry 73: /*
74: * char *realpath(const char *path, char resolved_path[MAXPATHLEN]);
75: *
76: * Find the real name of path, by removing all ".", ".." and symlink
77: * components. Returns (resolved) on success, or (NULL) on failure,
78: * in which case the path which caused trouble is left in (resolved).
79: */
80: char *
81: realpath(path, resolved)
82: const char *path;
83: char *resolved;
84: {
85: struct stat sb;
1.21 fvdl 86: int fd, n, rootd, serrno, nlnk = 0;
1.8 perry 87: char *p, *q, wbuf[MAXPATHLEN];
1.22 lukem 88:
89: _DIAGASSERT(path != NULL);
90: _DIAGASSERT(resolved != NULL);
1.8 perry 91:
92: /* Save the starting point. */
93: if ((fd = open(".", O_RDONLY)) < 0) {
1.28 itojun 94: (void)strlcpy(resolved, ".", MAXPATHLEN);
1.8 perry 95: return (NULL);
96: }
97:
98: /*
99: * Find the dirname and basename from the path to be resolved.
100: * Change directory to the dirname component.
101: * lstat the basename part.
102: * if it is a symlink, read in the value and loop.
103: * if it is a directory, then change to that directory.
104: * get the current directory name and append the basename.
105: */
1.31 itojun 106: if (strlcpy(resolved, path, MAXPATHLEN) >= MAXPATHLEN) {
107: errno = ENAMETOOLONG;
108: goto err1;
109: }
1.8 perry 110: loop:
111: q = strrchr(resolved, '/');
112: if (q != NULL) {
113: p = q + 1;
114: if (q == resolved)
115: q = "/";
116: else {
117: do {
118: --q;
119: } while (q > resolved && *q == '/');
120: q[1] = '\0';
121: q = resolved;
122: }
123: if (chdir(q) < 0)
124: goto err1;
125: } else
126: p = resolved;
127:
128: /* Deal with the last component. */
129: if (lstat(p, &sb) == 0) {
130: if (S_ISLNK(sb.st_mode)) {
1.21 fvdl 131: if (nlnk++ >= MAXSYMLINKS) {
132: errno = ELOOP;
133: goto err1;
134: }
1.26 provos 135: n = readlink(p, resolved, MAXPATHLEN-1);
1.8 perry 136: if (n < 0)
137: goto err1;
138: resolved[n] = '\0';
139: goto loop;
140: }
141: if (S_ISDIR(sb.st_mode)) {
142: if (chdir(p) < 0)
143: goto err1;
144: p = "";
145: }
146: }
147:
148: /*
149: * Save the last component name and get the full pathname of
150: * the current directory.
151: */
1.31 itojun 152: if (strlcpy(wbuf, p, sizeof(wbuf)) >= sizeof(wbuf)) {
153: errno = ENAMETOOLONG;
154: goto err1;
155: }
1.8 perry 156:
157: /*
158: * Call the inernal internal version of getcwd which
159: * does a physical search rather than using the $PWD short-cut
160: */
1.12 lukem 161: if (getcwd(resolved, MAXPATHLEN) == 0)
1.8 perry 162: goto err1;
163:
164: /*
165: * Join the two strings together, ensuring that the right thing
166: * happens if the last component is empty, or the dirname is root.
167: */
168: if (resolved[0] == '/' && resolved[1] == '\0')
169: rootd = 1;
170: else
171: rootd = 0;
172:
173: if (*wbuf) {
1.29 itojun 174: if (strlen(resolved) + strlen(wbuf) + (rootd ? 0 : 1) + 1 >
175: MAXPATHLEN) {
1.8 perry 176: errno = ENAMETOOLONG;
177: goto err1;
178: }
179: if (rootd == 0)
1.31 itojun 180: if (strlcat(resolved, "/", MAXPATHLEN) >= MAXPATHLEN) {
181: errno = ENAMETOOLONG;
182: goto err1;
183: }
184: if (strlcat(resolved, wbuf, MAXPATHLEN) >= MAXPATHLEN) {
185: errno = ENAMETOOLONG;
186: goto err1;
187: }
1.8 perry 188: }
189:
190: /* Go back to where we came from. */
191: if (fchdir(fd) < 0) {
192: serrno = errno;
193: goto err2;
194: }
195:
196: /* It's okay if the close fails, what's an fd more or less? */
197: (void)close(fd);
198: return (resolved);
199:
200: err1: serrno = errno;
201: (void)fchdir(fd);
202: err2: (void)close(fd);
203: errno = serrno;
204: return (NULL);
205: }
206:
1.16 sommerfe 207: #ifdef OLD_GETCWD
208:
1.12 lukem 209: char *
210: getcwd(pt, size)
1.8 perry 211: char *pt;
212: size_t size;
213: {
1.10 perry 214: struct dirent *dp;
215: DIR *dir;
216: dev_t dev;
217: ino_t ino;
218: int first;
219: char *bpt, *bup;
1.1 cgd 220: struct stat s;
221: dev_t root_dev;
222: ino_t root_ino;
223: size_t ptsize, upsize;
224: int save_errno;
1.33 ! christos 225: char *ept, *eup, *up, *nup;
1.15 christos 226: size_t dlen;
1.1 cgd 227:
228: /*
229: * If no buffer specified by the user, allocate one as necessary.
230: * If a buffer is specified, the size has to be non-zero. The path
231: * is built from the end of the buffer backwards.
232: */
233: if (pt) {
234: ptsize = 0;
235: if (!size) {
236: errno = EINVAL;
1.4 cgd 237: return (NULL);
1.1 cgd 238: }
239: ept = pt + size;
240: } else {
1.4 cgd 241: if ((pt = malloc(ptsize = 1024 - 4)) == NULL)
242: return (NULL);
1.1 cgd 243: ept = pt + ptsize;
244: }
245: bpt = ept - 1;
246: *bpt = '\0';
247:
248: /*
1.33 ! christos 249: * Allocate bytes for the string of "../"'s.
1.1 cgd 250: * Should always be enough (it's 340 levels). If it's not, allocate
1.8 perry 251: * as necessary. Special case the first stat, it's ".", not "..".
1.1 cgd 252: */
1.33 ! christos 253: if ((up = malloc(upsize = MAXPATHLEN)) == NULL)
1.1 cgd 254: goto err;
1.33 ! christos 255: eup = up + upsize;
1.1 cgd 256: bup = up;
257: up[0] = '.';
258: up[1] = '\0';
259:
260: /* Save root values, so know when to stop. */
261: if (stat("/", &s))
262: goto err;
263: root_dev = s.st_dev;
264: root_ino = s.st_ino;
265:
266: errno = 0; /* XXX readdir has no error return. */
267:
268: for (first = 1;; first = 0) {
269: /* Stat the current level. */
270: if (lstat(up, &s))
271: goto err;
272:
273: /* Save current node values. */
274: ino = s.st_ino;
275: dev = s.st_dev;
276:
277: /* Check for reaching root. */
278: if (root_dev == dev && root_ino == ino) {
279: *--bpt = '/';
280: /*
281: * It's unclear that it's a requirement to copy the
282: * path to the beginning of the buffer, but it's always
283: * been that way and stuff would probably break.
284: */
1.14 perry 285: memmove(pt, bpt, (size_t)(ept - bpt));
1.1 cgd 286: free(up);
1.4 cgd 287: return (pt);
1.1 cgd 288: }
289:
290: /*
291: * Build pointer to the parent directory, allocating memory
292: * as necessary. Max length is 3 for "../", the largest
293: * possible component name, plus a trailing NULL.
294: */
1.33 ! christos 295: if (bup + 3 + MAXNAMLEN + 1 >= eup) {
! 296: if ((nup = realloc(up, upsize *= 2)) == NULL)
1.1 cgd 297: goto err;
1.33 ! christos 298: bup = nup + (buf - up);
! 299: up = nup;
1.1 cgd 300: eup = up + upsize;
301: }
302: *bup++ = '.';
303: *bup++ = '.';
304: *bup = '\0';
305:
306: /* Open and stat parent directory. */
307: if (!(dir = opendir(up)) || fstat(dirfd(dir), &s))
308: goto err;
309:
310: /* Add trailing slash for next directory. */
311: *bup++ = '/';
312:
313: /*
314: * If it's a mount point, have to stat each element because
315: * the inode number in the directory is for the entry in the
316: * parent directory, not the inode number of the mounted file.
317: */
318: save_errno = 0;
319: if (s.st_dev == dev) {
320: for (;;) {
321: if (!(dp = readdir(dir)))
322: goto notfound;
1.15 christos 323: if (dp->d_fileno == ino) {
1.19 christos 324: #if defined(__SVR4) || defined(__svr4__) || defined(__linux__)
1.15 christos 325: dlen = strlen(dp->d_name);
326: #else
327: dlen = dp->d_namlen;
328: #endif
1.1 cgd 329: break;
1.15 christos 330: }
1.1 cgd 331: }
332: } else
333: for (;;) {
334: if (!(dp = readdir(dir)))
335: goto notfound;
336: if (ISDOT(dp))
337: continue;
1.19 christos 338: #if defined(__SVR4) || defined(__svr4__) || defined(__linux__)
1.15 christos 339: dlen = strlen(dp->d_name);
340: #else
341: dlen = dp->d_namlen;
342: #endif
343: memmove(bup, dp->d_name, dlen + 1);
1.1 cgd 344:
345: /* Save the first error for later. */
346: if (lstat(up, &s)) {
347: if (!save_errno)
348: save_errno = errno;
349: errno = 0;
350: continue;
351: }
352: if (s.st_dev == dev && s.st_ino == ino)
353: break;
354: }
355:
356: /*
357: * Check for length of the current name, preceding slash,
358: * leading slash.
359: */
1.15 christos 360: if (bpt - pt <= dlen + (first ? 1 : 2)) {
1.1 cgd 361: size_t len, off;
362:
363: if (!ptsize) {
364: errno = ERANGE;
365: goto err;
366: }
367: off = bpt - pt;
368: len = ept - bpt;
1.4 cgd 369: if ((pt = realloc(pt, ptsize *= 2)) == NULL)
1.1 cgd 370: goto err;
371: bpt = pt + off;
372: ept = pt + ptsize;
1.14 perry 373: memmove(ept - len, bpt, len);
1.1 cgd 374: bpt = ept - len;
375: }
376: if (!first)
377: *--bpt = '/';
1.15 christos 378: bpt -= dlen;
379: memmove(bpt, dp->d_name, dlen);
1.1 cgd 380: (void)closedir(dir);
381:
382: /* Truncate any file name. */
383: *bup = '\0';
384: }
385:
386: notfound:
387: /*
388: * If readdir set errno, use it, not any saved error; otherwise,
389: * didn't find the current directory in its parent directory, set
390: * errno to ENOENT.
391: */
392: if (!errno)
393: errno = save_errno ? save_errno : ENOENT;
394: /* FALLTHROUGH */
395: err:
396: if (ptsize)
397: free(pt);
398: free(up);
1.4 cgd 399: return (NULL);
1.1 cgd 400: }
1.16 sommerfe 401:
402: #else /* New getcwd */
403:
404: char *
405: getcwd(pt, size)
406: char *pt;
407: size_t size;
408: {
1.18 christos 409: size_t ptsize, bufsize;
410: int len;
1.16 sommerfe 411:
412: /*
413: * If no buffer specified by the user, allocate one as necessary.
414: * If a buffer is specified, the size has to be non-zero. The path
415: * is built from the end of the buffer backwards.
416: */
417: if (pt) {
418: ptsize = 0;
419: if (!size) {
420: errno = EINVAL;
421: return (NULL);
422: }
423: bufsize = size;
424: } else {
425: if ((pt = malloc(ptsize = 1024 - 4)) == NULL)
426: return (NULL);
427: bufsize = ptsize;
428: }
1.18 christos 429: for (;;) {
1.16 sommerfe 430: len = __getcwd(pt, bufsize);
431: if ((len < 0) && (size == 0) && (errno == ERANGE)) {
1.20 sommerfe 432: if (ptsize > (MAXPATHLEN*4))
433: return NULL;
1.16 sommerfe 434: if ((pt = realloc(pt, ptsize *= 2)) == NULL)
435: return NULL;
436: bufsize = ptsize;
437: continue;
438: }
1.18 christos 439: break;
440: }
1.16 sommerfe 441: if (len < 0)
442: return NULL;
443: else
444: return pt;
445: }
446:
447: #endif
CVSweb <webmaster@jp.NetBSD.org>