11305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood/* $OpenBSD: realpath.c,v 1.13 2005/08/08 08:05:37 espie Exp $ */ 21305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood/* 31305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * Copyright (c) 2003 Constantin S. Svintsoff <kostik@iclub.nsu.ru> 41305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * 51305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * Redistribution and use in source and binary forms, with or without 61305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * modification, are permitted provided that the following conditions 71305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * are met: 81305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * 1. Redistributions of source code must retain the above copyright 91305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * notice, this list of conditions and the following disclaimer. 101305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * 2. Redistributions in binary form must reproduce the above copyright 111305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * notice, this list of conditions and the following disclaimer in the 121305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * documentation and/or other materials provided with the distribution. 131305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * 3. The names of the authors may not be used to endorse or promote 141305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * products derived from this software without specific prior written 151305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * permission. 161305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * 171305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 181305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 191305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 201305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 211305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 221305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 231305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 241305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 251305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 261305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 271305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * SUCH DAMAGE. 281305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood */ 291305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 301305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood/* OPENBSD ORIGINAL: lib/libc/stdlib/realpath.c */ 311305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 321305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#include "includes.h" 331305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 341305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#if !defined(HAVE_REALPATH) || defined(BROKEN_REALPATH) 351305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 361305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#include <sys/param.h> 371305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#include <sys/stat.h> 381305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 391305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#include <errno.h> 401305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#include <stdlib.h> 411305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#include <string.h> 421305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#include <unistd.h> 431305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 441305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood/* 451305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * char *realpath(const char *path, char resolved[PATH_MAX]); 461305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * 471305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * Find the real name of path, by removing all ".", ".." and symlink 481305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * components. Returns (resolved) on success, or (NULL) on failure, 491305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * in which case the path which caused trouble is left in (resolved). 501305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood */ 511305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodchar * 521305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodrealpath(const char *path, char resolved[PATH_MAX]) 531305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood{ 541305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood struct stat sb; 551305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood char *p, *q, *s; 561305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood size_t left_len, resolved_len; 571305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood unsigned symlinks; 581305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood int serrno, slen; 591305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood char left[PATH_MAX], next_token[PATH_MAX], symlink[PATH_MAX]; 601305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 611305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood serrno = errno; 621305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood symlinks = 0; 631305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (path[0] == '/') { 641305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood resolved[0] = '/'; 651305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood resolved[1] = '\0'; 661305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (path[1] == '\0') 671305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood return (resolved); 681305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood resolved_len = 1; 691305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood left_len = strlcpy(left, path + 1, sizeof(left)); 701305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood } else { 711305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (getcwd(resolved, PATH_MAX) == NULL) { 721305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood strlcpy(resolved, ".", PATH_MAX); 731305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood return (NULL); 741305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood } 751305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood resolved_len = strlen(resolved); 761305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood left_len = strlcpy(left, path, sizeof(left)); 771305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood } 781305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (left_len >= sizeof(left) || resolved_len >= PATH_MAX) { 791305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood errno = ENAMETOOLONG; 801305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood return (NULL); 811305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood } 821305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 831305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood /* 841305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * Iterate over path components in `left'. 851305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood */ 861305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood while (left_len != 0) { 871305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood /* 881305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * Extract the next path component and adjust `left' 891305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * and its length. 901305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood */ 911305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood p = strchr(left, '/'); 921305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood s = p ? p : left + left_len; 931305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (s - left >= sizeof(next_token)) { 941305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood errno = ENAMETOOLONG; 951305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood return (NULL); 961305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood } 971305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood memcpy(next_token, left, s - left); 981305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood next_token[s - left] = '\0'; 991305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood left_len -= s - left; 1001305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (p != NULL) 1011305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood memmove(left, s + 1, left_len + 1); 1021305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (resolved[resolved_len - 1] != '/') { 1031305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (resolved_len + 1 >= PATH_MAX) { 1041305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood errno = ENAMETOOLONG; 1051305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood return (NULL); 1061305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood } 1071305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood resolved[resolved_len++] = '/'; 1081305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood resolved[resolved_len] = '\0'; 1091305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood } 1101305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (next_token[0] == '\0') 1111305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood continue; 1121305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood else if (strcmp(next_token, ".") == 0) 1131305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood continue; 1141305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood else if (strcmp(next_token, "..") == 0) { 1151305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood /* 1161305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * Strip the last path component except when we have 1171305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * single "/" 1181305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood */ 1191305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (resolved_len > 1) { 1201305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood resolved[resolved_len - 1] = '\0'; 1211305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood q = strrchr(resolved, '/') + 1; 1221305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood *q = '\0'; 1231305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood resolved_len = q - resolved; 1241305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood } 1251305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood continue; 1261305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood } 1271305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 1281305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood /* 1291305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * Append the next path component and lstat() it. If 1301305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * lstat() fails we still can return successfully if 1311305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * there are no more path components left. 1321305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood */ 1331305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood resolved_len = strlcat(resolved, next_token, PATH_MAX); 1341305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (resolved_len >= PATH_MAX) { 1351305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood errno = ENAMETOOLONG; 1361305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood return (NULL); 1371305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood } 1381305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (lstat(resolved, &sb) != 0) { 1391305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (errno == ENOENT && p == NULL) { 1401305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood errno = serrno; 1411305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood return (resolved); 1421305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood } 1431305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood return (NULL); 1441305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood } 1451305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (S_ISLNK(sb.st_mode)) { 1461305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (symlinks++ > MAXSYMLINKS) { 1471305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood errno = ELOOP; 1481305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood return (NULL); 1491305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood } 1501305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood slen = readlink(resolved, symlink, sizeof(symlink) - 1); 1511305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (slen < 0) 1521305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood return (NULL); 1531305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood symlink[slen] = '\0'; 1541305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (symlink[0] == '/') { 1551305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood resolved[1] = 0; 1561305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood resolved_len = 1; 1571305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood } else if (resolved_len > 1) { 1581305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood /* Strip the last path component. */ 1591305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood resolved[resolved_len - 1] = '\0'; 1601305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood q = strrchr(resolved, '/') + 1; 1611305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood *q = '\0'; 1621305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood resolved_len = q - resolved; 1631305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood } 1641305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 1651305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood /* 1661305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * If there are any path components left, then 1671305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * append them to symlink. The result is placed 1681305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * in `left'. 1691305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood */ 1701305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (p != NULL) { 1711305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (symlink[slen - 1] != '/') { 1721305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (slen + 1 >= sizeof(symlink)) { 1731305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood errno = ENAMETOOLONG; 1741305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood return (NULL); 1751305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood } 1761305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood symlink[slen] = '/'; 1771305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood symlink[slen + 1] = 0; 1781305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood } 1791305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood left_len = strlcat(symlink, left, sizeof(left)); 1801305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (left_len >= sizeof(left)) { 1811305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood errno = ENAMETOOLONG; 1821305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood return (NULL); 1831305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood } 1841305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood } 1851305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood left_len = strlcpy(left, symlink, sizeof(left)); 1861305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood } 1871305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood } 1881305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 1891305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood /* 1901305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * Remove trailing slash except when the resolved pathname 1911305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * is a single "/". 1921305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood */ 1931305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (resolved_len > 1 && resolved[resolved_len - 1] == '/') 1941305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood resolved[resolved_len - 1] = '\0'; 1951305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood return (resolved); 1961305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood} 1971305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#endif /* !defined(HAVE_REALPATH) || defined(BROKEN_REALPATH) */ 198