|
| 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 | +} |
0 commit comments