summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/git2/common.h13
-rw-r--r--src/refs.c45
-rw-r--r--src/refs.h3
-rw-r--r--src/settings.c5
4 files changed, 62 insertions, 4 deletions
diff --git a/include/git2/common.h b/include/git2/common.h
index 18abe46b3..02d263048 100644
--- a/include/git2/common.h
+++ b/include/git2/common.h
@@ -157,6 +157,7 @@ typedef enum {
GIT_OPT_SET_SSL_CERT_LOCATIONS,
GIT_OPT_SET_USER_AGENT,
GIT_OPT_ENABLE_STRICT_OBJECT_CREATION,
+ GIT_OPT_ENABLE_SYMBOLIC_REF_TARGET_VALIDATION,
GIT_OPT_SET_SSL_CIPHERS,
GIT_OPT_GET_USER_AGENT,
} git_libgit2_opt_t;
@@ -270,6 +271,18 @@ typedef enum {
* > example, when this is enabled, the parent(s) and tree inputs
* > will be validated when creating a new commit. This defaults
* > to disabled.
+ *
+ * * opts(GIT_OPT_ENABLE_SYMBOLIC_REF_TARGET_VALIDATION, int enabled)
+ *
+ * > Validate the target of a symbolic ref when creating it.
+ * > For example, 'foobar' is not a valid ref,
+ * > therefore 'foobar' is not a valid target
+ * > for a symbolic ref by default,
+ * > where as 'refs/heads/foobar' is.
+ * > Disabling this bypasses validation so that an arbitrary
+ * > strings such as 'foobar' can be used for a symbolic ref target.
+ * > This defaults to enabled.
+ *
* * opts(GIT_OPT_SET_SSL_CIPHERS, const char *ciphers)
*
* > Set the SSL ciphers use for HTTPS connections.
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) {
diff --git a/src/refs.h b/src/refs.h
index fda9532de..c4786ddb4 100644
--- a/src/refs.h
+++ b/src/refs.h
@@ -15,6 +15,8 @@
#include "buffer.h"
#include "oid.h"
+extern bool git_reference__enable_symbolic_ref_target_validation;
+
#define GIT_REFS_DIR "refs/"
#define GIT_REFS_HEADS_DIR GIT_REFS_DIR "heads/"
#define GIT_REFS_TAGS_DIR GIT_REFS_DIR "tags/"
@@ -53,6 +55,7 @@
#define GIT_REFS_STASH_FILE GIT_REFS_DIR GIT_STASH_FILE
#define GIT_REF_FORMAT__PRECOMPOSE_UNICODE (1u << 16)
+#define GIT_REF_VALIDATION_DISABLE (1u << 15)
#define GIT_REFNAME_MAX 1024
diff --git a/src/settings.c b/src/settings.c
index cb2317f74..1fcdce2ed 100644
--- a/src/settings.c
+++ b/src/settings.c
@@ -15,6 +15,7 @@
#include "cache.h"
#include "global.h"
#include "object.h"
+#include "refs.h"
void git_libgit2_version(int *major, int *minor, int *rev)
{
@@ -191,6 +192,10 @@ int git_libgit2_opts(int key, ...)
git_object__strict_input_validation = (va_arg(ap, int) != 0);
break;
+ case GIT_OPT_ENABLE_SYMBOLIC_REF_TARGET_VALIDATION:
+ git_reference__enable_symbolic_ref_target_validation = (va_arg(ap, int) != 0);
+ break;
+
case GIT_OPT_SET_SSL_CIPHERS:
#ifdef GIT_OPENSSL
{