diff options
| author | Konstantin Belousov <kib@FreeBSD.org> | 2010-04-20 10:16:44 +0000 | 
|---|---|---|
| committer | Konstantin Belousov <kib@FreeBSD.org> | 2010-04-20 10:16:44 +0000 | 
| commit | 9d79ec20fb18158492642c73fb8a17b531308a7d (patch) | |
| tree | 49cd6b92975d51b11b3034ce84d086a90b7f707b /lib/libc/stdlib/realpath.c | |
| parent | ee94f0a272922e3e5a9fa907e5e73497991b6fcf (diff) | |
Notes
Diffstat (limited to 'lib/libc/stdlib/realpath.c')
| -rw-r--r-- | lib/libc/stdlib/realpath.c | 54 | 
1 files changed, 49 insertions, 5 deletions
| diff --git a/lib/libc/stdlib/realpath.c b/lib/libc/stdlib/realpath.c index 3082f5f4b95a..31c93e677418 100644 --- a/lib/libc/stdlib/realpath.c +++ b/lib/libc/stdlib/realpath.c @@ -43,23 +43,37 @@ __FBSDID("$FreeBSD$");  #include "un-namespace.h"  /* - * char *realpath(const char *path, char resolved[PATH_MAX]); - *   * 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[PATH_MAX]) +realpath(const char * __restrict path, char * __restrict resolved)  {  	struct stat sb;  	char *p, *q, *s;  	size_t left_len, resolved_len;  	unsigned symlinks; -	int serrno, slen; +	int serrno, slen, m;  	char left[PATH_MAX], next_token[PATH_MAX], symlink[PATH_MAX]; +	if (path == NULL) { +		errno = EINVAL; +		return (NULL); +	} +	if (path[0] == '\0') { +		errno = ENOENT; +		return (NULL); +	}  	serrno = errno; +	if (resolved == NULL) { +		resolved = malloc(PATH_MAX); +		if (resolved == NULL) +			return (NULL); +		m = 1; +	} else +		m = 0; +  	symlinks = 0;  	if (path[0] == '/') {  		resolved[0] = '/'; @@ -71,12 +85,19 @@ realpath(const char *path, char resolved[PATH_MAX])  	} else {  		if (getcwd(resolved, PATH_MAX) == NULL) {  			strlcpy(resolved, ".", PATH_MAX); +			if (m) { +				serrno = errno; +				free(resolved); +				errno = serrno; +			}  			return (NULL);  		}  		resolved_len = strlen(resolved);  		left_len = strlcpy(left, path, sizeof(left));  	}  	if (left_len >= sizeof(left) || resolved_len >= PATH_MAX) { +		if (m) +			free(resolved);  		errno = ENAMETOOLONG;  		return (NULL);  	} @@ -92,6 +113,8 @@ realpath(const char *path, char resolved[PATH_MAX])  		p = strchr(left, '/');  		s = p ? p : left + left_len;  		if (s - left >= sizeof(next_token)) { +			if (m) +				free(resolved);  			errno = ENAMETOOLONG;  			return (NULL);  		} @@ -102,6 +125,8 @@ realpath(const char *path, char resolved[PATH_MAX])  			memmove(left, s + 1, left_len + 1);  		if (resolved[resolved_len - 1] != '/') {  			if (resolved_len + 1 >= PATH_MAX) { +				if (m) +					free(resolved);  				errno = ENAMETOOLONG;  				return (NULL);  			} @@ -133,6 +158,8 @@ realpath(const char *path, char resolved[PATH_MAX])  		 */  		resolved_len = strlcat(resolved, next_token, PATH_MAX);  		if (resolved_len >= PATH_MAX) { +			if (m) +				free(resolved);  			errno = ENAMETOOLONG;  			return (NULL);  		} @@ -141,16 +168,29 @@ realpath(const char *path, char resolved[PATH_MAX])  				errno = serrno;  				return (resolved);  			} +			if (m) { +				serrno = errno; +				free(resolved); +				errno = serrno; +			}  			return (NULL);  		}  		if (S_ISLNK(sb.st_mode)) {  			if (symlinks++ > MAXSYMLINKS) { +				if (m) +					free(resolved);  				errno = ELOOP;  				return (NULL);  			}  			slen = readlink(resolved, symlink, sizeof(symlink) - 1); -			if (slen < 0) +			if (slen < 0) { +				if (m) { +					serrno = errno; +					free(resolved); +					errno = serrno; +				}  				return (NULL); +			}  			symlink[slen] = '\0';  			if (symlink[0] == '/') {  				resolved[1] = 0; @@ -171,6 +211,8 @@ realpath(const char *path, char resolved[PATH_MAX])  			if (p != NULL) {  				if (symlink[slen - 1] != '/') {  					if (slen + 1 >= sizeof(symlink)) { +						if (m) +							free(resolved);  						errno = ENAMETOOLONG;  						return (NULL);  					} @@ -179,6 +221,8 @@ realpath(const char *path, char resolved[PATH_MAX])  				}  				left_len = strlcat(symlink, left, sizeof(left));  				if (left_len >= sizeof(left)) { +					if (m) +						free(resolved);  					errno = ENAMETOOLONG;  					return (NULL);  				} | 
