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