Coverage Report

Created: 2020-05-07 18:36

/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
}