summaryrefslogtreecommitdiff
path: root/src/refs.c
diff options
context:
space:
mode:
authorRichard Ipsum <richardipsum@fastmail.co.uk>2016-08-27 13:42:53 +0100
committerRichard Ipsum <richardipsum@fastmail.co.uk>2016-08-27 18:25:02 +0100
commit452bf57cbe665768810f2597aba50b9afc9509a7 (patch)
treec78160b18264df008d5cb35d9b1bf3d88033ab82 /src/refs.c
parent5671e81fdd68899b1646ae891b07a2c13d9faba7 (diff)
downloadlibgit2-452bf57cbe665768810f2597aba50b9afc9509a7.tar.gz
Make symbolic ref target validation optional
Introduce GIT_OPT_ENABLE_SYMBOLIC_REF_TARGET_VALIDATION option. Setting this option to 0 allows validation of a symbolic ref's target to be bypassed. This option is enabled by default. This mechanism is added primarily to address a discrepancy between git behaviour and libgit2 behaviour, whereby the former allows the symbolic ref target to carry an arbitrary string and the latter does not, so: $ git symbolic-ref refs/heads/foo bar $ cat .git/refs/heads/foo ref: bar where as attempting the same via libgit2 raises an error: The given reference name 'bar' is not valid this mechanism also allows those that might want to make use of git's more lenient treatment of symbolic ref targets to do so.
Diffstat (limited to 'src/refs.c')
-rw-r--r--src/refs.c45
1 files changed, 41 insertions, 4 deletions
diff --git a/src/refs.c b/src/refs.c
index bff443ac9..c77653da8 100644
--- a/src/refs.c
+++ b/src/refs.c
@@ -24,6 +24,8 @@
#include <git2/signature.h>
#include <git2/commit.h>
+bool git_reference__enable_symbolic_ref_target_validation = true;
+
GIT__USE_STRMAP
#define DEFAULT_NESTING_LEVEL 5
@@ -175,10 +177,11 @@ int git_reference_name_to_id(
return 0;
}
-static int reference_normalize_for_repo(
+static int reference__normalize_for_repo(
git_refname_t out,
git_repository *repo,
- const char *name)
+ const char *name,
+ bool validate)
{
int precompose;
unsigned int flags = GIT_REF_FORMAT_ALLOW_ONELEVEL;
@@ -187,9 +190,29 @@ static int reference_normalize_for_repo(
precompose)
flags |= GIT_REF_FORMAT__PRECOMPOSE_UNICODE;
+ if (!validate) {
+ flags |= GIT_REF_VALIDATION_DISABLE;
+ }
+
return git_reference_normalize_name(out, GIT_REFNAME_MAX, name, flags);
}
+static int reference_normalize_for_repo(
+ git_refname_t out,
+ git_repository *repo,
+ const char *name)
+{
+ return reference__normalize_for_repo(out, repo, name, true);
+}
+
+static int reference_normalize_for_repo_without_validation(
+ git_refname_t out,
+ git_repository *repo,
+ const char *name)
+{
+ return reference__normalize_for_repo(out, repo, name, false);
+}
+
int git_reference_lookup_resolved(
git_reference **ref_out,
git_repository *repo,
@@ -404,7 +427,13 @@ static int reference__create(
} else {
git_refname_t normalized_target;
- if ((error = reference_normalize_for_repo(normalized_target, repo, symbolic)) < 0)
+ if (git_reference__enable_symbolic_ref_target_validation) {
+ error = reference_normalize_for_repo(normalized_target, repo, symbolic);
+ } else {
+ error = reference_normalize_for_repo_without_validation(normalized_target, repo, symbolic);
+ }
+
+ if (error < 0)
return error;
ref = git_reference__alloc_symbolic(normalized, normalized_target);
@@ -876,6 +905,7 @@ int git_reference__normalize_name(
int segment_len, segments_count = 0, error = GIT_EINVALIDSPEC;
unsigned int process_flags;
bool normalize = (buf != NULL);
+ bool validate = (flags & GIT_REF_VALIDATION_DISABLE) == 0;
#ifdef GIT_USE_ICONV
git_path_iconv_t ic = GIT_PATH_ICONV_INIT;
@@ -886,7 +916,7 @@ int git_reference__normalize_name(
process_flags = flags;
current = (char *)name;
- if (*current == '/')
+ if (validate && *current == '/')
goto cleanup;
if (normalize)
@@ -902,6 +932,13 @@ int git_reference__normalize_name(
}
#endif
+ if (!validate) {
+ git_buf_sets(buf, current);
+
+ error = git_buf_oom(buf) ? -1 : 0;
+ goto cleanup;
+ }
+
while (true) {
segment_len = ensure_segment_validity(current);
if (segment_len < 0) {