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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202
diff --git a/src/transports/local.c b/src/transports/local.c
index 2937da0..a2135e7 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://");
-
-#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
+ 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);
+
+ } 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 8cbd8dd..1f40f32 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 ce2ffaf..c824704 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 b9003e7..961c623 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");
+}