summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/stdlib.h4
-rw-r--r--libc/stdlib/realpath.c22
2 files changed, 9 insertions, 17 deletions
diff --git a/include/stdlib.h b/include/stdlib.h
index e462c1c93..536f81a1e 100644
--- a/include/stdlib.h
+++ b/include/stdlib.h
@@ -659,7 +659,6 @@ extern char *canonicalize_file_name (__const char *__name)
__THROW __nonnull ((1)) __wur;
#endif
-#if defined __USE_BSD || defined __USE_XOPEN_EXTENDED
/* Return the canonical absolute name of file NAME. If RESOLVED is
null, the result is malloc'd; otherwise, if the canonical name is
PATH_MAX chars or more, returns null with `errno' set to
@@ -667,8 +666,7 @@ extern char *canonicalize_file_name (__const char *__name)
returns the name in RESOLVED. */
/* we choose to handle __resolved==NULL as crash :) */
extern char *realpath (__const char *__restrict __name,
- char *__restrict __resolved) __THROW __wur __nonnull((2));
-#endif
+ char *__restrict __resolved) __THROW __wur;
/* Shorthand for type of comparison functions. */
diff --git a/libc/stdlib/realpath.c b/libc/stdlib/realpath.c
index 1a00c3112..80c25f098 100644
--- a/libc/stdlib/realpath.c
+++ b/libc/stdlib/realpath.c
@@ -36,19 +36,10 @@
#define MAX_READLINKS 32
-#ifdef __STDC__
char *realpath(const char *path, char got_path[])
-#else
-char *realpath(path, got_path)
-const char *path;
-char got_path[];
-#endif
{
char copy_path[PATH_MAX];
- /* use user supplied buffer directly - reduces stack usage */
- /* char got_path[PATH_MAX]; */
- char *max_path;
- char *new_path;
+ char *max_path, *new_path, *allocated_path;
size_t path_len;
int readlinks = 0;
#ifdef S_IFLNK
@@ -72,12 +63,13 @@ char got_path[];
/* Copy so that path is at the end of copy_path[] */
strcpy(copy_path + (PATH_MAX-1) - path_len, path);
path = copy_path + (PATH_MAX-1) - path_len;
+ allocated_path = got_path ? NULL : (got_path = malloc(PATH_MAX));
max_path = got_path + PATH_MAX - 2; /* points to last non-NUL char */
new_path = got_path;
if (*path != '/') {
/* If it's a relative pathname use getcwd for starters. */
if (!getcwd(new_path, PATH_MAX - 1))
- return NULL;
+ goto err;
new_path += strlen(new_path);
if (new_path[-1] != '/')
*new_path++ = '/';
@@ -114,6 +106,8 @@ char got_path[];
while (*path != '\0' && *path != '/') {
if (new_path > max_path) {
__set_errno(ENAMETOOLONG);
+ err:
+ free(allocated_path);
return NULL;
}
*new_path++ = *path++;
@@ -122,7 +116,7 @@ char got_path[];
/* Protect against infinite loops. */
if (readlinks++ > MAX_READLINKS) {
__set_errno(ELOOP);
- return NULL;
+ goto err;
}
path_len = strlen(path);
/* See if last (so far) pathname component is a symlink. */
@@ -133,13 +127,13 @@ char got_path[];
if (link_len < 0) {
/* EINVAL means the file exists but isn't a symlink. */
if (errno != EINVAL) {
- return NULL;
+ goto err;
}
} else {
/* Safe sex check. */
if (path_len + link_len >= PATH_MAX - 2) {
__set_errno(ENAMETOOLONG);
- return NULL;
+ goto err;
}
/* Note: readlink doesn't add the null byte. */
/* copy_path[link_len] = '\0'; - we don't need it too */