Annotation of src/lib/libc/gen/getcwd.c, Revision 1.35
1.35 ! enami 1: /* $NetBSD: getcwd.c,v 1.34 2005/01/06 23:43:32 simonb 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.35 ! enami 40: __RCSID("$NetBSD: getcwd.c,v 1.34 2005/01/06 23:43:32 simonb 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:
1.8 perry 64: /*
65: * char *realpath(const char *path, char resolved_path[MAXPATHLEN]);
66: *
67: * Find the real name of path, by removing all ".", ".." and symlink
68: * components. Returns (resolved) on success, or (NULL) on failure,
69: * in which case the path which caused trouble is left in (resolved).
70: */
71: char *
72: realpath(path, resolved)
73: const char *path;
74: char *resolved;
75: {
76: struct stat sb;
1.21 fvdl 77: int fd, n, rootd, serrno, nlnk = 0;
1.8 perry 78: char *p, *q, wbuf[MAXPATHLEN];
1.22 lukem 79:
80: _DIAGASSERT(path != NULL);
81: _DIAGASSERT(resolved != NULL);
1.8 perry 82:
83: /* Save the starting point. */
84: if ((fd = open(".", O_RDONLY)) < 0) {
1.28 itojun 85: (void)strlcpy(resolved, ".", MAXPATHLEN);
1.8 perry 86: return (NULL);
87: }
88:
89: /*
90: * Find the dirname and basename from the path to be resolved.
91: * Change directory to the dirname component.
92: * lstat the basename part.
93: * if it is a symlink, read in the value and loop.
94: * if it is a directory, then change to that directory.
95: * get the current directory name and append the basename.
96: */
1.31 itojun 97: if (strlcpy(resolved, path, MAXPATHLEN) >= MAXPATHLEN) {
98: errno = ENAMETOOLONG;
99: goto err1;
100: }
1.8 perry 101: loop:
102: q = strrchr(resolved, '/');
103: if (q != NULL) {
104: p = q + 1;
105: if (q == resolved)
106: q = "/";
107: else {
108: do {
109: --q;
110: } while (q > resolved && *q == '/');
111: q[1] = '\0';
112: q = resolved;
113: }
114: if (chdir(q) < 0)
115: goto err1;
116: } else
117: p = resolved;
118:
119: /* Deal with the last component. */
120: if (lstat(p, &sb) == 0) {
121: if (S_ISLNK(sb.st_mode)) {
1.21 fvdl 122: if (nlnk++ >= MAXSYMLINKS) {
123: errno = ELOOP;
124: goto err1;
125: }
1.26 provos 126: n = readlink(p, resolved, MAXPATHLEN-1);
1.8 perry 127: if (n < 0)
128: goto err1;
129: resolved[n] = '\0';
130: goto loop;
131: }
132: if (S_ISDIR(sb.st_mode)) {
133: if (chdir(p) < 0)
134: goto err1;
135: p = "";
136: }
137: }
138:
139: /*
140: * Save the last component name and get the full pathname of
141: * the current directory.
142: */
1.31 itojun 143: if (strlcpy(wbuf, p, sizeof(wbuf)) >= sizeof(wbuf)) {
144: errno = ENAMETOOLONG;
145: goto err1;
146: }
1.8 perry 147:
148: /*
149: * Call the inernal internal version of getcwd which
150: * does a physical search rather than using the $PWD short-cut
151: */
1.12 lukem 152: if (getcwd(resolved, MAXPATHLEN) == 0)
1.8 perry 153: goto err1;
154:
155: /*
156: * Join the two strings together, ensuring that the right thing
157: * happens if the last component is empty, or the dirname is root.
158: */
159: if (resolved[0] == '/' && resolved[1] == '\0')
160: rootd = 1;
161: else
162: rootd = 0;
163:
164: if (*wbuf) {
1.29 itojun 165: if (strlen(resolved) + strlen(wbuf) + (rootd ? 0 : 1) + 1 >
166: MAXPATHLEN) {
1.8 perry 167: errno = ENAMETOOLONG;
168: goto err1;
169: }
170: if (rootd == 0)
1.31 itojun 171: if (strlcat(resolved, "/", MAXPATHLEN) >= MAXPATHLEN) {
172: errno = ENAMETOOLONG;
173: goto err1;
174: }
175: if (strlcat(resolved, wbuf, MAXPATHLEN) >= MAXPATHLEN) {
176: errno = ENAMETOOLONG;
177: goto err1;
178: }
1.8 perry 179: }
180:
181: /* Go back to where we came from. */
182: if (fchdir(fd) < 0) {
183: serrno = errno;
184: goto err2;
185: }
186:
187: /* It's okay if the close fails, what's an fd more or less? */
188: (void)close(fd);
189: return (resolved);
190:
191: err1: serrno = errno;
192: (void)fchdir(fd);
193: err2: (void)close(fd);
194: errno = serrno;
195: return (NULL);
196: }
197:
1.16 sommerfe 198: char *
1.35 ! enami 199: getcwd(char *pt, size_t size)
1.16 sommerfe 200: {
1.35 ! enami 201: char *npt;
! 202:
1.16 sommerfe 203: /*
1.35 ! enami 204: * If a buffer is specified, the size has to be non-zero.
1.16 sommerfe 205: */
1.35 ! enami 206: if (pt != NULL) {
! 207: if (size == 0) {
! 208: /* __getcwd(pt, 0) results ERANGE. */
1.16 sommerfe 209: errno = EINVAL;
210: return (NULL);
211: }
1.35 ! enami 212: if (__getcwd(pt, size) >= 0)
! 213: return (pt);
! 214: return (NULL);
1.16 sommerfe 215: }
1.35 ! enami 216:
! 217: /*
! 218: * If no buffer specified by the user, allocate one as necessary.
! 219: */
! 220: size = 1024 >> 1;
! 221: do {
! 222: if ((npt = realloc(pt, size <<= 1)) == NULL)
! 223: break;
! 224: pt = npt;
! 225: if (__getcwd(pt, size) >= 0)
! 226: return (pt);
! 227: } while (size <= MAXPATHLEN * 4 && errno == ERANGE);
! 228:
! 229: free(pt);
! 230: return (NULL);
1.16 sommerfe 231: }
CVSweb <webmaster@jp.NetBSD.org>