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