mirror of
https://git.proxmox.com/git/libgit2
synced 2025-05-06 11:19:47 +00:00
Handle local file:/// paths on Windows
Windows can't handle a path like `/c:/foo`; when turning file:/// URIs into local paths, we must strip the leading slash.
This commit is contained in:
parent
356b891e3e
commit
529fd30d1f
40
src/clone.c
40
src/clone.c
@ -371,27 +371,30 @@ cleanup:
|
|||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
int git_clone__should_clone_local(const char *url, git_clone_local_t local)
|
int git_clone__should_clone_local(const char *url_or_path, git_clone_local_t local)
|
||||||
{
|
{
|
||||||
const char *path;
|
git_buf fromurl = GIT_BUF_INIT;
|
||||||
int is_url;
|
const char *path = url_or_path;
|
||||||
|
bool is_url, is_local;
|
||||||
|
|
||||||
if (local == GIT_CLONE_NO_LOCAL)
|
if (local == GIT_CLONE_NO_LOCAL)
|
||||||
return false;
|
return 0;
|
||||||
|
|
||||||
is_url = !git__prefixcmp(url, "file://");
|
if (is_url = git_path_is_local_file_url(url_or_path)) {
|
||||||
|
if (git_path_fromurl(&fromurl, url_or_path) < 0) {
|
||||||
|
is_local = -1;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
if (is_url && local != GIT_CLONE_LOCAL && local != GIT_CLONE_LOCAL_NO_LINKS )
|
path = fromurl.ptr;
|
||||||
return false;
|
}
|
||||||
|
|
||||||
path = url;
|
is_local = (!is_url || local != GIT_CLONE_LOCAL_AUTO) &&
|
||||||
if (is_url)
|
git_path_isdir(path);
|
||||||
path = url + strlen("file://");
|
|
||||||
|
|
||||||
if ((git_path_exists(path) && git_path_isdir(path)) && local != GIT_CLONE_NO_LOCAL)
|
done:
|
||||||
return true;
|
git_buf_free(&fromurl);
|
||||||
|
return is_local;
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int git_clone(
|
int git_clone(
|
||||||
@ -434,16 +437,19 @@ int git_clone(
|
|||||||
return error;
|
return error;
|
||||||
|
|
||||||
if (!(error = create_and_configure_origin(&origin, repo, url, &options))) {
|
if (!(error = create_and_configure_origin(&origin, repo, url, &options))) {
|
||||||
if (git_clone__should_clone_local(url, options.local)) {
|
int should_clone = git_clone__should_clone_local(url, options.local);
|
||||||
int link = options.local != GIT_CLONE_LOCAL_NO_LINKS;
|
int link = options.local != GIT_CLONE_LOCAL_NO_LINKS;
|
||||||
|
|
||||||
|
if (should_clone == 1)
|
||||||
error = clone_local_into(
|
error = clone_local_into(
|
||||||
repo, origin, &options.checkout_opts,
|
repo, origin, &options.checkout_opts,
|
||||||
options.checkout_branch, link, options.signature);
|
options.checkout_branch, link, options.signature);
|
||||||
} else {
|
else if (should_clone == 0)
|
||||||
error = clone_into(
|
error = clone_into(
|
||||||
repo, origin, &options.checkout_opts,
|
repo, origin, &options.checkout_opts,
|
||||||
options.checkout_branch, options.signature);
|
options.checkout_branch, options.signature);
|
||||||
}
|
else
|
||||||
|
error = -1;
|
||||||
|
|
||||||
git_remote_free(origin);
|
git_remote_free(origin);
|
||||||
}
|
}
|
||||||
|
56
src/path.c
56
src/path.c
@ -377,26 +377,33 @@ static int error_invalid_local_file_uri(const char *uri)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int local_file_url_prefixlen(const char *file_url)
|
||||||
|
{
|
||||||
|
int len = -1;
|
||||||
|
|
||||||
|
if (git__prefixcmp(file_url, "file://") == 0) {
|
||||||
|
if (file_url[7] == '/')
|
||||||
|
len = 8;
|
||||||
|
else if (git__prefixcmp(file_url + 7, "localhost/") == 0)
|
||||||
|
len = 17;
|
||||||
|
}
|
||||||
|
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool git_path_is_local_file_url(const char *file_url)
|
||||||
|
{
|
||||||
|
return (local_file_url_prefixlen(file_url) > 0);
|
||||||
|
}
|
||||||
|
|
||||||
int git_path_fromurl(git_buf *local_path_out, const char *file_url)
|
int git_path_fromurl(git_buf *local_path_out, const char *file_url)
|
||||||
{
|
{
|
||||||
int offset = 0, len;
|
int offset;
|
||||||
|
|
||||||
assert(local_path_out && file_url);
|
assert(local_path_out && file_url);
|
||||||
|
|
||||||
if (git__prefixcmp(file_url, "file://") != 0)
|
if ((offset = local_file_url_prefixlen(file_url)) < 0 ||
|
||||||
return error_invalid_local_file_uri(file_url);
|
file_url[offset] == '\0' || file_url[offset] == '/')
|
||||||
|
|
||||||
offset += 7;
|
|
||||||
len = (int)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 error_invalid_local_file_uri(file_url);
|
|
||||||
|
|
||||||
if (offset >= len || file_url[offset] == '/')
|
|
||||||
return error_invalid_local_file_uri(file_url);
|
return error_invalid_local_file_uri(file_url);
|
||||||
|
|
||||||
#ifndef GIT_WIN32
|
#ifndef GIT_WIN32
|
||||||
@ -404,7 +411,6 @@ int git_path_fromurl(git_buf *local_path_out, const char *file_url)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
git_buf_clear(local_path_out);
|
git_buf_clear(local_path_out);
|
||||||
|
|
||||||
return git__percent_decode(local_path_out, file_url + offset);
|
return git__percent_decode(local_path_out, file_url + offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1130,18 +1136,8 @@ int git_path_dirload_with_stat(
|
|||||||
|
|
||||||
int git_path_from_url_or_path(git_buf *local_path_out, const char *url_or_path)
|
int git_path_from_url_or_path(git_buf *local_path_out, const char *url_or_path)
|
||||||
{
|
{
|
||||||
int error;
|
if (git_path_is_local_file_url(url_or_path))
|
||||||
|
return git_path_fromurl(local_path_out, url_or_path);
|
||||||
/* If url_or_path begins with file:// treat it as a URL */
|
else
|
||||||
if (!git__prefixcmp(url_or_path, "file://")) {
|
return git_buf_sets(local_path_out, url_or_path);
|
||||||
if ((error = git_path_fromurl(local_path_out, url_or_path)) < 0) {
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
} else { /* We assume url_or_path is already a path */
|
|
||||||
if ((error = git_buf_sets(local_path_out, url_or_path)) < 0) {
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
@ -439,6 +439,7 @@ extern int git_path_iconv(git_path_iconv_t *ic, char **in, size_t *inlen);
|
|||||||
extern bool git_path_does_fs_decompose_unicode(const char *root);
|
extern bool git_path_does_fs_decompose_unicode(const char *root);
|
||||||
|
|
||||||
/* Used for paths to repositories on the filesystem */
|
/* Used for paths to repositories on the filesystem */
|
||||||
|
extern bool git_path_is_local_file_url(const char *file_url);
|
||||||
extern int git_path_from_url_or_path(git_buf *local_path_out, const char *url_or_path);
|
extern int git_path_from_url_or_path(git_buf *local_path_out, const char *url_or_path);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -7,25 +7,55 @@
|
|||||||
#include "posix.h"
|
#include "posix.h"
|
||||||
#include "fileops.h"
|
#include "fileops.h"
|
||||||
|
|
||||||
|
static int file_url(git_buf *buf, const char *host, const char *path)
|
||||||
|
{
|
||||||
|
if (path[0] == '/')
|
||||||
|
path++;
|
||||||
|
|
||||||
|
git_buf_clear(buf);
|
||||||
|
return git_buf_printf(buf, "file://%s/%s", host, path);
|
||||||
|
}
|
||||||
|
|
||||||
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;
|
||||||
const char *path;
|
|
||||||
|
|
||||||
/* we use a fixture path because it needs to exist for us to want to clone */
|
/* 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(file_url(&buf, "", path));
|
||||||
|
cl_assert_equal_i(0, git_clone__should_clone_local(buf.ptr, GIT_CLONE_LOCAL_AUTO));
|
||||||
|
cl_assert_equal_i(1, git_clone__should_clone_local(buf.ptr, GIT_CLONE_LOCAL));
|
||||||
|
cl_assert_equal_i(1, git_clone__should_clone_local(buf.ptr, GIT_CLONE_LOCAL_NO_LINKS));
|
||||||
|
cl_assert_equal_i(0, git_clone__should_clone_local(buf.ptr, GIT_CLONE_NO_LOCAL));
|
||||||
|
|
||||||
|
cl_git_pass(file_url(&buf, "localhost", path));
|
||||||
|
cl_assert_equal_i(0, git_clone__should_clone_local(buf.ptr, GIT_CLONE_LOCAL_AUTO));
|
||||||
|
cl_assert_equal_i(1, git_clone__should_clone_local(buf.ptr, GIT_CLONE_LOCAL));
|
||||||
|
cl_assert_equal_i(1, git_clone__should_clone_local(buf.ptr, GIT_CLONE_LOCAL_NO_LINKS));
|
||||||
|
cl_assert_equal_i(0, git_clone__should_clone_local(buf.ptr, GIT_CLONE_NO_LOCAL));
|
||||||
|
|
||||||
|
cl_git_pass(file_url(&buf, "other-host.mycompany.com", path));
|
||||||
|
cl_assert_equal_i(0, git_clone__should_clone_local(buf.ptr, GIT_CLONE_LOCAL_AUTO));
|
||||||
|
cl_assert_equal_i(0, git_clone__should_clone_local(buf.ptr, GIT_CLONE_LOCAL));
|
||||||
|
cl_assert_equal_i(0, git_clone__should_clone_local(buf.ptr, GIT_CLONE_LOCAL_NO_LINKS));
|
||||||
|
cl_assert_equal_i(0, git_clone__should_clone_local(buf.ptr, GIT_CLONE_NO_LOCAL));
|
||||||
|
|
||||||
|
/* Ensure that file:/// urls are percent decoded: .git == %2e%67%69%74 */
|
||||||
|
cl_git_pass(file_url(&buf, "", path));
|
||||||
|
git_buf_shorten(&buf, 4);
|
||||||
|
cl_git_pass(git_buf_puts(&buf, "%2e%67%69%74"));
|
||||||
|
cl_assert_equal_i(0, git_clone__should_clone_local(buf.ptr, GIT_CLONE_LOCAL_AUTO));
|
||||||
|
cl_assert_equal_i(1, git_clone__should_clone_local(buf.ptr, GIT_CLONE_LOCAL));
|
||||||
|
cl_assert_equal_i(1, git_clone__should_clone_local(buf.ptr, GIT_CLONE_LOCAL_NO_LINKS));
|
||||||
|
cl_assert_equal_i(0, git_clone__should_clone_local(buf.ptr, GIT_CLONE_NO_LOCAL));
|
||||||
|
|
||||||
|
cl_assert_equal_i(1, git_clone__should_clone_local(path, GIT_CLONE_LOCAL_AUTO));
|
||||||
|
cl_assert_equal_i(1, git_clone__should_clone_local(path, GIT_CLONE_LOCAL));
|
||||||
|
cl_assert_equal_i(1, git_clone__should_clone_local(path, GIT_CLONE_LOCAL_NO_LINKS));
|
||||||
|
cl_assert_equal_i(0, git_clone__should_clone_local(path, GIT_CLONE_NO_LOCAL));
|
||||||
|
|
||||||
cl_git_pass(git_buf_printf(&buf, "file://%s", cl_fixture("testrepo.git")));
|
|
||||||
cl_assert_equal_i(false, git_clone__should_clone_local(buf.ptr, GIT_CLONE_LOCAL_AUTO));
|
|
||||||
cl_assert_equal_i(true, git_clone__should_clone_local(buf.ptr, GIT_CLONE_LOCAL));
|
|
||||||
cl_assert_equal_i(true, git_clone__should_clone_local(buf.ptr, GIT_CLONE_LOCAL_NO_LINKS));
|
|
||||||
cl_assert_equal_i(false, git_clone__should_clone_local(buf.ptr, GIT_CLONE_NO_LOCAL));
|
|
||||||
git_buf_free(&buf);
|
git_buf_free(&buf);
|
||||||
|
|
||||||
path = cl_fixture("testrepo.git");
|
|
||||||
cl_assert_equal_i(true, git_clone__should_clone_local(path, GIT_CLONE_LOCAL_AUTO));
|
|
||||||
cl_assert_equal_i(true, git_clone__should_clone_local(path, GIT_CLONE_LOCAL));
|
|
||||||
cl_assert_equal_i(true, git_clone__should_clone_local(path, GIT_CLONE_LOCAL_NO_LINKS));
|
|
||||||
cl_assert_equal_i(false, git_clone__should_clone_local(path, GIT_CLONE_NO_LOCAL));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_clone_local__hardlinks(void)
|
void test_clone_local__hardlinks(void)
|
||||||
|
Loading…
Reference in New Issue
Block a user