summaryrefslogtreecommitdiff
path: root/commit-graph.c
diff options
context:
space:
mode:
Diffstat (limited to 'commit-graph.c')
-rw-r--r--commit-graph.c143
1 files changed, 98 insertions, 45 deletions
diff --git a/commit-graph.c b/commit-graph.c
index 47e9be0a3a..7c5e54875f 100644
--- a/commit-graph.c
+++ b/commit-graph.c
@@ -80,25 +80,30 @@ 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(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(_("commit-graph file is too small"));
+ return NULL;
}
graph_map = xmmap(NULL, graph_size, PROT_READ, MAP_PRIVATE, fd, 0);
ret = parse_commit_graph(graph_map, fd, graph_size);
@@ -106,12 +111,41 @@ struct commit_graph *load_commit_graph_one(const char *graph_file)
if (!ret) {
munmap(graph_map, graph_size);
close(fd);
- exit(1);
}
return ret;
}
+static int verify_commit_graph_lite(struct commit_graph *g)
+{
+ /*
+ * Basic validation shared between parse_commit_graph()
+ * which'll be called every time the graph is used, and the
+ * much more expensive verify_commit_graph() used by
+ * "commit-graph verify".
+ *
+ * There should only be very basic checks here to ensure that
+ * we don't e.g. segfault in fill_commit_in_graph(), but
+ * because this is a very hot codepath nothing that e.g. loops
+ * over g->num_commits, or runs a checksum on the commit-graph
+ * itself.
+ */
+ if (!g->chunk_oid_fanout) {
+ error("commit-graph is missing the OID Fanout chunk");
+ return 1;
+ }
+ if (!g->chunk_oid_lookup) {
+ error("commit-graph is missing the OID Lookup chunk");
+ return 1;
+ }
+ if (!g->chunk_commit_data) {
+ error("commit-graph is missing the Commit Data chunk");
+ return 1;
+ }
+
+ return 0;
+}
+
struct commit_graph *parse_commit_graph(void *graph_map, int fd,
size_t graph_size)
{
@@ -133,21 +167,21 @@ struct commit_graph *parse_commit_graph(void *graph_map, int fd,
graph_signature = get_be32(data);
if (graph_signature != GRAPH_SIGNATURE) {
- error(_("graph signature %X does not match signature %X"),
+ error(_("commit-graph signature %X does not match signature %X"),
graph_signature, GRAPH_SIGNATURE);
return NULL;
}
graph_version = *(unsigned char*)(data + 4);
if (graph_version != GRAPH_VERSION) {
- error(_("graph version %X does not match version %X"),
+ error(_("commit-graph version %X does not match version %X"),
graph_version, GRAPH_VERSION);
return NULL;
}
hash_version = *(unsigned char*)(data + 5);
if (hash_version != oid_version()) {
- error(_("hash version %X does not match version %X"),
+ error(_("commit-graph hash version %X does not match version %X"),
hash_version, oid_version());
return NULL;
}
@@ -170,7 +204,7 @@ struct commit_graph *parse_commit_graph(void *graph_map, int fd,
if (data + graph_size - chunk_lookup <
GRAPH_CHUNKLOOKUP_WIDTH) {
- error(_("chunk lookup table entry missing; graph file may be incomplete"));
+ error(_("commit-graph chunk lookup table entry missing; file may be incomplete"));
free(graph);
return NULL;
}
@@ -181,7 +215,7 @@ struct commit_graph *parse_commit_graph(void *graph_map, int fd,
chunk_lookup += GRAPH_CHUNKLOOKUP_WIDTH;
if (chunk_offset > graph_size - the_hash_algo->rawsz) {
- error(_("improper chunk offset %08x%08x"), (uint32_t)(chunk_offset >> 32),
+ error(_("commit-graph improper chunk offset %08x%08x"), (uint32_t)(chunk_offset >> 32),
(uint32_t)chunk_offset);
free(graph);
return NULL;
@@ -218,7 +252,7 @@ struct commit_graph *parse_commit_graph(void *graph_map, int fd,
}
if (chunk_repeated) {
- error(_("chunk id %08x appears multiple times"), chunk_id);
+ error(_("commit-graph chunk id %08x appears multiple times"), chunk_id);
free(graph);
return NULL;
}
@@ -233,9 +267,27 @@ struct commit_graph *parse_commit_graph(void *graph_map, int fd,
last_chunk_offset = chunk_offset;
}
+ if (verify_commit_graph_lite(graph)) {
+ free(graph);
+ return NULL;
+ }
+
return graph;
}
+static 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(fd, &st);
+}
+
static void prepare_commit_graph_one(struct repository *r, const char *obj_dir)
{
char *graph_name;
@@ -261,6 +313,10 @@ static int prepare_commit_graph(struct repository *r)
struct object_directory *odb;
int config_value;
+ if (git_env_bool(GIT_TEST_COMMIT_GRAPH_DIE_ON_LOAD, 0))
+ die("dying as requested by the '%s' variable on commit-graph load!",
+ GIT_TEST_COMMIT_GRAPH_DIE_ON_LOAD);
+
if (r->objects->commit_graph_attempted)
return !!r->objects->commit_graph;
r->objects->commit_graph_attempted = 1;
@@ -343,6 +399,11 @@ static void fill_commit_graph_info(struct commit *item, struct commit_graph *g,
item->generation = get_be32(commit_data + g->hash_len + 8) >> 2;
}
+static inline void set_commit_tree(struct commit *c, struct tree *t)
+{
+ c->maybe_tree = t;
+}
+
static int fill_commit_in_graph(struct repository *r,
struct commit *item,
struct commit_graph *g, uint32_t pos)
@@ -356,7 +417,7 @@ static int fill_commit_in_graph(struct repository *r,
item->object.parsed = 1;
item->graph_pos = pos;
- item->maybe_tree = NULL;
+ set_commit_tree(item, NULL);
date_high = get_be32(commit_data + g->hash_len + 8) & 0x3;
date_low = get_be32(commit_data + g->hash_len + 12);
@@ -442,7 +503,7 @@ static struct tree *load_tree_for_commit(struct repository *r,
GRAPH_DATA_WIDTH * (c->graph_pos);
hashcpy(oid.hash, commit_data);
- c->maybe_tree = lookup_tree(r, &oid);
+ set_commit_tree(c, lookup_tree(r, &oid));
return c->maybe_tree;
}
@@ -525,7 +586,7 @@ static void write_graph_chunk_data(struct hashfile *f, int hash_len,
uint32_t packedDate[2];
display_progress(progress, ++*progress_cnt);
- parse_commit(*list);
+ parse_commit_no_graph(*list);
hashwrite(f, get_commit_tree_oid(*list)->hash, hash_len);
parent = (*list)->parents;
@@ -722,7 +783,7 @@ static void close_reachable(struct packed_oid_list *oids, int report_progress)
display_progress(progress, i + 1);
commit = lookup_commit(the_repository, &oids->list[i]);
- if (commit && !parse_commit(commit))
+ if (commit && !parse_commit_no_graph(commit))
add_missing_parents(oids, commit);
}
stop_progress(&progress);
@@ -971,7 +1032,7 @@ void write_commit_graph(const char *obj_dir,
continue;
commits.list[commits.nr] = lookup_commit(the_repository, &oids.list[i]);
- parse_commit(commits.list[commits.nr]);
+ parse_commit_no_graph(commits.list[commits.nr]);
for (parent = commits.list[commits.nr]->parents;
parent; parent = parent->next)
@@ -1089,15 +1150,7 @@ int verify_commit_graph(struct repository *r, struct commit_graph *g)
return 1;
}
- verify_commit_graph_error = 0;
-
- if (!g->chunk_oid_fanout)
- graph_report("commit-graph is missing the OID Fanout chunk");
- if (!g->chunk_oid_lookup)
- graph_report("commit-graph is missing the OID Lookup chunk");
- if (!g->chunk_commit_data)
- graph_report("commit-graph is missing the Commit Data chunk");
-
+ verify_commit_graph_error = verify_commit_graph_lite(g);
if (verify_commit_graph_error)
return verify_commit_graph_error;
@@ -1116,7 +1169,7 @@ int verify_commit_graph(struct repository *r, struct commit_graph *g)
hashcpy(cur_oid.hash, g->chunk_oid_lookup + g->hash_len * i);
if (i && oidcmp(&prev_oid, &cur_oid) >= 0)
- graph_report("commit-graph has incorrect OID order: %s then %s",
+ graph_report(_("commit-graph has incorrect OID order: %s then %s"),
oid_to_hex(&prev_oid),
oid_to_hex(&cur_oid));
@@ -1126,14 +1179,14 @@ int verify_commit_graph(struct repository *r, struct commit_graph *g)
uint32_t fanout_value = get_be32(g->chunk_oid_fanout + cur_fanout_pos);
if (i != fanout_value)
- graph_report("commit-graph has incorrect fanout value: fanout[%d] = %u != %u",
+ graph_report(_("commit-graph has incorrect fanout value: fanout[%d] = %u != %u"),
cur_fanout_pos, fanout_value, i);
cur_fanout_pos++;
}
graph_commit = lookup_commit(r, &cur_oid);
if (!parse_commit_in_graph_one(r, g, graph_commit))
- graph_report("failed to parse %s from commit-graph",
+ graph_report(_("failed to parse commit %s from commit-graph"),
oid_to_hex(&cur_oid));
}
@@ -1141,7 +1194,7 @@ int verify_commit_graph(struct repository *r, struct commit_graph *g)
uint32_t fanout_value = get_be32(g->chunk_oid_fanout + cur_fanout_pos);
if (g->num_commits != fanout_value)
- graph_report("commit-graph has incorrect fanout value: fanout[%d] = %u != %u",
+ graph_report(_("commit-graph has incorrect fanout value: fanout[%d] = %u != %u"),
cur_fanout_pos, fanout_value, i);
cur_fanout_pos++;
@@ -1163,14 +1216,14 @@ int verify_commit_graph(struct repository *r, struct commit_graph *g)
graph_commit = lookup_commit(r, &cur_oid);
odb_commit = (struct commit *)create_object(r, cur_oid.hash, alloc_commit_node(r));
if (parse_commit_internal(odb_commit, 0, 0)) {
- graph_report("failed to parse %s from object database",
+ graph_report(_("failed to parse commit %s from object database for commit-graph"),
oid_to_hex(&cur_oid));
continue;
}
if (!oideq(&get_commit_tree_in_graph_one(r, g, graph_commit)->object.oid,
get_commit_tree_oid(odb_commit)))
- graph_report("root tree OID for commit %s in commit-graph is %s != %s",
+ graph_report(_("root tree OID for commit %s in commit-graph is %s != %s"),
oid_to_hex(&cur_oid),
oid_to_hex(get_commit_tree_oid(graph_commit)),
oid_to_hex(get_commit_tree_oid(odb_commit)));
@@ -1180,13 +1233,13 @@ int verify_commit_graph(struct repository *r, struct commit_graph *g)
while (graph_parents) {
if (odb_parents == NULL) {
- graph_report("commit-graph parent list for commit %s is too long",
+ graph_report(_("commit-graph parent list for commit %s is too long"),
oid_to_hex(&cur_oid));
break;
}
if (!oideq(&graph_parents->item->object.oid, &odb_parents->item->object.oid))
- graph_report("commit-graph parent for %s is %s != %s",
+ graph_report(_("commit-graph parent for %s is %s != %s"),
oid_to_hex(&cur_oid),
oid_to_hex(&graph_parents->item->object.oid),
oid_to_hex(&odb_parents->item->object.oid));
@@ -1199,16 +1252,16 @@ int verify_commit_graph(struct repository *r, struct commit_graph *g)
}
if (odb_parents != NULL)
- graph_report("commit-graph parent list for commit %s terminates early",
+ graph_report(_("commit-graph parent list for commit %s terminates early"),
oid_to_hex(&cur_oid));
if (!graph_commit->generation) {
if (generation_zero == GENERATION_NUMBER_EXISTS)
- graph_report("commit-graph has generation number zero for commit %s, but non-zero elsewhere",
+ graph_report(_("commit-graph has generation number zero for commit %s, but non-zero elsewhere"),
oid_to_hex(&cur_oid));
generation_zero = GENERATION_ZERO_EXISTS;
} else if (generation_zero == GENERATION_ZERO_EXISTS)
- graph_report("commit-graph has non-zero generation number for commit %s, but zero elsewhere",
+ graph_report(_("commit-graph has non-zero generation number for commit %s, but zero elsewhere"),
oid_to_hex(&cur_oid));
if (generation_zero == GENERATION_ZERO_EXISTS)
@@ -1223,13 +1276,13 @@ int verify_commit_graph(struct repository *r, struct commit_graph *g)
max_generation--;
if (graph_commit->generation != max_generation + 1)
- graph_report("commit-graph generation for commit %s is %u != %u",
+ graph_report(_("commit-graph generation for commit %s is %u != %u"),
oid_to_hex(&cur_oid),
graph_commit->generation,
max_generation + 1);
if (graph_commit->date != odb_commit->date)
- graph_report("commit date for commit %s in commit-graph is %"PRItime" != %"PRItime,
+ graph_report(_("commit date for commit %s in commit-graph is %"PRItime" != %"PRItime),
oid_to_hex(&cur_oid),
graph_commit->date,
odb_commit->date);