@matheusbsbs / matheus-bagliano / commits / 02e5ba4ae6
Fork 0

config: handle lack of newline at end of file better

The config parsing routines use the static global 'config_file' to store the FILE* pointing to the current config file being parsed. The function get_next_char() automatically converts an EOF on this file to a newline for the convenience of its callers, and it sets config_file to NULL to indicate that EOF was reached. This throws away useful information, though, since some routines want to call ftell on 'config_file' to find out exactly _where_ the routine ended. In the case of a key ending at EOF boundary, we ended up segfaulting in some cases (changing that key or adding another key in its section), or failing to provide the necessary newline (adding a new section). This patch adds a new flag to indicate EOF and uses that instead of setting config_file to NULL. It also makes sure to add newlines where necessary for truncated input. All three included tests fail without the patch. Signed-off-by: Junio C Hamano <gitster@pobox.com>

Jeff King committed Jan 1, 2008 at 01:17 UTC 02e5ba4ae63729c28704280f1b8cfcb205c06960
2 files changed +46 -5
config.c
+9 -5
@@ -13,6 +13,7 @@
13 static FILE *config_file;
14 static const char *config_file_name;
15 static int config_linenr;
16 +static int config_file_eof;
17 static int zlib_compression_seen;
18
19 static int get_next_char(void)
@@ -34,7 +35,7 @@ static int get_next_char(void)
35 if (c == '\n')
36 config_linenr++;
37 if (c == EOF) {
37 - config_file = NULL;
38 + config_file_eof = 1;
39 c = '\n';
40 }
41 }
@@ -118,7 +119,7 @@ static int get_value(config_fn_t fn, char *name, unsigned int len)
119 /* Get the full name */
120 for (;;) {
121 c = get_next_char();
121 - if (c == EOF)
122 + if (config_file_eof)
123 break;
124 if (!iskeychar(c))
125 break;
@@ -182,7 +183,7 @@ static int get_base_var(char *name)
183
184 for (;;) {
185 int c = get_next_char();
185 - if (c == EOF)
186 + if (config_file_eof)
187 return -1;
188 if (c == ']')
189 return baselen;
@@ -205,8 +206,7 @@ static int git_parse_file(config_fn_t fn)
206 for (;;) {
207 int c = get_next_char();
208 if (c == '\n') {
208 - /* EOF? */
209 - if (!config_file)
209 + if (config_file_eof)
210 return 0;
211 comment = 0;
212 continue;
@@ -469,6 +469,7 @@ int git_config_from_file(config_fn_t fn, const char *filename)
469 config_file = f;
470 config_file_name = filename;
471 config_linenr = 1;
472 + config_file_eof = 0;
473 ret = git_parse_file(fn);
474 fclose(f);
475 config_file_name = NULL;
@@ -918,6 +919,9 @@ int git_config_set_multivar(const char* key, const char* value,
919 contents, contents_sz,
920 store.offset[i]-2, &new_line);
921
922 + if (copy_end > 0 && contents[copy_end-1] != '\n')
923 + new_line = 1;
924 +
925 /* write the first part of the config */
926 if (copy_end > copy_begin) {
927 if (write_in_full(fd, contents + copy_begin,
t/t1303-wacky-config.sh new
+37
@@ -0,0 +1,37 @@
1 +#!/bin/sh
2 +
3 +test_description='Test wacky input to git config'
4 +. ./test-lib.sh
5 +
6 +setup() {
7 + (printf "[section]\n" &&
8 + printf " key = foo") >.git/config
9 +}
10 +
11 +check() {
12 + echo "$2" >expected
13 + git config --get "$1" >actual
14 + git diff actual expected
15 +}
16 +
17 +test_expect_success 'modify same key' '
18 + setup &&
19 + git config section.key bar &&
20 + check section.key bar
21 +'
22 +
23 +test_expect_success 'add key in same section' '
24 + setup &&
25 + git config section.other bar &&
26 + check section.key foo &&
27 + check section.other bar
28 +'
29 +
30 +test_expect_success 'add key in different section' '
31 + setup &&
32 + git config section2.key bar &&
33 + check section.key foo &&
34 + check section2.key bar
35 +'
36 +
37 +test_done