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