diff --git a/src/basic/fs-util.c b/src/basic/fs-util.c index e31fa2711a..8fe19ee4e4 100644 --- a/src/basic/fs-util.c +++ b/src/basic/fs-util.c @@ -723,6 +723,8 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags, return -errno; if (S_ISLNK(st.st_mode)) { + char *joined; + _cleanup_free_ char *destination = NULL; /* This is a symlink, in this case read the destination. But let's make sure we don't follow @@ -746,9 +748,6 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags, if (fd < 0) return -errno; - free_and_replace(buffer, destination); - - todo = buffer; free(done); /* Note that we do not revalidate the root, we take it as is. */ @@ -760,20 +759,18 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags, return -ENOMEM; } - } else { - char *joined; - - /* A relative destination. If so, this is what we'll prefix what's left to do with what - * we just read, and start the loop again, but remain in the current directory. */ - - joined = strjoin("/", destination, todo); - if (!joined) - return -ENOMEM; - - free(buffer); - todo = buffer = joined; } + /* Prefix what's left to do with what we just read, and start the loop again, + * but remain in the current directory. */ + + joined = strjoin("/", destination, todo); + if (!joined) + return -ENOMEM; + + free(buffer); + todo = buffer = joined; + continue; } diff --git a/src/test/test-fs-util.c b/src/test/test-fs-util.c index ae68587be9..4cb465d0d2 100644 --- a/src/test/test-fs-util.c +++ b/src/test/test-fs-util.c @@ -186,6 +186,13 @@ static void test_chase_symlinks(void) { r = chase_symlinks(p, NULL, CHASE_NONEXISTENT, &result); assert_se(r == -ENOENT); + p = strjoina(temp, "/target"); + q = strjoina(temp, "/top"); + assert_se(symlink(q, p) >= 0); + p = strjoina(temp, "/target/idontexist"); + r = chase_symlinks(p, NULL, 0, &result); + assert_se(r == -ENOENT); + assert_se(rm_rf(temp, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0); }