From eb8de7476b4d3caeac518ff9af459c49cfd78e35 Mon Sep 17 00:00:00 2001 From: nulltoken Date: Wed, 28 Dec 2011 20:24:58 +0100 Subject: [PATCH 1/4] util: add git__fromhex() --- src/oid.c | 28 +++++----------------------- src/util.h | 23 +++++++++++++++++++++++ tests-clay/clay.h | 1 + tests-clay/clay_main.c | 13 +++++++++++-- tests-clay/core/hex.c | 22 ++++++++++++++++++++++ tests-clay/object/raw/chars.c | 15 ++------------- tests/t01-rawobj.c | 15 ++------------- 7 files changed, 66 insertions(+), 51 deletions(-) create mode 100644 tests-clay/core/hex.c diff --git a/src/oid.c b/src/oid.c index 4b3080430..61bf6da8a 100644 --- a/src/oid.c +++ b/src/oid.c @@ -11,24 +11,6 @@ #include #include -static signed char from_hex[] = { --1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 00 */ --1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 10 */ --1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 20 */ - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, /* 30 */ --1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 40 */ --1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 50 */ --1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 60 */ --1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 70 */ --1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 80 */ --1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 90 */ --1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* a0 */ --1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* b0 */ --1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* c0 */ --1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* d0 */ --1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* e0 */ --1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* f0 */ -}; static char to_hex[] = "0123456789abcdef"; int git_oid_fromstrn(git_oid *out, const char *str, size_t length) @@ -43,8 +25,8 @@ int git_oid_fromstrn(git_oid *out, const char *str, size_t length) length = GIT_OID_HEXSZ; for (p = 0; p < length - 1; p += 2) { - v = (from_hex[(unsigned char)str[p + 0]] << 4) - | from_hex[(unsigned char)str[p + 1]]; + v = (git__fromhex(str[p + 0]) << 4) + | git__fromhex(str[p + 1]); if (v < 0) return git__throw(GIT_ENOTOID, "Failed to generate sha1. Given string is not a valid sha1 hash"); @@ -53,7 +35,7 @@ int git_oid_fromstrn(git_oid *out, const char *str, size_t length) } if (length % 2) { - v = (from_hex[(unsigned char)str[p + 0]] << 4); + v = (git__fromhex(str[p + 0]) << 4); if (v < 0) return git__throw(GIT_ENOTOID, "Failed to generate sha1. Given string is not a valid sha1 hash"); @@ -346,7 +328,7 @@ int git_oid_shorten_add(git_oid_shorten *os, const char *text_oid) is_leaf = 0; for (i = 0; i < GIT_OID_HEXSZ; ++i) { - int c = from_hex[(int)text_oid[i]]; + int c = git__fromhex(text_oid[i]); trie_node *node; if (c == -1) @@ -360,7 +342,7 @@ int git_oid_shorten_add(git_oid_shorten *os, const char *text_oid) tail = node->tail; node->tail = NULL; - node = push_leaf(os, idx, from_hex[(int)tail[0]], &tail[1]); + node = push_leaf(os, idx, git__fromhex(tail[0]), &tail[1]); if (node == NULL) return GIT_ENOMEM; } diff --git a/src/util.h b/src/util.h index 4b1104b7b..ebc1ad08a 100644 --- a/src/util.h +++ b/src/util.h @@ -133,5 +133,28 @@ typedef void (*git_refcount_freeptr)(void *r); #define GIT_REFCOUNT_OWNER(r) (((git_refcount *)(r))->owner) +static signed char from_hex[] = { +-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 00 */ +-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 10 */ +-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 20 */ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, /* 30 */ +-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 40 */ +-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 50 */ +-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 60 */ +-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 70 */ +-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 80 */ +-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 90 */ +-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* a0 */ +-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* b0 */ +-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* c0 */ +-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* d0 */ +-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* e0 */ +-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* f0 */ +}; + +GIT_INLINE(int) git__fromhex(char h) +{ + return from_hex[(unsigned char) h]; +} #endif /* INCLUDE_util_h__ */ diff --git a/tests-clay/clay.h b/tests-clay/clay.h index c9fe4c166..c2b69c8a5 100644 --- a/tests-clay/clay.h +++ b/tests-clay/clay.h @@ -106,6 +106,7 @@ extern void test_core_filebuf__2(void); extern void test_core_filebuf__3(void); extern void test_core_filebuf__4(void); extern void test_core_filebuf__5(void); +extern void test_core_hex__fromhex(void); extern void test_core_oid__initialize(void); extern void test_core_oid__streq(void); extern void test_core_path__0_dirname(void); diff --git a/tests-clay/clay_main.c b/tests-clay/clay_main.c index 318e096b6..7df342cdf 100644 --- a/tests-clay/clay_main.c +++ b/tests-clay/clay_main.c @@ -167,6 +167,9 @@ static const struct clay_func _clay_cb_core_filebuf[] = { {"4", &test_core_filebuf__4}, {"5", &test_core_filebuf__5} }; +static const struct clay_func _clay_cb_core_hex[] = { + {"fromhex", &test_core_hex__fromhex} +}; static const struct clay_func _clay_cb_core_oid[] = { {"streq", &test_core_oid__streq} }; @@ -361,6 +364,12 @@ static const struct clay_suite _clay_suites[] = { {NULL, NULL}, {NULL, NULL}, _clay_cb_core_filebuf, 6 + }, + { + "core::hex", + {NULL, NULL}, + {NULL, NULL}, + _clay_cb_core_hex, 1 }, { "core::oid", @@ -538,8 +547,8 @@ static const struct clay_suite _clay_suites[] = { } }; -static size_t _clay_suite_count = 38; -static size_t _clay_callback_count = 122; +static size_t _clay_suite_count = 39; +static size_t _clay_callback_count = 123; /* Core test functions */ static void diff --git a/tests-clay/core/hex.c b/tests-clay/core/hex.c new file mode 100644 index 000000000..391a286be --- /dev/null +++ b/tests-clay/core/hex.c @@ -0,0 +1,22 @@ +#include "clay_libgit2.h" +#include "util.h" + +void test_core_hex__fromhex(void) +{ + /* Passing cases */ + cl_assert(git__fromhex('0') == 0x0); + cl_assert(git__fromhex('1') == 0x1); + cl_assert(git__fromhex('3') == 0x3); + cl_assert(git__fromhex('9') == 0x9); + cl_assert(git__fromhex('A') == 0xa); + cl_assert(git__fromhex('C') == 0xc); + cl_assert(git__fromhex('F') == 0xf); + cl_assert(git__fromhex('a') == 0xa); + cl_assert(git__fromhex('c') == 0xc); + cl_assert(git__fromhex('f') == 0xf); + + /* Failing cases */ + cl_assert(git__fromhex('g') == -1); + cl_assert(git__fromhex('z') == -1); + cl_assert(git__fromhex('X') == -1); +} diff --git a/tests-clay/object/raw/chars.c b/tests-clay/object/raw/chars.c index eba352b40..83bcbeb79 100644 --- a/tests-clay/object/raw/chars.c +++ b/tests-clay/object/raw/chars.c @@ -3,17 +3,6 @@ #include "odb.h" -static int from_hex(unsigned int i) -{ - if (i >= '0' && i <= '9') - return i - '0'; - if (i >= 'a' && i <= 'f') - return 10 + (i - 'a'); - if (i >= 'A' && i <= 'F') - return 10 + (i - 'A'); - return -1; -} - void test_object_raw_chars__find_invalid_chars_in_oid(void) { git_oid out; @@ -28,8 +17,8 @@ void test_object_raw_chars__find_invalid_chars_in_oid(void) for (i = 0; i < 256; i++) { in[38] = (char)i; - if (from_hex(i) >= 0) { - exp[19] = (unsigned char)(from_hex(i) << 4); + if (git__fromhex(i) >= 0) { + exp[19] = (unsigned char)(git__fromhex(i) << 4); cl_git_pass(git_oid_fromstr(&out, in)); cl_assert(memcmp(out.id, exp, sizeof(out.id)) == 0); } else { diff --git a/tests/t01-rawobj.c b/tests/t01-rawobj.c index 8b05f3394..7b9ca1ee1 100644 --- a/tests/t01-rawobj.c +++ b/tests/t01-rawobj.c @@ -52,17 +52,6 @@ BEGIN_TEST(oid2, "fail when parsing an invalid string as oid") must_fail(git_oid_fromstr(&out, "moo")); END_TEST -static int from_hex(unsigned int i) -{ - if (i >= '0' && i <= '9') - return i - '0'; - if (i >= 'a' && i <= 'f') - return 10 + (i - 'a'); - if (i >= 'A' && i <= 'F') - return 10 + (i - 'A'); - return -1; -} - BEGIN_TEST(oid3, "find all invalid characters when parsing an oid") git_oid out; unsigned char exp[] = { @@ -77,8 +66,8 @@ BEGIN_TEST(oid3, "find all invalid characters when parsing an oid") for (i = 0; i < 256; i++) { in[38] = (char)i; - if (from_hex(i) >= 0) { - exp[19] = (unsigned char)(from_hex(i) << 4); + if (git__fromhex(i) >= 0) { + exp[19] = (unsigned char)(git__fromhex(i) << 4); must_pass(git_oid_fromstr(&out, in)); must_be_true(memcmp(out.id, exp, sizeof(out.id)) == 0); } else { From 459e2dcd7deb379b9a013ab70aa70206fc17f16a Mon Sep 17 00:00:00 2001 From: nulltoken Date: Tue, 27 Dec 2011 11:18:57 +0100 Subject: [PATCH 2/4] path: add git__percent_decode() --- src/path.c | 35 +++++++++++++++++++++++++++++++++++ src/path.h | 2 ++ tests-clay/clay.h | 1 + tests-clay/clay_main.c | 7 ++++--- tests-clay/core/path.c | 24 ++++++++++++++++++++++++ 5 files changed, 66 insertions(+), 3 deletions(-) diff --git a/src/path.c b/src/path.c index e4b49f35d..bd62a3e4d 100644 --- a/src/path.c +++ b/src/path.c @@ -237,3 +237,38 @@ void git_path_string_to_dir(char* path, size_t size) } } +int git__percent_decode(git_buf *decoded_out, const char *input) +{ + int len, hi, lo, i, error = GIT_SUCCESS; + assert(decoded_out && input); + + len = strlen(input); + git_buf_clear(decoded_out); + + for(i = 0; i < len; i++) + { + char c = input[i]; + + if (c != '%') + goto append; + + if (i >= len - 2) + goto append; + + hi = git__fromhex(input[i + 1]); + lo = git__fromhex(input[i + 2]); + + if (hi < 0 || lo < 0) + goto append; + + c = (char)(hi << 4 | lo); + i += 2; + +append: + error = git_buf_putc(decoded_out, c); + if (error < GIT_SUCCESS) + return git__rethrow(error, "Failed to percent decode '%s'.", input); + } + + return error; +} diff --git a/src/path.h b/src/path.h index 0c8cc349c..6397feedf 100644 --- a/src/path.h +++ b/src/path.h @@ -74,4 +74,6 @@ GIT_INLINE(void) git_path_mkposix(char *path) # define git_path_mkposix(p) /* blank */ #endif +extern int git__percent_decode(git_buf *decoded_out, const char *input); + #endif diff --git a/tests-clay/clay.h b/tests-clay/clay.h index c2b69c8a5..b2b31bef7 100644 --- a/tests-clay/clay.h +++ b/tests-clay/clay.h @@ -116,6 +116,7 @@ extern void test_core_path__5_joins(void); extern void test_core_path__6_long_joins(void); extern void test_core_path__7_path_to_dir(void); extern void test_core_path__8_self_join(void); +extern void test_core_path__9_percent_decode(void); extern void test_core_rmdir__delete_recursive(void); extern void test_core_rmdir__fail_to_delete_non_empty_dir(void); extern void test_core_rmdir__initialize(void); diff --git a/tests-clay/clay_main.c b/tests-clay/clay_main.c index 7df342cdf..e6bb80440 100644 --- a/tests-clay/clay_main.c +++ b/tests-clay/clay_main.c @@ -180,7 +180,8 @@ static const struct clay_func _clay_cb_core_path[] = { {"5_joins", &test_core_path__5_joins}, {"6_long_joins", &test_core_path__6_long_joins}, {"7_path_to_dir", &test_core_path__7_path_to_dir}, - {"8_self_join", &test_core_path__8_self_join} + {"8_self_join", &test_core_path__8_self_join}, + {"9_percent_decode", &test_core_path__9_percent_decode} }; static const struct clay_func _clay_cb_core_rmdir[] = { {"delete_recursive", &test_core_rmdir__delete_recursive}, @@ -381,7 +382,7 @@ static const struct clay_suite _clay_suites[] = { "core::path", {NULL, NULL}, {NULL, NULL}, - _clay_cb_core_path, 7 + _clay_cb_core_path, 8 }, { "core::rmdir", @@ -548,7 +549,7 @@ static const struct clay_suite _clay_suites[] = { }; static size_t _clay_suite_count = 39; -static size_t _clay_callback_count = 123; +static size_t _clay_callback_count = 124; /* Core test functions */ static void diff --git a/tests-clay/core/path.c b/tests-clay/core/path.c index 49f85f085..8744247d2 100644 --- a/tests-clay/core/path.c +++ b/tests-clay/core/path.c @@ -273,3 +273,27 @@ void test_core_path__8_self_join(void) git_buf_free(&path); } + +static void check_percent_decoding(const char *expected_result, const char *input) +{ + git_buf buf = GIT_BUF_INIT; + + cl_git_pass(git__percent_decode(&buf, input)); + cl_assert_strequal(expected_result, git_buf_cstr(&buf)); + + git_buf_free(&buf); +} + +void test_core_path__9_percent_decode(void) +{ + check_percent_decoding("abcd", "abcd"); + check_percent_decoding("a2%", "a2%"); + check_percent_decoding("a2%3", "a2%3"); + check_percent_decoding("a2%%3", "a2%%3"); + check_percent_decoding("a2%3z", "a2%3z"); + check_percent_decoding("a,", "a%2c"); + check_percent_decoding("a21", "a2%31"); + check_percent_decoding("a2%1", "a2%%31"); + check_percent_decoding("a bc ", "a%20bc%20"); + check_percent_decoding("Vicent Mart" "\355", "Vicent%20Mart%ED"); +} From 2017a15d6ca7f756dcf036499a02e15393609c83 Mon Sep 17 00:00:00 2001 From: nulltoken Date: Tue, 27 Dec 2011 16:03:28 +0100 Subject: [PATCH 3/4] path: add git_path_fromurl() --- src/path.c | 35 +++++++++++++++++++++++++++ src/path.h | 1 + tests-clay/clay.h | 17 +++++++------ tests-clay/clay_main.c | 21 ++++++++-------- tests-clay/core/path.c | 55 ++++++++++++++++++++++++++++++++++++------ 5 files changed, 103 insertions(+), 26 deletions(-) diff --git a/src/path.c b/src/path.c index bd62a3e4d..53f0f3dc6 100644 --- a/src/path.c +++ b/src/path.c @@ -272,3 +272,38 @@ append: return error; } + +int git_path_fromurl(git_buf *local_path_out, const char *file_url) +{ + int error = GIT_SUCCESS, offset = 0, len; + + assert(local_path_out && file_url); + + if (git__prefixcmp(file_url, "file://") != 0) + return git__throw(GIT_EINVALIDPATH, "Parsing of '%s' failed. A file Uri is expected (ie. with 'file://' scheme).", file_url); + + offset += 7; + len = strlen(file_url); + + if (offset < len && file_url[offset] == '/') + offset++; + else if (offset < len && git__prefixcmp(file_url + offset, "localhost/") == 0) + offset += 10; + else + return git__throw(GIT_EINVALIDPATH, "Parsing of '%s' failed. A local file Uri is expected.", file_url); + + if (offset >= len || file_url[offset] == '/') + return git__throw(GIT_EINVALIDPATH, "Parsing of '%s' failed. Invalid file Uri format.", file_url); + +#ifndef _MSC_VER + offset--; /* A *nix absolute path starts with a forward slash */ +#endif + + git_buf_clear(local_path_out); + + error = git__percent_decode(local_path_out, file_url + offset); + if (error < GIT_SUCCESS) + return git__rethrow(error, "Parsing of '%s' failed.", file_url); + + return error; +} diff --git a/src/path.h b/src/path.h index 6397feedf..c308c5bd4 100644 --- a/src/path.h +++ b/src/path.h @@ -75,5 +75,6 @@ GIT_INLINE(void) git_path_mkposix(char *path) #endif extern int git__percent_decode(git_buf *decoded_out, const char *input); +extern int git_path_fromurl(git_buf *local_path_out, const char *file_url); #endif diff --git a/tests-clay/clay.h b/tests-clay/clay.h index b2b31bef7..8cbd8ddf8 100644 --- a/tests-clay/clay.h +++ b/tests-clay/clay.h @@ -109,14 +109,15 @@ extern void test_core_filebuf__5(void); extern void test_core_hex__fromhex(void); extern void test_core_oid__initialize(void); extern void test_core_oid__streq(void); -extern void test_core_path__0_dirname(void); -extern void test_core_path__1_basename(void); -extern void test_core_path__2_topdir(void); -extern void test_core_path__5_joins(void); -extern void test_core_path__6_long_joins(void); -extern void test_core_path__7_path_to_dir(void); -extern void test_core_path__8_self_join(void); -extern void test_core_path__9_percent_decode(void); +extern void test_core_path__00_dirname(void); +extern void test_core_path__01_basename(void); +extern void test_core_path__02_topdir(void); +extern void test_core_path__05_joins(void); +extern void test_core_path__06_long_joins(void); +extern void test_core_path__07_path_to_dir(void); +extern void test_core_path__08_self_join(void); +extern void test_core_path__09_percent_decode(void); +extern void test_core_path__10_fromurl(void); extern void test_core_rmdir__delete_recursive(void); extern void test_core_rmdir__fail_to_delete_non_empty_dir(void); extern void test_core_rmdir__initialize(void); diff --git a/tests-clay/clay_main.c b/tests-clay/clay_main.c index e6bb80440..ce2ffaff4 100644 --- a/tests-clay/clay_main.c +++ b/tests-clay/clay_main.c @@ -174,14 +174,15 @@ static const struct clay_func _clay_cb_core_oid[] = { {"streq", &test_core_oid__streq} }; static const struct clay_func _clay_cb_core_path[] = { - {"0_dirname", &test_core_path__0_dirname}, - {"1_basename", &test_core_path__1_basename}, - {"2_topdir", &test_core_path__2_topdir}, - {"5_joins", &test_core_path__5_joins}, - {"6_long_joins", &test_core_path__6_long_joins}, - {"7_path_to_dir", &test_core_path__7_path_to_dir}, - {"8_self_join", &test_core_path__8_self_join}, - {"9_percent_decode", &test_core_path__9_percent_decode} + {"00_dirname", &test_core_path__00_dirname}, + {"01_basename", &test_core_path__01_basename}, + {"02_topdir", &test_core_path__02_topdir}, + {"05_joins", &test_core_path__05_joins}, + {"06_long_joins", &test_core_path__06_long_joins}, + {"07_path_to_dir", &test_core_path__07_path_to_dir}, + {"08_self_join", &test_core_path__08_self_join}, + {"09_percent_decode", &test_core_path__09_percent_decode}, + {"10_fromurl", &test_core_path__10_fromurl} }; static const struct clay_func _clay_cb_core_rmdir[] = { {"delete_recursive", &test_core_rmdir__delete_recursive}, @@ -382,7 +383,7 @@ static const struct clay_suite _clay_suites[] = { "core::path", {NULL, NULL}, {NULL, NULL}, - _clay_cb_core_path, 8 + _clay_cb_core_path, 9 }, { "core::rmdir", @@ -549,7 +550,7 @@ static const struct clay_suite _clay_suites[] = { }; static size_t _clay_suite_count = 39; -static size_t _clay_callback_count = 124; +static size_t _clay_callback_count = 125; /* Core test functions */ static void diff --git a/tests-clay/core/path.c b/tests-clay/core/path.c index 8744247d2..bdebfb9c5 100644 --- a/tests-clay/core/path.c +++ b/tests-clay/core/path.c @@ -70,7 +70,7 @@ check_joinpath_n( /* get the dirname of a path */ -void test_core_path__0_dirname(void) +void test_core_path__00_dirname(void) { check_dirname(NULL, "."); check_dirname("", "."); @@ -90,7 +90,7 @@ void test_core_path__0_dirname(void) } /* get the base name of a path */ -void test_core_path__1_basename(void) +void test_core_path__01_basename(void) { check_basename(NULL, "."); check_basename("", "."); @@ -107,7 +107,7 @@ void test_core_path__1_basename(void) } /* get the latest component in a path */ -void test_core_path__2_topdir(void) +void test_core_path__02_topdir(void) { check_topdir(".git/", ".git/"); check_topdir("/.git/", ".git/"); @@ -124,7 +124,7 @@ void test_core_path__2_topdir(void) } /* properly join path components */ -void test_core_path__5_joins(void) +void test_core_path__05_joins(void) { check_joinpath("", "", ""); check_joinpath("", "a", "a"); @@ -159,7 +159,7 @@ void test_core_path__5_joins(void) } /* properly join path components for more than one path */ -void test_core_path__6_long_joins(void) +void test_core_path__06_long_joins(void) { check_joinpath_n("", "", "", "", ""); check_joinpath_n("", "a", "", "", "a/"); @@ -212,7 +212,7 @@ check_string_to_dir( } /* convert paths to dirs */ -void test_core_path__7_path_to_dir(void) +void test_core_path__07_path_to_dir(void) { check_path_to_dir("", ""); check_path_to_dir(".", "./"); @@ -240,7 +240,7 @@ void test_core_path__7_path_to_dir(void) } /* join path to itself */ -void test_core_path__8_self_join(void) +void test_core_path__08_self_join(void) { git_buf path = GIT_BUF_INIT; ssize_t asize = 0; @@ -284,7 +284,7 @@ static void check_percent_decoding(const char *expected_result, const char *inpu git_buf_free(&buf); } -void test_core_path__9_percent_decode(void) +void test_core_path__09_percent_decode(void) { check_percent_decoding("abcd", "abcd"); check_percent_decoding("a2%", "a2%"); @@ -297,3 +297,42 @@ void test_core_path__9_percent_decode(void) check_percent_decoding("a bc ", "a%20bc%20"); check_percent_decoding("Vicent Mart" "\355", "Vicent%20Mart%ED"); } + +static void check_fromurl(const char *expected_result, const char *input, int should_fail) +{ + git_buf buf = GIT_BUF_INIT; + + assert(should_fail || expected_result); + + if (!should_fail) { + cl_git_pass(git_path_fromurl(&buf, input)); + cl_assert_strequal(expected_result, git_buf_cstr(&buf)); + } else + cl_git_fail(git_path_fromurl(&buf, input)); + + git_buf_free(&buf); +} + +#ifdef _MSC_VER +#define ABS_PATH_MARKER "" +#else +#define ABS_PATH_MARKER "/" +#endif + +void test_core_path__10_fromurl(void) +{ + /* Failing cases */ + check_fromurl(NULL, "a", 1); + check_fromurl(NULL, "http:///c:/Temp%20folder/note.txt", 1); + check_fromurl(NULL, "file://c:/Temp%20folder/note.txt", 1); + check_fromurl(NULL, "file:////c:/Temp%20folder/note.txt", 1); + check_fromurl(NULL, "file:///", 1); + check_fromurl(NULL, "file:////", 1); + check_fromurl(NULL, "file://servername/c:/Temp%20folder/note.txt", 1); + + /* Passing cases */ + check_fromurl(ABS_PATH_MARKER "c:/Temp folder/note.txt", "file:///c:/Temp%20folder/note.txt", 0); + check_fromurl(ABS_PATH_MARKER "c:/Temp folder/note.txt", "file://localhost/c:/Temp%20folder/note.txt", 0); + check_fromurl(ABS_PATH_MARKER "c:/Temp+folder/note.txt", "file:///c:/Temp+folder/note.txt", 0); + check_fromurl(ABS_PATH_MARKER "a", "file:///a", 0); +} From e2580375dc76f46dce9963225449fcc872e86b0b Mon Sep 17 00:00:00 2001 From: nulltoken Date: Wed, 28 Dec 2011 11:36:18 +0100 Subject: [PATCH 4/4] transport: make local transport accept a file Uri containing percent-encoded characters This makes libgit2 compliant with the following scenario $ git ls-remote file:///d:/temp/dwm%20tinou 732d790b702db4b8985f5104fc44642654f6a6b6 HEAD 732d790b702db4b8985f5104fc44642654f6a6b6 refs/heads/master 732d790b702db4b8985f5104fc44642654f6a6b6 refs/remotes/origin/HEAD 732d790b702db4b8985f5104fc44642654f6a6b6 refs/remotes/origin/master $ mv "/d/temp/dwm tinou" /d/temp/dwm+tinou $ git ls-remote file:///d:/temp/dwm%20tinou fatal: 'd:/temp/dwm tinou' does not appear to be a git repository fatal: The remote end hung up unexpectedly $ git ls-remote file:///d:/temp/dwm+tinou 732d790b702db4b8985f5104fc44642654f6a6b6 HEAD 732d790b702db4b8985f5104fc44642654f6a6b6 refs/heads/master 732d790b702db4b8985f5104fc44642654f6a6b6 refs/remotes/origin/HEAD 732d790b702db4b8985f5104fc44642654f6a6b6 refs/remotes/origin/master --- src/transports/local.c | 25 ++++++++------- tests-clay/clay.h | 1 + tests-clay/clay_main.c | 7 +++-- tests-clay/network/remotelocal.c | 52 +++++++++++++++++++++++++++----- 4 files changed, 63 insertions(+), 22 deletions(-) diff --git a/src/transports/local.c b/src/transports/local.c index 2937da06d..a2135e73e 100644 --- a/src/transports/local.c +++ b/src/transports/local.c @@ -13,6 +13,8 @@ #include "refs.h" #include "transport.h" #include "posix.h" +#include "path.h" +#include "buffer.h" typedef struct { git_transport parent; @@ -148,7 +150,6 @@ static int local_ls(git_transport *transport, git_headlist_cb list_cb, void *pay return GIT_SUCCESS; } - /* * Try to open the url as a git directory. The direction doesn't * matter in this case because we're calulating the heads ourselves. @@ -159,24 +160,26 @@ static int local_connect(git_transport *transport, int GIT_UNUSED(direction)) int error; transport_local *t = (transport_local *) transport; const char *path; + git_buf buf = GIT_BUF_INIT; + GIT_UNUSED_ARG(direction); /* The repo layer doesn't want the prefix */ if (!git__prefixcmp(transport->url, "file://")) { - path = transport->url + strlen("file://"); + error = git_path_fromurl(&buf, transport->url); + if (error < GIT_SUCCESS) { + git_buf_free(&buf); + return git__rethrow(error, "Failed to parse remote path"); + } + path = git_buf_cstr(&buf); -#ifdef _MSC_VER - /* skip the leading slash on windows before the drive letter */ - if (*path != '/') - return git__throw(GIT_EINVALIDPATH, "Invalid local uri '%s'.", transport->url); - - path++; -#endif - - } else + } else /* We assume transport->url is already a path */ path = transport->url; error = git_repository_open(&repo, path); + + git_buf_free(&buf); + if (error < GIT_SUCCESS) return git__rethrow(error, "Failed to open remote"); diff --git a/tests-clay/clay.h b/tests-clay/clay.h index 8cbd8ddf8..1f40f3267 100644 --- a/tests-clay/clay.h +++ b/tests-clay/clay.h @@ -132,6 +132,7 @@ extern void test_index_rename__single_file(void); extern void test_network_remotelocal__cleanup(void); extern void test_network_remotelocal__initialize(void); extern void test_network_remotelocal__retrieve_advertised_references(void); +extern void test_network_remotelocal__retrieve_advertised_references_from_spaced_repository(void); extern void test_network_remotes__cleanup(void); extern void test_network_remotes__fnmatch(void); extern void test_network_remotes__initialize(void); diff --git a/tests-clay/clay_main.c b/tests-clay/clay_main.c index ce2ffaff4..c8247041d 100644 --- a/tests-clay/clay_main.c +++ b/tests-clay/clay_main.c @@ -205,7 +205,8 @@ static const struct clay_func _clay_cb_index_rename[] = { {"single_file", &test_index_rename__single_file} }; static const struct clay_func _clay_cb_network_remotelocal[] = { - {"retrieve_advertised_references", &test_network_remotelocal__retrieve_advertised_references} + {"retrieve_advertised_references", &test_network_remotelocal__retrieve_advertised_references}, + {"retrieve_advertised_references_from_spaced_repository", &test_network_remotelocal__retrieve_advertised_references_from_spaced_repository} }; static const struct clay_func _clay_cb_network_remotes[] = { {"fnmatch", &test_network_remotes__fnmatch}, @@ -419,7 +420,7 @@ static const struct clay_suite _clay_suites[] = { "network::remotelocal", {"initialize", &test_network_remotelocal__initialize}, {"cleanup", &test_network_remotelocal__cleanup}, - _clay_cb_network_remotelocal, 1 + _clay_cb_network_remotelocal, 2 }, { "network::remotes", @@ -550,7 +551,7 @@ static const struct clay_suite _clay_suites[] = { }; static size_t _clay_suite_count = 39; -static size_t _clay_callback_count = 125; +static size_t _clay_callback_count = 126; /* Core test functions */ static void diff --git a/tests-clay/network/remotelocal.c b/tests-clay/network/remotelocal.c index b9003e7ca..961c623a1 100644 --- a/tests-clay/network/remotelocal.c +++ b/tests-clay/network/remotelocal.c @@ -2,6 +2,7 @@ #include "transport.h" #include "buffer.h" #include "path.h" +#include "posix.h" static git_repository *repo; static git_buf file_path_buf = GIT_BUF_INIT; @@ -9,9 +10,11 @@ static git_remote *remote; static void build_local_file_url(git_buf *out, const char *fixture) { + const char *in_buf; + git_buf path_buf = GIT_BUF_INIT; - cl_git_pass(git_path_prettify_dir(&path_buf, cl_fixture(fixture), NULL)); + cl_git_pass(git_path_prettify_dir(&path_buf, fixture, NULL)); cl_git_pass(git_buf_puts(out, "file://")); #ifdef _MSC_VER @@ -27,21 +30,27 @@ static void build_local_file_url(git_buf *out, const char *fixture) cl_git_pass(git_buf_putc(out, '/')); #endif - cl_git_pass(git_buf_puts(out, git_buf_cstr(&path_buf))); + in_buf = git_buf_cstr(&path_buf); + + /* + * A very hacky Url encoding that only takes care of escaping the spaces + */ + while (*in_buf) { + if (*in_buf == ' ') + cl_git_pass(git_buf_puts(out, "%20")); + else + cl_git_pass(git_buf_putc(out, *in_buf)); + + in_buf++; + } git_buf_free(&path_buf); } void test_network_remotelocal__initialize(void) { - cl_fixture("remotelocal"); cl_git_pass(git_repository_init(&repo, "remotelocal/", 0)); cl_assert(repo != NULL); - - build_local_file_url(&file_path_buf, "testrepo.git"); - - cl_git_pass(git_remote_new(&remote, repo, git_buf_cstr(&file_path_buf), NULL)); - cl_git_pass(git_remote_connect(remote, GIT_DIR_FETCH)); } void test_network_remotelocal__cleanup(void) @@ -62,11 +71,38 @@ static int count_ref__cb(git_remote_head *head, void *payload) return GIT_SUCCESS; } +static void connect_to_local_repository(const char *local_repository) +{ + build_local_file_url(&file_path_buf, local_repository); + + cl_git_pass(git_remote_new(&remote, repo, git_buf_cstr(&file_path_buf), NULL)); + cl_git_pass(git_remote_connect(remote, GIT_DIR_FETCH)); + +} + void test_network_remotelocal__retrieve_advertised_references(void) { int how_many_refs = 0; + connect_to_local_repository(cl_fixture("testrepo.git")); + cl_git_pass(git_remote_ls(remote, &count_ref__cb, &how_many_refs)); cl_assert(how_many_refs == 12); /* 1 HEAD + 9 refs + 2 peeled tags */ } + +void test_network_remotelocal__retrieve_advertised_references_from_spaced_repository(void) +{ + int how_many_refs = 0; + + cl_fixture_sandbox("testrepo.git"); + cl_git_pass(p_rename("testrepo.git", "spaced testrepo.git")); + + connect_to_local_repository("spaced testrepo.git"); + + cl_git_pass(git_remote_ls(remote, &count_ref__cb, &how_many_refs)); + + cl_assert(how_many_refs == 12); /* 1 HEAD */ + + cl_fixture_cleanup("spaced testrepo.git"); +}