1246223Ssjg/* $Id: realpath.c,v 1.3 2013/01/25 17:06:09 sjg Exp $ */ 2246223Ssjg/* from: $NetBSD: getcwd.c,v 1.53 2012/06/21 23:29:23 enami Exp $ */ 3236769Sobrien 4236769Sobrien/* 5236769Sobrien * Copyright (c) 1989, 1991, 1993, 1995 6236769Sobrien * The Regents of the University of California. All rights reserved. 7236769Sobrien * 8236769Sobrien * This code is derived from software contributed to Berkeley by 9236769Sobrien * Jan-Simon Pendry. 10236769Sobrien * 11236769Sobrien * Redistribution and use in source and binary forms, with or without 12236769Sobrien * modification, are permitted provided that the following conditions 13236769Sobrien * are met: 14236769Sobrien * 1. Redistributions of source code must retain the above copyright 15236769Sobrien * notice, this list of conditions and the following disclaimer. 16236769Sobrien * 2. Redistributions in binary form must reproduce the above copyright 17236769Sobrien * notice, this list of conditions and the following disclaimer in the 18236769Sobrien * documentation and/or other materials provided with the distribution. 19236769Sobrien * 3. Neither the name of the University nor the names of its contributors 20236769Sobrien * may be used to endorse or promote products derived from this software 21236769Sobrien * without specific prior written permission. 22236769Sobrien * 23236769Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24236769Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25236769Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26236769Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27236769Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28236769Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29236769Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30236769Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31236769Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32236769Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33236769Sobrien * SUCH DAMAGE. 34236769Sobrien */ 35236769Sobrien#ifdef HAVE_CONFIG_H 36236769Sobrien# include <config.h> 37236769Sobrien#endif 38236769Sobrien#ifndef HAVE_REALPATH 39236769Sobrien 40236769Sobrien#include <sys/cdefs.h> 41236769Sobrien#include <sys/param.h> 42236769Sobrien#include <sys/stat.h> 43236769Sobrien 44236769Sobrien#include <errno.h> 45236769Sobrien#ifdef HAVE_STDLIB_H 46236769Sobrien# include <stdlib.h> 47236769Sobrien#endif 48236769Sobrien#ifdef HAVE_STRING_H 49236769Sobrien# include <string.h> 50236769Sobrien#endif 51236769Sobrien#ifdef HAVE_UNISTD_H 52236769Sobrien# include <unistd.h> 53236769Sobrien#endif 54236769Sobrien 55246223Ssjg#ifndef __restrict 56246223Ssjg# define __restrict /* restrict */ 57246223Ssjg#endif 58246223Ssjg 59236769Sobrien/* 60246223Ssjg * char *realpath(const char *path, char *resolved); 61236769Sobrien * 62236769Sobrien * Find the real name of path, by removing all ".", ".." and symlink 63236769Sobrien * components. Returns (resolved) on success, or (NULL) on failure, 64236769Sobrien * in which case the path which caused trouble is left in (resolved). 65236769Sobrien */ 66236769Sobrienchar * 67246223Ssjgrealpath(const char * __restrict path, char * __restrict resolved) 68236769Sobrien{ 69236769Sobrien struct stat sb; 70246223Ssjg int idx = 0, nlnk = 0; 71236769Sobrien const char *q; 72246223Ssjg char *p, wbuf[2][MAXPATHLEN], *fres; 73236769Sobrien size_t len; 74246223Ssjg ssize_t n; 75236769Sobrien 76246223Ssjg /* POSIX sez we must test for this */ 77246223Ssjg if (path == NULL) { 78246223Ssjg errno = EINVAL; 79246223Ssjg return NULL; 80246223Ssjg } 81236769Sobrien 82246223Ssjg if (resolved == NULL) { 83246223Ssjg fres = resolved = malloc(MAXPATHLEN); 84246223Ssjg if (resolved == NULL) 85246223Ssjg return NULL; 86246223Ssjg } else 87246223Ssjg fres = NULL; 88246223Ssjg 89246223Ssjg 90236769Sobrien /* 91236769Sobrien * Build real path one by one with paying an attention to ., 92236769Sobrien * .. and symbolic link. 93236769Sobrien */ 94236769Sobrien 95236769Sobrien /* 96236769Sobrien * `p' is where we'll put a new component with prepending 97236769Sobrien * a delimiter. 98236769Sobrien */ 99236769Sobrien p = resolved; 100236769Sobrien 101246223Ssjg if (*path == '\0') { 102246223Ssjg *p = '\0'; 103236769Sobrien errno = ENOENT; 104246223Ssjg goto out; 105236769Sobrien } 106236769Sobrien 107236769Sobrien /* If relative path, start from current working directory. */ 108236769Sobrien if (*path != '/') { 109236769Sobrien /* check for resolved pointer to appease coverity */ 110236769Sobrien if (resolved && getcwd(resolved, MAXPATHLEN) == NULL) { 111236769Sobrien p[0] = '.'; 112246223Ssjg p[1] = '\0'; 113246223Ssjg goto out; 114236769Sobrien } 115236769Sobrien len = strlen(resolved); 116236769Sobrien if (len > 1) 117236769Sobrien p += len; 118236769Sobrien } 119236769Sobrien 120236769Sobrienloop: 121236769Sobrien /* Skip any slash. */ 122236769Sobrien while (*path == '/') 123236769Sobrien path++; 124236769Sobrien 125246223Ssjg if (*path == '\0') { 126236769Sobrien if (p == resolved) 127236769Sobrien *p++ = '/'; 128246223Ssjg *p = '\0'; 129246223Ssjg return resolved; 130236769Sobrien } 131236769Sobrien 132236769Sobrien /* Find the end of this component. */ 133236769Sobrien q = path; 134236769Sobrien do 135236769Sobrien q++; 136246223Ssjg while (*q != '/' && *q != '\0'); 137236769Sobrien 138236769Sobrien /* Test . or .. */ 139236769Sobrien if (path[0] == '.') { 140236769Sobrien if (q - path == 1) { 141236769Sobrien path = q; 142236769Sobrien goto loop; 143236769Sobrien } 144236769Sobrien if (path[1] == '.' && q - path == 2) { 145236769Sobrien /* Trim the last component. */ 146236769Sobrien if (p != resolved) 147236769Sobrien while (*--p != '/') 148246223Ssjg continue; 149236769Sobrien path = q; 150236769Sobrien goto loop; 151236769Sobrien } 152236769Sobrien } 153236769Sobrien 154236769Sobrien /* Append this component. */ 155236769Sobrien if (p - resolved + 1 + q - path + 1 > MAXPATHLEN) { 156236769Sobrien errno = ENAMETOOLONG; 157236769Sobrien if (p == resolved) 158236769Sobrien *p++ = '/'; 159246223Ssjg *p = '\0'; 160246223Ssjg goto out; 161236769Sobrien } 162236769Sobrien p[0] = '/'; 163236769Sobrien memcpy(&p[1], path, 164236769Sobrien /* LINTED We know q > path. */ 165236769Sobrien q - path); 166246223Ssjg p[1 + q - path] = '\0'; 167236769Sobrien 168236769Sobrien /* 169236769Sobrien * If this component is a symlink, toss it and prepend link 170236769Sobrien * target to unresolved path. 171236769Sobrien */ 172246223Ssjg if (lstat(resolved, &sb) == -1) 173246223Ssjg goto out; 174246223Ssjg 175236769Sobrien if (S_ISLNK(sb.st_mode)) { 176236769Sobrien if (nlnk++ >= MAXSYMLINKS) { 177236769Sobrien errno = ELOOP; 178246223Ssjg goto out; 179236769Sobrien } 180236769Sobrien n = readlink(resolved, wbuf[idx], sizeof(wbuf[0]) - 1); 181236769Sobrien if (n < 0) 182246223Ssjg goto out; 183236769Sobrien if (n == 0) { 184236769Sobrien errno = ENOENT; 185246223Ssjg goto out; 186236769Sobrien } 187236769Sobrien 188236769Sobrien /* Append unresolved path to link target and switch to it. */ 189236769Sobrien if (n + (len = strlen(q)) + 1 > sizeof(wbuf[0])) { 190236769Sobrien errno = ENAMETOOLONG; 191246223Ssjg goto out; 192236769Sobrien } 193236769Sobrien memcpy(&wbuf[idx][n], q, len + 1); 194236769Sobrien path = wbuf[idx]; 195236769Sobrien idx ^= 1; 196236769Sobrien 197236769Sobrien /* If absolute symlink, start from root. */ 198236769Sobrien if (*path == '/') 199236769Sobrien p = resolved; 200236769Sobrien goto loop; 201236769Sobrien } 202236769Sobrien if (*q == '/' && !S_ISDIR(sb.st_mode)) { 203236769Sobrien errno = ENOTDIR; 204246223Ssjg goto out; 205236769Sobrien } 206236769Sobrien 207236769Sobrien /* Advance both resolved and unresolved path. */ 208236769Sobrien p += 1 + q - path; 209236769Sobrien path = q; 210236769Sobrien goto loop; 211246223Ssjgout: 212246223Ssjg free(fres); 213246223Ssjg return NULL; 214236769Sobrien} 215236769Sobrien#endif 216