Skip to content

Commit 49295d4

Browse files
mhaggergitster
authored andcommitted
Refactor check_refname_format()
Among other things, extract a function check_refname_component(). Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu> Signed-off-by: Junio C Hamano <gitster@pobox.com>
1 parent 8d9c501 commit 49295d4

File tree

1 file changed

+55
-40
lines changed

1 file changed

+55
-40
lines changed

refs.c

Lines changed: 55 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -872,55 +872,70 @@ static inline int bad_ref_char(int ch)
872872
return 0;
873873
}
874874

875+
/*
876+
* Try to read one refname component from the front of ref. Return
877+
* the length of the component found, or -1 if the component is not
878+
* legal.
879+
*/
880+
static int check_refname_component(const char *ref)
881+
{
882+
const char *cp;
883+
char last = '\0';
884+
885+
for (cp = ref; ; cp++) {
886+
char ch = *cp;
887+
if (ch == '\0' || ch == '/')
888+
break;
889+
if (bad_ref_char(ch))
890+
return -1; /* Illegal character in refname. */
891+
if (last == '.' && ch == '.')
892+
return -1; /* Refname contains "..". */
893+
if (last == '@' && ch == '{')
894+
return -1; /* Refname contains "@{". */
895+
last = ch;
896+
}
897+
if (cp == ref)
898+
return -1; /* Component has zero length. */
899+
if (ref[0] == '.')
900+
return -1; /* Component starts with '.'. */
901+
return cp - ref;
902+
}
903+
875904
int check_refname_format(const char *ref, int flags)
876905
{
877-
int ch, level, last;
878-
const char *cp = ref;
906+
int component_len, component_count = 0;
879907

880-
level = 0;
881908
while (1) {
882-
while ((ch = *cp++) == '/')
883-
; /* tolerate duplicated slashes */
884-
if (!ch)
885-
/* should not end with slashes */
886-
return -1;
887-
888-
/* we are at the beginning of the path component */
889-
if (ch == '.')
890-
return -1;
891-
if (bad_ref_char(ch)) {
892-
if ((flags & REFNAME_REFSPEC_PATTERN) && ch == '*' &&
893-
(!*cp || *cp == '/'))
909+
while (*ref == '/')
910+
ref++; /* tolerate leading and repeated slashes */
911+
912+
/* We are at the start of a path component. */
913+
component_len = check_refname_component(ref);
914+
if (component_len < 0) {
915+
if ((flags & REFNAME_REFSPEC_PATTERN) &&
916+
ref[0] == '*' &&
917+
(ref[1] == '\0' || ref[1] == '/')) {
894918
/* Accept one wildcard as a full refname component. */
895919
flags &= ~REFNAME_REFSPEC_PATTERN;
896-
else
897-
return -1;
898-
}
899-
900-
last = ch;
901-
/* scan the rest of the path component */
902-
while ((ch = *cp++) != 0) {
903-
if (bad_ref_char(ch))
904-
return -1;
905-
if (ch == '/')
906-
break;
907-
if (last == '.' && ch == '.')
908-
return -1;
909-
if (last == '@' && ch == '{')
910-
return -1;
911-
last = ch;
912-
}
913-
level++;
914-
if (!ch) {
915-
if (ref <= cp - 2 && cp[-2] == '.')
916-
return -1;
917-
if (level < 2 && !(flags & REFNAME_ALLOW_ONELEVEL))
918-
return -1;
919-
if (has_extension(ref, ".lock"))
920+
component_len = 1;
921+
} else {
920922
return -1;
921-
return 0;
923+
}
922924
}
925+
component_count++;
926+
if (ref[component_len] == '\0')
927+
break;
928+
/* Skip to next component. */
929+
ref += component_len + 1;
923930
}
931+
932+
if (ref[component_len - 1] == '.')
933+
return -1; /* Refname ends with '.'. */
934+
if (component_len >= 5 && !memcmp(&ref[component_len - 5], ".lock", 5))
935+
return -1; /* Refname ends with ".lock". */
936+
if (!(flags & REFNAME_ALLOW_ONELEVEL) && component_count < 2)
937+
return -1; /* Refname has only one component. */
938+
return 0;
924939
}
925940

926941
const char *prettify_refname(const char *name)

0 commit comments

Comments
 (0)