Skip to content

Commit e103f72

Browse files
derrickstoleegitster
authored andcommitted
commit-graph: return with errors during write
The write_commit_graph() method uses die() to report failure and exit when confronted with an unexpected condition. This use of die() in a library function is incorrect and is now replaced by error() statements and an int return type. Return zero on success and a negative value on failure. Now that we use 'goto cleanup' to jump to the terminal condition on an error, we have new paths that could lead to uninitialized values. New initializers are added to correct for this. The builtins 'commit-graph', 'gc', and 'commit' call these methods, so update them to check the return value. Test that 'git commit-graph write' returns a proper error code when hitting a failure condition in write_commit_graph(). Signed-off-by: Derrick Stolee <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent c794405 commit e103f72

File tree

6 files changed

+77
-39
lines changed

6 files changed

+77
-39
lines changed

builtin/commit-graph.c

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@ static int graph_write(int argc, const char **argv)
141141
struct string_list *pack_indexes = NULL;
142142
struct string_list *commit_hex = NULL;
143143
struct string_list lines;
144+
int result = 0;
144145

145146
static struct option builtin_commit_graph_write_options[] = {
146147
OPT_STRING(0, "object-dir", &opts.obj_dir,
@@ -168,10 +169,8 @@ static int graph_write(int argc, const char **argv)
168169

169170
read_replace_refs = 0;
170171

171-
if (opts.reachable) {
172-
write_commit_graph_reachable(opts.obj_dir, opts.append, 1);
173-
return 0;
174-
}
172+
if (opts.reachable)
173+
return write_commit_graph_reachable(opts.obj_dir, opts.append, 1);
175174

176175
string_list_init(&lines, 0);
177176
if (opts.stdin_packs || opts.stdin_commits) {
@@ -188,14 +187,15 @@ static int graph_write(int argc, const char **argv)
188187
UNLEAK(buf);
189188
}
190189

191-
write_commit_graph(opts.obj_dir,
192-
pack_indexes,
193-
commit_hex,
194-
opts.append,
195-
1);
190+
if (write_commit_graph(opts.obj_dir,
191+
pack_indexes,
192+
commit_hex,
193+
opts.append,
194+
1))
195+
result = 1;
196196

197197
UNLEAK(lines);
198-
return 0;
198+
return result;
199199
}
200200

201201
int cmd_commit_graph(int argc, const char **argv, const char *prefix)

builtin/commit.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1669,8 +1669,9 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
16691669
"new_index file. Check that disk is not full and quota is\n"
16701670
"not exceeded, and then \"git reset HEAD\" to recover."));
16711671

1672-
if (git_env_bool(GIT_TEST_COMMIT_GRAPH, 0))
1673-
write_commit_graph_reachable(get_object_directory(), 0, 0);
1672+
if (git_env_bool(GIT_TEST_COMMIT_GRAPH, 0) &&
1673+
write_commit_graph_reachable(get_object_directory(), 0, 0))
1674+
return 1;
16741675

16751676
repo_rerere(the_repository, 0);
16761677
run_command_v_opt(argv_gc_auto, RUN_GIT_CMD);

builtin/gc.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -664,9 +664,10 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
664664
clean_pack_garbage();
665665
}
666666

667-
if (gc_write_commit_graph)
668-
write_commit_graph_reachable(get_object_directory(), 0,
669-
!quiet && !daemonized);
667+
if (gc_write_commit_graph &&
668+
write_commit_graph_reachable(get_object_directory(), 0,
669+
!quiet && !daemonized))
670+
return 1;
670671

