@@ -1098,6 +1098,75 @@ int git_config_set(const char *key, const char *value)
10981098 return git_config_set_multivar (key , value , NULL , 0 );
10991099}
11001100
1101+ /*
1102+ * Auxiliary function to sanity-check and split the key into the section
1103+ * identifier and variable name.
1104+ *
1105+ * Returns 0 on success, -1 when there is an invalid character in the key and
1106+ * -2 if there is no section name in the key.
1107+ *
1108+ * store_key - pointer to char* which will hold a copy of the key with
1109+ * lowercase section and variable name
1110+ * baselen - pointer to int which will hold the length of the
1111+ * section + subsection part, can be NULL
1112+ */
1113+ int git_config_parse_key (const char * key , char * * store_key , int * baselen_ )
1114+ {
1115+ int i , dot , baselen ;
1116+ const char * last_dot = strrchr (key , '.' );
1117+
1118+ /*
1119+ * Since "key" actually contains the section name and the real
1120+ * key name separated by a dot, we have to know where the dot is.
1121+ */
1122+
1123+ if (last_dot == NULL || last_dot == key ) {
1124+ error ("key does not contain a section: %s" , key );
1125+ return -2 ;
1126+ }
1127+
1128+ if (!last_dot [1 ]) {
1129+ error ("key does not contain variable name: %s" , key );
1130+ return -2 ;
1131+ }
1132+
1133+ baselen = last_dot - key ;
1134+ if (baselen_ )
1135+ * baselen_ = baselen ;
1136+
1137+ /*
1138+ * Validate the key and while at it, lower case it for matching.
1139+ */
1140+ * store_key = xmalloc (strlen (key ) + 1 );
1141+
1142+ dot = 0 ;
1143+ for (i = 0 ; key [i ]; i ++ ) {
1144+ unsigned char c = key [i ];
1145+ if (c == '.' )
1146+ dot = 1 ;
1147+ /* Leave the extended basename untouched.. */
1148+ if (!dot || i > baselen ) {
1149+ if (!iskeychar (c ) ||
1150+ (i == baselen + 1 && !isalpha (c ))) {
1151+ error ("invalid key: %s" , key );
1152+ goto out_free_ret_1 ;
1153+ }
1154+ c = tolower (c );
1155+ } else if (c == '\n' ) {
1156+ error ("invalid key (newline): %s" , key );
1157+ goto out_free_ret_1 ;
1158+ }
1159+ (* store_key )[i ] = c ;
1160+ }
1161+ (* store_key )[i ] = 0 ;
1162+
1163+ return 0 ;
1164+
1165+ out_free_ret_1 :
1166+ free (* store_key );
1167+ return -1 ;
1168+ }
1169+
11011170/*
11021171 * If value==NULL, unset in (remove from) config,
11031172 * if value_regex!=NULL, disregard key/value pairs where value does not match.
@@ -1124,59 +1193,23 @@ int git_config_set(const char *key, const char *value)
11241193int git_config_set_multivar (const char * key , const char * value ,
11251194 const char * value_regex , int multi_replace )
11261195{
1127- int i , dot ;
11281196 int fd = -1 , in_fd ;
11291197 int ret ;
11301198 char * config_filename ;
11311199 struct lock_file * lock = NULL ;
1132- const char * last_dot = strrchr (key , '.' );
11331200
11341201 if (config_exclusive_filename )
11351202 config_filename = xstrdup (config_exclusive_filename );
11361203 else
11371204 config_filename = git_pathdup ("config" );
11381205
1139- /*
1140- * Since "key" actually contains the section name and the real
1141- * key name separated by a dot, we have to know where the dot is.
1142- */
1143-
1144- if (last_dot == NULL ) {
1145- error ("key does not contain a section: %s" , key );
1146- ret = 2 ;
1206+ /* parse-key returns negative; flip the sign to feed exit(3) */
1207+ ret = 0 - git_config_parse_key (key , & store .key , & store .baselen );
1208+ if (ret )
11471209 goto out_free ;
1148- }
1149- store .baselen = last_dot - key ;
11501210
11511211 store .multi_replace = multi_replace ;
11521212
1153- /*
1154- * Validate the key and while at it, lower case it for matching.
1155- */
1156- store .key = xmalloc (strlen (key ) + 1 );
1157- dot = 0 ;
1158- for (i = 0 ; key [i ]; i ++ ) {
1159- unsigned char c = key [i ];
1160- if (c == '.' )
1161- dot = 1 ;
1162- /* Leave the extended basename untouched.. */
1163- if (!dot || i > store .baselen ) {
1164- if (!iskeychar (c ) || (i == store .baselen + 1 && !isalpha (c ))) {
1165- error ("invalid key: %s" , key );
1166- free (store .key );
1167- ret = 1 ;
1168- goto out_free ;
1169- }
1170- c = tolower (c );
1171- } else if (c == '\n' ) {
1172- error ("invalid key (newline): %s" , key );
1173- free (store .key );
1174- ret = 1 ;
1175- goto out_free ;
1176- }
1177- store .key [i ] = c ;
1178- }
1179- store .key [i ] = 0 ;
11801213
11811214 /*
11821215 * The lock serves a purpose in addition to locking: the new
0 commit comments