diff options
| author | Peter Wemm <peter@FreeBSD.org> | 1997-03-13 06:58:46 +0000 | 
|---|---|---|
| committer | Peter Wemm <peter@FreeBSD.org> | 1997-03-13 06:58:46 +0000 | 
| commit | d01a28e222cb4a0478324b12527a31cbfa4b8dfa (patch) | |
| tree | 2a9506e47f62cc8177ea79c3cf83ab94ad79eb64 /lib/libc/stdlib/realpath.c | |
| parent | 098f04f5d1fdc1b2dc7d9eacdbab932a97861f24 (diff) | |
Notes
Diffstat (limited to 'lib/libc/stdlib/realpath.c')
| -rw-r--r-- | lib/libc/stdlib/realpath.c | 158 | 
1 files changed, 158 insertions, 0 deletions
| diff --git a/lib/libc/stdlib/realpath.c b/lib/libc/stdlib/realpath.c new file mode 100644 index 000000000000..28380d72183a --- /dev/null +++ b/lib/libc/stdlib/realpath.c @@ -0,0 +1,158 @@ +/* + * Copyright (c) 1994 + *	The Regents of the University of California.  All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + *    notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + *    notice, this list of conditions and the following disclaimer in the + *    documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + *    must display the following acknowledgement: + *	This product includes software developed by the University of + *	California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + *    may be used to endorse or promote products derived from this software + *    without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)realpath.c	8.1 (Berkeley) 2/16/94"; +#endif /* LIBC_SCCS and not lint */ + +#include <sys/param.h> +#include <sys/stat.h> + +#include <errno.h> +#include <fcntl.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +/* + * char *realpath(const char *path, char resolved_path[MAXPATHLEN]); + * + * Find the real name of path, by removing all ".", ".." and symlink + * components.  Returns (resolved) on success, or (NULL) on failure, + * in which case the path which caused trouble is left in (resolved). + */ +char * +realpath(path, resolved) +	const char *path; +	char *resolved; +{ +	struct stat sb; +	int fd, n, rootd, serrno; +	char *p, *q, wbuf[MAXPATHLEN]; + +	/* Save the starting point. */ +	if ((fd = open(".", O_RDONLY)) < 0) { +		(void)strcpy(resolved, "."); +		return (NULL); +	} + +	/* +	 * Find the dirname and basename from the path to be resolved. +	 * Change directory to the dirname component. +	 * lstat the basename part. +	 *     if it is a symlink, read in the value and loop. +	 *     if it is a directory, then change to that directory. +	 * get the current directory name and append the basename. +	 */ +	(void)strncpy(resolved, path, MAXPATHLEN - 1); +	resolved[MAXPATHLEN - 1] = '\0'; +loop: +	q = strrchr(resolved, '/'); +	if (q != NULL) { +		p = q + 1; +		if (q == resolved) +			q = "/"; +		else { +			do { +				--q; +			} while (q > resolved && *q == '/'); +			q[1] = '\0'; +			q = resolved; +		} +		if (chdir(q) < 0) +			goto err1; +	} else +		p = resolved; + +	/* Deal with the last component. */ +	if (*p != '\0' && lstat(p, &sb) == 0) { +		if (S_ISLNK(sb.st_mode)) { +			n = readlink(p, resolved, MAXPATHLEN); +			if (n < 0) +				goto err1; +			resolved[n] = '\0'; +			goto loop; +		} +		if (S_ISDIR(sb.st_mode)) { +			if (chdir(p) < 0) +				goto err1; +			p = ""; +		} +	} + +	/* +	 * Save the last component name and get the full pathname of +	 * the current directory. +	 */ +	(void)strcpy(wbuf, p); +	if (getcwd(resolved, MAXPATHLEN) == 0) +		goto err1; + +	/* +	 * Join the two strings together, ensuring that the right thing +	 * happens if the last component is empty, or the dirname is root. +	 */ +	if (resolved[0] == '/' && resolved[1] == '\0') +		rootd = 1; +	else +		rootd = 0; + +	if (*wbuf) { +		if (strlen(resolved) + strlen(wbuf) + rootd + 1 > MAXPATHLEN) { +			errno = ENAMETOOLONG; +			goto err1; +		} +		if (rootd == 0) +			(void)strcat(resolved, "/"); +		(void)strcat(resolved, wbuf); +	} + +	/* Go back to where we came from. */ +	if (fchdir(fd) < 0) { +		serrno = errno; +		goto err2; +	} + +	/* It's okay if the close fails, what's an fd more or less? */ +	(void)close(fd); +	return (resolved); + +err1:	serrno = errno; +	(void)fchdir(fd); +err2:	(void)close(fd); +	errno = serrno; +	return (NULL); +} | 
