Commit c655aa5209e94200fd05bd618f48a757b2a6b2c8

Vicent Martí 2013-10-01T05:54:54

Merge pull request #1882 from linquize/config-subsection-fix Config subsection name should allow to have ']' and '\\' should allow to escape any characters

diff --git a/src/config_file.c b/src/config_file.c
index 1a845d8..8fb43b9 100644
--- a/src/config_file.c
+++ b/src/config_file.c
@@ -712,7 +712,6 @@ static int parse_section_header_ext(struct reader *reader, const char *line, con
 	int c, rpos;
 	char *first_quote, *last_quote;
 	git_buf buf = GIT_BUF_INIT;
-	int quote_marks;
 	/*
 	 * base_name is what came before the space. We should be at the
 	 * first quotation mark, except for now, line isn't being kept in
@@ -731,21 +730,15 @@ static int parse_section_header_ext(struct reader *reader, const char *line, con
 	git_buf_printf(&buf, "%s.", base_name);
 
 	rpos = 0;
-	quote_marks = 0;
 
 	line = first_quote;
-	c = line[rpos++];
+	c = line[++rpos];
 
 	/*
 	 * At the end of each iteration, whatever is stored in c will be
 	 * added to the string. In case of error, jump to out
 	 */
 	do {
-		if (quote_marks == 2) {
-			set_parse_error(reader, rpos, "Unexpected text after closing quotes");
-			git_buf_free(&buf);
-			return -1;
-		}
 
 		switch (c) {
 		case 0:
@@ -754,25 +747,13 @@ static int parse_section_header_ext(struct reader *reader, const char *line, con
 			return -1;
 
 		case '"':
-			++quote_marks;
-			continue;
+			goto end_parse;
 
 		case '\\':
-			c = line[rpos++];
-
-			switch (c) {
-			case '"':
-				if (&line[rpos-1] == last_quote) {
-					set_parse_error(reader, 0, "Missing closing quotation mark in section header");
-					git_buf_free(&buf);
-					return -1;
-				}
-
-			case '\\':
-				break;
+			c = line[++rpos];
 
-			default:
-				set_parse_error(reader, rpos, "Unsupported escape sequence");
+			if (c == 0) {
+				set_parse_error(reader, rpos, "Unexpected end-of-line in section header");
 				git_buf_free(&buf);
 				return -1;
 			}
@@ -782,7 +763,15 @@ static int parse_section_header_ext(struct reader *reader, const char *line, con
 		}
 
 		git_buf_putc(&buf, (char)c);
-	} while ((c = line[rpos++]) != ']');
+		c = line[++rpos];
+	} while (line + rpos < last_quote);
+
+end_parse:
+	if (line[rpos] != '"' || line[rpos + 1] != ']') {
+		set_parse_error(reader, rpos, "Unexpected text after closing quotes");
+		git_buf_free(&buf);
+		return -1;
+	}
 
 	*section_name = git_buf_detach(&buf);
 	return 0;
@@ -800,7 +789,7 @@ static int parse_section_header(struct reader *reader, char **section_out)
 		return -1;
 
 	/* find the end of the variable's name */
-	name_end = strchr(line, ']');
+	name_end = strrchr(line, ']');
 	if (name_end == NULL) {
 		git__free(line);
 		set_parse_error(reader, 0, "Missing ']' in section header");
diff --git a/tests-clar/config/read.c b/tests-clar/config/read.c
index 722a15a..abc088d 100644
--- a/tests-clar/config/read.c
+++ b/tests-clar/config/read.c
@@ -164,6 +164,13 @@ void test_config_read__empty_files(void)
 	git_config_free(cfg);
 }
 
+void test_config_read__symbol_headers(void)
+{
+	git_config *cfg;
+	cl_git_pass(git_config_open_ondisk(&cfg, cl_fixture("config/config20")));
+	git_config_free(cfg);
+}
+
 void test_config_read__header_in_last_line(void)
 {
 	git_config *cfg;
@@ -524,6 +531,28 @@ void test_config_read__corrupt_header(void)
 	git_config_free(cfg);
 }
 
+void test_config_read__corrupt_header2(void)
+{
+	git_config *cfg;
+
+	cl_set_cleanup(&clean_test_config, NULL);
+	cl_git_mkfile("./testconfig", "[unclosed \"bracket\"\n    lib = git2\n");
+	cl_git_fail(git_config_open_ondisk(&cfg, "./testconfig"));
+
+	git_config_free(cfg);
+}
+
+void test_config_read__corrupt_header3(void)
+{
+	git_config *cfg;
+
+	cl_set_cleanup(&clean_test_config, NULL);
+	cl_git_mkfile("./testconfig", "[unclosed \"slash\\\"]\n    lib = git2\n");
+	cl_git_fail(git_config_open_ondisk(&cfg, "./testconfig"));
+
+	git_config_free(cfg);
+}
+
 void test_config_read__override_variable(void)
 {
 	git_config *cfg;
diff --git a/tests-clar/resources/config/config20 b/tests-clar/resources/config/config20
new file mode 100644
index 0000000..8f0f12c
--- /dev/null
+++ b/tests-clar/resources/config/config20
@@ -0,0 +1,11 @@
+[valid "[subsection]"]
+    something = a
+; we don't allow anything after closing "
+[sec "[subsec]/child"]
+    parent = grand
+[sec2 "[subsec2]/child2"]
+    type = dvcs
+[sec3 "escape\"quote"]
+    vcs = git
+[sec4 "escaping\\slash"]
+    lib = git2