671672
if (auto_gc && too_many_loose_objects())
672673
warning(_("There are too many unreachable loose objects; "

commit-graph.c

Lines changed: 41 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -851,27 +851,30 @@ static int add_ref_to_list(const char *refname,
851851
return 0;
852852
}
853853

854-
void write_commit_graph_reachable(const char *obj_dir, int append,
855-
int report_progress)
854+
int write_commit_graph_reachable(const char *obj_dir, int append,
855+
int report_progress)
856856
{
857857
struct string_list list = STRING_LIST_INIT_DUP;
858+
int result;
858859

859860
for_each_ref(add_ref_to_list, &list);
860-
write_commit_graph(obj_dir, NULL, &list, append, report_progress);
861+
result = write_commit_graph(obj_dir, NULL, &list,
862+
append, report_progress);
861863

862864
string_list_clear(&list, 0);
865+
return result;
863866
}
864867

865-
void write_commit_graph(const char *obj_dir,
866-
struct string_list *pack_indexes,
867-
struct string_list *commit_hex,
868-
int append, int report_progress)
868+
int write_commit_graph(const char *obj_dir,
869+
struct string_list *pack_indexes,
870+
struct string_list *commit_hex,
871+
int append, int report_progress)
869872
{
870873
struct packed_oid_list oids;
871874
struct packed_commit_list commits;
872875
struct hashfile *f;
873876
uint32_t i, count_distinct = 0;
874-
char *graph_name;
877+
char *graph_name = NULL;
875878
struct lock_file lk = LOCK_INIT;
876879
uint32_t chunk_ids[5];
877880
uint64_t chunk_offsets[5];
@@ -883,15 +886,17 @@ void write_commit_graph(const char *obj_dir,
883886
uint64_t progress_cnt = 0;
884887
struct strbuf progress_title = STRBUF_INIT;
885888
unsigned long approx_nr_objects;
889+
int res = 0;
886890

887891
if (!commit_graph_compatible(the_repository))
888-
return;
892+
return 0;
889893

890894
oids.nr = 0;
891895
approx_nr_objects = approximate_object_count();
892896
oids.alloc = approx_nr_objects / 32;
893897
oids.progress = NULL;
894898
oids.progress_done = 0;
899+
commits.list = NULL;
895900

896901
if (append) {
897902
prepare_commit_graph_one(the_repository, obj_dir);
@@ -932,10 +937,16 @@ void write_commit_graph(const char *obj_dir,
932937
strbuf_setlen(&packname, dirlen);
933938
strbuf_addstr(&packname, pack_indexes->items[i].string);
934939
p = add_packed_git(packname.buf, packname.len, 1);
935-
if (!p)
936-
die(_("error adding pack %s"), packname.buf);
937-
if (open_pack_index(p))
938-
die(_("error opening index for %s"), packname.buf);
940+
if (!p) {
941+
error(_("error adding pack %s"), packname.buf);
942+
res = -1;
943+
goto cleanup;
944+
}
945+
if (open_pack_index(p)) {
946+
error(_("error opening index for %s"), packname.buf);
947+
res = -1;
948+
goto cleanup;
949+
}
939950
for_each_object_in_pack(p, add_packed_commits, &oids,
940951
FOR_EACH_OBJECT_PACK_ORDER);
941952
close_pack(p);
@@ -1006,8 +1017,11 @@ void write_commit_graph(const char *obj_dir,
10061017
}
10071018
stop_progress(&progress);
10081019

1009-
if (count_distinct >= GRAPH_EDGE_LAST_MASK)
1010-
die(_("the commit graph format cannot write %d commits"), count_distinct);
1020+
if (count_distinct >= GRAPH_EDGE_LAST_MASK) {
1021+
error(_("the commit graph format cannot write %d commits"), count_distinct);
1022+
res = -1;
1023+
goto cleanup;
1024+
}
10111025

10121026
commits.nr = 0;
10131027
commits.alloc = count_distinct;
@@ -1039,16 +1053,21 @@ void write_commit_graph(const char *obj_dir,
10391053
num_chunks = num_extra_edges ? 4 : 3;
10401054
stop_progress(&progress);
10411055

1042-
if (commits.nr >= GRAPH_EDGE_LAST_MASK)
1043-
die(_("too many commits to write graph"));
1056+
if (commits.nr >= GRAPH_EDGE_LAST_MASK) {
1057+
error(_("too many commits to write graph"));
1058+
res = -1;
1059+
goto cleanup;
1060+
}
10441061

10451062
compute_generation_numbers(&commits, report_progress);
10461063

10471064
graph_name = get_commit_graph_filename(obj_dir);
10481065
if (safe_create_leading_directories(graph_name)) {
10491066
UNLEAK(graph_name);
1050-
die_errno(_("unable to create leading directories of %s"),
1051-
graph_name);
1067+
error(_("unable to create leading directories of %s"),
1068+
graph_name);
1069+
res = -1;
1070+
goto cleanup;
10521071
}
10531072

10541073
hold_lock_file_for_update(&lk, graph_name, LOCK_DIE_ON_ERROR);
@@ -1107,9 +1126,12 @@ void write_commit_graph(const char *obj_dir,
11071126
finalize_hashfile(f, NULL, CSUM_HASH_IN_STREAM | CSUM_FSYNC);
11081127
commit_lock_file(&lk);
11091128

1129+
cleanup:
11101130
free(graph_name);
11111131
free(commits.list);
11121132
free(oids.list);
1133+
1134+
return res;
11131135
}
11141136

11151137
#define VERIFY_COMMIT_GRAPH_ERROR_HASH 2

commit-graph.h

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -65,12 +65,18 @@ struct commit_graph *parse_commit_graph(void *graph_map, int fd,
6565
*/
6666
int generation_numbers_enabled(struct repository *r);
6767

68-
void write_commit_graph_reachable(const char *obj_dir, int append,
68+
/*
69+
* The write_commit_graph* methods return zero on success
70+
* and a negative value on failure. Note that if the repository
71+
* is not compatible with the commit-graph feature, then the
72+
* methods will return 0 without writing a commit-graph.
73+
*/
74+
int write_commit_graph_reachable(const char *obj_dir, int append,
6975
int report_progress);
70-
void write_commit_graph(const char *obj_dir,
71-
struct string_list *pack_indexes,
72-
struct string_list *commit_hex,
73-
int append, int report_progress);
76+
int write_commit_graph(const char *obj_dir,
77+
struct string_list *pack_indexes,
78+
struct string_list *commit_hex,
79+
int append, int report_progress);
7480

7581
int verify_commit_graph(struct repository *r, struct commit_graph *g);
7682

t/t5318-commit-graph.sh

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,14 @@ test_expect_success 'write graph with no packs' '
2323
test_path_is_file info/commit-graph
2424
'
2525

26+
test_expect_success 'close with correct error on bad input' '
27+
cd "$TRASH_DIRECTORY/full" &&
28+
echo doesnotexist >in &&
29+
{ git commit-graph write --stdin-packs <in 2>stderr; ret=$?; } &&
30+
test "$ret" = 1 &&
31+
test_i18ngrep "error adding pack" stderr
32+
'
33+
2634
test_expect_success 'create commits and repack' '
2735
cd "$TRASH_DIRECTORY/full" &&
2836
for i in $(test_seq 3)

0 commit comments

Comments
 (0)