diff options
Diffstat (limited to '20120831/realpath.c')
-rw-r--r-- | 20120831/realpath.c | 196 |
1 files changed, 196 insertions, 0 deletions
diff --git a/20120831/realpath.c b/20120831/realpath.c new file mode 100644 index 0000000..1ef2cd8 --- /dev/null +++ b/20120831/realpath.c @@ -0,0 +1,196 @@ +/* $Id: realpath.c,v 1.2 2010/04/21 17:47:49 sjg Exp $ */ +/* from: $NetBSD: getcwd.c,v 1.45 2007/10/26 19:48:14 christos Exp $ */ + +/* + * Copyright (c) 1989, 1991, 1993, 1995 + * 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. 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. + */ +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif +#ifndef HAVE_REALPATH + +#include <sys/cdefs.h> +#include <sys/param.h> +#include <sys/stat.h> + +#include <errno.h> +#ifdef HAVE_STDLIB_H +# include <stdlib.h> +#endif +#ifdef HAVE_STRING_H +# include <string.h> +#endif +#ifdef HAVE_UNISTD_H +# include <unistd.h> +#endif + +/* + * char *realpath(const char *path, char resolved[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(const char *path, char *resolved) +{ + struct stat sb; + int idx = 0, n, nlnk = 0; + const char *q; + char *p, wbuf[2][MAXPATHLEN]; + size_t len; + + if (!path || !resolved || path == resolved) + return (NULL); + + /* + * Build real path one by one with paying an attention to ., + * .. and symbolic link. + */ + + /* + * `p' is where we'll put a new component with prepending + * a delimiter. + */ + p = resolved; + + if (*path == 0) { + *p = 0; + errno = ENOENT; + return (NULL); + } + + /* If relative path, start from current working directory. */ + if (*path != '/') { + /* check for resolved pointer to appease coverity */ + if (resolved && getcwd(resolved, MAXPATHLEN) == NULL) { + p[0] = '.'; + p[1] = 0; + return (NULL); + } + len = strlen(resolved); + if (len > 1) + p += len; + } + +loop: + /* Skip any slash. */ + while (*path == '/') + path++; + + if (*path == 0) { + if (p == resolved) + *p++ = '/'; + *p = 0; + return (resolved); + } + + /* Find the end of this component. */ + q = path; + do + q++; + while (*q != '/' && *q != 0); + + /* Test . or .. */ + if (path[0] == '.') { + if (q - path == 1) { + path = q; + goto loop; + } + if (path[1] == '.' && q - path == 2) { + /* Trim the last component. */ + if (p != resolved) + while (*--p != '/') + ; + path = q; + goto loop; + } + } + + /* Append this component. */ + if (p - resolved + 1 + q - path + 1 > MAXPATHLEN) { + errno = ENAMETOOLONG; + if (p == resolved) + *p++ = '/'; + *p = 0; + return (NULL); + } + p[0] = '/'; + memcpy(&p[1], path, + /* LINTED We know q > path. */ + q - path); + p[1 + q - path] = 0; + + /* + * If this component is a symlink, toss it and prepend link + * target to unresolved path. + */ + if (lstat(resolved, &sb) == -1) { + return (NULL); + } + if (S_ISLNK(sb.st_mode)) { + if (nlnk++ >= MAXSYMLINKS) { + errno = ELOOP; + return (NULL); + } + n = readlink(resolved, wbuf[idx], sizeof(wbuf[0]) - 1); + if (n < 0) + return (NULL); + if (n == 0) { + errno = ENOENT; + return (NULL); + } + + /* Append unresolved path to link target and switch to it. */ + if (n + (len = strlen(q)) + 1 > sizeof(wbuf[0])) { + errno = ENAMETOOLONG; + return (NULL); + } + memcpy(&wbuf[idx][n], q, len + 1); + path = wbuf[idx]; + idx ^= 1; + + /* If absolute symlink, start from root. */ + if (*path == '/') + p = resolved; + goto loop; + } + if (*q == '/' && !S_ISDIR(sb.st_mode)) { + errno = ENOTDIR; + return (NULL); + } + + /* Advance both resolved and unresolved path. */ + p += 1 + q - path; + path = q; + goto loop; +} +#endif |