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