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