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