Coverage Report

Created: 2025-12-31 07:01

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/git/reftable/iter.c
Line
Count
Source
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 "iter.h"
10
11
#include "system.h"
12
13
#include "block.h"
14
#include "blocksource.h"
15
#include "constants.h"
16
#include "reftable-error.h"
17
#include "table.h"
18
19
int iterator_seek(struct reftable_iterator *it, struct reftable_record *want)
20
0
{
21
0
  return it->ops->seek(it->iter_arg, want);
22
0
}
23
24
int iterator_next(struct reftable_iterator *it, struct reftable_record *rec)
25
0
{
26
0
  return it->ops->next(it->iter_arg, rec);
27
0
}
28
29
static int empty_iterator_seek(void *arg REFTABLE_UNUSED, struct reftable_record *want REFTABLE_UNUSED)
30
0
{
31
0
  return 0;
32
0
}
33
34
static int empty_iterator_next(void *arg REFTABLE_UNUSED, struct reftable_record *rec REFTABLE_UNUSED)
35
0
{
36
0
  return 1;
37
0
}
38
39
static void empty_iterator_close(void *arg REFTABLE_UNUSED)
40
0
{
41
0
}
42
43
static struct reftable_iterator_vtable empty_vtable = {
44
  .seek = &empty_iterator_seek,
45
  .next = &empty_iterator_next,
46
  .close = &empty_iterator_close,
47
};
48
49
void iterator_set_empty(struct reftable_iterator *it)
50
0
{
51
0
  assert(!it->ops);
52
0
  it->iter_arg = NULL;
53
0
  it->ops = &empty_vtable;
54
0
}
55
56
static void filtering_ref_iterator_close(void *iter_arg)
57
0
{
58
0
  struct filtering_ref_iterator *fri = iter_arg;
59
0
  reftable_buf_release(&fri->oid);
60
0
  reftable_iterator_destroy(&fri->it);
61
0
}
62
63
static int filtering_ref_iterator_seek(void *iter_arg,
64
               struct reftable_record *want)
65
0
{
66
0
  struct filtering_ref_iterator *fri = iter_arg;
67
0
  return iterator_seek(&fri->it, want);
68
0
}
69
70
static int filtering_ref_iterator_next(void *iter_arg,
71
               struct reftable_record *rec)
72
0
{
73
0
  struct filtering_ref_iterator *fri = iter_arg;
74
0
  struct reftable_ref_record *ref = &rec->u.ref;
75
0
  int err = 0;
76
0
  while (1) {
77
0
    err = reftable_iterator_next_ref(&fri->it, ref);
78
0
    if (err != 0) {
79
0
      break;
80
0
    }
81
82
0
    if (ref->value_type == REFTABLE_REF_VAL2 &&
83
0
        (!memcmp(fri->oid.buf, ref->value.val2.target_value,
84
0
           fri->oid.len) ||
85
0
         !memcmp(fri->oid.buf, ref->value.val2.value,
86
0
           fri->oid.len)))
87
0
      return 0;
88
89
0
    if (ref->value_type == REFTABLE_REF_VAL1 &&
90
0
        !memcmp(fri->oid.buf, ref->value.val1, fri->oid.len)) {
91
0
      return 0;
92
0
    }
93
0
  }
94
95
0
  reftable_ref_record_release(ref);
96
0
  return err;
97
0
}
98
99
static struct reftable_iterator_vtable filtering_ref_iterator_vtable = {
100
  .seek = &filtering_ref_iterator_seek,
101
  .next = &filtering_ref_iterator_next,
102
  .close = &filtering_ref_iterator_close,
103
};
104
105
void iterator_from_filtering_ref_iterator(struct reftable_iterator *it,
106
            struct filtering_ref_iterator *fri)
107
0
{
108
0
  assert(!it->ops);
109
0
  it->iter_arg = fri;
110
0
  it->ops = &filtering_ref_iterator_vtable;
111
0
}
112
113
static void indexed_table_ref_iter_close(void *p)
114
0
{
115
0
  struct indexed_table_ref_iter *it = p;
116
0
  block_iter_close(&it->cur);
117
0
  block_source_release_data(&it->block.block_data);
118
0
  reftable_free(it->offsets);
119
0
  reftable_buf_release(&it->oid);
120
0
}
121
122
static int indexed_table_ref_iter_next_block(struct indexed_table_ref_iter *it)
123
0
{
124
0
  uint64_t off;
125
0
  int err = 0;
126
0
  if (it->offset_idx == it->offset_len) {
127
0
    it->is_finished = 1;
128
0
    return 1;
129
0
  }
130
131
0
  block_source_release_data(&it->block.block_data);
132
133
0
  off = it->offsets[it->offset_idx++];
134
0
  err = table_init_block(it->table, &it->block, off, REFTABLE_BLOCK_TYPE_REF);
135
0
  if (err < 0) {
136
0
    return err;
137
0
  }
138
0
  if (err > 0) {
139
    /* indexed block does not exist. */
140
0
    return REFTABLE_FORMAT_ERROR;
141
0
  }
142
0
  block_iter_init(&it->cur, &it->block);
143
0
  return 0;
144
0
}
145
146
static int indexed_table_ref_iter_seek(void *p REFTABLE_UNUSED,
147
               struct reftable_record *want REFTABLE_UNUSED)
