chunk-format: create chunk format write API
[git] / chunk-format.c
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 }