Commit 196f3b1a by Edward Thomson

Merge pull request #2619 from ethomson/remotes_with_unc

Remote paths: canonicalize UNC paths on Win32
parents 89244e7f 12f32d91
...@@ -114,10 +114,30 @@ static int get_check_cert(int *out, git_repository *repo) ...@@ -114,10 +114,30 @@ static int get_check_cert(int *out, git_repository *repo)
} }
#endif #endif
static int canonicalize_url(git_buf *out, const char *in)
{
const char *c;
#ifdef GIT_WIN32
/* Given a UNC path like \\server\path, we need to convert this
* to //server/path for compatibility with core git.
*/
if (in[0] == '\\' && in[1] == '\\' &&
(git__isalpha(in[2]) || git__isdigit(in[2]))) {
for (c = in; *c; c++)
git_buf_putc(out, *c == '\\' ? '/' : *c);
return git_buf_oom(out) ? -1 : 0;
}
#endif
return git_buf_puts(out, in);
}
static int create_internal(git_remote **out, git_repository *repo, const char *name, const char *url, const char *fetch) static int create_internal(git_remote **out, git_repository *repo, const char *name, const char *url, const char *fetch)
{ {
git_remote *remote; git_remote *remote;
git_buf fetchbuf = GIT_BUF_INIT; git_buf canonical_url = GIT_BUF_INIT, fetchbuf = GIT_BUF_INIT;
int error = -1; int error = -1;
/* name is optional */ /* name is optional */
...@@ -129,11 +149,11 @@ static int create_internal(git_remote **out, git_repository *repo, const char *n ...@@ -129,11 +149,11 @@ static int create_internal(git_remote **out, git_repository *repo, const char *n
remote->repo = repo; remote->repo = repo;
remote->update_fetchhead = 1; remote->update_fetchhead = 1;
if (git_vector_init(&remote->refs, 32, NULL) < 0) if (git_vector_init(&remote->refs, 32, NULL) < 0 ||
canonicalize_url(&canonical_url, url) < 0)
goto on_error; goto on_error;
remote->url = git__strdup(url); remote->url = git_buf_detach(&canonical_url);
GITERR_CHECK_ALLOC(remote->url);
if (name != NULL) { if (name != NULL) {
remote->name = git__strdup(name); remote->name = git__strdup(name);
...@@ -151,11 +171,13 @@ static int create_internal(git_remote **out, git_repository *repo, const char *n ...@@ -151,11 +171,13 @@ static int create_internal(git_remote **out, git_repository *repo, const char *n
*out = remote; *out = remote;
git_buf_free(&fetchbuf); git_buf_free(&fetchbuf);
git_buf_free(&canonical_url);
return 0; return 0;
on_error: on_error:
git_remote_free(remote); git_remote_free(remote);
git_buf_free(&fetchbuf); git_buf_free(&fetchbuf);
git_buf_free(&canonical_url);
return error; return error;
} }
......
...@@ -16,6 +16,40 @@ static int file_url(git_buf *buf, const char *host, const char *path) ...@@ -16,6 +16,40 @@ static int file_url(git_buf *buf, const char *host, const char *path)
return git_buf_printf(buf, "file://%s/%s", host, path); return git_buf_printf(buf, "file://%s/%s", host, path);
} }
static int git_style_unc_path(git_buf *buf, const char *host, const char *path)
{
git_buf_clear(buf);
if (host)
git_buf_printf(buf, "//%s/", host);
if (path[0] == '/')
path++;
if (isalpha(path[0]) && path[1] == ':' && path[2] == '/') {
git_buf_printf(buf, "%c$/", path[0]);
path += 3;
}
git_buf_puts(buf, path);
return git_buf_oom(buf) ? -1 : 0;
}
static int unc_path(git_buf *buf, const char *host, const char *path)
{
char *c;
if (git_style_unc_path(buf, host, path) < 0)
return -1;
for (c = buf->ptr; *c; c++)
if (*c == '/')
*c = '\\';
return 0;
}
void test_clone_local__should_clone_local(void) void test_clone_local__should_clone_local(void)
{ {
git_buf buf = GIT_BUF_INIT; git_buf buf = GIT_BUF_INIT;
...@@ -121,3 +155,57 @@ void test_clone_local__hardlinks(void) ...@@ -121,3 +155,57 @@ void test_clone_local__hardlinks(void)
cl_git_pass(git_futils_rmdir_r("./clone3.git", NULL, GIT_RMDIR_REMOVE_FILES)); cl_git_pass(git_futils_rmdir_r("./clone3.git", NULL, GIT_RMDIR_REMOVE_FILES));
cl_git_pass(git_futils_rmdir_r("./clone4.git", NULL, GIT_RMDIR_REMOVE_FILES)); cl_git_pass(git_futils_rmdir_r("./clone4.git", NULL, GIT_RMDIR_REMOVE_FILES));
} }
void test_clone_local__standard_unc_paths_are_written_git_style(void)
{
#ifdef GIT_WIN32
git_repository *repo;
git_remote *remote;
git_clone_options opts = GIT_CLONE_OPTIONS_INIT;
git_buf unc = GIT_BUF_INIT, git_unc = GIT_BUF_INIT;
/* we use a fixture path because it needs to exist for us to want to clone */
const char *path = cl_fixture("testrepo.git");
cl_git_pass(unc_path(&unc, "localhost", path));
cl_git_pass(git_style_unc_path(&git_unc, "localhost", path));
cl_git_pass(git_clone(&repo, unc.ptr, "./clone.git", &opts));
cl_git_pass(git_remote_load(&remote, repo, "origin"));
cl_assert_equal_s(git_unc.ptr, git_remote_url(remote));
git_remote_free(remote);
git_repository_free(repo);
git_buf_free(&unc);
git_buf_free(&git_unc);
cl_git_pass(git_futils_rmdir_r("./clone.git", NULL, GIT_RMDIR_REMOVE_FILES));
#endif
}
void test_clone_local__git_style_unc_paths(void)
{
#ifdef GIT_WIN32
git_repository *repo;
git_remote *remote;
git_clone_options opts = GIT_CLONE_OPTIONS_INIT;
git_buf git_unc = GIT_BUF_INIT;
/* we use a fixture path because it needs to exist for us to want to clone */
const char *path = cl_fixture("testrepo.git");
cl_git_pass(git_style_unc_path(&git_unc, "localhost", path));
cl_git_pass(git_clone(&repo, git_unc.ptr, "./clone.git", &opts));
cl_git_pass(git_remote_load(&remote, repo, "origin"));
cl_assert_equal_s(git_unc.ptr, git_remote_url(remote));
git_remote_free(remote);
git_repository_free(repo);
git_buf_free(&git_unc);
cl_git_pass(git_futils_rmdir_r("./clone.git", NULL, GIT_RMDIR_REMOVE_FILES));
#endif
}
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