@@ -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+
875904int 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
926941const char * prettify_refname (const char * name )
0 commit comments