Annotation of src/lib/libc/gen/getcwd.c, Revision 1.34
1.34 ! simonb 1: /* $NetBSD: getcwd.c,v 1.33 2005/01/06 00:07:41 christos 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.34 ! simonb 40: __RCSID("$NetBSD: getcwd.c,v 1.33 2005/01/06 00:07:41 christos 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: char *
208: getcwd(pt, size)
209: char *pt;
210: size_t size;
211: {
1.18 christos 212: size_t ptsize, bufsize;
213: int len;
1.16 sommerfe 214:
215: /*
216: * If no buffer specified by the user, allocate one as necessary.
217: * If a buffer is specified, the size has to be non-zero. The path
218: * is built from the end of the buffer backwards.
219: */
220: if (pt) {
221: ptsize = 0;
222: if (!size) {
223: errno = EINVAL;
224: return (NULL);
225: }
226: bufsize = size;
227: } else {
228: if ((pt = malloc(ptsize = 1024 - 4)) == NULL)
229: return (NULL);
230: bufsize = ptsize;
231: }
1.18 christos 232: for (;;) {
1.16 sommerfe 233: len = __getcwd(pt, bufsize);
234: if ((len < 0) && (size == 0) && (errno == ERANGE)) {
1.20 sommerfe 235: if (ptsize > (MAXPATHLEN*4))
236: return NULL;
1.16 sommerfe 237: if ((pt = realloc(pt, ptsize *= 2)) == NULL)
238: return NULL;
239: bufsize = ptsize;
240: continue;
241: }
1.18 christos 242: break;
243: }
1.16 sommerfe 244: if (len < 0)
245: return NULL;
246: else
247: return pt;
248: }
CVSweb <webmaster@jp.NetBSD.org>