1299425Smm/* $Id: realpath.c,v 1.3 2013/01/25 17:06:09 sjg Exp $ */ 2299425Smm/* from: $NetBSD: getcwd.c,v 1.53 2012/06/21 23:29:23 enami Exp $ */ 3299425Smm 4299425Smm/* 5299425Smm * Copyright (c) 1989, 1991, 1993, 1995 6299425Smm * The Regents of the University of California. All rights reserved. 7299425Smm * 8299425Smm * This code is derived from software contributed to Berkeley by 9299425Smm * Jan-Simon Pendry. 10299425Smm * 11299425Smm * Redistribution and use in source and binary forms, with or without 12299425Smm * modification, are permitted provided that the following conditions 13299425Smm * are met: 14299425Smm * 1. Redistributions of source code must retain the above copyright 15299425Smm * notice, this list of conditions and the following disclaimer. 16299425Smm * 2. Redistributions in binary form must reproduce the above copyright 17299425Smm * notice, this list of conditions and the following disclaimer in the 18299425Smm * documentation and/or other materials provided with the distribution. 19299425Smm * 3. Neither the name of the University nor the names of its contributors 20299425Smm * may be used to endorse or promote products derived from this software 21299425Smm * without specific prior written permission. 22299425Smm * 23299425Smm * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24299425Smm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25299425Smm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26299425Smm * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27358088Smm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28358088Smm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29358088Smm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30299425Smm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31299425Smm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32299425Smm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33299425Smm * SUCH DAMAGE. 34299425Smm */ 35299425Smm#ifdef HAVE_CONFIG_H 36299425Smm# include <config.h> 37299425Smm#endif 38299425Smm#ifndef HAVE_REALPATH 39299425Smm 40299425Smm#include <sys/cdefs.h> 41299425Smm#include <sys/param.h> 42299425Smm#include <sys/stat.h> 43299425Smm 44299425Smm#include <errno.h> 45299425Smm#ifdef HAVE_STDLIB_H 46299425Smm# include <stdlib.h> 47299425Smm#endif 48299425Smm#ifdef HAVE_STRING_H 49# include <string.h> 50#endif 51#ifdef HAVE_UNISTD_H 52# include <unistd.h> 53#endif 54 55#ifndef __restrict 56# define __restrict /* restrict */ 57#endif 58 59/* 60 * char *realpath(const char *path, char *resolved); 61 * 62 * Find the real name of path, by removing all ".", ".." and symlink 63 * components. Returns (resolved) on success, or (NULL) on failure, 64 * in which case the path which caused trouble is left in (resolved). 65 */ 66char * 67realpath(const char * __restrict path, char * __restrict resolved) 68{ 69 struct stat sb; 70 int idx = 0, nlnk = 0; 71 const char *q; 72 char *p, wbuf[2][MAXPATHLEN], *fres; 73 size_t len; 74 ssize_t n; 75 76 /* POSIX sez we must test for this */ 77 if (path == NULL) { 78 errno = EINVAL; 79 return NULL; 80 } 81 82 if (resolved == NULL) { 83 fres = resolved = malloc(MAXPATHLEN); 84 if (resolved == NULL) 85 return NULL; 86 } else 87 fres = NULL; 88 89 90 /* 91 * Build real path one by one with paying an attention to ., 92 * .. and symbolic link. 93 */ 94 95 /* 96 * `p' is where we'll put a new component with prepending 97 * a delimiter. 98 */ 99 p = resolved; 100 101 if (*path == '\0') { 102 *p = '\0'; 103 errno = ENOENT; 104 goto out; 105 } 106 107 /* If relative path, start from current working directory. */ 108 if (*path != '/') { 109 /* check for resolved pointer to appease coverity */ 110 if (resolved && getcwd(resolved, MAXPATHLEN) == NULL) { 111 p[0] = '.'; 112 p[1] = '\0'; 113 goto out; 114 } 115 len = strlen(resolved); 116 if (len > 1) 117 p += len; 118 } 119 120loop: 121 /* Skip any slash. */ 122 while (*path == '/') 123 path++; 124 125 if (*path == '\0') { 126 if (p == resolved) 127 *p++ = '/'; 128 *p = '\0'; 129 return resolved; 130 } 131 132 /* Find the end of this component. */ 133 q = path; 134 do 135 q++; 136 while (*q != '/' && *q != '\0'); 137 138 /* Test . or .. */ 139 if (path[0] == '.') { 140 if (q - path == 1) { 141 path = q; 142 goto loop; 143 } 144 if (path[1] == '.' && q - path == 2) { 145 /* Trim the last component. */ 146 if (p != resolved) 147 while (*--p != '/') 148 continue; 149 path = q; 150 goto loop; 151 } 152 } 153 154 /* Append this component. */ 155 if (p - resolved + 1 + q - path + 1 > MAXPATHLEN) { 156 errno = ENAMETOOLONG; 157 if (p == resolved) 158 *p++ = '/'; 159 *p = '\0'; 160 goto out; 161 } 162 p[0] = '/'; 163 memcpy(&p[1], path, 164 /* LINTED We know q > path. */ 165 q - path); 166 p[1 + q - path] = '\0'; 167 168 /* 169 * If this component is a symlink, toss it and prepend link 170 * target to unresolved path. 171 */ 172 if (lstat(resolved, &sb) == -1) 173 goto out; 174 175 if (S_ISLNK(sb.st_mode)) { 176 if (nlnk++ >= MAXSYMLINKS) { 177 errno = ELOOP; 178 goto out; 179 } 180 n = readlink(resolved, wbuf[idx], sizeof(wbuf[0]) - 1); 181 if (n < 0) 182 goto out; 183 if (n == 0) { 184 errno = ENOENT; 185 goto out; 186 } 187 188 /* Append unresolved path to link target and switch to it. */ 189 if (n + (len = strlen(q)) + 1 > sizeof(wbuf[0])) { 190 errno = ENAMETOOLONG; 191 goto out; 192 } 193 memcpy(&wbuf[idx][n], q, len + 1); 194 path = wbuf[idx]; 195 idx ^= 1; 196 197 /* If absolute symlink, start from root. */ 198 if (*path == '/') 199 p = resolved; 200 goto loop; 201 } 202 if (*q == '/' && !S_ISDIR(sb.st_mode)) { 203 errno = ENOTDIR; 204 goto out; 205 } 206 207 /* Advance both resolved and unresolved path. */ 208 p += 1 + q - path; 209 path = q; 210 goto loop; 211out: 212 free(fres); 213 return NULL; 214} 215#endif 216