]> git.ipfire.org Git - thirdparty/git.git/blame - chunk-format.c
environment.h: move declarations for environment.c functions from cache.h
[thirdparty/git.git] / chunk-format.c
CommitLineData
36bf1958
EN
1#include "git-compat-util.h"
2#include "alloc.h"
570df426
DS
3#include "chunk-format.h"
4#include "csum-file.h"
f394e093 5#include "gettext.h"
570df426
DS
6
7/*
8 * When writing a chunk-based file format, collect the chunks in
9 * an array of chunk_info structs. The size stores the _expected_
10 * amount of data that will be written by write_fn.
11 */
12struct chunk_info {
13 uint32_t id;
14 uint64_t size;
15 chunk_write_fn write_fn;
5f0879f5
DS
16
17 const void *start;
570df426
DS
18};
19
20struct chunkfile {
21 struct hashfile *f;
22
23 struct chunk_info *chunks;
24 size_t chunks_nr;
25 size_t chunks_alloc;
26};
27
28struct chunkfile *init_chunkfile(struct hashfile *f)
29{
30 struct chunkfile *cf = xcalloc(1, sizeof(*cf));
31 cf->f = f;
32 return cf;
33}
34
35void free_chunkfile(struct chunkfile *cf)
36{
37 if (!cf)
38 return;
39 free(cf->chunks);
40 free(cf);
41}
42
43int get_num_chunks(struct chunkfile *cf)
44{
45 return cf->chunks_nr;
46}
47
48void add_chunk(struct chunkfile *cf,
49 uint32_t id,
50 size_t size,
51 chunk_write_fn fn)
52{
53 ALLOC_GROW(cf->chunks, cf->chunks_nr + 1, cf->chunks_alloc);
54
55 cf->chunks[cf->chunks_nr].id = id;
56 cf->chunks[cf->chunks_nr].write_fn = fn;
57 cf->chunks[cf->chunks_nr].size = size;
58 cf->chunks_nr++;
59}
60
61int write_chunkfile(struct chunkfile *cf, void *data)
62{
2ca245f8 63 int i, result = 0;
570df426
DS
64 uint64_t cur_offset = hashfile_total(cf->f);
65
2ca245f8
DS
66 trace2_region_enter("chunkfile", "write", the_repository);
67
570df426
DS
68 /* Add the table of contents to the current offset */
69 cur_offset += (cf->chunks_nr + 1) * CHUNK_TOC_ENTRY_SIZE;
70
71 for (i = 0; i < cf->chunks_nr; i++) {
72 hashwrite_be32(cf->f, cf->chunks[i].id);
73 hashwrite_be64(cf->f, cur_offset);
74
75 cur_offset += cf->chunks[i].size;
76 }
77
78 /* Trailing entry marks the end of the chunks */
79 hashwrite_be32(cf->f, 0);
80 hashwrite_be64(cf->f, cur_offset);
81
82 for (i = 0; i < cf->chunks_nr; i++) {
83 off_t start_offset = hashfile_total(cf->f);
2ca245f8 84 result = cf->chunks[i].write_fn(cf->f, data);
570df426
DS
85
86 if (result)
2ca245f8 87 goto cleanup;
570df426
DS
88
89 if (hashfile_total(cf->f) - start_offset != cf->chunks[i].size)
90 BUG("expected to write %"PRId64" bytes to chunk %"PRIx32", but wrote %"PRId64" instead",
91 cf->chunks[i].size, cf->chunks[i].id,
92 hashfile_total(cf->f) - start_offset);
93 }
94
2ca245f8
DS
95cleanup:
96 trace2_region_leave("chunkfile", "write", the_repository);
97 return result;
570df426 98}
5f0879f5
DS
99
100int read_table_of_contents(struct chunkfile *cf,
101 const unsigned char *mfile,
102 size_t mfile_size,
103 uint64_t toc_offset,
104 int toc_length)
105{
5387fefa 106 int i;
5f0879f5
DS
107 uint32_t chunk_id;
108 const unsigned char *table_of_contents = mfile + toc_offset;
109
110 ALLOC_GROW(cf->chunks, toc_length, cf->chunks_alloc);
111
112 while (toc_length--) {
113 uint64_t chunk_offset, next_chunk_offset;
114
115 chunk_id = get_be32(table_of_contents);
116 chunk_offset = get_be64(table_of_contents + 4);
117
118 if (!chunk_id) {
119 error(_("terminating chunk id appears earlier than expected"));
120 return 1;
121 }
122
123 table_of_contents += CHUNK_TOC_ENTRY_SIZE;
124 next_chunk_offset = get_be64(table_of_contents + 4);
125
126 if (next_chunk_offset < chunk_offset ||
127 next_chunk_offset > mfile_size - the_hash_algo->rawsz) {
128 error(_("improper chunk offset(s) %"PRIx64" and %"PRIx64""),
129 chunk_offset, next_chunk_offset);
130 return -1;
131 }
132
5387fefa
DS
133 for (i = 0; i < cf->chunks_nr; i++) {
134 if (cf->chunks[i].id == chunk_id) {
135 error(_("duplicate chunk ID %"PRIx32" found"),
136 chunk_id);
137 return -1;
138 }
139 }
140
5f0879f5
DS
141 cf->chunks[cf->chunks_nr].id = chunk_id;
142 cf->chunks[cf->chunks_nr].start = mfile + chunk_offset;
143 cf->chunks[cf->chunks_nr].size = next_chunk_offset - chunk_offset;
144 cf->chunks_nr++;
145 }
146
147 chunk_id = get_be32(table_of_contents);
148 if (chunk_id) {
149 error(_("final chunk has non-zero id %"PRIx32""), chunk_id);
150 return -1;
151 }
152
153 return 0;
154}
155
156static int pair_chunk_fn(const unsigned char *chunk_start,
157 size_t chunk_size,
158 void *data)
159{
160 const unsigned char **p = data;
161 *p = chunk_start;
162 return 0;
163}
164
165int pair_chunk(struct chunkfile *cf,
166 uint32_t chunk_id,
167 const unsigned char **p)
168{
169 return read_chunk(cf, chunk_id, pair_chunk_fn, p);
170}
171
172int read_chunk(struct chunkfile *cf,
173 uint32_t chunk_id,
174 chunk_read_fn fn,
175 void *data)
176{
177 int i;
178
179 for (i = 0; i < cf->chunks_nr; i++) {
180 if (cf->chunks[i].id == chunk_id)
181 return fn(cf->chunks[i].start, cf->chunks[i].size, data);
182 }
183
184 return CHUNK_NOT_FOUND;
185}
d9fef9d9
TB
186
187uint8_t oid_version(const struct git_hash_algo *algop)
188{
189 switch (hash_algo_by_ptr(algop)) {
190 case GIT_HASH_SHA1:
191 return 1;
192 case GIT_HASH_SHA256:
193 return 2;
194 default:
195 die(_("invalid hash version"));
196 }
197}