realpath.c revision 263212
1205354Simp/* $Id: realpath.c,v 1.3 2013/01/25 17:06:09 sjg Exp $ */ 2205354Simp/* from: $NetBSD: getcwd.c,v 1.53 2012/06/21 23:29:23 enami Exp $ */ 3205354Simp 4205354Simp/* 5205354Simp * Copyright (c) 1989, 1991, 1993, 1995 6205354Simp * The Regents of the University of California. All rights reserved. 7205354Simp * 8205354Simp * This code is derived from software contributed to Berkeley by 9205354Simp * Jan-Simon Pendry. 10205354Simp * 11205354Simp * Redistribution and use in source and binary forms, with or without 12205354Simp * modification, are permitted provided that the following conditions 13205354Simp * are met: 14205354Simp * 1. Redistributions of source code must retain the above copyright 15205354Simp * notice, this list of conditions and the following disclaimer. 16205354Simp * 2. Redistributions in binary form must reproduce the above copyright 17205354Simp * notice, this list of conditions and the following disclaimer in the 18205354Simp * documentation and/or other materials provided with the distribution. 19205354Simp * 3. Neither the name of the University nor the names of its contributors 20205354Simp * may be used to endorse or promote products derived from this software 21205354Simp * without specific prior written permission. 22205354Simp * 23205354Simp * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24205354Simp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25205354Simp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26205354Simp * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27205354Simp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28205354Simp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29205354Simp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30205354Simp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31205354Simp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32205354Simp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33205354Simp * SUCH DAMAGE. 34205354Simp */ 35205354Simp#ifdef HAVE_CONFIG_H 36205354Simp# include <config.h> 37205354Simp#endif 38205354Simp#ifndef HAVE_REALPATH 39205354Simp 40205354Simp#include <sys/cdefs.h> 41205354Simp#include <sys/param.h> 42205354Simp#include <sys/stat.h> 43205354Simp 44205354Simp#include <errno.h> 45205354Simp#ifdef HAVE_STDLIB_H 46205354Simp# include <stdlib.h> 47205354Simp#endif 48205354Simp#ifdef HAVE_STRING_H 49205354Simp# include <string.h> 50205354Simp#endif 51205354Simp#ifdef HAVE_UNISTD_H 52205354Simp# include <unistd.h> 53205354Simp#endif 54205354Simp 55205354Simp#ifndef __restrict 56205354Simp# define __restrict /* restrict */ 57205354Simp#endif 58205354Simp 59205354Simp/* 60205354Simp * char *realpath(const char *path, char *resolved); 61205354Simp * 62205354Simp * Find the real name of path, by removing all ".", ".." and symlink 63205354Simp * components. Returns (resolved) on success, or (NULL) on failure, 64205354Simp * in which case the path which caused trouble is left in (resolved). 65205354Simp */ 66205354Simpchar * 67205354Simprealpath(const char * __restrict path, char * __restrict resolved) 68205354Simp{ 69205354Simp struct stat sb; 70205354Simp int idx = 0, nlnk = 0; 71205354Simp const char *q; 72205354Simp char *p, wbuf[2][MAXPATHLEN], *fres; 73205354Simp size_t len; 74205354Simp ssize_t n; 75205354Simp 76205354Simp /* POSIX sez we must test for this */ 77205354Simp if (path == NULL) { 78205354Simp errno = EINVAL; 79205354Simp return NULL; 80205354Simp } 81205354Simp 82205354Simp if (resolved == NULL) { 83210397Sandrew fres = resolved = malloc(MAXPATHLEN); 84210397Sandrew if (resolved == NULL) 85210397Sandrew return NULL; 86210397Sandrew } else 87205354Simp fres = NULL; 88205354Simp 89205354Simp 90210396Sandrew /* 91205354Simp * Build real path one by one with paying an attention to ., 92205354Simp * .. and symbolic link. 93205354Simp */ 94205354Simp 95210396Sandrew /* 96205354Simp * `p' is where we'll put a new component with prepending 97205354Simp * a delimiter. 98205354Simp */ 99205354Simp p = resolved; 100210396Sandrew 101205354Simp if (*path == '\0') { 102205354Simp *p = '\0'; 103205354Simp errno = ENOENT; 104205354Simp goto out; 105210396Sandrew } 106205354Simp 107205354Simp /* If relative path, start from current working directory. */ 108205354Simp if (*path != '/') { 109205354Simp /* check for resolved pointer to appease coverity */ 110205354Simp if (resolved && getcwd(resolved, MAXPATHLEN) == NULL) { 111205354Simp p[0] = '.'; 112205354Simp p[1] = '\0'; 113205354Simp goto out; 114205354Simp } 115205354Simp len = strlen(resolved); 116205354Simp if (len > 1) 117205354Simp p += len; 118205354Simp } 119205354Simp 120205354Simploop: 121210458Sandrew /* Skip any slash. */ 122210458Sandrew while (*path == '/') 123205354Simp path++; 124205354Simp 125205354Simp if (*path == '\0') { 126205354Simp if (p == resolved) 127205354Simp *p++ = '/'; 128205354Simp *p = '\0'; 129205354Simp return resolved; 130205354Simp } 131205354Simp 132205354Simp /* Find the end of this component. */ 133205354Simp q = path; 134205354Simp do 135205354Simp q++; 136205354Simp while (*q != '/' && *q != '\0'); 137205354Simp 138205354Simp /* Test . or .. */ 139210458Sandrew if (path[0] == '.') { 140205354Simp if (q - path == 1) { 141205354Simp path = q; 142205354Simp goto loop; 143205354Simp } 144205354Simp if (path[1] == '.' && q - path == 2) { 145205354Simp /* Trim the last component. */ 146205354Simp if (p != resolved) 147205354Simp while (*--p != '/') 148205354Simp continue; 149205354Simp path = q; 150205354Simp goto loop; 151205354Simp } 152205354Simp } 153205354Simp 154205354Simp /* Append this component. */ 155205354Simp if (p - resolved + 1 + q - path + 1 > MAXPATHLEN) { 156205354Simp errno = ENAMETOOLONG; 157205354Simp if (p == resolved) 158205354Simp *p++ = '/'; 159205354Simp *p = '\0'; 160205354Simp goto out; 161205354Simp } 162205354Simp p[0] = '/'; 163205354Simp memcpy(&p[1], path, 164205354Simp /* LINTED We know q > path. */ 165205354Simp q - path); 166205354Simp p[1 + q - path] = '\0'; 167205354Simp 168205354Simp /* 169205354Simp * If this component is a symlink, toss it and prepend link 170205354Simp * target to unresolved path. 171205354Simp */ 172205354Simp if (lstat(resolved, &sb) == -1) 173205354Simp goto out; 174205354Simp 175205354Simp if (S_ISLNK(sb.st_mode)) { 176205354Simp if (nlnk++ >= MAXSYMLINKS) { 177205354Simp errno = ELOOP; 178205354Simp goto out; 179205354Simp } 180205354Simp n = readlink(resolved, wbuf[idx], sizeof(wbuf[0]) - 1); 181205354Simp if (n < 0) 182210458Sandrew goto out; 183210458Sandrew if (n == 0) { 184210458Sandrew errno = ENOENT; 185210458Sandrew goto out; 186210458Sandrew } 187210458Sandrew 188210458Sandrew /* Append unresolved path to link target and switch to it. */ 189210458Sandrew if (n + (len = strlen(q)) + 1 > sizeof(wbuf[0])) { 190210458Sandrew errno = ENAMETOOLONG; 191210458Sandrew goto out; 192210458Sandrew } 193210458Sandrew memcpy(&wbuf[idx][n], q, len + 1); 194210458Sandrew path = wbuf[idx]; 195210458Sandrew idx ^= 1; 196210458Sandrew 197210458Sandrew /* If absolute symlink, start from root. */ 198210458Sandrew if (*path == '/') 199210458Sandrew p = resolved; 200210458Sandrew goto loop; 201210458Sandrew } 202210458Sandrew if (*q == '/' && !S_ISDIR(sb.st_mode)) { 203210458Sandrew errno = ENOTDIR; 204210458Sandrew goto out; 205210458Sandrew } 206205354Simp 207205354Simp /* Advance both resolved and unresolved path. */ 208205354Simp p += 1 + q - path; 209205354Simp path = q; 210205354Simp goto loop; 211205354Simpout: 212205354Simp free(fres); 213205354Simp return NULL; 214205354Simp} 215205354Simp#endif 216205354Simp