@@ -29,6 +29,7 @@ git_attr_t git_attr_value(const char *attr)
2929
3030static int collect_attr_files (
3131 git_repository * repo ,
32+ git_attr_session * attr_session ,
3233 uint32_t flags ,
3334 const char * path ,
3435 git_vector * files );
@@ -57,7 +58,7 @@ int git_attr_get(
5758 if (git_attr_path__init (& path , pathname , git_repository_workdir (repo )) < 0 )
5859 return -1 ;
5960
60- if ((error = collect_attr_files (repo , flags , pathname , & files )) < 0 )
61+ if ((error = collect_attr_files (repo , NULL , flags , pathname , & files )) < 0 )
6162 goto cleanup ;
6263
6364 memset (& attr , 0 , sizeof (attr ));
@@ -90,9 +91,10 @@ typedef struct {
9091 git_attr_assignment * found ;
9192} attr_get_many_info ;
9293
93- int git_attr_get_many (
94+ int git_attr_get_many_with_session (
9495 const char * * values ,
9596 git_repository * repo ,
97+ git_attr_session * attr_session ,
9698 uint32_t flags ,
9799 const char * pathname ,
98100 size_t num_attr ,
@@ -115,7 +117,7 @@ int git_attr_get_many(
115117 if (git_attr_path__init (& path , pathname , git_repository_workdir (repo )) < 0 )
116118 return -1 ;
117119
118- if ((error = collect_attr_files (repo , flags , pathname , & files )) < 0 )
120+ if ((error = collect_attr_files (repo , attr_session , flags , pathname , & files )) < 0 )
119121 goto cleanup ;
120122
121123 info = git__calloc (num_attr , sizeof (attr_get_many_info ));
@@ -161,6 +163,17 @@ int git_attr_get_many(
161163 return error ;
162164}
163165
166+ int git_attr_get_many (
167+ const char * * values ,
168+ git_repository * repo ,
169+ uint32_t flags ,
170+ const char * pathname ,
171+ size_t num_attr ,
172+ const char * * names )
173+ {
174+ return git_attr_get_many_with_session (
175+ values , repo , NULL , flags , pathname , num_attr , names );
176+ }
164177
165178int git_attr_foreach (
166179 git_repository * repo ,
@@ -183,7 +196,7 @@ int git_attr_foreach(
183196 if (git_attr_path__init (& path , pathname , git_repository_workdir (repo )) < 0 )
184197 return -1 ;
185198
186- if ((error = collect_attr_files (repo , flags , pathname , & files )) < 0 ||
199+ if ((error = collect_attr_files (repo , NULL , flags , pathname , & files )) < 0 ||
187200 (error = git_strmap_alloc (& seen )) < 0 )
188201 goto cleanup ;
189202
@@ -219,6 +232,7 @@ int git_attr_foreach(
219232
220233static int preload_attr_file (
221234 git_repository * repo ,
235+ git_attr_session * attr_session ,
222236 git_attr_file_source source ,
223237 const char * base ,
224238 const char * file )
@@ -229,59 +243,101 @@ static int preload_attr_file(
229243 if (!file )
230244 return 0 ;
231245 if (!(error = git_attr_cache__get (
232- & preload , repo , source , base , file , git_attr_file__parse_buffer )))
246+ & preload , repo , attr_session , source , base , file , git_attr_file__parse_buffer )))
233247 git_attr_file__free (preload );
234248
235249 return error ;
236250}
237251
238- static int attr_setup (git_repository * repo )
252+ static int system_attr_file (
253+ git_buf * out ,
254+ git_attr_session * attr_session )
255+ {
256+ int error ;
257+
258+ if (!attr_session ) {
259+ error = git_sysdir_find_system_file (out , GIT_ATTR_FILE_SYSTEM );
260+
261+ if (error == GIT_ENOTFOUND )
262+ giterr_clear ();
263+
264+ return error ;
265+ }
266+
267+ if (!attr_session -> init_sysdir ) {
268+ error = git_sysdir_find_system_file (& attr_session -> sysdir , GIT_ATTR_FILE_SYSTEM );
269+
270+ if (error == GIT_ENOTFOUND )
271+ giterr_clear ();
272+ else if (error )
273+ return error ;
274+
275+ attr_session -> init_sysdir = 1 ;
276+ }
277+
278+ if (attr_session -> sysdir .size == 0 )
279+ return GIT_ENOTFOUND ;
280+
281+ /* We can safely provide a git_buf with no allocation (asize == 0) to
282+ * a consumer. This allows them to treat this as a regular `git_buf`,
283+ * but their call to `git_buf_free` will not attempt to free it.
284+ */
285+ out -> ptr = attr_session -> sysdir .ptr ;
286+ out -> size = attr_session -> sysdir .size ;
287+ out -> asize = 0 ;
288+ return 0 ;
289+ }
290+
291+ static int attr_setup (git_repository * repo , git_attr_session * attr_session )
239292{
240293 int error = 0 ;
241294 const char * workdir = git_repository_workdir (repo );
242295 git_index * idx = NULL ;
243296 git_buf sys = GIT_BUF_INIT ;
244297
298+ if (attr_session && attr_session -> init_setup )
299+ return 0 ;
300+
245301 if ((error = git_attr_cache__init (repo )) < 0 )
246302 return error ;
247303
248304 /* preload attribute files that could contain macros so the
249305 * definitions will be available for later file parsing
250306 */
251307
252- if (!(error = git_sysdir_find_system_file (& sys , GIT_ATTR_FILE_SYSTEM ))) {
308+ error = system_attr_file (& sys , attr_session );
309+
310+ if (error == 0 )
253311 error = preload_attr_file (
254- repo , GIT_ATTR_FILE__FROM_FILE , NULL , sys .ptr );
255- git_buf_free (& sys );
256- }
257- if (error < 0 ) {
258- if (error == GIT_ENOTFOUND ) {
259- giterr_clear ();
260- error = 0 ;
261- } else
262- return error ;
263- }
312+ repo , attr_session , GIT_ATTR_FILE__FROM_FILE , NULL , sys .ptr );
313+ else if (error != GIT_ENOTFOUND )
314+ return error ;
315+
316+ git_buf_free (& sys );
264317
265318 if ((error = preload_attr_file (
266- repo , GIT_ATTR_FILE__FROM_FILE ,
319+ repo , attr_session , GIT_ATTR_FILE__FROM_FILE ,
267320 NULL , git_repository_attr_cache (repo )-> cfg_attr_file )) < 0 )
268321 return error ;
269322
270323 if ((error = preload_attr_file (
271- repo , GIT_ATTR_FILE__FROM_FILE ,
324+ repo , attr_session , GIT_ATTR_FILE__FROM_FILE ,
272325 git_repository_path (repo ), GIT_ATTR_FILE_INREPO )) < 0 )
273326 return error ;
274327
275328 if (workdir != NULL &&
276329 (error = preload_attr_file (
277- repo , GIT_ATTR_FILE__FROM_FILE , workdir , GIT_ATTR_FILE )) < 0 )
330+ repo , attr_session , GIT_ATTR_FILE__FROM_FILE , workdir , GIT_ATTR_FILE )) < 0 )
278331 return error ;
279332
280333 if ((error = git_repository_index__weakptr (& idx , repo )) < 0 ||
281334 (error = preload_attr_file (
282- repo , GIT_ATTR_FILE__FROM_INDEX , NULL , GIT_ATTR_FILE )) < 0 )
335+ repo , attr_session , GIT_ATTR_FILE__FROM_INDEX , NULL , GIT_ATTR_FILE )) < 0 )
283336 return error ;
284337
338+ if (attr_session )
339+ attr_session -> init_setup = 1 ;
340+
285341 return error ;
286342}
287343
@@ -321,6 +377,7 @@ int git_attr_add_macro(
321377
322378typedef struct {
323379 git_repository * repo ;
380+ git_attr_session * attr_session ;
324381 uint32_t flags ;
325382 const char * workdir ;
326383 git_index * index ;
@@ -356,6 +413,7 @@ static int attr_decide_sources(
356413
357414static int push_attr_file (
358415 git_repository * repo ,
416+ git_attr_session * attr_session ,
359417 git_vector * list ,
360418 git_attr_file_source source ,
361419 const char * base ,
@@ -364,8 +422,9 @@ static int push_attr_file(
364422 int error = 0 ;
365423 git_attr_file * file = NULL ;
366424
367- error = git_attr_cache__get (
368- & file , repo , source , base , filename , git_attr_file__parse_buffer );
425+ error = git_attr_cache__get (& file , repo , attr_session ,
426+ source , base , filename , git_attr_file__parse_buffer );
427+
369428 if (error < 0 )
370429 return error ;
371430
@@ -387,8 +446,8 @@ static int push_one_attr(void *ref, const char *path)
387446 info -> flags , info -> workdir != NULL , info -> index != NULL , src );
388447
389448 for (i = 0 ; !error && i < n_src ; ++ i )
390- error = push_attr_file (
391- info -> repo , info -> files , src [i ], path , GIT_ATTR_FILE );
449+ error = push_attr_file (info -> repo , info -> attr_session ,
450+ info -> files , src [i ], path , GIT_ATTR_FILE );
392451
393452 return error ;
394453}
@@ -407,6 +466,7 @@ static void release_attr_files(git_vector *files)
407466
408467static int collect_attr_files (
409468 git_repository * repo ,
469+ git_attr_session * attr_session ,
410470 uint32_t flags ,
411471 const char * path ,
412472 git_vector * files )
@@ -416,7 +476,7 @@ static int collect_attr_files(
416476 const char * workdir = git_repository_workdir (repo );
417477 attr_walk_up_info info = { NULL };
418478
419- if ((error = attr_setup (repo )) < 0 )
479+ if ((error = attr_setup (repo , attr_session )) < 0 )
420480 return error ;
421481
422482 /* Resolve path in a non-bare repo */
@@ -435,12 +495,13 @@ static int collect_attr_files(
435495 */
436496
437497 error = push_attr_file (
438- repo , files , GIT_ATTR_FILE__FROM_FILE ,
498+ repo , attr_session , files , GIT_ATTR_FILE__FROM_FILE ,
439499 git_repository_path (repo ), GIT_ATTR_FILE_INREPO );
440500 if (error < 0 )
441501 goto cleanup ;
442502
443- info .repo = repo ;
503+ info .repo = repo ;
504+ info .attr_session = attr_session ;
444505 info .flags = flags ;
445506 info .workdir = workdir ;
446507 if (git_repository_index__weakptr (& info .index , repo ) < 0 )
@@ -457,21 +518,21 @@ static int collect_attr_files(
457518
458519 if (git_repository_attr_cache (repo )-> cfg_attr_file != NULL ) {
459520 error = push_attr_file (
460- repo , files , GIT_ATTR_FILE__FROM_FILE ,
521+ repo , attr_session , files , GIT_ATTR_FILE__FROM_FILE ,
461522 NULL , git_repository_attr_cache (repo )-> cfg_attr_file );
462523 if (error < 0 )
463524 goto cleanup ;
464525 }
465526
466527 if ((flags & GIT_ATTR_CHECK_NO_SYSTEM ) == 0 ) {
467- error = git_sysdir_find_system_file (& dir , GIT_ATTR_FILE_SYSTEM );
528+ error = system_attr_file (& dir , attr_session );
529+
468530 if (!error )
469531 error = push_attr_file (
470- repo , files , GIT_ATTR_FILE__FROM_FILE , NULL , dir . ptr );
471- else if ( error == GIT_ENOTFOUND ) {
472- giterr_clear ();
532+ repo , attr_session , files , GIT_ATTR_FILE__FROM_FILE ,
533+ NULL , dir . ptr );
534+ else if ( error == GIT_ENOTFOUND )
473535 error = 0 ;
474- }
475536 }
476537
477538 cleanup :
0 commit comments