Commit 6d9a6c5c by Nikolai Vladimirov

path: properly resolve relative paths

parent c46fe0c6
......@@ -646,12 +646,33 @@ int git_path_resolve_relative(git_buf *path, size_t ceiling)
/* do nothing with singleton dot */;
else if (len == 2 && from[0] == '.' && from[1] == '.') {
while (to > base && to[-1] == '/') to--;
while (to > base && to[-1] != '/') to--;
}
/* error out if trying to up one from a hard base */
if (to == base && ceiling != 0) {
giterr_set(GITERR_INVALID,
"Cannot strip root component off url");
return -1;
}
/* no more path segments to strip,
* use '../' as a new base path */
if (to == base) {
if (*next == '/')
len++;
else {
if (*next == '/')
if (to != from)
memmove(to, from, len);
to += len;
/* this is now the base, can't back up from a
* relative prefix */
base = to;
} else {
/* back up a path segment */
while (to > base && to[-1] == '/') to--;
while (to > base && to[-1] != '/') to--;
}
} else {
if (*next == '/' && *from != '/')
len++;
if (to != from)
......
......@@ -446,16 +446,15 @@ void test_core_path__14_apply_relative(void)
cl_git_pass(git_path_apply_relative(&p, "../../../../../.."));
cl_assert_equal_s("/this/", p.ptr);
cl_git_pass(git_path_apply_relative(&p, "../../../../../"));
cl_git_pass(git_path_apply_relative(&p, "../"));
cl_assert_equal_s("/", p.ptr);
cl_git_pass(git_path_apply_relative(&p, "../../../../.."));
cl_assert_equal_s("/", p.ptr);
cl_git_fail(git_path_apply_relative(&p, "../../.."));
cl_git_pass(git_buf_sets(&p, "d:/another/test"));
cl_git_pass(git_path_apply_relative(&p, "../../../../.."));
cl_git_pass(git_path_apply_relative(&p, "../.."));
cl_assert_equal_s("d:/", p.ptr);
cl_git_pass(git_path_apply_relative(&p, "from/here/to/../and/./back/."));
......@@ -473,8 +472,97 @@ void test_core_path__14_apply_relative(void)
cl_git_pass(git_path_apply_relative(&p, ".."));
cl_assert_equal_s("https://my.url.com/full/path/", p.ptr);
cl_git_pass(git_path_apply_relative(&p, "../../../../../"));
cl_git_pass(git_path_apply_relative(&p, "../../../"));
cl_assert_equal_s("https://", p.ptr);
cl_git_pass(git_buf_sets(&p, "../../this/is/relative"));
cl_git_pass(git_path_apply_relative(&p, "../../preserves/the/prefix"));
cl_assert_equal_s("../../this/preserves/the/prefix", p.ptr);
cl_git_pass(git_path_apply_relative(&p, "../../../../that"));
cl_assert_equal_s("../../that", p.ptr);
cl_git_pass(git_path_apply_relative(&p, "../there"));
cl_assert_equal_s("../../there", p.ptr);
git_buf_free(&p);
}
static inline void assert_resolve_relative(git_buf *buf, const char *expected, const char *path)
{
cl_git_pass(git_buf_sets(buf, path));
cl_git_pass(git_path_resolve_relative(buf, 0));
cl_assert_equal_s(expected, buf->ptr);
}
void test_core_path__15_resolve_relative(void)
{
git_buf buf = GIT_BUF_INIT;
assert_resolve_relative(&buf, "", "");
assert_resolve_relative(&buf, "", ".");
assert_resolve_relative(&buf, "", "./");
assert_resolve_relative(&buf, "..", "..");
assert_resolve_relative(&buf, "../", "../");
assert_resolve_relative(&buf, "..", "./..");
assert_resolve_relative(&buf, "../", "./../");
assert_resolve_relative(&buf, "../", "../.");
assert_resolve_relative(&buf, "../", ".././");
assert_resolve_relative(&buf, "../..", "../..");
assert_resolve_relative(&buf, "../../", "../../");
assert_resolve_relative(&buf, "/", "/");
assert_resolve_relative(&buf, "/", "/.");
assert_resolve_relative(&buf, "", "a/..");
assert_resolve_relative(&buf, "", "a/../");
assert_resolve_relative(&buf, "", "a/../.");
assert_resolve_relative(&buf, "/a", "/a");
assert_resolve_relative(&buf, "/a/", "/a/.");
assert_resolve_relative(&buf, "/", "/a/../");
assert_resolve_relative(&buf, "/", "/a/../.");
assert_resolve_relative(&buf, "/", "/a/.././");
assert_resolve_relative(&buf, "a", "a");
assert_resolve_relative(&buf, "a/", "a/");
assert_resolve_relative(&buf, "a/", "a/.");
assert_resolve_relative(&buf, "a/", "a/./");
assert_resolve_relative(&buf, "a/b", "a//b");
assert_resolve_relative(&buf, "a/b/c", "a/b/c");
assert_resolve_relative(&buf, "b/c", "./b/c");
assert_resolve_relative(&buf, "a/c", "a/./c");
assert_resolve_relative(&buf, "a/b/", "a/b/.");
assert_resolve_relative(&buf, "/a/b/c", "///a/b/c");
assert_resolve_relative(&buf, "/a/b/c", "//a/b/c");
assert_resolve_relative(&buf, "/", "////");
assert_resolve_relative(&buf, "/a", "///a");
assert_resolve_relative(&buf, "/", "///.");
assert_resolve_relative(&buf, "/", "///a/..");
assert_resolve_relative(&buf, "../../path", "../../test//../././path");
assert_resolve_relative(&buf, "../d", "a/b/../../../c/../d");
cl_git_pass(git_buf_sets(&buf, "/.."));
cl_git_fail(git_path_resolve_relative(&buf, 0));
cl_git_pass(git_buf_sets(&buf, "/./.."));
cl_git_fail(git_path_resolve_relative(&buf, 0));
cl_git_pass(git_buf_sets(&buf, "/.//.."));
cl_git_fail(git_path_resolve_relative(&buf, 0));
cl_git_pass(git_buf_sets(&buf, "/../."));
cl_git_fail(git_path_resolve_relative(&buf, 0));
cl_git_pass(git_buf_sets(&buf, "/../.././../a"));
cl_git_fail(git_path_resolve_relative(&buf, 0));
cl_git_pass(git_buf_sets(&buf, "////.."));
cl_git_fail(git_path_resolve_relative(&buf, 0));
git_buf_free(&buf);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment