/proc/self/cwd/c/reader.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | Copyright 2020 Google LLC |
3 | | |
4 | | Use of this source code is governed by a BSD-style |
5 | | license that can be found in the LICENSE file or at |
6 | | https://developers.google.com/open-source/licenses/bsd |
7 | | */ |
8 | | |
9 | | #include "reader.h" |
10 | | |
11 | | #include "system.h" |
12 | | #include "block.h" |
13 | | #include "constants.h" |
14 | | #include "iter.h" |
15 | | #include "record.h" |
16 | | #include "reftable.h" |
17 | | #include "tree.h" |
18 | | |
19 | | uint64_t block_source_size(struct reftable_block_source source) |
20 | 347 | { |
21 | 347 | return source.ops->size(source.arg); |
22 | 347 | } |
23 | | |
24 | | int block_source_read_block(struct reftable_block_source source, |
25 | | struct reftable_block *dest, uint64_t off, |
26 | | uint32_t size) |
27 | 2.35k | { |
28 | 2.35k | int result = source.ops->read_block(source.arg, dest, off, size); |
29 | 2.35k | dest->source = source; |
30 | 2.35k | return result; |
31 | 2.35k | } |
32 | | |
33 | | void reftable_block_done(struct reftable_block *blockp) |
34 | 2.40k | { |
35 | 2.40k | struct reftable_block_source source = blockp->source; |
36 | 2.40k | if (blockp != NULL && source.ops != NULL) |
37 | 2.40k | source.ops->return_block(source.arg, blockp); |
38 | 2.40k | blockp->data = NULL; |
39 | 2.40k | blockp->len = 0; |
40 | 2.40k | blockp->source.ops = NULL; |
41 | 2.40k | blockp->source.arg = NULL; |
42 | 2.40k | } |
43 | | |
44 | | void block_source_close(struct reftable_block_source *source) |
45 | 535 | { |
46 | 535 | if (source->ops == NULL) { |
47 | 188 | return; |
48 | 188 | } |
49 | 347 | |
50 | 347 | source->ops->close(source->arg); |
51 | 347 | source->ops = NULL; |
52 | 347 | } |
53 | | |
54 | | static struct reftable_reader_offsets * |
55 | | reader_offsets_for(struct reftable_reader *r, byte typ) |
56 | 3.48k | { |
57 | 3.48k | switch (typ) { |
58 | 3.48k | case BLOCK_TYPE_REF: |
59 | 3.20k | return &r->ref_offsets; |
60 | 3.48k | case BLOCK_TYPE_LOG: |
61 | 284 | return &r->log_offsets; |
62 | 3.48k | case BLOCK_TYPE_OBJ: |
63 | 3 | return &r->obj_offsets; |
64 | 0 | } |
65 | 0 | abort(); |
66 | 0 | } |
67 | | |
68 | | static int reader_get_block(struct reftable_reader *r, |
69 | | struct reftable_block *dest, uint64_t off, |
70 | | uint32_t sz) |
71 | 1.66k | { |
72 | 1.66k | if (off >= r->size) { |
73 | 0 | return 0; |
74 | 0 | } |
75 | 1.66k | |
76 | 1.66k | if (off + sz > r->size) { |
77 | 944 | sz = r->size - off; |
78 | 944 | } |
79 | 1.66k | |
80 | 1.66k | return block_source_read_block(r->source, dest, off, sz); |
81 | 1.66k | } |
82 | | |
83 | | uint32_t reftable_reader_hash_id(struct reftable_reader *r) |
84 | 4 | { |
85 | 4 | return r->hash_id; |
86 | 4 | } |
87 | | |
88 | | const char *reader_name(struct reftable_reader *r) |
89 | 187 | { |
90 | 187 | return r->name; |
91 | 187 | } |
92 | | |
93 | | static int parse_footer(struct reftable_reader *r, byte *footer, byte *header) |
94 | 346 | { |
95 | 346 | byte *f = footer; |
96 | 346 | int err = 0; |
97 | 346 | if (memcmp(f, "REFT", 4)) { |
98 | 0 | err = REFTABLE_FORMAT_ERROR; |
99 | 0 | goto exit; |
100 | 0 | } |
101 | 346 | f += 4; |
102 | 346 | |
103 | 346 | if (memcmp(footer, header, header_size(r->version))) { |
104 | 0 | err = REFTABLE_FORMAT_ERROR; |
105 | 0 | goto exit; |
106 | 0 | } |
107 | 346 | |
108 | 346 | f++; |
109 | 346 | r->block_size = get_be24(f); |
110 | 346 | |
111 | 346 | f += 3; |
112 | 346 | r->min_update_index = get_be64(f); |
113 | 346 | f += 8; |
114 | 346 | r->max_update_index = get_be64(f); |
115 | 346 | f += 8; |
116 | 346 | |
117 | 346 | if (r->version == 1) { |
118 | 345 | r->hash_id = SHA1_ID; |
119 | 345 | } else { |
120 | 1 | r->hash_id = get_be32(f); |
121 | 1 | switch (r->hash_id) { |
122 | 1 | case SHA1_ID: |
123 | 0 | break; |
124 | 1 | case SHA256_ID: |
125 | 1 | break; |
126 | 1 | default: |
127 | 0 | err = REFTABLE_FORMAT_ERROR; |
128 | 0 | goto exit; |
129 | 1 | } |
130 | 1 | f += 4; |
131 | 1 | } |
132 | 346 | |
133 | 346 | r->ref_offsets.index_offset = get_be64(f); |
134 | 346 | f += 8; |
135 | 346 | |
136 | 346 | r->obj_offsets.offset = get_be64(f); |
137 | 346 | f += 8; |
138 | 346 | |
139 | 346 | r->object_id_len = r->obj_offsets.offset & ((1 << 5) - 1); |
140 | 346 | r->obj_offsets.offset >>= 5; |
141 | 346 | |
142 | 346 | r->obj_offsets.index_offset = get_be64(f); |
143 | 346 | f += 8; |
144 | 346 | r->log_offsets.offset = get_be64(f); |
145 | 346 | f += 8; |
146 | 346 | r->log_offsets.index_offset = get_be64(f); |
147 | 346 | f += 8; |
148 | 346 | |
149 | 346 | { |
150 | 346 | uint32_t computed_crc = crc32(0, footer, f - footer); |
151 | 346 | uint32_t file_crc = get_be32(f); |
152 | 346 | f += 4; |
153 | 346 | if (computed_crc != file_crc) { |
154 | 0 | err = REFTABLE_FORMAT_ERROR; |
155 | 0 | goto exit; |
156 | 0 | } |
157 | 346 | } |
158 | 346 | |
159 | 346 | { |
160 | 346 | byte first_block_typ = header[header_size(r->version)]; |
161 | 346 | r->ref_offsets.present = (first_block_typ == BLOCK_TYPE_REF); |
162 | 346 | r->ref_offsets.offset = 0; |
163 | 346 | r->log_offsets.present = (first_block_typ == BLOCK_TYPE_LOG || |
164 | 346 | r->log_offsets.offset > 0); |
165 | 346 | r->obj_offsets.present = r->obj_offsets.offset > 0; |
166 | 346 | } |
167 | 346 | err = 0; |
168 | 346 | exit: |
169 | 346 | return err; |
170 | 346 | } |
171 | | |
172 | | int init_reader(struct reftable_reader *r, struct reftable_block_source source, |
173 | | const char *name) |
174 | 346 | { |
175 | 346 | struct reftable_block footer = { 0 }; |
176 | 346 | struct reftable_block header = { 0 }; |
177 | 346 | int err = 0; |
178 | 346 | |
179 | 346 | memset(r, 0, sizeof(struct reftable_reader)); |
180 | 346 | |
181 | 346 | /* Need +1 to read type of first block. */ |
182 | 346 | err = block_source_read_block(source, &header, 0, header_size(2) + 1); |
183 | 346 | if (err != header_size(2) + 1) { |
184 | 0 | err = REFTABLE_IO_ERROR; |
185 | 0 | goto exit; |
186 | 0 | } |
187 | 346 | |
188 | 346 | if (memcmp(header.data, "REFT", 4)) { |
189 | 0 | err = REFTABLE_FORMAT_ERROR; |
190 | 0 | goto exit; |
191 | 0 | } |
192 | 346 | r->version = header.data[4]; |
193 | 346 | if (r->version != 1 && r->version != 2) { |
194 | 0 | err = REFTABLE_FORMAT_ERROR; |
195 | 0 | goto exit; |
196 | 0 | } |
197 | 346 | |
198 | 346 | r->size = block_source_size(source) - footer_size(r->version); |
199 | 346 | r->source = source; |
200 | 346 | r->name = xstrdup(name); |
201 | 346 | r->hash_id = 0; |
202 | 346 | |
203 | 346 | err = block_source_read_block(source, &footer, r->size, |
204 | 346 | footer_size(r->version)); |
205 | 346 | if (err != footer_size(r->version)) { |
206 | 0 | err = REFTABLE_IO_ERROR; |
207 | 0 | goto exit; |
208 | 0 | } |
209 | 346 | |
210 | 346 | err = parse_footer(r, footer.data, header.data); |
211 | 346 | exit: |
212 | 346 | reftable_block_done(&footer); |
213 | 346 | reftable_block_done(&header); |
214 | 346 | return err; |
215 | 346 | } |
216 | | |
217 | | struct table_iter { |
218 | | struct reftable_reader *r; |
219 | | byte typ; |
220 | | uint64_t block_off; |
221 | | struct block_iter bi; |
222 | | bool finished; |
223 | | }; |
224 | | |
225 | | static void table_iter_copy_from(struct table_iter *dest, |
226 | | struct table_iter *src) |
227 | 401 | { |
228 | 401 | dest->r = src->r; |
229 | 401 | dest->typ = src->typ; |
230 | 401 | dest->block_off = src->block_off; |
231 | 401 | dest->finished = src->finished; |
232 | 401 | block_iter_copy_from(&dest->bi, &src->bi); |
233 | 401 | } |
234 | | |
235 | | static int table_iter_next_in_block(struct table_iter *ti, struct record rec) |
236 | 2.04k | { |
237 | 2.04k | int res = block_iter_next(&ti->bi, rec); |
238 | 2.04k | if (res == 0 && record_type(rec) == BLOCK_TYPE_REF) { |
239 | 1.21k | ((struct reftable_ref_record *)rec.data)->update_index += |
240 | 1.21k | ti->r->min_update_index; |
241 | 1.21k | } |
242 | 2.04k | |
243 | 2.04k | return res; |
244 | 2.04k | } |
245 | | |
246 | | static void table_iter_block_done(struct table_iter *ti) |
247 | 2.26k | { |
248 | 2.26k | if (ti->bi.br == NULL) { |
249 | 683 | return; |
250 | 683 | } |
251 | 1.58k | reftable_block_done(&ti->bi.br->block); |
252 | 1.58k | FREE_AND_NULL(ti->bi.br); |
253 | 1.58k | |
254 | 1.58k | ti->bi.last_key.len = 0; |
255 | 1.58k | ti->bi.next_off = 0; |
256 | 1.58k | } |
257 | | |
258 | | static int32_t extract_block_size(byte *data, byte *typ, uint64_t off, |
259 | | int version) |
260 | 1.66k | { |
261 | 1.66k | int32_t result = 0; |
262 | 1.66k | |
263 | 1.66k | if (off == 0) { |
264 | 1.04k | data += header_size(version); |
265 | 1.04k | } |
266 | 1.66k | |
267 | 1.66k | *typ = data[0]; |
268 | 1.66k | if (is_block_type(*typ)) { |
269 | 1.66k | result = get_be24(data + 1); |
270 | 1.66k | } |
271 | 1.66k | return result; |
272 | 1.66k | } |
273 | | |
274 | | int reader_init_block_reader(struct reftable_reader *r, struct block_reader *br, |
275 | | uint64_t next_off, byte want_typ) |
276 | 3.21k | { |
277 | 3.21k | int32_t guess_block_size = r->block_size ? r->block_size : |
278 | 3.21k | DEFAULT_BLOCK_SIZE; |
279 | 3.21k | struct reftable_block block = { 0 }; |
280 | 3.21k | byte block_typ = 0; |
281 | 3.21k | int err = 0; |
282 | 3.21k | uint32_t header_off = next_off ? 0 : header_size(r->version); |
283 | 3.21k | int32_t block_size = 0; |
284 | 3.21k | |
285 | 3.21k | if (next_off >= r->size) { |
286 | 1.55k | return 1; |
287 | 1.55k | } |
288 | 1.66k | |
289 | 1.66k | err = reader_get_block(r, &block, next_off, guess_block_size); |
290 | 1.66k | if (err < 0) { |
291 | 0 | return err; |
292 | 0 | } |
293 | 1.66k | |
294 | 1.66k | block_size = extract_block_size(block.data, &block_typ, next_off, |
295 | 1.66k | r->version); |
296 | 1.66k | if (block_size < 0) { |
297 | 0 | return block_size; |
298 | 0 | } |
299 | 1.66k | |
300 | 1.66k | if (want_typ != BLOCK_TYPE_ANY && block_typ != want_typ) { |
301 | 73 | reftable_block_done(&block); |
302 | 73 | return 1; |
303 | 73 | } |
304 | 1.58k | |
305 | 1.58k | if (block_size > guess_block_size) { |
306 | 0 | reftable_block_done(&block); |
307 | 0 | err = reader_get_block(r, &block, next_off, block_size); |
308 | 0 | if (err < 0) { |
309 | 0 | return err; |
310 | 0 | } |
311 | 1.58k | } |
312 | 1.58k | |
313 | 1.58k | return block_reader_init(br, &block, header_off, r->block_size, |
314 | 1.58k | hash_size(r->hash_id)); |
315 | 1.58k | } |
316 | | |
317 | | static int table_iter_next_block(struct table_iter *dest, |
318 | | struct table_iter *src) |
319 | 2.06k | { |
320 | 2.06k | uint64_t next_block_off = src->block_off + src->bi.br->full_block_size; |
321 | 2.06k | struct block_reader br = { 0 }; |
322 | 2.06k | int err = 0; |
323 | 2.06k | |
324 | 2.06k | dest->r = src->r; |
325 | 2.06k | dest->typ = src->typ; |
326 | 2.06k | dest->block_off = next_block_off; |
327 | 2.06k | |
328 | 2.06k | err = reader_init_block_reader(src->r, &br, next_block_off, src->typ); |
329 | 2.06k | if (err > 0) { |
330 | 1.62k | dest->finished = true; |
331 | 1.62k | return 1; |
332 | 1.62k | } |
333 | 440 | if (err != 0) { |
334 | 0 | return err; |
335 | 0 | } |
336 | 440 | |
337 | 440 | { |
338 | 440 | struct block_reader *brp = |
339 | 440 | reftable_malloc(sizeof(struct block_reader)); |
340 | 440 | *brp = br; |
341 | 440 | |
342 | 440 | dest->finished = false; |
343 | 440 | block_reader_start(brp, &dest->bi); |
344 | 440 | } |
345 | 440 | return 0; |
346 | 440 | } |
347 | | |
348 | | static int table_iter_next(struct table_iter *ti, struct record rec) |
349 | 2.02k | { |
350 | 2.02k | if (record_type(rec) != ti->typ) { |
351 | 1 | return REFTABLE_API_ERROR; |
352 | 1 | } |
353 | 2.02k | |
354 | 2.04k | while (true) { |
355 | 2.04k | struct table_iter next = { 0 }; |
356 | 2.04k | int err = 0; |
357 | 2.04k | if (ti->finished) { |
358 | 0 | return 1; |
359 | 0 | } |
360 | 2.04k | |
361 | 2.04k | err = table_iter_next_in_block(ti, rec); |
362 | 2.04k | if (err <= 0) { |
363 | 1.39k | return err; |
364 | 1.39k | } |
365 | 651 | |
366 | 651 | err = table_iter_next_block(&next, ti); |
367 | 651 | if (err != 0) { |
368 | 629 | ti->finished = true; |
369 | 629 | } |
370 | 651 | table_iter_block_done(ti); |
371 | 651 | if (err != 0) { |
372 | 629 | return err; |
373 | 629 | } |
374 | 22 | table_iter_copy_from(ti, &next); |
375 | 22 | block_iter_close(&next.bi); |
376 | 22 | } |
377 | 2.02k | } |
378 | | |
379 | | static int table_iter_next_void(void *ti, struct record rec) |
380 | 1.97k | { |
381 | 1.97k | return table_iter_next((struct table_iter *)ti, rec); |
382 | 1.97k | } |
383 | | |
384 | | static void table_iter_close(void *p) |
385 | 1.14k | { |
386 | 1.14k | struct table_iter *ti = (struct table_iter *)p; |
387 | 1.14k | table_iter_block_done(ti); |
388 | 1.14k | block_iter_close(&ti->bi); |
389 | 1.14k | } |
390 | | |
391 | | struct reftable_iterator_vtable table_iter_vtable = { |
392 | | .next = &table_iter_next_void, |
393 | | .close = &table_iter_close, |
394 | | }; |
395 | | |
396 | | static void iterator_from_table_iter(struct reftable_iterator *it, |
397 | | struct table_iter *ti) |
398 | 1.09k | { |
399 | 1.09k | assert(it->ops == NULL); |
400 | 1.09k | it->iter_arg = ti; |
401 | 1.09k | it->ops = &table_iter_vtable; |
402 | 1.09k | } |
403 | | |
404 | | static int reader_table_iter_at(struct reftable_reader *r, |
405 | | struct table_iter *ti, uint64_t off, byte typ) |
406 | 1.14k | { |
407 | 1.14k | struct block_reader br = { 0 }; |
408 | 1.14k | struct block_reader *brp = NULL; |
409 | 1.14k | |
410 | 1.14k | int err = reader_init_block_reader(r, &br, off, typ); |
411 | 1.14k | if (err != 0) { |
412 | 0 | return err; |
413 | 0 | } |
414 | 1.14k | |
415 | 1.14k | brp = reftable_malloc(sizeof(struct block_reader)); |
416 | 1.14k | *brp = br; |
417 | 1.14k | ti->r = r; |
418 | 1.14k | ti->typ = block_reader_type(brp); |
419 | 1.14k | ti->block_off = off; |
420 | 1.14k | block_reader_start(brp, &ti->bi); |
421 | 1.14k | return 0; |
422 | 1.14k | } |
423 | | |
424 | | static int reader_start(struct reftable_reader *r, struct table_iter *ti, |
425 | | byte typ, bool index) |
426 | 1.09k | { |
427 | 1.09k | struct reftable_reader_offsets *offs = reader_offsets_for(r, typ); |
428 | 1.09k | uint64_t off = offs->offset; |
429 | 1.09k | if (index) { |
430 | 54 | off = offs->index_offset; |
431 | 54 | if (off == 0) { |
432 | 0 | return 1; |
433 | 0 | } |
434 | 54 | typ = BLOCK_TYPE_INDEX; |
435 | 54 | } |
436 | 1.09k | |
437 | 1.09k | return reader_table_iter_at(r, ti, off, typ); |
438 | 1.09k | } |
439 | | |
440 | | static int reader_seek_linear(struct reftable_reader *r, struct table_iter *ti, |
441 | | struct record want) |
442 | 1.09k | { |
443 | 1.09k | struct record rec = new_record(record_type(want)); |
444 | 1.09k | struct slice want_key = { 0 }; |
445 | 1.09k | struct slice got_key = { 0 }; |
446 | 1.09k | struct table_iter next = { 0 }; |
447 | 1.09k | int err = -1; |
448 | 1.09k | record_key(want, &want_key); |
449 | 1.09k | |
450 | 1.41k | while (true) { |
451 | 1.41k | err = table_iter_next_block(&next, ti); |
452 | 1.41k | if (err < 0) { |
453 | 0 | goto exit; |
454 | 0 | } |
455 | 1.41k | |
456 | 1.41k | if (err > 0) { |
457 | 999 | break; |
458 | 999 | } |
459 | 418 | |
460 | 418 | err = block_reader_first_key(next.bi.br, &got_key); |
461 | 418 | if (err < 0) { |
462 | 0 | goto exit; |
463 | 0 | } |
464 | 418 | { |
465 | 418 | int cmp = slice_compare(got_key, want_key); |
466 | 418 | if (cmp > 0) { |
467 | 92 | table_iter_block_done(&next); |
468 | 92 | break; |
469 | 92 | } |
470 | 326 | } |
471 | 326 | |
472 | 326 | table_iter_block_done(ti); |
473 | 326 | table_iter_copy_from(ti, &next); |
474 | 326 | } |
475 | 1.09k | |
476 | 1.09k | err = block_iter_seek(&ti->bi, want_key); |
477 | 1.09k | if (err < 0) { |
478 | 0 | goto exit; |
479 | 0 | } |
480 | 1.09k | err = 0; |
481 | 1.09k | |
482 | 1.09k | exit: |
483 | 1.09k | block_iter_close(&next.bi); |
484 | 1.09k | record_destroy(&rec); |
485 | 1.09k | slice_clear(&want_key); |
486 | 1.09k | slice_clear(&got_key); |
487 | 1.09k | return err; |
488 | 1.09k | } |
489 | | |
490 | | static int reader_seek_indexed(struct reftable_reader *r, |
491 | | struct reftable_iterator *it, struct record rec) |
492 | 54 | { |
493 | 54 | struct index_record want_index = { 0 }; |
494 | 54 | struct record want_index_rec = { 0 }; |
495 | 54 | struct index_record index_result = { 0 }; |
496 | 54 | struct record index_result_rec = { 0 }; |
497 | 54 | struct table_iter index_iter = { 0 }; |
498 | 54 | struct table_iter next = { 0 }; |
499 | 54 | int err = 0; |
500 | 54 | |
501 | 54 | record_key(rec, &want_index.last_key); |
502 | 54 | record_from_index(&want_index_rec, &want_index); |
503 | 54 | record_from_index(&index_result_rec, &index_result); |
504 | 54 | |
505 | 54 | err = reader_start(r, &index_iter, record_type(rec), true); |
506 | 54 | if (err < 0) { |
507 | 0 | goto exit; |
508 | 0 | } |
509 | 54 | |
510 | 54 | err = reader_seek_linear(r, &index_iter, want_index_rec); |
511 | 54 | while (true) { |
512 | 54 | err = table_iter_next(&index_iter, index_result_rec); |
513 | 54 | table_iter_block_done(&index_iter); |
514 | 54 | if (err != 0) { |
515 | 1 | goto exit; |
516 | 1 | } |
517 | 53 | |
518 | 53 | err = reader_table_iter_at(r, &next, index_result.offset, 0); |
519 | 53 | if (err != 0) { |
520 | 0 | goto exit; |
521 | 0 | } |
522 | 53 | |
523 | 53 | err = block_iter_seek(&next.bi, want_index.last_key); |
524 | 53 | if (err < 0) { |
525 | 0 | goto exit; |
526 | 0 | } |
527 | 53 | |
528 | 53 | if (next.typ == record_type(rec)) { |
529 | 53 | err = 0; |
530 | 53 | break; |
531 | 53 | } |
532 | 0 | |
533 | 0 | if (next.typ != BLOCK_TYPE_INDEX) { |
534 | 0 | err = REFTABLE_FORMAT_ERROR; |
535 | 0 | break; |
536 | 0 | } |
537 | 0 | |
538 | 0 | table_iter_copy_from(&index_iter, &next); |
539 | 0 | } |
540 | 54 | |
541 | 54 | if (err == 0) { |
542 | 53 | struct table_iter *malloced = |
543 | 53 | reftable_calloc(sizeof(struct table_iter)); |
544 | 53 | table_iter_copy_from(malloced, &next); |
545 | 53 | iterator_from_table_iter(it, malloced); |
546 | 53 | } |
547 | 54 | exit: |
548 | 54 | block_iter_close(&next.bi); |
549 | 54 | table_iter_close(&index_iter); |
550 | 54 | record_clear(want_index_rec); |
551 | 54 | record_clear(index_result_rec); |
552 | 54 | return err; |
553 | 53 | } |
554 | | |
555 | | static int reader_seek_internal(struct reftable_reader *r, |
556 | | struct reftable_iterator *it, struct record rec) |
557 | 1.09k | { |
558 | 1.09k | struct reftable_reader_offsets *offs = |
559 | 1.09k | reader_offsets_for(r, record_type(rec)); |
560 | 1.09k | uint64_t idx = offs->index_offset; |
561 | 1.09k | struct table_iter ti = { 0 }; |
562 | 1.09k | int err = 0; |
563 | 1.09k | if (idx > 0) { |
564 | 54 | return reader_seek_indexed(r, it, rec); |
565 | 54 | } |
566 | 1.03k | |
567 | 1.03k | err = reader_start(r, &ti, record_type(rec), false); |
568 | 1.03k | if (err < 0) { |
569 | 0 | return err; |
570 | 0 | } |
571 | 1.03k | err = reader_seek_linear(r, &ti, rec); |
572 | 1.03k | if (err < 0) { |
573 | 0 | return err; |
574 | 0 | } |
575 | 1.03k | |
576 | 1.03k | { |
577 | 1.03k | struct table_iter *p = |
578 | 1.03k | reftable_malloc(sizeof(struct table_iter)); |
579 | 1.03k | *p = ti; |
580 | 1.03k | iterator_from_table_iter(it, p); |
581 | 1.03k | } |
582 | 1.03k | |
583 | 1.03k | return 0; |
584 | 1.03k | } |
585 | | |
586 | | int reader_seek(struct reftable_reader *r, struct reftable_iterator *it, |
587 | | struct record rec) |
588 | 1.30k | { |
589 | 1.30k | byte typ = record_type(rec); |
590 | 1.30k | |
591 | 1.30k | struct reftable_reader_offsets *offs = reader_offsets_for(r, typ); |
592 | 1.30k | if (!offs->present) { |
593 | 215 | iterator_set_empty(it); |
594 | 215 | return 0; |
595 | 215 | } |
596 | 1.09k | |
597 | 1.09k | return reader_seek_internal(r, it, rec); |
598 | 1.09k | } |
599 | | |
600 | | int reftable_reader_seek_ref(struct reftable_reader *r, |
601 | | struct reftable_iterator *it, const char *name) |
602 | 290 | { |
603 | 290 | struct reftable_ref_record ref = { |
604 | 290 | .ref_name = (char *)name, |
605 | 290 | }; |
606 | 290 | struct record rec = { 0 }; |
607 | 290 | record_from_ref(&rec, &ref); |
608 | 290 | return reader_seek(r, it, rec); |
609 | 290 | } |
610 | | |
611 | | int reftable_reader_seek_log_at(struct reftable_reader *r, |
612 | | struct reftable_iterator *it, const char *name, |
613 | | uint64_t update_index) |
614 | 1 | { |
615 | 1 | struct reftable_log_record log = { |
616 | 1 | .ref_name = (char *)name, |
617 | 1 | .update_index = update_index, |
618 | 1 | }; |
619 | 1 | struct record rec = { 0 }; |
620 | 1 | record_from_log(&rec, &log); |
621 | 1 | return reader_seek(r, it, rec); |
622 | 1 | } |
623 | | |
624 | | int reftable_reader_seek_log(struct reftable_reader *r, |
625 | | struct reftable_iterator *it, const char *name) |
626 | 1 | { |
627 | 1 | uint64_t max = ~((uint64_t)0); |
628 | 1 | return reftable_reader_seek_log_at(r, it, name, max); |
629 | 1 | } |
630 | | |
631 | | void reader_close(struct reftable_reader *r) |
632 | 534 | { |
633 | 534 | block_source_close(&r->source); |
634 | 534 | FREE_AND_NULL(r->name); |
635 | 534 | } |
636 | | |
637 | | int reftable_new_reader(struct reftable_reader **p, |
638 | | struct reftable_block_source src, char const *name) |
639 | 338 | { |
640 | 338 | struct reftable_reader *rd = |
641 | 338 | reftable_calloc(sizeof(struct reftable_reader)); |
642 | 338 | int err = init_reader(rd, src, name); |
643 | 338 | if (err == 0) { |
644 | 338 | *p = rd; |
645 | 338 | } else { |
646 | 0 | block_source_close(&src); |
647 | 0 | reftable_free(rd); |
648 | 0 | } |
649 | 338 | return err; |
650 | 338 | } |
651 | | |
652 | | void reftable_reader_free(struct reftable_reader *r) |
653 | 338 | { |
654 | 338 | reader_close(r); |
655 | 338 | reftable_free(r); |
656 | 338 | } |
657 | | |
658 | | static int reftable_reader_refs_for_indexed(struct reftable_reader *r, |
659 | | struct reftable_iterator *it, |
660 | | byte *oid) |
661 | 1 | { |
662 | 1 | struct obj_record want = { |
663 | 1 | .hash_prefix = oid, |
664 | 1 | .hash_prefix_len = r->object_id_len, |
665 | 1 | }; |
666 | 1 | struct record want_rec = { 0 }; |
667 | 1 | struct reftable_iterator oit = { 0 }; |
668 | 1 | struct obj_record got = { 0 }; |
669 | 1 | struct record got_rec = { 0 }; |
670 | 1 | int err = 0; |
671 | 1 | |
672 | 1 | /* Look through the reverse index. */ |
673 | 1 | record_from_obj(&want_rec, &want); |
674 | 1 | err = reader_seek(r, &oit, want_rec); |
675 | 1 | if (err != 0) { |
676 | 0 | goto exit; |
677 | 0 | } |
678 | 1 | |
679 | 1 | /* read out the obj_record */ |
680 | 1 | record_from_obj(&got_rec, &got); |
681 | 1 | err = iterator_next(oit, got_rec); |
682 | 1 | if (err < 0) { |
683 | 0 | goto exit; |
684 | 0 | } |
685 | 1 | |
686 | 1 | if (err > 0 || |
687 | 1 | memcmp(want.hash_prefix, got.hash_prefix, r->object_id_len)) { |
688 | 0 | /* didn't find it; return empty iterator */ |
689 | 0 | iterator_set_empty(it); |
690 | 0 | err = 0; |
691 | 0 | goto exit; |
692 | 0 | } |
693 | 1 | |
694 | 1 | { |
695 | 1 | struct indexed_table_ref_iter *itr = NULL; |
696 | 1 | err = new_indexed_table_ref_iter(&itr, r, oid, |
697 | 1 | hash_size(r->hash_id), |
698 | 1 | got.offsets, got.offset_len); |
699 | 1 | if (err < 0) { |
700 | 0 | goto exit; |
701 | 0 | } |
702 | 1 | got.offsets = NULL; |
703 | 1 | iterator_from_indexed_table_ref_iter(it, itr); |
704 | 1 | } |
705 | 1 | |
706 | 1 | exit: |
707 | 1 | reftable_iterator_destroy(&oit); |
708 | 1 | record_clear(got_rec); |
709 | 1 | return err; |
710 | 1 | } |
711 | | |
712 | | static int reftable_reader_refs_for_unindexed(struct reftable_reader *r, |
713 | | struct reftable_iterator *it, |
714 | | byte *oid) |
715 | 1 | { |
716 | 1 | struct table_iter *ti = reftable_calloc(sizeof(struct table_iter)); |
717 | 1 | struct filtering_ref_iterator *filter = NULL; |
718 | 1 | int oid_len = hash_size(r->hash_id); |
719 | 1 | int err = reader_start(r, ti, BLOCK_TYPE_REF, false); |
720 | 1 | if (err < 0) { |
721 | 0 | reftable_free(ti); |
722 | 0 | return err; |
723 | 0 | } |
724 | 1 | |
725 | 1 | filter = reftable_calloc(sizeof(struct filtering_ref_iterator)); |
726 | 1 | slice_resize(&filter->oid, oid_len); |
727 | 1 | memcpy(filter->oid.buf, oid, oid_len); |
728 | 1 | reftable_table_from_reader(&filter->tab, r); |
729 | 1 | filter->double_check = false; |
730 | 1 | iterator_from_table_iter(&filter->it, ti); |
731 | 1 | |
732 | 1 | iterator_from_filtering_ref_iterator(it, filter); |
733 | 1 | return 0; |
734 | 1 | } |
735 | | |
736 | | int reftable_reader_refs_for(struct reftable_reader *r, |
737 | | struct reftable_iterator *it, byte *oid) |
738 | 2 | { |
739 | 2 | if (r->obj_offsets.present) { |
740 | 1 | return reftable_reader_refs_for_indexed(r, it, oid); |
741 | 1 | } |
742 | 1 | return reftable_reader_refs_for_unindexed(r, it, oid); |
743 | 1 | } |
744 | | |
745 | | uint64_t reftable_reader_max_update_index(struct reftable_reader *r) |
746 | 1.12k | { |
747 | 1.12k | return r->max_update_index; |
748 | 1.12k | } |
749 | | |
750 | | uint64_t reftable_reader_min_update_index(struct reftable_reader *r) |
751 | 875 | { |
752 | 875 | return r->min_update_index; |
753 | 875 | } |