@@ -44,7 +44,7 @@ typedef struct {
4444 git_filebuf locked_buf ;
4545 git_buf locked_content ;
4646
47- struct config_file file ;
47+ git_config_file file ;
4848} diskfile_backend ;
4949
5050typedef struct {
@@ -62,6 +62,7 @@ typedef struct {
6262} diskfile_parse_state ;
6363
6464static int config_read (git_config_entries * entries , const git_repository * repo , git_config_file * file , git_config_level_t level , int depth );
65+ static int config_read_buffer (git_config_entries * entries , const git_repository * repo , git_config_file * file , git_config_level_t level , int depth , const char * buf , size_t buflen );
6566static int config_write (diskfile_backend * cfg , const char * orig_key , const char * key , const p_regex_t * preg , const char * value );
6667static char * escape_value (const char * ptr );
6768
@@ -95,9 +96,9 @@ static git_config_entries *diskfile_entries_take(diskfile_header *h)
9596 return entries ;
9697}
9798
98- static void config_file_clear (struct config_file * file )
99+ static void config_file_clear (git_config_file * file )
99100{
100- struct config_file * include ;
101+ git_config_file * include ;
101102 uint32_t i ;
102103
103104 if (file == NULL )
@@ -133,7 +134,7 @@ static int config_open(git_config_backend *cfg, git_config_level_t level, const
133134 return res ;
134135}
135136
136- static int config_is_modified (int * modified , struct config_file * file )
137+ static int config_is_modified (int * modified , git_config_file * file )
137138{
138139 git_config_file * include ;
139140 git_buf buf = GIT_BUF_INIT ;
@@ -143,6 +144,9 @@ static int config_is_modified(int *modified, struct config_file *file)
143144
144145 * modified = 0 ;
145146
147+ if (!git_futils_filestamp_check (& file -> stamp , file -> path ))
148+ goto check_includes ;
149+
146150 if ((error = git_futils_readbuffer (& buf , file -> path )) < 0 )
147151 goto out ;
148152
@@ -154,6 +158,7 @@ static int config_is_modified(int *modified, struct config_file *file)
154158 goto out ;
155159 }
156160
161+ check_includes :
157162 git_array_foreach (file -> includes , i , include ) {
158163 if ((error = config_is_modified (modified , include )) < 0 || * modified )
159164 goto out ;
@@ -165,47 +170,73 @@ static int config_is_modified(int *modified, struct config_file *file)
165170 return error ;
166171}
167172
168- static int config_refresh (git_config_backend * cfg )
173+ static int config_set_entries (git_config_backend * cfg , git_config_entries * entries )
169174{
170175 diskfile_backend * b = (diskfile_backend * )cfg ;
171- git_config_entries * entries = NULL , * tmp ;
176+ git_config_entries * old = NULL ;
172177 git_config_file * include ;
173- int error , modified ;
174- uint32_t i ;
178+ int error ;
179+ size_t i ;
175180
176181 if (b -> header .parent .readonly )
177182 return config_error_readonly ();
178183
179- error = config_is_modified (& modified , & b -> file );
180- if (error < 0 && error != GIT_ENOTFOUND )
181- goto out ;
182-
183- if (!modified )
184- return 0 ;
185-
186- if ((error = git_config_entries_new (& entries )) < 0 )
187- goto out ;
188-
189- /* Reparse the current configuration */
190- git_array_foreach (b -> file .includes , i , include ) {
184+ git_array_foreach (b -> file .includes , i , include )
191185 config_file_clear (include );
192- }
193186 git_array_clear (b -> file .includes );
194187
195- if ((error = config_read (entries , b -> header .repo , & b -> file , b -> header .level , 0 )) < 0 )
196- goto out ;
197-
198188 if ((error = git_mutex_lock (& b -> header .values_mutex )) < 0 ) {
199189 git_error_set (GIT_ERROR_OS , "failed to lock config backend" );
200190 goto out ;
201191 }
202192
203- tmp = b -> header .entries ;
193+ old = b -> header .entries ;
204194 b -> header .entries = entries ;
205- entries = tmp ;
206195
207196 git_mutex_unlock (& b -> header .values_mutex );
208197
198+ out :
199+ git_config_entries_free (old );
200+ return error ;
201+ }
202+
203+ static int config_refresh_from_buffer (git_config_backend * cfg , const char * buf , size_t buflen )
204+ {
205+ diskfile_backend * b = GIT_CONTAINER_OF (cfg , diskfile_backend , header .parent );
206+ git_config_entries * entries = NULL ;
207+ int error ;
208+
209+ if ((error = git_config_entries_new (& entries )) < 0 ||
210+ (error = config_read_buffer (entries , b -> header .repo , & b -> file ,
211+ b -> header .level , 0 , buf , buflen )) < 0 ||
212+ (error = config_set_entries (cfg , entries )) < 0 )
213+ goto out ;
214+
215+ entries = NULL ;
216+ out :
217+ git_config_entries_free (entries );
218+ return error ;
219+ }
220+
221+ static int config_refresh (git_config_backend * cfg )
222+ {
223+ diskfile_backend * b = GIT_CONTAINER_OF (cfg , diskfile_backend , header .parent );
224+ git_config_entries * entries = NULL ;
225+ int error , modified ;
226+
227+ error = config_is_modified (& modified , & b -> file );
228+ if (error < 0 && error != GIT_ENOTFOUND )
229+ goto out ;
230+
231+ if (!modified )
232+ return 0 ;
233+
234+ if ((error = git_config_entries_new (& entries )) < 0 ||
235+ (error = config_read (entries , b -> header .repo , & b -> file , b -> header .level , 0 )) < 0 ||
236+ (error = config_set_entries (cfg , entries )) < 0 )
237+ goto out ;
238+
239+ entries = NULL ;
209240out :
210241 git_config_entries_free (entries );
211242
@@ -280,8 +311,6 @@ static int config_set(git_config_backend *cfg, const char *name, const char *val
280311 if ((error = config_write (b , name , key , NULL , esc_value )) < 0 )
281312 goto out ;
282313
283- error = config_refresh (cfg );
284-
285314out :
286315 git_config_entries_free (entries );
287316 git__free (esc_value );
@@ -348,8 +377,6 @@ static int config_set_multivar(
348377 if ((result = config_write (b , name , key , & preg , value )) < 0 )
349378 goto out ;
350379
351- result = config_refresh (cfg );
352-
353380out :
354381 git__free (key );
355382 p_regfree (& preg );
@@ -381,9 +408,6 @@ static int config_delete(git_config_backend *cfg, const char *name)
381408 if ((error = config_write (b , name , entry -> name , NULL , NULL )) < 0 )
382409 goto out ;
383410
384- if ((error = config_refresh (cfg )) < 0 )
385- goto out ;
386-
387411out :
388412 git_config_entries_free (entries );
389413 git__free (key );
@@ -422,9 +446,6 @@ static int config_delete_multivar(git_config_backend *cfg, const char *name, con
422446 if ((result = config_write (b , name , key , & preg , NULL )) < 0 )
423447 goto out ;
424448
425- if ((result = config_refresh (cfg )) < 0 )
426- goto out ;
427-
428449out :
429450 git_config_entries_free (entries );
430451 git__free (key );
@@ -659,7 +680,7 @@ static char *escape_value(const char *ptr)
659680static int parse_include (git_config_parser * reader ,
660681 diskfile_parse_state * parse_data , const char * file )
661682{
662- struct config_file * include ;
683+ git_config_file * include ;
663684 git_buf path = GIT_BUF_INIT ;
664685 char * dir ;
665686 int result ;
@@ -851,38 +872,33 @@ static int read_on_variable(
851872 return result ;
852873}
853874
854- static int config_read (
875+ static int config_read_buffer (
855876 git_config_entries * entries ,
856877 const git_repository * repo ,
857878 git_config_file * file ,
858879 git_config_level_t level ,
859- int depth )
880+ int depth ,
881+ const char * buf ,
882+ size_t buflen )
860883{
861884 diskfile_parse_state parse_data ;
862885 git_config_parser reader ;
863- git_buf contents = GIT_BUF_INIT ;
864886 int error ;
865887
866888 if (depth >= MAX_INCLUDE_DEPTH ) {
867889 git_error_set (GIT_ERROR_CONFIG , "maximum config include depth reached" );
868890 return -1 ;
869891 }
870892
871- if ((error = git_futils_readbuffer (& contents , file -> path )) < 0 )
872- goto out ;
873-
874- git_parse_ctx_init (& reader .ctx , contents .ptr , contents .size );
875-
876- if ((error = git_hash_buf (& file -> checksum , contents .ptr , contents .size )) < 0 )
877- goto out ;
878-
879893 /* Initialize the reading position */
880894 reader .file = file ;
881- git_parse_ctx_init (& reader .ctx , contents . ptr , contents . size );
895+ git_parse_ctx_init (& reader .ctx , buf , buflen );
882896
883897 /* If the file is empty, there's nothing for us to do */
884- if (!reader .ctx .content || * reader .ctx .content == '\0' )
898+ if (!reader .ctx .content || * reader .ctx .content == '\0' ) {
899+ error = 0 ;
885900 goto out ;
901+ }
886902
887903 parse_data .repo = repo ;
888904 parse_data .file_path = file -> path ;
@@ -892,6 +908,37 @@ static int config_read(
892908
893909 error = git_config_parse (& reader , NULL , read_on_variable , NULL , NULL , & parse_data );
894910
911+ out :
912+ return error ;
913+ }
914+
915+ static int config_read (
916+ git_config_entries * entries ,
917+ const git_repository * repo ,
918+ git_config_file * file ,
919+ git_config_level_t level ,
920+ int depth )
921+ {
922+ git_buf contents = GIT_BUF_INIT ;
923+ struct stat st ;
924+ int error ;
925+
926+ if (p_stat (file -> path , & st ) < 0 ) {
927+ error = git_path_set_error (errno , file -> path , "stat" );
928+ goto out ;
929+ }
930+
931+ if ((error = git_futils_readbuffer (& contents , file -> path )) < 0 )
932+ goto out ;
933+
934+ git_futils_filestamp_set_from_stat (& file -> stamp , & st );
935+ if ((error = git_hash_buf (& file -> checksum , contents .ptr , contents .size )) < 0 )
936+ goto out ;
937+
938+ if ((error = config_read_buffer (entries , repo , file , level , depth ,
939+ contents .ptr , contents .size )) < 0 )
940+ goto out ;
941+
895942out :
896943 git_buf_dispose (& contents );
897944 return error ;
@@ -1197,7 +1244,12 @@ static int config_write(diskfile_backend *cfg, const char *orig_key, const char
11971244 git_buf_attach (& cfg -> locked_content , git_buf_detach (& buf ), len );
11981245 } else {
11991246 git_filebuf_write (& file , git_buf_cstr (& buf ), git_buf_len (& buf ));
1200- result = git_filebuf_commit (& file );
1247+
1248+ if ((result = git_filebuf_commit (& file )) < 0 )
1249+ goto done ;
1250+
1251+ if ((result = config_refresh_from_buffer (& cfg -> header .parent , buf .ptr , buf .size )) < 0 )
1252+ goto done ;
12011253 }
12021254
12031255done :
0 commit comments