195 lines
		
	
	
		
			4.3 KiB
		
	
	
	
		
			C
		
	
	
			
		
		
	
	
			195 lines
		
	
	
		
			4.3 KiB
		
	
	
	
		
			C
		
	
	
| /*
 | |
| Copyright 2020 Google LLC
 | |
| 
 | |
| Use of this source code is governed by a BSD-style
 | |
| license that can be found in the LICENSE file or at
 | |
| https://developers.google.com/open-source/licenses/bsd
 | |
| */
 | |
| 
 | |
| #include "iter.h"
 | |
| 
 | |
| #include "system.h"
 | |
| 
 | |
| #include "block.h"
 | |
| #include "generic.h"
 | |
| #include "constants.h"
 | |
| #include "reader.h"
 | |
| #include "reftable-error.h"
 | |
| 
 | |
| int iterator_is_null(struct reftable_iterator *it)
 | |
| {
 | |
| 	return !it->ops;
 | |
| }
 | |
| 
 | |
| static void filtering_ref_iterator_close(void *iter_arg)
 | |
| {
 | |
| 	struct filtering_ref_iterator *fri = iter_arg;
 | |
| 	strbuf_release(&fri->oid);
 | |
| 	reftable_iterator_destroy(&fri->it);
 | |
| }
 | |
| 
 | |
| static int filtering_ref_iterator_next(void *iter_arg,
 | |
| 				       struct reftable_record *rec)
 | |
