From 68f9d6b2833774c279964790eda97363225e09a7 Mon Sep 17 00:00:00 2001 From: Arthur Schreiber Date: Thu, 15 May 2014 22:44:50 +0200 Subject: [PATCH 1/4] Refs: Fix some issue when core.precomposeunicode = true. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This fixes two issues I found when core.precomposeunicode is enabled: * When creating a reference with a NFD string, the returned git_reference would return this NFD string as the reference’s name. But when looking up the reference later, the name would then be returned as NFC string. * Renaming a reference would not honor the core.precomposeunicode and apply no normalization to the new reference name. --- src/refs.c | 33 +++++++++------------------------ src/refs.h | 1 - 2 files changed, 9 insertions(+), 25 deletions(-) diff --git a/src/refs.c b/src/refs.c index 9428f617d..adbabb452 100644 --- a/src/refs.c +++ b/src/refs.c @@ -365,7 +365,7 @@ static int reference__create( if (ref_out) *ref_out = NULL; - error = git_reference__normalize_name_lax(normalized, sizeof(normalized), name); + error = reference_normalize_for_repo(normalized, sizeof(normalized), repo, name); if (error < 0) return error; @@ -388,15 +388,15 @@ static int reference__create( return -1; } - ref = git_reference__alloc(name, oid, NULL); + ref = git_reference__alloc(normalized, oid, NULL); } else { char normalized_target[GIT_REFNAME_MAX]; - if ((error = git_reference__normalize_name_lax( - normalized_target, sizeof(normalized_target), symbolic)) < 0) + if ((error = reference_normalize_for_repo( + normalized_target, sizeof(normalized_target), repo, symbolic)) < 0) return error; - ref = git_reference__alloc_symbolic(name, normalized_target); + ref = git_reference__alloc_symbolic(normalized, normalized_target); } GITERR_CHECK_ALLOC(ref); @@ -569,18 +569,14 @@ int git_reference_symbolic_set_target( static int reference__rename(git_reference **out, git_reference *ref, const char *new_name, int force, const git_signature *signature, const char *message) { - unsigned int normalization_flags; char normalized[GIT_REFNAME_MAX]; bool should_head_be_updated = false; int error = 0; assert(ref && new_name && signature); - normalization_flags = ref->type == GIT_REF_SYMBOLIC ? - GIT_REF_FORMAT_ALLOW_ONELEVEL : GIT_REF_FORMAT_NORMAL; - - if ((error = git_reference_normalize_name( - normalized, sizeof(normalized), new_name, normalization_flags)) < 0) + if ((error = reference_normalize_for_repo( + normalized, sizeof(normalized), git_reference_owner(ref), new_name)) < 0) return error; @@ -590,12 +586,12 @@ static int reference__rename(git_reference **out, git_reference *ref, const char should_head_be_updated = (error > 0); - if ((error = git_refdb_rename(out, ref->db, ref->name, new_name, force, signature, message)) < 0) + if ((error = git_refdb_rename(out, ref->db, ref->name, normalized, force, signature, message)) < 0) return error; /* Update HEAD it was pointing to the reference being renamed */ if (should_head_be_updated && - (error = git_repository_set_head(ref->db->repo, new_name, signature, message)) < 0) { + (error = git_repository_set_head(ref->db->repo, normalized, signature, message)) < 0) { giterr_set(GITERR_REFERENCE, "Failed to update HEAD after renaming reference"); return error; } @@ -1018,17 +1014,6 @@ cleanup: return error; } -int git_reference__normalize_name_lax( - char *buffer_out, - size_t out_size, - const char *name) -{ - return git_reference_normalize_name( - buffer_out, - out_size, - name, - GIT_REF_FORMAT_ALLOW_ONELEVEL); -} #define GIT_REF_TYPEMASK (GIT_REF_OID | GIT_REF_SYMBOLIC) int git_reference_cmp( diff --git a/src/refs.h b/src/refs.h index d57d67026..7337e2a48 100644 --- a/src/refs.h +++ b/src/refs.h @@ -66,7 +66,6 @@ struct git_reference { git_reference *git_reference__set_name(git_reference *ref, const char *name); -int git_reference__normalize_name_lax(char *buffer_out, size_t out_size, const char *name); int git_reference__normalize_name(git_buf *buf, const char *name, unsigned int flags); int git_reference__update_terminal(git_repository *repo, const char *ref_name, const git_oid *oid, const git_signature *signature, const char *log_message); int git_reference__is_valid_name(const char *refname, unsigned int flags); From 824f755f101525d60adb7a73b407880c4aaec950 Mon Sep 17 00:00:00 2001 From: Arthur Schreiber Date: Tue, 20 May 2014 17:31:53 +0200 Subject: [PATCH 2/4] Refs: Introduce `git_refname_t`. --- src/refs.c | 23 ++++++++++------------- src/refs.h | 2 ++ 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/src/refs.c b/src/refs.c index adbabb452..1603876da 100644 --- a/src/refs.c +++ b/src/refs.c @@ -159,8 +159,7 @@ int git_reference_name_to_id( } static int reference_normalize_for_repo( - char *out, - size_t out_size, + git_refname_t out, git_repository *repo, const char *name) { @@ -171,7 +170,7 @@ static int reference_normalize_for_repo( precompose) flags |= GIT_REF_FORMAT__PRECOMPOSE_UNICODE; - return git_reference_normalize_name(out, out_size, name, flags); + return git_reference_normalize_name(out, GIT_REFNAME_MAX, name, flags); } int git_reference_lookup_resolved( @@ -180,7 +179,7 @@ int git_reference_lookup_resolved( const char *name, int max_nesting) { - char scan_name[GIT_REFNAME_MAX]; + git_refname_t scan_name; git_ref_t scan_type; int error = 0, nesting; git_reference *ref = NULL; @@ -197,8 +196,7 @@ int git_reference_lookup_resolved( scan_type = GIT_REF_SYMBOLIC; - if ((error = reference_normalize_for_repo( - scan_name, sizeof(scan_name), repo, name)) < 0) + if ((error = reference_normalize_for_repo(scan_name, repo, name)) < 0) return error; if ((error = git_repository_refdb__weakptr(&refdb, repo)) < 0) @@ -354,7 +352,7 @@ static int reference__create( const git_oid *old_id, const char *old_target) { - char normalized[GIT_REFNAME_MAX]; + git_refname_t normalized; git_refdb *refdb; git_reference *ref = NULL; int error = 0; @@ -365,7 +363,7 @@ static int reference__create( if (ref_out) *ref_out = NULL; - error = reference_normalize_for_repo(normalized, sizeof(normalized), repo, name); + error = reference_normalize_for_repo(normalized, repo, name); if (error < 0) return error; @@ -390,10 +388,9 @@ static int reference__create( ref = git_reference__alloc(normalized, oid, NULL); } else { - char normalized_target[GIT_REFNAME_MAX]; + git_refname_t normalized_target; - if ((error = reference_normalize_for_repo( - normalized_target, sizeof(normalized_target), repo, symbolic)) < 0) + if ((error = reference_normalize_for_repo(normalized_target, repo, symbolic)) < 0) return error; ref = git_reference__alloc_symbolic(normalized, normalized_target); @@ -569,14 +566,14 @@ int git_reference_symbolic_set_target( static int reference__rename(git_reference **out, git_reference *ref, const char *new_name, int force, const git_signature *signature, const char *message) { - char normalized[GIT_REFNAME_MAX]; + git_refname_t normalized; bool should_head_be_updated = false; int error = 0; assert(ref && new_name && signature); if ((error = reference_normalize_for_repo( - normalized, sizeof(normalized), git_reference_owner(ref), new_name)) < 0) + normalized, git_reference_owner(ref), new_name)) < 0) return error; diff --git a/src/refs.h b/src/refs.h index 7337e2a48..f75a4bf7e 100644 --- a/src/refs.h +++ b/src/refs.h @@ -51,6 +51,8 @@ #define GIT_REFNAME_MAX 1024 +typedef char git_refname_t[GIT_REFNAME_MAX]; + struct git_reference { git_refdb *db; git_ref_t type; From 1a90b1e3f106139f75183ef21dd5b461d9d83f1d Mon Sep 17 00:00:00 2001 From: Arthur Schreiber Date: Fri, 30 May 2014 14:53:28 +0200 Subject: [PATCH 3/4] Refs: Add a unicode test for git_branch_move. This tests that decomposed branch names are correctly precomposed when passed to `git_branch_move` and `core.precomposeunicode` is enabled. --- tests/refs/branches/move.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/tests/refs/branches/move.c b/tests/refs/branches/move.c index 6c6dbbe21..f136b00d6 100644 --- a/tests/refs/branches/move.c +++ b/tests/refs/branches/move.c @@ -241,3 +241,20 @@ void test_refs_branches_move__default_reflog_message(void) git_reflog_free(log); git_signature_free(sig); } + +void test_refs_branches_move__can_move_with_unicode(void) +{ + git_reference *original_ref, *new_ref; + const char *new_branch_name = "\x41\xCC\x8A\x73\x74\x72\x6F\xCC\x88\x6D"; + + cl_git_pass(git_reference_lookup(&original_ref, repo, "refs/heads/br2")); + cl_git_pass(git_branch_move(&new_ref, original_ref, new_branch_name, 0, NULL, NULL)); + + if (cl_repo_get_bool(repo, "core.precomposeunicode")) + cl_assert_equal_s(GIT_REFS_HEADS_DIR "\xC3\x85\x73\x74\x72\xC3\xB6\x6D", git_reference_name(new_ref)); + else + cl_assert_equal_s(GIT_REFS_HEADS_DIR "\x41\xCC\x8A\x73\x74\x72\x6F\xCC\x88\x6D", git_reference_name(new_ref)); + + git_reference_free(original_ref); + git_reference_free(new_ref); +} From 9d6c3d2853901f2fba049ba80cadb71caa8535c1 Mon Sep 17 00:00:00 2001 From: Arthur Schreiber Date: Fri, 30 May 2014 15:15:54 +0200 Subject: [PATCH 4/4] Refs: Extend unicode test for branch creation. This adds another assertion to ensure that the reference name inside the git_reference struct returned by `git_branch_create` is returned as precomposed if `core.precomposeunicode` is enabled. --- tests/refs/branches/create.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/refs/branches/create.c b/tests/refs/branches/create.c index 864640ab3..3a4f33b6e 100644 --- a/tests/refs/branches/create.c +++ b/tests/refs/branches/create.c @@ -179,11 +179,14 @@ void test_refs_branches_create__can_create_branch_with_unicode(void) expected[0] = nfd; for (i = 0; i < ARRAY_SIZE(names); ++i) { + const char *name; cl_git_pass(git_branch_create( &branch, repo, names[i], target, 0, NULL, NULL)); cl_git_pass(git_oid_cmp( git_reference_target(branch), git_commit_id(target))); + cl_git_pass(git_branch_name(&name, branch)); + cl_assert_equal_s(expected[i], name); assert_branch_matches_name(expected[i], names[i]); if (fs_decompose_unicode && alt[i]) assert_branch_matches_name(expected[i], alt[i]);