148
0
{
149
0
  return REFTABLE_API_ERROR;
150
0
}
151
152
static int indexed_table_ref_iter_next(void *p, struct reftable_record *rec)
153
0
{
154
0
  struct indexed_table_ref_iter *it = p;
155
0
  struct reftable_ref_record *ref = &rec->u.ref;
156
157
0
  while (1) {
158
0
    int err = block_iter_next(&it->cur, rec);
159
0
    if (err < 0) {
160
0
      return err;
161
0
    }
162
163
0
    if (err > 0) {
164
0
      err = indexed_table_ref_iter_next_block(it);
165
0
      if (err < 0) {
166
0
        return err;
167
0
      }
168
169
0
      if (it->is_finished) {
170
0
        return 1;
171
0
      }
172
0
      continue;
173
0
    }
174
    /* BUG */
175
0
    if (!memcmp(it->oid.buf, ref->value.val2.target_value,
176
0
          it->oid.len) ||
177
0
        !memcmp(it->oid.buf, ref->value.val2.value, it->oid.len)) {
178
0
      return 0;
179
0
    }
180
0
  }
181
0
}
182
183
int indexed_table_ref_iter_new(struct indexed_table_ref_iter **dest,
184
             struct reftable_table *t, uint8_t *oid,
185
             int oid_len, uint64_t *offsets, int offset_len)
186
0
{
187
0
  struct indexed_table_ref_iter empty = INDEXED_TABLE_REF_ITER_INIT;
188
0
  struct indexed_table_ref_iter *itr;
189
0
  int err = 0;
190
191
0
  itr = reftable_calloc(1, sizeof(*itr));
192
0
  if (!itr) {
193
0
    err = REFTABLE_OUT_OF_MEMORY_ERROR;
194
0
    goto out;
195
0
  }
196
197
0
  *itr = empty;
198
0
  itr->table = t;
199
200
0
  err = reftable_buf_add(&itr->oid, oid, oid_len);
201
0
  if (err < 0)
202
0
    goto out;
203
204
0
  itr->offsets = offsets;
205
0
  itr->offset_len = offset_len;
206
207
0
  err = indexed_table_ref_iter_next_block(itr);
208
0
  if (err < 0)
209
0
    goto out;
210
211
0
  *dest = itr;
212
0
  err = 0;
213
214
0
out:
215
0
  if (err < 0) {
216
0
    *dest = NULL;
217
0
    reftable_free(itr);
218
0
  }
219
0
  return err;
220
0
}
221
222
static struct reftable_iterator_vtable indexed_table_ref_iter_vtable = {
223
  .seek = &indexed_table_ref_iter_seek,
224
  .next = &indexed_table_ref_iter_next,
225
  .close = &indexed_table_ref_iter_close,
226
};
227
228
void iterator_from_indexed_table_ref_iter(struct reftable_iterator *it,
229
            struct indexed_table_ref_iter *itr)
230
0
{
231
0
  assert(!it->ops);
232
0
  it->iter_arg = itr;
233
0
  it->ops = &indexed_table_ref_iter_vtable;
234
0
}
235
236
void reftable_iterator_destroy(struct reftable_iterator *it)
237
0
{
238
0
  if (!it->ops)
239
0
    return;
240
0
  it->ops->close(it->iter_arg);
241
0
  it->ops = NULL;
242
0
  REFTABLE_FREE_AND_NULL(it->iter_arg);
243
0
}
244
245
int reftable_iterator_seek_ref(struct reftable_iterator *it,
246
             const char *name)
247
0
{
248
0
  struct reftable_record want = {
249
0
    .type = REFTABLE_BLOCK_TYPE_REF,
250
0
    .u.ref = {
251
0
      .refname = (char *)name,
252
0
    },
253
0
  };
254
0
  return it->ops->seek(it->iter_arg, &want);
255
0
}
256
257
int reftable_iterator_next_ref(struct reftable_iterator *it,
258
             struct reftable_ref_record *ref)
259
0
{
260
0
  struct reftable_record rec = {
261
0
    .type = REFTABLE_BLOCK_TYPE_REF,
262
0
    .u = {
263
0
      .ref = *ref
264
0
    },
265
0
  };
266
0
  int err = iterator_next(it, &rec);
267
0
  *ref = rec.u.ref;
268
0
  return err;
269
0
}
270
271
int reftable_iterator_seek_log_at(struct reftable_iterator *it,
272
          const char *name, uint64_t update_index)
273
0
{
274
0
  struct reftable_record want = {
275
0
    .type = REFTABLE_BLOCK_TYPE_LOG,
276
0
    .u.log = {
277
0
      .refname = (char *)name,
278
0
      .update_index = update_index,
279
0
    },
280
0
  };
281
0
  return it->ops->seek(it->iter_arg, &want);
282
0
}
283
284
int reftable_iterator_seek_log(struct reftable_iterator *it,
285
             const char *name)
286
0
{
287
0
  return reftable_iterator_seek_log_at(it, name, ~((uint64_t) 0));
288
0
}
289
290
int reftable_iterator_next_log(struct reftable_iterator *it,
291
             struct reftable_log_record *log)
292
0
{
293
0
  struct reftable_record rec = {
294
0
    .type = REFTABLE_BLOCK_TYPE_LOG,
295
0
    .u = {
296
0
      .log = *log,
297
0
    },
298
0
  };
299
0
  int err = iterator_next(it, &rec);
300
0
  *log = rec.u.log;
301
0
  return err;
302
0
}