realpath.c revision 56698
155714Skris/* 255714Skris * Copyright (c) 1994 355714Skris * The Regents of the University of California. All rights reserved. 455714Skris * 555714Skris * This code is derived from software contributed to Berkeley by 655714Skris * Jan-Simon Pendry. 755714Skris * 855714Skris * Redistribution and use in source and binary forms, with or without 955714Skris * modification, are permitted provided that the following conditions 1055714Skris * are met: 1155714Skris * 1. Redistributions of source code must retain the above copyright 1255714Skris * notice, this list of conditions and the following disclaimer. 1355714Skris * 2. Redistributions in binary form must reproduce the above copyright 1455714Skris * notice, this list of conditions and the following disclaimer in the 1555714Skris * documentation and/or other materials provided with the distribution. 1655714Skris * 3. All advertising materials mentioning features or use of this software 1755714Skris * must display the following acknowledgement: 1855714Skris * This product includes software developed by the University of 1955714Skris * California, Berkeley and its contributors. 2055714Skris * 4. Neither the name of the University nor the names of its contributors 2155714Skris * may be used to endorse or promote products derived from this software 2255714Skris * without specific prior written permission. 2355714Skris * 2455714Skris * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2555714Skris * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2655714Skris * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2755714Skris * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2855714Skris * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2955714Skris * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3055714Skris * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3155714Skris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3255714Skris * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3355714Skris * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3455714Skris * SUCH DAMAGE. 3555714Skris * 3655714Skris * $FreeBSD: head/lib/libc/stdlib/realpath.c 56698 2000-01-27 23:07:25Z jasone $ 3755714Skris */ 3855714Skris 3955714Skris#if defined(LIBC_SCCS) && !defined(lint) 4055714Skrisstatic char sccsid[] = "@(#)realpath.c 8.1 (Berkeley) 2/16/94"; 4155714Skris#endif /* LIBC_SCCS and not lint */ 4255714Skris 4355714Skris#include <sys/param.h> 4455714Skris#include <sys/stat.h> 4555714Skris 4655714Skris#include <errno.h> 4755714Skris#include <fcntl.h> 4855714Skris#include <stdlib.h> 4955714Skris#include <string.h> 5055714Skris#include <unistd.h> 5155714Skris 5255714Skris/* 5355714Skris * char *realpath(const char *path, char resolved_path[MAXPATHLEN]); 5455714Skris * 5555714Skris * Find the real name of path, by removing all ".", ".." and symlink 5655714Skris * components. Returns (resolved) on success, or (NULL) on failure, 5755714Skris * in which case the path which caused trouble is left in (resolved). 5855714Skris */ 5955714Skrischar * 6055714Skrisrealpath(path, resolved) 6155714Skris const char *path; 6255714Skris char *resolved; 6355714Skris{ 6455714Skris struct stat sb; 6555714Skris int fd, n, rootd, serrno; 6655714Skris char *p, *q, wbuf[MAXPATHLEN]; 6755714Skris int symlinks = 0; 6855714Skris 6955714Skris /* Save the starting point. */ 7055714Skris if ((fd = _open(".", O_RDONLY)) < 0) { 7155714Skris (void)strcpy(resolved, "."); 7255714Skris return (NULL); 7355714Skris } 7455714Skris 7555714Skris /* 7655714Skris * Find the dirname and basename from the path to be resolved. 7755714Skris * Change directory to the dirname component. 7855714Skris * lstat the basename part. 7955714Skris * if it is a symlink, read in the value and loop. 8055714Skris * if it is a directory, then change to that directory. 81 * get the current directory name and append the basename. 82 */ 83 (void)strncpy(resolved, path, MAXPATHLEN - 1); 84 resolved[MAXPATHLEN - 1] = '\0'; 85loop: 86 q = strrchr(resolved, '/'); 87 if (q != NULL) { 88 p = q + 1; 89 if (q == resolved) 90 q = "/"; 91 else { 92 do { 93 --q; 94 } while (q > resolved && *q == '/'); 95 q[1] = '\0'; 96 q = resolved; 97 } 98 if (chdir(q) < 0) 99 goto err1; 100 } else 101 p = resolved; 102 103 /* Deal with the last component. */ 104 if (*p != '\0' && lstat(p, &sb) == 0) { 105 if (S_ISLNK(sb.st_mode)) { 106 if (++symlinks > MAXSYMLINKS) { 107 errno = ELOOP; 108 goto err1; 109 } 110 n = readlink(p, resolved, MAXPATHLEN - 1); 111 if (n < 0) 112 goto err1; 113 resolved[n] = '\0'; 114 goto loop; 115 } 116 if (S_ISDIR(sb.st_mode)) { 117 if (chdir(p) < 0) 118 goto err1; 119 p = ""; 120 } 121 } 122 123 /* 124 * Save the last component name and get the full pathname of 125 * the current directory. 126 */ 127 (void)strcpy(wbuf, p); 128 if (getcwd(resolved, MAXPATHLEN) == 0) 129 goto err1; 130 131 /* 132 * Join the two strings together, ensuring that the right thing 133 * happens if the last component is empty, or the dirname is root. 134 */ 135 if (resolved[0] == '/' && resolved[1] == '\0') 136 rootd = 1; 137 else 138 rootd = 0; 139 140 if (*wbuf) { 141 if (strlen(resolved) + strlen(wbuf) + rootd + 1 > MAXPATHLEN) { 142 errno = ENAMETOOLONG; 143 goto err1; 144 } 145 if (rootd == 0) 146 (void)strcat(resolved, "/"); 147 (void)strcat(resolved, wbuf); 148 } 149 150 /* Go back to where we came from. */ 151 if (fchdir(fd) < 0) { 152 serrno = errno; 153 goto err2; 154 } 155 156 /* It's okay if the close fails, what's an fd more or less? */ 157 (void)_close(fd); 158 return (resolved); 159 160err1: serrno = errno; 161 (void)fchdir(fd); 162err2: (void)_close(fd); 163 errno = serrno; 164 return (NULL); 165} 166