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