| {
 | |
| 	struct filtering_ref_iterator *fri = iter_arg;
 | |
| 	struct reftable_ref_record *ref = &rec->u.ref;
 | |
| 	int err = 0;
 | |
| 	while (1) {
 | |
| 		err = reftable_iterator_next_ref(&fri->it, ref);
 | |
| 		if (err != 0) {
 | |
| 			break;
 | |
| 		}
 | |
| 
 | |
| 		if (fri->double_check) {
 | |
| 			struct reftable_iterator it = { NULL };
 | |
| 
 | |
| 			err = reftable_table_seek_ref(&fri->tab, &it,
 | |
| 						      ref->refname);
 | |
| 			if (err == 0) {
 | |
| 				err = reftable_iterator_next_ref(&it, ref);
 | |
| 			}
 | |
| 
 | |
| 			reftable_iterator_destroy(&it);
 | |
| 
 | |
| 			if (err < 0) {
 | |
| 				break;
 | |
| 			}
 | |
| 
 | |
| 			if (err > 0) {
 | |
| 				continue;
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		if (ref->value_type == REFTABLE_REF_VAL2 &&
 | |
| 		    (!memcmp(fri->oid.buf, ref->value.val2.target_value,
 | |
| 			     fri->oid.len) ||
 | |
| 		     !memcmp(fri->oid.buf, ref->value.val2.value,
 | |
| 			     fri->oid.len)))
 | |
| 			return 0;
 | |
| 
 | |
| 		if (ref->value_type == REFTABLE_REF_VAL1 &&
 | |
| 		    !memcmp(fri->oid.buf, ref->value.val1, fri->oid.len)) {
 | |
| 			return 0;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	reftable_ref_record_release(ref);
 | |
| 	return err;
 | |
| }
 | |
| 
 | |
| static struct reftable_iterator_vtable filtering_ref_iterator_vtable = {
 | |
| 	.next = &filtering_ref_iterator_next,
 | |
| 	.close = &filtering_ref_iterator_close,
 | |
| };
 | |
| 
 | |
| void iterator_from_filtering_ref_iterator(struct reftable_iterator *it,
 | |
| 					  struct filtering_ref_iterator *fri)
 | |
| {
 | |
| 	assert(!it->ops);
 | |
| 	it->iter_arg = fri;
 | |
| 	it->ops = &filtering_ref_iterator_vtable;
 | |
| }
 | |
| 
 | |
| static void indexed_table_ref_iter_close(void *p)
 | |
| {
 | |
| 	struct indexed_table_ref_iter *it = p;
 | |
| 	block_iter_close(&it->cur);
 | |
| 	reftable_block_done(&it->block_reader.block);
 | |
| 	reftable_free(it->offsets);
 | |
| 	strbuf_release(&it->oid);
 | |
| }
 | |
| 
 | |
| static int indexed_table_ref_iter_next_block(struct indexed_table_ref_iter *it)
 | |
| {
 | |
| 	uint64_t off;
 | |
| 	int err = 0;
 | |
| 	if (it->offset_idx == it->offset_len) {
 | |
| 		it->is_finished = 1;
 | |
| 		return 1;
 | |
| 	}
 | |
| 
 | |
| 	reftable_block_done(&it->block_reader.block);
 | |
| 
 | |
| 	off = it->offsets[it->offset_idx++];
 | |
| 	err = reader_init_block_reader(it->r, &it->block_reader, off,
 | |
| 				       BLOCK_TYPE_REF);
 | |
| 	if (err < 0) {
 | |
| 		return err;
 | |
| 	}
 | |
| 	if (err > 0) {
 | |
| 		/* indexed block does not exist. */
 | |
| 		return REFTABLE_FORMAT_ERROR;
 | |
| 	}
 | |
| 	block_reader_start(&it->block_reader, &it->cur);
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static int indexed_table_ref_iter_next(void *p, struct reftable_record *rec)
 | |
| {
 | |
| 	struct indexed_table_ref_iter *it = p;
 | |
| 	struct reftable_ref_record *ref = &rec->u.ref;
 | |
| 
 | |
| 	while (1) {
 | |
| 		int err = block_iter_next(&it->cur, rec);
 | |
| 		if (err < 0) {
 | |
| 			return err;
 | |
| 		}
 | |
| 
 | |
| 		if (err > 0) {
 | |
| 			err = indexed_table_ref_iter_next_block(it);
 | |
| 			if (err < 0) {
 | |
| 				return err;
 | |
| 			}
 | |
| 
 | |
| 			if (it->is_finished) {
 | |
| 				return 1;
 | |
| 			}
 | |
| 			continue;
 | |
| 		}
 | |
| 		/* BUG */
 | |
| 		if (!memcmp(it->oid.buf, ref->value.val2.target_value,
 | |
| 			    it->oid.len) ||
 | |
| 		    !memcmp(it->oid.buf, ref->value.val2.value, it->oid.len)) {
 | |
| 			return 0;
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| int new_indexed_table_ref_iter(struct indexed_table_ref_iter **dest,
 | |
| 			       struct reftable_reader *r, uint8_t *oid,
 | |
| 			       int oid_len, uint64_t *offsets, int offset_len)
 | |
| {
 | |
| 	struct indexed_table_ref_iter empty = INDEXED_TABLE_REF_ITER_INIT;
 | |
| 	struct indexed_table_ref_iter *itr =
 | |
| 		reftable_calloc(sizeof(struct indexed_table_ref_iter));
 | |
| 	int err = 0;
 | |
| 
 | |
| 	*itr = empty;
 | |
| 	itr->r = r;
 | |
| 	strbuf_add(&itr->oid, oid, oid_len);
 | |
| 
 | |
| 	itr->offsets = offsets;
 | |
| 	itr->offset_len = offset_len;
 | |
| 
 | |
| 	err = indexed_table_ref_iter_next_block(itr);
 | |
| 	if (err < 0) {
 | |
| 		reftable_free(itr);
 | |
| 	} else {
 | |
| 		*dest = itr;
 | |
| 	}
 | |
| 	return err;
 | |
| }
 | |
| 
 | |
| static struct reftable_iterator_vtable indexed_table_ref_iter_vtable = {
 | |
| 	.next = &indexed_table_ref_iter_next,
 | |
| 	.close = &indexed_table_ref_iter_close,
 | |
| };
 | |
| 
 | |
| void iterator_from_indexed_table_ref_iter(struct reftable_iterator *it,
 | |
| 					  struct indexed_table_ref_iter *itr)
 | |
| {
 | |
| 	assert(!it->ops);
 | |
| 	it->iter_arg = itr;
 | |
| 	it->ops = &indexed_table_ref_iter_vtable;
 | |
| }
 |