summaryrefslogtreecommitdiffhomepage
path: root/libbb/xreadlink.c
diff options
context:
space:
mode:
Diffstat (limited to 'libbb/xreadlink.c')
-rw-r--r--libbb/xreadlink.c75
1 files changed, 45 insertions, 30 deletions
diff --git a/libbb/xreadlink.c b/libbb/xreadlink.c
index a18dd0748..2682f6975 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;