commit-graph: add base graphs chunk

To quickly verify a commit-graph chain is valid on load, we will read from the new "Base Graphs Chunk" of each file in the chain. This will prevent accidentally loading incorrect data from manually editing the commit-graph-chain file or renaming graph-{hash}.graph files. The commit_graph struct already had an object_id struct "oid", but it was never initialized or used. Add a line to read the hash from the end of the commit-graph file and into the oid member. Signed-off-by: Derrick Stolee <dstolee@microsoft.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Derrick Stolee committed Jun 18, 2019 at 11:14 UTC 118bd570029f5610abdbf1a220e87d3a5c241f5f
3 files changed +32 -2
Documentation/technical/commit-graph-format.txt
+9 -2
@@ -44,8 +44,9 @@ HEADER:
44
45 1-byte number (C) of "chunks"
46
47 - 1-byte (reserved for later use)
48 - Current clients should ignore this value.
47 + 1-byte number (B) of base commit-graphs
48 + We infer the length (H*B) of the Base Graphs chunk
49 + from this value.
50
51 CHUNK LOOKUP:
52
@@ -92,6 +93,12 @@ CHUNK DATA:
93 positions for the parents until reaching a value with the most-significant
94 bit on. The other bits correspond to the position of the last parent.
95
96 + Base Graphs List (ID: {'B', 'A', 'S', 'E'}) [Optional]
97 + This list of H-byte hashes describe a set of B commit-graph files that
98 + form a commit-graph chain. The graph position for the ith commit in this
99 + file's OID Lookup chunk is equal to i plus the number of commits in all
100 + base graphs. If B is non-zero, this chunk must exist.
101 +
102 TRAILER:
103
104 H-byte HASH-checksum of all of the above.
commit-graph.c
+22
@@ -22,6 +22,7 @@
22 #define GRAPH_CHUNKID_OIDLOOKUP 0x4f49444c /* "OIDL" */
23 #define GRAPH_CHUNKID_DATA 0x43444154 /* "CDAT" */
24 #define GRAPH_CHUNKID_EXTRAEDGES 0x45444745 /* "EDGE" */
25 +#define GRAPH_CHUNKID_BASE 0x42415345 /* "BASE" */
26
27 #define GRAPH_DATA_WIDTH (the_hash_algo->rawsz + 16)
28
@@ -262,6 +263,12 @@ struct commit_graph *parse_commit_graph(void *graph_map, int fd,
263 else
264 graph->chunk_extra_edges = data + chunk_offset;
265 break;
266 +
267 + case GRAPH_CHUNKID_BASE:
268 + if (graph->chunk_base_graphs)
269 + chunk_repeated = 1;
270 + else
271 + graph->chunk_base_graphs = data + chunk_offset;
272 }
273
274 if (chunk_repeated) {
@@ -280,6 +287,8 @@ struct commit_graph *parse_commit_graph(void *graph_map, int fd,
287 last_chunk_offset = chunk_offset;
288 }
289
290 + hashcpy(graph->oid.hash, graph->data + graph->data_len - graph->hash_len);
291 +
292 if (verify_commit_graph_lite(graph))
293 return NULL;
294
@@ -315,8 +324,21 @@ static int add_graph_to_chain(struct commit_graph *g,
324 {
325 struct commit_graph *cur_g = chain;
326
327 + if (n && !g->chunk_base_graphs) {
328 + warning(_("commit-graph has no base graphs chunk"));
329 + return 0;
330 + }
331 +
332 while (n) {
333 n--;
334 +
335 + if (!cur_g ||
336 + !oideq(&oids[n], &cur_g->oid) ||
337 + !hasheq(oids[n].hash, g->chunk_base_graphs + g->hash_len * n)) {
338 + warning(_("commit-graph chain does not match"));
339 + return 0;
340 + }
341 +
342 cur_g = cur_g->base_graph;
343 }
344
commit-graph.h
+1
@@ -55,6 +55,7 @@ struct commit_graph {
55 const unsigned char *chunk_oid_lookup;
56 const unsigned char *chunk_commit_data;
57 const unsigned char *chunk_extra_edges;
58 + const unsigned char *chunk_base_graphs;
59 };
60
61 struct commit_graph *load_commit_graph_one_fd_st(int fd, struct stat *st);