git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH 4/8] commit-graph: don't early exit(1) on e.g. "git status"

From
Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Date
Feb 21, 2019, 22:37 UTC
Message-ID
<20190221223753.20070-5-avarab@gmail.com>
In-Reply-To
<20190221223753.20070-1-avarab@gmail.com>

Make the commit-graph loading code work as a library that returns an error code instead of calling exit(1) when the commit-graph is corrupt. This means that e.g. "status" will now report commit-graph corruption as an "error: [...]" at the top of its output, but then proceed to work normally.

This required splitting up the load_commit_graph_one() function so that the code that deals with open()-ing and stat()-ing the graph can now be called independently as open_commit_graph().

This is needed because "commit-graph verify" where the graph doesn't exist isn't an error. See the third paragraph in 283e68c72f ("commit-graph: add 'verify' subcommand", 2018-06-27). There's a bug in that logic where we conflate the intended ENOENT with other errno values (e.g. EACCES), but this change doesn't address that. That'll be addressed in a follow-up change.

I'm then splitting most of the logic out of load_commit_graph_one() into load_commit_graph_one_fd_st(), which allows for providing an existing file descriptor and stat information to the loading code. This isn't strictly needed, but it would be redundant and confusing to open() and stat() the file twice for some of the codepaths, this allows for calling open_commit_graph() followed by load_commit_graph_one_fd_st(). The "graph_file" still needs to be passed to that function for the the "graph file %s is too small" error message.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 builtin/commit-graph.c  | 21 +++++++++++++++++----
 commit-graph.c          | 42 +++++++++++++++++++++++++++++------------
 commit-graph.h          |  3 +++
 t/t5318-commit-graph.sh |  2 +-
 4 files changed, 51 insertions(+), 17 deletions(-)
