@@ -74,9 +74,14 @@ typedef struct git_config_file_iter {
7474 (iter) && (((tmp) = CVAR_LIST_NEXT(iter) || 1));\
7575 (iter) = (tmp))
7676
77- struct reader {
77+ struct config_file {
7878 git_oid checksum ;
79- char * file_path ;
79+ char * path ;
80+ git_array_t (struct config_file ) includes ;
81+ };
82+
83+ struct reader {
84+ struct config_file * file ;
8085 git_buf buffer ;
8186 char * read_ptr ;
8287 int line_number ;
@@ -100,13 +105,11 @@ typedef struct {
100105
101106 git_config_level_t level ;
102107
103- git_array_t (struct reader ) readers ;
104-
105108 bool locked ;
106109 git_filebuf locked_buf ;
107110 git_buf locked_content ;
108111
109- char * file_path ;
112+ struct config_file file ;
110113} diskfile_backend ;
111114
112115typedef struct {
@@ -125,7 +128,7 @@ static int config_snapshot(git_config_backend **out, git_config_backend *in);
125128static void set_parse_error (struct reader * reader , int col , const char * error_str )
126129{
127130 giterr_set (GITERR_CONFIG , "failed to parse config file: %s (in %s:%d, column %d)" ,
128- error_str , reader -> file_path , reader -> line_number , col );
131+ error_str , reader -> file -> path , reader -> line_number , col );
129132}
130133
131134static int config_error_readonly (void )
@@ -261,123 +264,140 @@ static int refcounted_strmap_alloc(refcounted_strmap **out)
261264 return error ;
262265}
263266
267+ static void reader_init (struct reader * reader , struct config_file * file )
268+ {
269+ memset (reader , 0 , sizeof (* reader ));
270+ git_buf_init (& reader -> buffer , 0 );
271+ reader -> file = file ;
272+ }
273+
274+ static void config_file_clear (struct config_file * file )
275+ {
276+ struct config_file * include ;
277+ uint32_t i ;
278+
279+ if (file == NULL )
280+ return ;
281+
282+ git_array_foreach (file -> includes , i , include ) {
283+ config_file_clear (include );
284+ }
285+ git_array_clear (file -> includes );
286+
287+ git__free (file -> path );
288+ }
289+
264290static int config_open (git_config_backend * cfg , git_config_level_t level )
265291{
266292 int res ;
267- struct reader * reader ;
293+ struct reader reader ;
268294 diskfile_backend * b = (diskfile_backend * )cfg ;
269295
270296 b -> level = level ;
271297
272298 if ((res = refcounted_strmap_alloc (& b -> header .values )) < 0 )
273299 return res ;
274300
275- git_array_init (b -> readers );
276- reader = git_array_alloc (b -> readers );
277- if (!reader ) {
278- refcounted_strmap_free (b -> header .values );
279- return -1 ;
280- }
281- memset (reader , 0 , sizeof (struct reader ));
282-
283- reader -> file_path = git__strdup (b -> file_path );
284- GITERR_CHECK_ALLOC (reader -> file_path );
301+ reader_init (& reader , & b -> file );
285302
286- git_buf_init (& reader -> buffer , 0 );
287303 res = git_futils_readbuffer_updated (
288- & reader -> buffer , b -> file_path , & reader -> checksum , NULL );
304+ & reader . buffer , b -> file . path , & b -> file . checksum , NULL );
289305
290306 /* It's fine if the file doesn't exist */
291307 if (res == GIT_ENOTFOUND )
292308 return 0 ;
293309
294- if (res < 0 || (res = config_read (b -> header .values -> values , b , reader , level , 0 )) < 0 ) {
310+ if (res < 0 || (res = config_read (b -> header .values -> values , b , & reader , level , 0 )) < 0 ) {
295311 refcounted_strmap_free (b -> header .values );
296312 b -> header .values = NULL ;
297313 }
298314
299- reader = git_array_get (b -> readers , 0 );
300- git_buf_free (& reader -> buffer );
315+ git_buf_free (& reader .buffer );
301316
302317 return res ;
303318}
304319
305320/* The meat of the refresh, as we want to use it in different places */
306- static int config__refresh (git_config_backend * cfg )
321+ static int config__refresh (diskfile_backend * b , struct reader * reader , refcounted_strmap * values )
307322{
308- refcounted_strmap * values = NULL , * tmp ;
309- diskfile_backend * b = (diskfile_backend * )cfg ;
310- struct reader * reader = NULL ;
311323 int error = 0 ;
312324
313- if ((error = refcounted_strmap_alloc (& values )) < 0 )
314- goto out ;
315-
316- reader = git_array_get (b -> readers , git_array_size (b -> readers ) - 1 );
317- GITERR_CHECK_ALLOC (reader );
318-
319- if ((error = config_read (values -> values , b , reader , b -> level , 0 )) < 0 )
320- goto out ;
321-
322325 if ((error = git_mutex_lock (& b -> header .values_mutex )) < 0 ) {
323326 giterr_set (GITERR_OS , "failed to lock config backend" );
324327 goto out ;
325328 }
326329
327- tmp = b -> header .values ;
328- b -> header .values = values ;
329- values = tmp ;
330+ if ((error = config_read (values -> values , b , reader , b -> level , 0 )) < 0 )
331+ goto out ;
330332
331333 git_mutex_unlock (& b -> header .values_mutex );
332334
333335out :
334- refcounted_strmap_free (values );
335- if (reader )
336- git_buf_free (& reader -> buffer );
337336 return error ;
338337}
339338
340339static int config_refresh (git_config_backend * cfg )
341340{
342- int error = 0 , updated = 0 , any_updated = 0 ;
343341 diskfile_backend * b = (diskfile_backend * )cfg ;
344- struct reader * reader = NULL ;
342+ refcounted_strmap * values = NULL , * tmp ;
343+ struct config_file * include ;
344+ struct reader reader ;
345+ int error , updated ;
345346 uint32_t i ;
346347
347- for (i = 0 ; i < git_array_size (b -> readers ); i ++ ) {
348- reader = git_array_get (b -> readers , i );
349- error = git_futils_readbuffer_updated (
350- & reader -> buffer , reader -> file_path ,
351- & reader -> checksum , & updated );
348+ reader_init (& reader , & b -> file );
349+
350+ error = git_futils_readbuffer_updated (
351+ & reader .buffer , b -> file .path , & b -> file .checksum , & updated );
352+
353+ if (error < 0 && error != GIT_ENOTFOUND )
354+ goto out ;
355+
356+ if (updated ) {
357+ if ((error = refcounted_strmap_alloc (& values )) < 0 )
358+ goto out ;
359+
360+ /* Reparse the current configuration */
361+ git_array_foreach (b -> file .includes , i , include ) {
362+ config_file_clear (include );
363+ }
364+
365+ git_array_clear (b -> file .includes );
352366
353- if (error < 0 && error != GIT_ENOTFOUND )
354- return error ;
367+ if (( error = config__refresh ( b , & reader , values )) < 0 )
368+ goto out ;
355369
356- if (updated )
357- any_updated = 1 ;
370+ tmp = b -> header .values ;
371+ b -> header .values = values ;
372+ values = tmp ;
373+ } else {
374+ /* Refresh included configuration files */
375+ git_array_foreach (b -> file .includes , i , include ) {
376+ git_buf_free (& reader .buffer );
377+ reader_init (& reader , include );
378+ error = git_futils_readbuffer_updated (& reader .buffer , b -> file .path ,
379+ & b -> file .checksum , NULL );
380+
381+ if ((error = config__refresh (b , & reader , b -> header .values )) < 0 )
382+ goto out ;
383+ }
358384 }
359385
360- if (!any_updated )
361- return (error == GIT_ENOTFOUND ) ? 0 : error ;
386+ out :
387+ refcounted_strmap_free (values );
388+ git_buf_free (& reader .buffer );
362389
363- return config__refresh ( cfg ) ;
390+ return ( error == GIT_ENOTFOUND ) ? 0 : error ;
364391}
365392
366393static void backend_free (git_config_backend * _backend )
367394{
368395 diskfile_backend * backend = (diskfile_backend * )_backend ;
369- uint32_t i ;
370396
371397 if (backend == NULL )
372398 return ;
373399
374- for (i = 0 ; i < git_array_size (backend -> readers ); i ++ ) {
375- struct reader * r = git_array_get (backend -> readers , i );
376- git__free (r -> file_path );
377- }
378- git_array_clear (backend -> readers );
379-
380- git__free (backend -> file_path );
400+ config_file_clear (& backend -> file );
381401 refcounted_strmap_free (backend -> header .values );
382402 git_mutex_free (& backend -> header .values_mutex );
383403 git__free (backend );
@@ -685,10 +705,10 @@ static int config_lock(git_config_backend *_cfg)
685705 diskfile_backend * cfg = (diskfile_backend * ) _cfg ;
686706 int error ;
687707
688- if ((error = git_filebuf_open (& cfg -> locked_buf , cfg -> file_path , 0 , GIT_CONFIG_FILE_MODE )) < 0 )
708+ if ((error = git_filebuf_open (& cfg -> locked_buf , cfg -> file . path , 0 , GIT_CONFIG_FILE_MODE )) < 0 )
689709 return error ;
690710
691- error = git_futils_readbuffer (& cfg -> locked_content , cfg -> file_path );
711+ error = git_futils_readbuffer (& cfg -> locked_content , cfg -> file . path );
692712 if (error < 0 && error != GIT_ENOTFOUND ) {
693713 git_filebuf_cleanup (& cfg -> locked_buf );
694714 return error ;
@@ -726,8 +746,9 @@ int git_config_file__ondisk(git_config_backend **out, const char *path)
726746 backend -> header .parent .version = GIT_CONFIG_BACKEND_VERSION ;
727747 git_mutex_init (& backend -> header .values_mutex );
728748
729- backend -> file_path = git__strdup (path );
730- GITERR_CHECK_ALLOC (backend -> file_path );
749+ backend -> file .path = git__strdup (path );
750+ GITERR_CHECK_ALLOC (backend -> file .path );
751+ git_array_init (backend -> file .includes );
731752
732753 backend -> header .parent .open = config_open ;
733754 backend -> header .parent .get = config_get ;
@@ -1549,7 +1570,6 @@ static int config_parse(
15491570struct parse_data {
15501571 git_strmap * values ;
15511572 diskfile_backend * cfg_file ;
1552- uint32_t reader_idx ;
15531573 git_config_level_t level ;
15541574 int depth ;
15551575};
@@ -1597,44 +1617,41 @@ static int read_on_variable(
15971617
15981618 /* Add or append the new config option */
15991619 if (!git__strcmp (var -> entry -> name , "include.path" )) {
1600- struct reader * r ;
1620+ struct config_file * include ;
1621+ struct reader r ;
16011622 git_buf path = GIT_BUF_INIT ;
16021623 char * dir ;
1603- uint32_t index ;
1604-
1605- r = git_array_alloc (parse_data -> cfg_file -> readers );
1606- /* The reader may have been reallocated */
1607- * reader = git_array_get (parse_data -> cfg_file -> readers , parse_data -> reader_idx );
1608- memset (r , 0 , sizeof (struct reader ));
16091624
1610- if ((result = git_path_dirname_r (& path , (* reader )-> file_path )) < 0 )
1625+ if ((result = git_path_dirname_r (& path , (* reader )-> file -> path )) < 0 )
16111626 return result ;
16121627
1613- /* We need to know our index in the array, as the next config_parse call may realloc */
1614- index = git_array_size (parse_data -> cfg_file -> readers ) - 1 ;
16151628 dir = git_buf_detach (& path );
16161629 result = included_path (& path , dir , var -> entry -> value );
16171630 git__free (dir );
16181631
16191632 if (result < 0 )
16201633 return result ;
16211634
1622- r -> file_path = git_buf_detach (& path );
1623- git_buf_init (& r -> buffer , 0 );
1635+ include = git_array_alloc ((* reader )-> file -> includes );
1636+ memset (include , 0 , sizeof (* include ));
1637+ git_array_init (include -> includes );
1638+ include -> path = git_buf_detach (& path );
1639+
1640+ git_buf_init (& r .buffer , 0 );
1641+ memset (& r , 0 , sizeof (r ));
1642+ r .file = include ;
16241643
16251644 result = git_futils_readbuffer_updated (
1626- & r -> buffer , r -> file_path , & r -> checksum , NULL );
1645+ & r . buffer , include -> path , & include -> checksum , NULL );
16271646
16281647 if (result == 0 ) {
1629- result = config_read (parse_data -> values , parse_data -> cfg_file , r , parse_data -> level , parse_data -> depth + 1 );
1630- r = git_array_get (parse_data -> cfg_file -> readers , index );
1631- * reader = git_array_get (parse_data -> cfg_file -> readers , parse_data -> reader_idx );
1648+ result = config_read (parse_data -> values , parse_data -> cfg_file , & r , parse_data -> level , parse_data -> depth + 1 );
16321649 } else if (result == GIT_ENOTFOUND ) {
16331650 giterr_clear ();
16341651 result = 0 ;
16351652 }
16361653
1637- git_buf_free (& r -> buffer );
1654+ git_buf_free (& r . buffer );
16381655 }
16391656
16401657 return result ;
@@ -1659,7 +1676,6 @@ static int config_read(git_strmap *values, diskfile_backend *cfg_file, struct re
16591676
16601677 parse_data .values = values ;
16611678 parse_data .cfg_file = cfg_file ;
1662- parse_data .reader_idx = git_array_size (cfg_file -> readers ) - 1 ;
16631679 parse_data .level = level ;
16641680 parse_data .depth = depth ;
16651681
@@ -1896,31 +1912,33 @@ static int config_write(diskfile_backend *cfg, const char *key, const regex_t *p
18961912 char * section , * name , * ldot ;
18971913 git_filebuf file = GIT_FILEBUF_INIT ;
18981914 git_buf buf = GIT_BUF_INIT ;
1899- struct reader * reader = git_array_get ( cfg -> readers , 0 ) ;
1915+ struct reader reader ;
19001916 struct write_data write_data ;
19011917
1918+ reader_init (& reader , & cfg -> file );
1919+
19021920 if (cfg -> locked ) {
1903- result = git_buf_puts (& reader -> buffer , git_buf_cstr (& cfg -> locked_content ));
1921+ result = git_buf_puts (& reader . buffer , git_buf_cstr (& cfg -> locked_content ));
19041922 } else {
19051923 /* Lock the file */
19061924 if ((result = git_filebuf_open (
1907- & file , cfg -> file_path , GIT_FILEBUF_HASH_CONTENTS , GIT_CONFIG_FILE_MODE )) < 0 ) {
1908- git_buf_free (& reader -> buffer );
1925+ & file , cfg -> file . path , GIT_FILEBUF_HASH_CONTENTS , GIT_CONFIG_FILE_MODE )) < 0 ) {
1926+ git_buf_free (& reader . buffer );
19091927 return result ;
19101928 }
19111929
19121930 /* We need to read in our own config file */
1913- result = git_futils_readbuffer (& reader -> buffer , cfg -> file_path );
1931+ result = git_futils_readbuffer (& reader . buffer , cfg -> file . path );
19141932 }
19151933
19161934 /* Initialise the reading position */
19171935 if (result == GIT_ENOTFOUND ) {
1918- reader -> read_ptr = NULL ;
1919- reader -> eof = 1 ;
1920- git_buf_clear (& reader -> buffer );
1936+ reader . read_ptr = NULL ;
1937+ reader . eof = 1 ;
1938+ git_buf_clear (& reader . buffer );
19211939 } else if (result == 0 ) {
1922- reader -> read_ptr = reader -> buffer .ptr ;
1923- reader -> eof = 0 ;
1940+ reader . read_ptr = reader . buffer .ptr ;
1941+ reader . eof = 0 ;
19241942 } else {
19251943 git_filebuf_cleanup (& file );
19261944 return -1 ; /* OS error when reading the file */
@@ -1939,7 +1957,7 @@ static int config_write(diskfile_backend *cfg, const char *key, const regex_t *p
19391957 write_data .preg = preg ;
19401958 write_data .value = value ;
19411959
1942- result = config_parse (reader , write_on_section , write_on_variable , write_on_comment , write_on_eof , & write_data );
1960+ result = config_parse (& reader , write_on_section , write_on_variable , write_on_comment , write_on_eof , & write_data );
19431961 git__free (section );
19441962 git_buf_free (& write_data .buffered_comment );
19451963
@@ -1960,6 +1978,6 @@ static int config_write(diskfile_backend *cfg, const char *key, const regex_t *p
19601978
19611979done :
19621980 git_buf_free (& buf );
1963- git_buf_free (& reader -> buffer );
1981+ git_buf_free (& reader . buffer );
19641982 return result ;
19651983}
0 commit comments