@@ -34,7 +34,6 @@ struct git_attr {
3434 int maybe_real ;
3535 char name [FLEX_ARRAY ]; /* attribute name */
3636};
37- static int attr_nr ;
3837
3938/*
4039 * NEEDSWORK: maybe-real, maybe-macro are not property of
@@ -45,9 +44,6 @@ static int attr_nr;
4544 */
4645static int cannot_trust_maybe_real ;
4746
48- /* NEEDSWORK: This will become per git_attr_check */
49- static struct attr_check_item * check_all_attr ;
50-
5147const char * git_attr_name (const struct git_attr * attr )
5248{
5349 return attr -> name ;
@@ -143,6 +139,57 @@ static void attr_hashmap_add(struct attr_hashmap *map,
143139 hashmap_add (& map -> map , e );
144140}
145141
142+ struct all_attrs_item {
143+ const struct git_attr * attr ;
144+ const char * value ;
145+ };
146+
147+ /*
148+ * Reallocate and reinitialize the array of all attributes (which is used in
149+ * the attribute collection process) in 'check' based on the global dictionary
150+ * of attributes.
151+ */
152+ static void all_attrs_init (struct attr_hashmap * map , struct attr_check * check )
153+ {
154+ int i ;
155+
156+ hashmap_lock (map );
157+
158+ if (map -> map .size < check -> all_attrs_nr )
159+ die ("BUG: interned attributes shouldn't be deleted" );
160+
161+ /*
162+ * If the number of attributes in the global dictionary has increased
163+ * (or this attr_check instance doesn't have an initialized all_attrs
164+ * field), reallocate the provided attr_check instance's all_attrs
165+ * field and fill each entry with its corresponding git_attr.
166+ */
167+ if (map -> map .size != check -> all_attrs_nr ) {
168+ struct attr_hash_entry * e ;
169+ struct hashmap_iter iter ;
170+ hashmap_iter_init (& map -> map , & iter );
171+
172+ REALLOC_ARRAY (check -> all_attrs , map -> map .size );
173+ check -> all_attrs_nr = map -> map .size ;
174+
175+ while ((e = hashmap_iter_next (& iter ))) {
176+ const struct git_attr * a = e -> value ;
177+ check -> all_attrs [a -> attr_nr ].attr = a ;
178+ }
179+ }
180+
181+ hashmap_unlock (map );
182+
183+ /*
184+ * Re-initialize every entry in check->all_attrs.
185+ * This re-initialization can live outside of the locked region since
186+ * the attribute dictionary is no longer being accessed.
187+ */
188+ for (i = 0 ; i < check -> all_attrs_nr ; i ++ ) {
189+ check -> all_attrs [i ].value = ATTR__UNKNOWN ;
190+ }
191+ }
192+
146193static int attr_name_valid (const char * name , size_t namelen )
147194{
148195 /*
@@ -196,16 +243,6 @@ static struct git_attr *git_attr_internal(const char *name, int namelen)
196243
197244 attr_hashmap_add (& g_attr_hashmap , a -> name , namelen , a );
198245 assert (a -> attr_nr == (g_attr_hashmap .map .size - 1 ));
199-
200- /*
201- * NEEDSWORK: per git_attr_check check_all_attr
202- * will be initialized a lot more lazily, not
203- * like this, and not here.
204- */
205- REALLOC_ARRAY (check_all_attr , ++ attr_nr );
206- check_all_attr [a -> attr_nr ].attr = a ;
207- check_all_attr [a -> attr_nr ].value = ATTR__UNKNOWN ;
208- assert (a -> attr_nr == (attr_nr - 1 ));
209246 }
210247
211248 hashmap_unlock (& g_attr_hashmap );
@@ -513,6 +550,10 @@ void attr_check_clear(struct attr_check *check)
513550 check -> items = NULL ;
514551 check -> alloc = 0 ;
515552 check -> nr = 0 ;
553+
554+ free (check -> all_attrs );
555+ check -> all_attrs = NULL ;
556+ check -> all_attrs_nr = 0 ;
516557}
517558
518559void attr_check_free (struct attr_check * check )
@@ -860,16 +901,16 @@ static int path_matches(const char *pathname, int pathlen,
860901 pattern , prefix , pat -> patternlen , pat -> flags );
861902}
862903
863- static int macroexpand_one (int attr_nr , int rem );
904+ static int macroexpand_one (struct all_attrs_item * all_attrs , int nr , int rem );
864905
865- static int fill_one (const char * what , struct match_attr * a , int rem )
906+ static int fill_one (const char * what , struct all_attrs_item * all_attrs ,
907+ struct match_attr * a , int rem )
866908{
867- struct attr_check_item * check = check_all_attr ;
868909 int i ;
869910
870- for (i = a -> num_attr - 1 ; 0 < rem && 0 <= i ; i -- ) {
911+ for (i = a -> num_attr - 1 ; rem > 0 && i >= 0 ; i -- ) {
871912 struct git_attr * attr = a -> state [i ].attr ;
872- const char * * n = & (check [attr -> attr_nr ].value );
913+ const char * * n = & (all_attrs [attr -> attr_nr ].value );
873914 const char * v = a -> state [i ].setto ;
874915
875916 if (* n == ATTR__UNKNOWN ) {
@@ -878,14 +919,15 @@ static int fill_one(const char *what, struct match_attr *a, int rem)
878919 attr , v );
879920 * n = v ;
880921 rem -- ;
881- rem = macroexpand_one (attr -> attr_nr , rem );
922+ rem = macroexpand_one (all_attrs , attr -> attr_nr , rem );
882923 }
883924 }
884925 return rem ;
885926}
886927
887928static int fill (const char * path , int pathlen , int basename_offset ,
888- struct attr_stack * stk , int rem )
929+ struct attr_stack * stk , struct all_attrs_item * all_attrs ,
930+ int rem )
889931{
890932 int i ;
891933 const char * base = stk -> origin ? stk -> origin : "" ;
@@ -896,18 +938,18 @@ static int fill(const char *path, int pathlen, int basename_offset,
896938 continue ;
897939 if (path_matches (path , pathlen , basename_offset ,
898940 & a -> u .pat , base , stk -> originlen ))
899- rem = fill_one ("fill" , a , rem );
941+ rem = fill_one ("fill" , all_attrs , a , rem );
900942 }
901943 return rem ;
902944}
903945
904- static int macroexpand_one (int nr , int rem )
946+ static int macroexpand_one (struct all_attrs_item * all_attrs , int nr , int rem )
905947{
906948 struct attr_stack * stk ;
907949 int i ;
908950
909- if (check_all_attr [nr ].value != ATTR__TRUE ||
910- !check_all_attr [nr ].attr -> maybe_macro )
951+ if (all_attrs [nr ].value != ATTR__TRUE ||
952+ !all_attrs [nr ].attr -> maybe_macro )
911953 return rem ;
912954
913955 for (stk = attr_stack ; stk ; stk = stk -> prev ) {
@@ -916,17 +958,17 @@ static int macroexpand_one(int nr, int rem)
916958 if (!ma -> is_macro )
917959 continue ;
918960 if (ma -> u .attr -> attr_nr == nr )
919- return fill_one ("expand" , ma , rem );
961+ return fill_one ("expand" , all_attrs , ma , rem );
920962 }
921963 }
922964
923965 return rem ;
924966}
925967
926968/*
927- * Collect attributes for path into the array pointed to by
928- * check_all_attr. If num is non-zero, only attributes in check[] are
929- * collected. Otherwise all attributes are collected.
969+ * Collect attributes for path into the array pointed to by check->all_attrs.
970+ * If check->check_nr is non-zero, only attributes in check[] are collected.
971+ * Otherwise all attributes are collected.
930972 */
931973static void collect_some_attrs (const char * path , struct attr_check * check )
932974{
@@ -949,15 +991,15 @@ static void collect_some_attrs(const char *path, struct attr_check *check)
949991 }
950992
951993 prepare_attr_stack (path , dirlen );
952- for ( i = 0 ; i < attr_nr ; i ++ )
953- check_all_attr [ i ]. value = ATTR__UNKNOWN ;
994+ all_attrs_init ( & g_attr_hashmap , check );
995+
954996 if (check -> nr && !cannot_trust_maybe_real ) {
955997 rem = 0 ;
956998 for (i = 0 ; i < check -> nr ; i ++ ) {
957999 const struct git_attr * a = check -> items [i ].attr ;
9581000 if (!a -> maybe_real ) {
959- struct attr_check_item * c ;
960- c = check_all_attr + a -> attr_nr ;
1001+ struct all_attrs_item * c ;
1002+ c = check -> all_attrs + a -> attr_nr ;
9611003 c -> value = ATTR__UNSET ;
9621004 rem ++ ;
9631005 }
@@ -966,9 +1008,9 @@ static void collect_some_attrs(const char *path, struct attr_check *check)
9661008 return ;
9671009 }
9681010
969- rem = attr_nr ;
1011+ rem = check -> all_attrs_nr ;
9701012 for (stk = attr_stack ; 0 < rem && stk ; stk = stk -> prev )
971- rem = fill (path , pathlen , basename_offset , stk , rem );
1013+ rem = fill (path , pathlen , basename_offset , stk , check -> all_attrs , rem );
9721014}
9731015
9741016int git_check_attr (const char * path , struct attr_check * check )
@@ -978,7 +1020,8 @@ int git_check_attr(const char *path, struct attr_check *check)
9781020 collect_some_attrs (path , check );
9791021
9801022 for (i = 0 ; i < check -> nr ; i ++ ) {
981- const char * value = check_all_attr [check -> items [i ].attr -> attr_nr ].value ;
1023+ size_t n = check -> items [i ].attr -> attr_nr ;
1024+ const char * value = check -> all_attrs [n ].value ;
9821025 if (value == ATTR__UNKNOWN )
9831026 value = ATTR__UNSET ;
9841027 check -> items [i ].value = value ;
@@ -994,9 +1037,9 @@ void git_all_attrs(const char *path, struct attr_check *check)
9941037 attr_check_reset (check );
9951038 collect_some_attrs (path , check );
9961039
997- for (i = 0 ; i < attr_nr ; i ++ ) {
998- const char * name = check_all_attr [i ].attr -> name ;
999- const char * value = check_all_attr [i ].value ;
1040+ for (i = 0 ; i < check -> all_attrs_nr ; i ++ ) {
1041+ const char * name = check -> all_attrs [i ].attr -> name ;
1042+ const char * value = check -> all_attrs [i ].value ;
10001043 struct attr_check_item * item ;
10011044 if (value == ATTR__UNSET || value == ATTR__UNKNOWN )
10021045 continue ;
0 commit comments