Skip to content

Commit 8d3b39a

Browse files
author
Edward Thomson
committed
Merge branch 'pr/3912'
2 parents 0418d3b + 28d0ba0 commit 8d3b39a

File tree

4 files changed

+41
-6
lines changed

4 files changed

+41
-6
lines changed

include/git2/common.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@ typedef enum {
175175
GIT_OPT_SET_SSL_CERT_LOCATIONS,
176176
GIT_OPT_SET_USER_AGENT,
177177
GIT_OPT_ENABLE_STRICT_OBJECT_CREATION,
178+
GIT_OPT_ENABLE_STRICT_SYMBOLIC_REF_CREATION,
178179
GIT_OPT_SET_SSL_CIPHERS,
179180
GIT_OPT_GET_USER_AGENT,
180181
} git_libgit2_opt_t;
@@ -289,6 +290,15 @@ typedef enum {
289290
* > will be validated when creating a new commit. This defaults
290291
* > to enabled.
291292
*
293+
* * opts(GIT_OPT_ENABLE_STRICT_SYMBOLIC_REF_CREATION, int enabled)
294+
*
295+
* > Validate the target of a symbolic ref when creating it. For
296+
* > example, `foobar` is not a valid ref, therefore `foobar` is
297+
* > not a valid target for a symbolic ref by default, whereas
298+
* > `refs/heads/foobar` is. Disabling this bypasses validation
299+
* > so that an arbitrary strings such as `foobar` can be used
300+
* > for a symbolic ref target. This defaults to enabled.
301+
*
292302
* * opts(GIT_OPT_SET_SSL_CIPHERS, const char *ciphers)
293303
*
294304
* > Set the SSL ciphers use for HTTPS connections.

src/refs.c

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
#include <git2/signature.h>
2525
#include <git2/commit.h>
2626

27+
bool git_reference__enable_symbolic_ref_target_validation = true;
28+
2729
GIT__USE_STRMAP
2830

2931
#define DEFAULT_NESTING_LEVEL 5
@@ -178,7 +180,8 @@ int git_reference_name_to_id(
178180
static int reference_normalize_for_repo(
179181
git_refname_t out,
180182
git_repository *repo,
181-
const char *name)
183+
const char *name,
184+
bool validate)
182185
{
183186
int precompose;
184187
unsigned int flags = GIT_REF_FORMAT_ALLOW_ONELEVEL;
@@ -187,6 +190,9 @@ static int reference_normalize_for_repo(
187190
precompose)
188191
flags |= GIT_REF_FORMAT__PRECOMPOSE_UNICODE;
189192

193+
if (!validate)
194+
flags |= GIT_REF_FORMAT__VALIDATION_DISABLE;
195+
190196
return git_reference_normalize_name(out, GIT_REFNAME_MAX, name, flags);
191197
}
192198

@@ -213,7 +219,7 @@ int git_reference_lookup_resolved(
213219

214220
scan_type = GIT_REF_SYMBOLIC;
215221

216-
if ((error = reference_normalize_for_repo(scan_name, repo, name)) < 0)
222+
if ((error = reference_normalize_for_repo(scan_name, repo, name, true)) < 0)
217223
return error;
218224

219225
if ((error = git_repository_refdb__weakptr(&refdb, repo)) < 0)
@@ -383,7 +389,7 @@ static int reference__create(
383389
if (ref_out)
384390
*ref_out = NULL;
385391

386-
error = reference_normalize_for_repo(normalized, repo, name);
392+
error = reference_normalize_for_repo(normalized, repo, name, true);
387393
if (error < 0)
388394
return error;
389395

@@ -404,7 +410,10 @@ static int reference__create(
404410
} else {
405411
git_refname_t normalized_target;
406412

407-
if ((error = reference_normalize_for_repo(normalized_target, repo, symbolic)) < 0)
413+
error = reference_normalize_for_repo(normalized_target, repo,
414+
symbolic, git_reference__enable_symbolic_ref_target_validation);
415+
416+
if (error < 0)
408417
return error;
409418

410419
ref = git_reference__alloc_symbolic(normalized, normalized_target);
@@ -583,7 +592,7 @@ static int reference__rename(git_reference **out, git_reference *ref, const char
583592
assert(ref && new_name && signature);
584593

585594
if ((error = reference_normalize_for_repo(
586-
normalized, git_reference_owner(ref), new_name)) < 0)
595+
normalized, git_reference_owner(ref), new_name, true)) < 0)
587596
return error;
588597

589598

@@ -876,6 +885,7 @@ int git_reference__normalize_name(
876885
int segment_len, segments_count = 0, error = GIT_EINVALIDSPEC;
877886
unsigned int process_flags;
878887
bool normalize = (buf != NULL);
888+
bool validate = (flags & GIT_REF_FORMAT__VALIDATION_DISABLE) == 0;
879889

880890
#ifdef GIT_USE_ICONV
881891
git_path_iconv_t ic = GIT_PATH_ICONV_INIT;
@@ -886,7 +896,7 @@ int git_reference__normalize_name(
886896
process_flags = flags;
887897
current = (char *)name;
888898

889-
if (*current == '/')
899+
if (validate && *current == '/')
890900
goto cleanup;
891901

892902
if (normalize)
@@ -902,6 +912,13 @@ int git_reference__normalize_name(
902912
}
903913
#endif
904914

915+
if (!validate) {
916+
git_buf_sets(buf, current);
917+
918+
error = git_buf_oom(buf) ? -1 : 0;
919+
goto cleanup;
920+
}
921+
905922
while (true) {
906923
segment_len = ensure_segment_validity(current);
907924
if (segment_len < 0) {

src/refs.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
#include "buffer.h"
1616
#include "oid.h"
1717

18+
extern bool git_reference__enable_symbolic_ref_target_validation;
19+
1820
#define GIT_REFS_DIR "refs/"
1921
#define GIT_REFS_HEADS_DIR GIT_REFS_DIR "heads/"
2022
#define GIT_REFS_TAGS_DIR GIT_REFS_DIR "tags/"
@@ -53,6 +55,7 @@
5355
#define GIT_REFS_STASH_FILE GIT_REFS_DIR GIT_STASH_FILE
5456

5557
#define GIT_REF_FORMAT__PRECOMPOSE_UNICODE (1u << 16)
58+
#define GIT_REF_FORMAT__VALIDATION_DISABLE (1u << 15)
5659

5760
#define GIT_REFNAME_MAX 1024
5861

src/settings.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include "cache.h"
1616
#include "global.h"
1717
#include "object.h"
18+
#include "refs.h"
1819

1920
void git_libgit2_version(int *major, int *minor, int *rev)
2021
{
@@ -193,6 +194,10 @@ int git_libgit2_opts(int key, ...)
193194
git_object__strict_input_validation = (va_arg(ap, int) != 0);
194195
break;
195196

197+
case GIT_OPT_ENABLE_STRICT_SYMBOLIC_REF_CREATION:
198+
git_reference__enable_symbolic_ref_target_validation = (va_arg(ap, int) != 0);
199+
break;
200+
196201
case GIT_OPT_SET_SSL_CIPHERS:
197202
#ifdef GIT_OPENSSL
198203
{

0 commit comments

Comments
 (0)