mirror of
https://git.proxmox.com/git/libgit2
synced 2025-05-07 19:43:37 +00:00
Merge pull request #2619 from ethomson/remotes_with_unc
Remote paths: canonicalize UNC paths on Win32
This commit is contained in:
commit
196f3b1a9f
30
src/remote.c
30
src/remote.c
@ -114,10 +114,30 @@ static int get_check_cert(int *out, git_repository *repo)
|
||||
}
|
||||
#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)
|
||||
{
|
||||
git_remote *remote;
|
||||
git_buf fetchbuf = GIT_BUF_INIT;
|
||||
git_buf canonical_url = GIT_BUF_INIT, fetchbuf = GIT_BUF_INIT;
|
||||
int error = -1;
|
||||
|
||||
/* name is optional */
|
||||
@ -129,11 +149,11 @@ static int create_internal(git_remote **out, git_repository *repo, const char *n
|
||||
remote->repo = repo;
|
||||
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;
|
||||
|
||||
remote->url = git__strdup(url);
|
||||
GITERR_CHECK_ALLOC(remote->url);
|
||||
remote->url = git_buf_detach(&canonical_url);
|
||||
|
||||
if (name != NULL) {
|
||||
remote->name = git__strdup(name);
|
||||
@ -151,11 +171,13 @@ static int create_internal(git_remote **out, git_repository *repo, const char *n
|
||||
|
||||
*out = remote;
|
||||
git_buf_free(&fetchbuf);
|
||||
git_buf_free(&canonical_url);
|
||||
return 0;
|
||||
|
||||
on_error:
|
||||
git_remote_free(remote);
|
||||
git_buf_free(&fetchbuf);
|
||||
git_buf_free(&canonical_url);
|
||||
return error;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
git_buf buf = GIT_BUF_INIT;
|
||||
@ -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("./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
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user