diff --git a/builtin/commit-graph.c b/builtin/commit-graph.c
index 4ae502754c..32bcc63427 100644
--- a/builtin/commit-graph.c
+++ b/builtin/commit-graph.c
@@ -42,6 +42,9 @@ static int graph_verify(int argc, const char **argv)
 {
 	struct commit_graph *graph = NULL;
 	char *graph_name;
+	int open_ok;
+	int fd;
+	struct stat st;
 
 	static struct option builtin_commit_graph_verify_options[] = {
 		OPT_STRING(0, "object-dir", &opts.obj_dir,
@@ -58,11 +61,14 @@ static int graph_verify(int argc, const char **argv)
 		opts.obj_dir = get_object_directory();
 
 	graph_name = get_commit_graph_filename(opts.obj_dir);
-	graph = load_commit_graph_one(graph_name);
+	open_ok = open_commit_graph(graph_name, &fd, &st);
+	if (!open_ok)
+		return 0;
+	graph = load_commit_graph_one_fd_st(graph_name, fd, &st);
 	FREE_AND_NULL(graph_name);
 
 	if (!graph)
-		return 0;
+		return 1;
 
 	UNLEAK(graph);
 	return verify_commit_graph(the_repository, graph);
@@ -72,6 +78,9 @@ static int graph_read(int argc, const char **argv)
 {
 	struct commit_graph *graph = NULL;
 	char *graph_name;
+	int open_ok;
+	int fd;
+	struct stat st;
 
 	static struct option builtin_commit_graph_read_options[] = {
 		OPT_STRING(0, "object-dir", &opts.obj_dir,
@@ -88,10 +97,14 @@ static int graph_read(int argc, const char **argv)
 		opts.obj_dir = get_object_directory();
 
 	graph_name = get_commit_graph_filename(opts.obj_dir);
-	graph = load_commit_graph_one(graph_name);
 
+	open_ok = open_commit_graph(graph_name, &fd, &st);
+	if (!open_ok)
+		die_errno(_("Could not open commit-graph '%s'"), graph_name);
+
+	graph = load_commit_graph_one_fd_st(graph_name, fd, &st);
 	if (!graph)
-		die("graph file %s does not exist", graph_name);
+		return 1;
 
 	FREE_AND_NULL(graph_name);
 
diff --git a/commit-graph.c b/commit-graph.c
index 980fbf47ea..b1ba7a09cc 100644
--- a/commit-graph.c
+++ b/commit-graph.c
@@ -80,25 +80,31 @@ static int commit_graph_compatible(struct repository *r)
 	return 1;
 }
 
-struct commit_graph *load_commit_graph_one(const char *graph_file)
+int open_commit_graph(const char *graph_file, int *fd, struct stat *st)
+{
+	*fd = git_open(graph_file);
+	if (*fd < 0)
+		return 0;
+	if (fstat(*fd, st)) {
+		close(*fd);
+		return 0;
+	}
+	return 1;
+}
+
+struct commit_graph *load_commit_graph_one_fd_st(const char *graph_file,
+						 int fd, struct stat *st)
 {
 	void *graph_map;
 	size_t graph_size;
-	struct stat st;
 	struct commit_graph *ret;
-	int fd = git_open(graph_file);
 
-	if (fd < 0)
-		return NULL;
-	if (fstat(fd, &st)) {
-		close(fd);
-		return NULL;
-	}
-	graph_size = xsize_t(st.st_size);
+	graph_size = xsize_t(st->st_size);
 
 	if (graph_size < GRAPH_MIN_SIZE) {
 		close(fd);
-		die(_("graph file %s is too small"), graph_file);
+		error(_("graph file %s is too small"), graph_file);
+		return 0;
 	}
 	graph_map = xmmap(NULL, graph_size, PROT_READ, MAP_PRIVATE, fd, 0);
 	ret = parse_commit_graph(graph_map, fd, graph_size);
@@ -106,12 +112,24 @@ struct commit_graph *load_commit_graph_one(const char *graph_file)
 	if (!ret) {
 		munmap(graph_map, graph_size);
 		close(fd);
-		exit(1);
 	}
 
 	return ret;
 }
 
+struct commit_graph *load_commit_graph_one(const char *graph_file)
+{
+
+	struct stat st;
+	int fd;
+	int open_ok = open_commit_graph(graph_file, &fd, &st);
+
+	if (!open_ok)
+		return NULL;
+
+	return load_commit_graph_one_fd_st(graph_file, fd, &st);
+}
+
 struct commit_graph *parse_commit_graph(void *graph_map, int fd,
 					size_t graph_size)
 {
diff --git a/commit-graph.h b/commit-graph.h
index 275f97d006..e4f17071e2 100644
--- a/commit-graph.h
+++ b/commit-graph.h
@@ -11,6 +11,7 @@
 struct commit;
 
 char *get_commit_graph_filename(const char *obj_dir);
+int open_commit_graph(const char *graph_file, int *fd, struct stat *st);
 
 /*
  * Given a commit struct, try to fill the commit struct info, including:
@@ -53,6 +54,8 @@ struct commit_graph {
 };
 
 struct commit_graph *load_commit_graph_one(const char *graph_file);
+struct commit_graph *load_commit_graph_one_fd_st(const char *graph_file,
+						 int fd, struct stat *st);
 
 struct commit_graph *parse_commit_graph(void *graph_map, int fd,
 					size_t graph_size);
diff --git a/t/t5318-commit-graph.sh b/t/t5318-commit-graph.sh
index b3f3e515fc..0d012f55e5 100755
--- a/t/t5318-commit-graph.sh
+++ b/t/t5318-commit-graph.sh
@@ -377,7 +377,7 @@ corrupt_graph_verify() {
 	test_must_fail git commit-graph verify 2>test_err &&
 	grep -v "^+" test_err >err &&
 	test_i18ngrep "$grepstr" err &&
-	test_might_fail git status --short
+	git status --short
 }
 
 # usage: corrupt_graph_and_verify <position> <data> <string> [<zero_pos>]
-- 
2.21.0.rc0.258.g878e2cd30e
Previous: Ævar Arnfjörð BjarmasonNext: Ævar Arnfjörð Bjarmason
Message 5 of 36 in “commit-graph: segfault & other fixes for broken graphs”
  1. 0/8 commit-graph: segfault & other fixes for broken graphsÆvar Arnfjörð Bjarmason, Feb 21, 2019
  2. 1/8 commit-graph tests: split up corrupt_graph_and_verify()Ævar Arnfjörð Bjarmason, Feb 21, 2019
  3. 2/8 commit-graph tests: test a graph that's too smallÆvar Arnfjörð Bjarmason, Feb 21, 2019
  4. 3/8 commit-graph: fix segfault on e.g. "git status"Ævar Arnfjörð Bjarmason, Feb 21, 2019
  5. 4/8 commit-graph: don't early exit(1) on e.g. "git status"Ævar Arnfjörð Bjarmason, Feb 21, 2019
  6. 6/8 commit-graph verify: detect inability to read the graphÆvar Arnfjörð Bjarmason, Feb 21, 2019
  7. SZEDER GáborFeb 21, 2019
  8. 5/8 commit-graph: don't pass filename to load_commit_graph_one_fd_st()Ævar Arnfjörð Bjarmason, Feb 21, 2019
  9. 7/8 commit-graph write: don't die if the existing graph is corruptÆvar Arnfjörð Bjarmason, Feb 21, 2019
  10. Junio C HamanoFeb 22, 2019
  11. Eric SunshineFeb 23, 2019
  12. 8/8 commit-graph: improve & i18n error messagesÆvar Arnfjörð Bjarmason, Feb 21, 2019
  13. 0/8 commit-graph: segfault & other fixes for broken graphsÆvar Arnfjörð Bjarmason, Mar 14, 2019
  14. Eric SunshineMar 15, 2019
  15. Ævar Arnfjörð BjarmasonMar 15, 2019
  16. 0/8 commit-graph: segfault & other fixes for broken graphsÆvar Arnfjörð Bjarmason, Mar 25, 2019
  17. 1/8 commit-graph tests: split up corrupt_graph_and_verify()Ævar Arnfjörð Bjarmason, Mar 25, 2019
  18. 2/8 commit-graph tests: test a graph that's too smallÆvar Arnfjörð Bjarmason, Mar 25, 2019
  19. 3/8 commit-graph: fix segfault on e.g. "git status"Ævar Arnfjörð Bjarmason, Mar 25, 2019
  20. 4/8 commit-graph: don't early exit(1) on e.g. "git status"Ævar Arnfjörð Bjarmason, Mar 25, 2019
  21. Ævar Arnfjörð BjarmasonApr 27, 2019
  22. Derrick StoleeApr 29, 2019
  23. Ævar Arnfjörð BjarmasonApr 29, 2019
  24. Jeff KingMay 1, 2019
  25. 5/8 commit-graph: don't pass filename to load_commit_graph_one_fd_st()Ævar Arnfjörð Bjarmason, Mar 25, 2019
  26. 8/8 commit-graph: improve & i18n error messagesÆvar Arnfjörð Bjarmason, Mar 25, 2019
  27. 7/8 commit-graph write: don't die if the existing graph is corruptÆvar Arnfjörð Bjarmason, Mar 25, 2019
  28. 6/8 commit-graph verify: detect inability to read the graphÆvar Arnfjörð Bjarmason, Mar 25, 2019
  29. 1/8 commit-graph tests: split up corrupt_graph_and_verify()Ævar Arnfjörð Bjarmason, Mar 14, 2019
  30. 2/8 commit-graph tests: test a graph that's too smallÆvar Arnfjörð Bjarmason, Mar 14, 2019
  31. 3/8 commit-graph: fix segfault on e.g. "git status"Ævar Arnfjörð Bjarmason, Mar 14, 2019
  32. 5/8 commit-graph: don't pass filename to load_commit_graph_one_fd_st()Ævar Arnfjörð Bjarmason, Mar 14, 2019
  33. 4/8 commit-graph: don't early exit(1) on e.g. "git status"Ævar Arnfjörð Bjarmason, Mar 14, 2019
  34. 6/8 commit-graph verify: detect inability to read the graphÆvar Arnfjörð Bjarmason, Mar 14, 2019
  35. 7/8 commit-graph write: don't die if the existing graph is corruptÆvar Arnfjörð Bjarmason, Mar 14, 2019
  36. 8/8 commit-graph: improve & i18n error messagesÆvar Arnfjörð Bjarmason, Mar 14, 2019

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.