diff options
Diffstat (limited to 'libbb')
-rw-r--r-- | libbb/xreadlink.c | 75 |
1 files changed, 45 insertions, 30 deletions
diff --git a/libbb/xreadlink.c b/libbb/xreadlink.c index a18dd07..2682f69 100644 --- a/libbb/xreadlink.c +++ b/libbb/xreadlink.c @@ -123,7 +123,7 @@ char* FAST_FUNC xmalloc_realpath(const char *path) #endif } -char* FAST_FUNC xmalloc_realpath_coreutils(const char *path) +char* FAST_FUNC xmalloc_realpath_coreutils(char *path) { char *buf; @@ -137,32 +137,19 @@ char* FAST_FUNC xmalloc_realpath_coreutils(const char *path) * (the directory must exist). */ if (!buf && errno == ENOENT) { - char *last_slash = strrchr(path, '/'); - if (last_slash) { - *last_slash++ = '\0'; - buf = xmalloc_realpath(path); - if (buf) { - unsigned len = strlen(buf); - buf = xrealloc(buf, len + strlen(last_slash) + 2); - buf[len++] = '/'; - strcpy(buf + len, last_slash); - } - } else { - char *target = xmalloc_readlink(path); - if (target) { - char *cwd; - if (target[0] == '/') { - /* - * $ ln -s /bin/qwe symlink # note: /bin is a link to /usr/bin - * $ readlink -f symlink - * /usr/bin/qwe/target_does_not_exist - * $ realpath symlink - * /usr/bin/qwe/target_does_not_exist - */ - buf = xmalloc_realpath_coreutils(target); - free(target); - return buf; - } + char *target, c, *last_slash; + size_t i; + + target = xmalloc_readlink(path); + if (target) { + /* + * $ ln -s /bin/qwe symlink # note: /bin is a link to /usr/bin + * $ readlink -f symlink + * /usr/bin/qwe + * $ realpath symlink + * /usr/bin/qwe + */ + if (target[0] != '/') { /* * $ ln -s target_does_not_exist symlink * $ readlink -f symlink @@ -170,13 +157,41 @@ char* FAST_FUNC xmalloc_realpath_coreutils(const char *path) * $ realpath symlink * /CURDIR/target_does_not_exist */ - cwd = xrealloc_getcwd_or_warn(NULL); - buf = concat_path_file(cwd, target); + char *cwd = xrealloc_getcwd_or_warn(NULL); + char *tmp = concat_path_file(cwd, target); free(cwd); free(target); - return buf; + target = tmp; + } + buf = xmalloc_realpath_coreutils(target); + free(target); + return buf; + } + + /* ignore leading and trailing slashes */ + while (path[0] == '/' && path[1] == '/') + ++path; + i = strlen(path) - 1; + while (i > 0 && path[i] == '/') + i--; + c = path[i + 1]; + path[i + 1] = '\0'; + + last_slash = strrchr(path, '/'); + if (last_slash == path) + buf = xstrdup(path); + else if (last_slash) { + *last_slash = '\0'; + buf = xmalloc_realpath(path); + *last_slash++ = '/'; + if (buf) { + unsigned len = strlen(buf); + buf = xrealloc(buf, len + strlen(last_slash) + 2); + buf[len++] = '/'; + strcpy(buf + len, last_slash); } } + path[i + 1] = c; } return buf; |