diff options
Diffstat (limited to 'dist/realpath.c')
-rw-r--r-- | dist/realpath.c | 77 |
1 files changed, 48 insertions, 29 deletions
diff --git a/dist/realpath.c b/dist/realpath.c index 1ef2cd8..fbf0335 100644 --- a/dist/realpath.c +++ b/dist/realpath.c @@ -1,5 +1,5 @@ -/* $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 $ */ +/* $Id: realpath.c,v 1.3 2013/01/25 17:06:09 sjg Exp $ */ +/* from: $NetBSD: getcwd.c,v 1.53 2012/06/21 23:29:23 enami Exp $ */ /* * Copyright (c) 1989, 1991, 1993, 1995 @@ -52,24 +52,40 @@ # include <unistd.h> #endif +#ifndef __restrict +# define __restrict /* restrict */ +#endif + /* - * char *realpath(const char *path, char resolved[MAXPATHLEN]); + * char *realpath(const char *path, char *resolved); * * 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) +realpath(const char * __restrict path, char * __restrict resolved) { struct stat sb; - int idx = 0, n, nlnk = 0; + int idx = 0, nlnk = 0; const char *q; - char *p, wbuf[2][MAXPATHLEN]; + char *p, wbuf[2][MAXPATHLEN], *fres; size_t len; + ssize_t n; + + /* POSIX sez we must test for this */ + if (path == NULL) { + errno = EINVAL; + return NULL; + } + + if (resolved == NULL) { + fres = resolved = malloc(MAXPATHLEN); + if (resolved == NULL) + return NULL; + } else + fres = NULL; - if (!path || !resolved || path == resolved) - return (NULL); /* * Build real path one by one with paying an attention to ., @@ -82,10 +98,10 @@ realpath(const char *path, char *resolved) */ p = resolved; - if (*path == 0) { - *p = 0; + if (*path == '\0') { + *p = '\0'; errno = ENOENT; - return (NULL); + goto out; } /* If relative path, start from current working directory. */ @@ -93,8 +109,8 @@ realpath(const char *path, char *resolved) /* check for resolved pointer to appease coverity */ if (resolved && getcwd(resolved, MAXPATHLEN) == NULL) { p[0] = '.'; - p[1] = 0; - return (NULL); + p[1] = '\0'; + goto out; } len = strlen(resolved); if (len > 1) @@ -106,18 +122,18 @@ loop: while (*path == '/') path++; - if (*path == 0) { + if (*path == '\0') { if (p == resolved) *p++ = '/'; - *p = 0; - return (resolved); + *p = '\0'; + return resolved; } /* Find the end of this component. */ q = path; do q++; - while (*q != '/' && *q != 0); + while (*q != '/' && *q != '\0'); /* Test . or .. */ if (path[0] == '.') { @@ -129,7 +145,7 @@ loop: /* Trim the last component. */ if (p != resolved) while (*--p != '/') - ; + continue; path = q; goto loop; } @@ -140,39 +156,39 @@ loop: errno = ENAMETOOLONG; if (p == resolved) *p++ = '/'; - *p = 0; - return (NULL); + *p = '\0'; + goto out; } p[0] = '/'; memcpy(&p[1], path, /* LINTED We know q > path. */ q - path); - p[1 + q - path] = 0; + 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 (lstat(resolved, &sb) == -1) + goto out; + if (S_ISLNK(sb.st_mode)) { if (nlnk++ >= MAXSYMLINKS) { errno = ELOOP; - return (NULL); + goto out; } n = readlink(resolved, wbuf[idx], sizeof(wbuf[0]) - 1); if (n < 0) - return (NULL); + goto out; if (n == 0) { errno = ENOENT; - return (NULL); + goto out; } /* Append unresolved path to link target and switch to it. */ if (n + (len = strlen(q)) + 1 > sizeof(wbuf[0])) { errno = ENAMETOOLONG; - return (NULL); + goto out; } memcpy(&wbuf[idx][n], q, len + 1); path = wbuf[idx]; @@ -185,12 +201,15 @@ loop: } if (*q == '/' && !S_ISDIR(sb.st_mode)) { errno = ENOTDIR; - return (NULL); + goto out; } /* Advance both resolved and unresolved path. */ p += 1 + q - path; path = q; goto loop; +out: + free(fres); + return NULL; } #endif |