1299425Smm/* $Id: realpath.c,v 1.3 2013/01/25 17:06:09 sjg Exp $ */
2299425Smm/* from: $NetBSD: getcwd.c,v 1.53 2012/06/21 23:29:23 enami Exp $	*/
3299425Smm
4299425Smm/*
5299425Smm * Copyright (c) 1989, 1991, 1993, 1995
6299425Smm *	The Regents of the University of California.  All rights reserved.
7299425Smm *
8299425Smm * This code is derived from software contributed to Berkeley by
9299425Smm * Jan-Simon Pendry.
10299425Smm *
11299425Smm * Redistribution and use in source and binary forms, with or without
12299425Smm * modification, are permitted provided that the following conditions
13299425Smm * are met:
14299425Smm * 1. Redistributions of source code must retain the above copyright
15299425Smm *    notice, this list of conditions and the following disclaimer.
16299425Smm * 2. Redistributions in binary form must reproduce the above copyright
17299425Smm *    notice, this list of conditions and the following disclaimer in the
18299425Smm *    documentation and/or other materials provided with the distribution.
19299425Smm * 3. Neither the name of the University nor the names of its contributors
20299425Smm *    may be used to endorse or promote products derived from this software
21299425Smm *    without specific prior written permission.
22299425Smm *
23299425Smm * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24299425Smm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25299425Smm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26299425Smm * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27358088Smm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28358088Smm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29358088Smm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30299425Smm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31299425Smm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32299425Smm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33299425Smm * SUCH DAMAGE.
34299425Smm */
35299425Smm#ifdef HAVE_CONFIG_H
36299425Smm# include <config.h>
37299425Smm#endif
38299425Smm#ifndef HAVE_REALPATH
39299425Smm
40299425Smm#include <sys/cdefs.h>
41299425Smm#include <sys/param.h>
42299425Smm#include <sys/stat.h>
43299425Smm
44299425Smm#include <errno.h>
45299425Smm#ifdef HAVE_STDLIB_H
46299425Smm# include <stdlib.h>
47299425Smm#endif
48299425Smm#ifdef HAVE_STRING_H
49# include <string.h>
50#endif
51#ifdef HAVE_UNISTD_H
52# include <unistd.h>
53#endif
54
55#ifndef __restrict
56# define __restrict /* restrict */
57#endif
58
59/*
60 * char *realpath(const char *path, char *resolved);
61 *
62 * Find the real name of path, by removing all ".", ".." and symlink
63 * components.  Returns (resolved) on success, or (NULL) on failure,
64 * in which case the path which caused trouble is left in (resolved).
65 */
66char *
67realpath(const char * __restrict path, char * __restrict resolved)
68{
69	struct stat sb;
70	int idx = 0, nlnk = 0;
71	const char *q;
72	char *p, wbuf[2][MAXPATHLEN], *fres;
73	size_t len;
74	ssize_t n;
75
76	/* POSIX sez we must test for this */
77	if (path == NULL) {
78		errno = EINVAL;
79		return NULL;
80	}
81
82	if (resolved == NULL) {
83		fres = resolved = malloc(MAXPATHLEN);
84		if (resolved == NULL)
85			return NULL;
86	} else
87		fres = NULL;
88
89
90	/*
91	 * Build real path one by one with paying an attention to .,
92	 * .. and symbolic link.
93	 */
94
95	/*
96	 * `p' is where we'll put a new component with prepending
97	 * a delimiter.
98	 */
99	p = resolved;
100
101	if (*path == '\0') {
102		*p = '\0';
103		errno = ENOENT;
104		goto out;
105	}
106
107	/* If relative path, start from current working directory. */
108	if (*path != '/') {
109		/* check for resolved pointer to appease coverity */
110		if (resolved && getcwd(resolved, MAXPATHLEN) == NULL) {
111			p[0] = '.';
112			p[1] = '\0';
113			goto out;
114		}
115		len = strlen(resolved);
116		if (len > 1)
117			p += len;
118	}
119
120loop:
121	/* Skip any slash. */
122	while (*path == '/')
123		path++;
124
125	if (*path == '\0') {
126		if (p == resolved)
127			*p++ = '/';
128		*p = '\0';
129		return resolved;
130	}
131
132	/* Find the end of this component. */
133	q = path;
134	do
135		q++;
136	while (*q != '/' && *q != '\0');
137
138	/* Test . or .. */
139	if (path[0] == '.') {
140		if (q - path == 1) {
141			path = q;
142			goto loop;
143		}
144		if (path[1] == '.' && q - path == 2) {
145			/* Trim the last component. */
146			if (p != resolved)
147				while (*--p != '/')
148					continue;
149			path = q;
150			goto loop;
151		}
152	}
153
154	/* Append this component. */
155	if (p - resolved + 1 + q - path + 1 > MAXPATHLEN) {
156		errno = ENAMETOOLONG;
157		if (p == resolved)
158			*p++ = '/';
159		*p = '\0';
160		goto out;
161	}
162	p[0] = '/';
163	memcpy(&p[1], path,
164	    /* LINTED We know q > path. */
165	    q - path);
166	p[1 + q - path] = '\0';
167
168	/*
169	 * If this component is a symlink, toss it and prepend link
170	 * target to unresolved path.
171	 */
172	if (lstat(resolved, &sb) == -1)
173		goto out;
174
175	if (S_ISLNK(sb.st_mode)) {
176		if (nlnk++ >= MAXSYMLINKS) {
177			errno = ELOOP;
178			goto out;
179		}
180		n = readlink(resolved, wbuf[idx], sizeof(wbuf[0]) - 1);
181		if (n < 0)
182			goto out;
183		if (n == 0) {
184			errno = ENOENT;
185			goto out;
186		}
187
188		/* Append unresolved path to link target and switch to it. */
189		if (n + (len = strlen(q)) + 1 > sizeof(wbuf[0])) {
190			errno = ENAMETOOLONG;
191			goto out;
192		}
193		memcpy(&wbuf[idx][n], q, len + 1);
194		path = wbuf[idx];
195		idx ^= 1;
196
197		/* If absolute symlink, start from root. */
198		if (*path == '/')
199			p = resolved;
200		goto loop;
201	}
202	if (*q == '/' && !S_ISDIR(sb.st_mode)) {
203		errno = ENOTDIR;
204		goto out;
205	}
206
207	/* Advance both resolved and unresolved path. */
208	p += 1 + q - path;
209	path = q;
210	goto loop;
211out:
212	free(fres);
213	return NULL;
214}
215#endif
216