1
+#include "cache.h"
2
+#include "chunk-format.h"
3
+#include "csum-file.h"
4
+
5
+/*
6
+ * When writing a chunk-based file format, collect the chunks in
7
+ * an array of chunk_info structs. The size stores the _expected_
8
+ * amount of data that will be written by write_fn.
9
+ */
10
+struct chunk_info {
11
+ uint32_t id;
12
+ uint64_t size;
13
+ chunk_write_fn write_fn;
14
+};
15
+
16
+struct chunkfile {
17
+ struct hashfile *f;
18
+
19
+ struct chunk_info *chunks;
20
+ size_t chunks_nr;
21
+ size_t chunks_alloc;
22
+};
23
+
24
+struct chunkfile *init_chunkfile(struct hashfile *f)
25
+{
26
+ struct chunkfile *cf = xcalloc(1, sizeof(*cf));
27
+ cf->f = f;
28
+ return cf;
29
+}
30
+
31
+void free_chunkfile(struct chunkfile *cf)
32
+{
33
+ if (!cf)
34
+ return;
35
+ free(cf->chunks);
36
+ free(cf);
37
+}
38
+
39
+int get_num_chunks(struct chunkfile *cf)
40
+{
41
+ return cf->chunks_nr;
42
+}
43
+
44
+void add_chunk(struct chunkfile *cf,
45
+ uint32_t id,
46
+ size_t size,
47
+ chunk_write_fn fn)
48
+{
49
+ ALLOC_GROW(cf->chunks, cf->chunks_nr + 1, cf->chunks_alloc);
50
+
51
+ cf->chunks[cf->chunks_nr].id = id;
52
+ cf->chunks[cf->chunks_nr].write_fn = fn;
53
+ cf->chunks[cf->chunks_nr].size = size;
54
+ cf->chunks_nr++;
55
+}
56
+
57
+int write_chunkfile(struct chunkfile *cf, void *data)
58
+{
59
+ int i;
60
+ uint64_t cur_offset = hashfile_total(cf->f);
61
+
62
+ /* Add the table of contents to the current offset */
63
+ cur_offset += (cf->chunks_nr + 1) * CHUNK_TOC_ENTRY_SIZE;
64
+
65
+ for (i = 0; i < cf->chunks_nr; i++) {
66
+ hashwrite_be32(cf->f, cf->chunks[i].id);
67
+ hashwrite_be64(cf->f, cur_offset);
68
+
69
+ cur_offset += cf->chunks[i].size;
70
+ }
71
+
72
+ /* Trailing entry marks the end of the chunks */
73
+ hashwrite_be32(cf->f, 0);
74
+ hashwrite_be64(cf->f, cur_offset);
75
+
76
+ for (i = 0; i < cf->chunks_nr; i++) {
77
+ off_t start_offset = hashfile_total(cf->f);
78
+ int result = cf->chunks[i].write_fn(cf->f, data);
79
+
80
+ if (result)
81
+ return result;
82
+
83
+ if (hashfile_total(cf->f) - start_offset != cf->chunks[i].size)
84
+ BUG("expected to write %"PRId64" bytes to chunk %"PRIx32", but wrote %"PRId64" instead",
85
+ cf->chunks[i].size, cf->chunks[i].id,
86
+ hashfile_total(cf->f) - start_offset);
87
+ }
88
+
89
+ return 0;
90
+}