diff options
Diffstat (limited to 'reftable/writer.c')
| -rw-r--r-- | reftable/writer.c | 154 |
1 files changed, 102 insertions, 52 deletions
diff --git a/reftable/writer.c b/reftable/writer.c index 9d5e6072bc..b032a47dec 100644 --- a/reftable/writer.c +++ b/reftable/writer.c @@ -49,8 +49,14 @@ static int padded_write(struct reftable_writer *w, uint8_t *data, size_t len, { int n = 0; if (w->pending_padding > 0) { - uint8_t *zeroed = reftable_calloc(w->pending_padding, sizeof(*zeroed)); - int n = w->write(w->write_arg, zeroed, w->pending_padding); + uint8_t *zeroed; + int n; + + zeroed = reftable_calloc(w->pending_padding, sizeof(*zeroed)); + if (!zeroed) + return -1; + + n = w->write(w->write_arg, zeroed, w->pending_padding); if (n < 0) return n; @@ -102,28 +108,37 @@ static int writer_write_header(struct reftable_writer *w, uint8_t *dest) return header_size(writer_version(w)); } -static void writer_reinit_block_writer(struct reftable_writer *w, uint8_t typ) +static int writer_reinit_block_writer(struct reftable_writer *w, uint8_t typ) { - int block_start = 0; - if (w->next == 0) { + int block_start = 0, ret; + + if (w->next == 0) block_start = header_size(writer_version(w)); - } strbuf_reset(&w->last_key); - block_writer_init(&w->block_writer_data, typ, w->block, - w->opts.block_size, block_start, - hash_size(w->opts.hash_id)); + ret = block_writer_init(&w->block_writer_data, typ, w->block, + w->opts.block_size, block_start, + hash_size(w->opts.hash_id)); + if (ret < 0) + return ret; + w->block_writer = &w->block_writer_data; w->block_writer->restart_interval = w->opts.restart_interval; + + return 0; } -struct reftable_writer * -reftable_new_writer(ssize_t (*writer_func)(void *, const void *, size_t), - int (*flush_func)(void *), - void *writer_arg, const struct reftable_write_options *_opts) +int reftable_writer_new(struct reftable_writer **out, + ssize_t (*writer_func)(void *, const void *, size_t), + int (*flush_func)(void *), + void *writer_arg, const struct reftable_write_options *_opts) { - struct reftable_writer *wp = reftable_calloc(1, sizeof(*wp)); struct reftable_write_options opts = {0}; + struct reftable_writer *wp; + + wp = reftable_calloc(1, sizeof(*wp)); + if (!wp) + return REFTABLE_OUT_OF_MEMORY_ERROR; if (_opts) opts = *_opts; @@ -134,13 +149,19 @@ reftable_new_writer(ssize_t (*writer_func)(void *, const void *, size_t), strbuf_init(&wp->block_writer_data.last_key, 0); strbuf_init(&wp->last_key, 0); REFTABLE_CALLOC_ARRAY(wp->block, opts.block_size); + if (!wp->block) { + reftable_free(wp); + return REFTABLE_OUT_OF_MEMORY_ERROR; + } wp->write = writer_func; wp->write_arg = writer_arg; wp->opts = opts; wp->flush = flush_func; writer_reinit_block_writer(wp, BLOCK_TYPE_REF); - return wp; + *out = wp; + + return 0; } void reftable_writer_set_limits(struct reftable_writer *w, uint64_t min, @@ -186,34 +207,40 @@ static int obj_index_tree_node_compare(const void *a, const void *b) &((const struct obj_index_tree_node *)b)->hash); } -static void writer_index_hash(struct reftable_writer *w, struct strbuf *hash) +static int writer_index_hash(struct reftable_writer *w, struct strbuf *hash) { uint64_t off = w->next; - struct obj_index_tree_node want = { .hash = *hash }; + struct obj_index_tree_node *key; + struct tree_node *node; - struct tree_node *node = tree_search(&want, &w->obj_index_tree, - &obj_index_tree_node_compare, 0); - struct obj_index_tree_node *key = NULL; + node = tree_search(w->obj_index_tree, &want, &obj_index_tree_node_compare); if (!node) { struct obj_index_tree_node empty = OBJ_INDEX_TREE_NODE_INIT; - key = reftable_malloc(sizeof(struct obj_index_tree_node)); + + key = reftable_malloc(sizeof(*key)); + if (!key) + return REFTABLE_OUT_OF_MEMORY_ERROR; + *key = empty; strbuf_reset(&key->hash); strbuf_addbuf(&key->hash, hash); - tree_search((void *)key, &w->obj_index_tree, - &obj_index_tree_node_compare, 1); + tree_insert(&w->obj_index_tree, key, + &obj_index_tree_node_compare); } else { key = node->key; } - if (key->offset_len > 0 && key->offsets[key->offset_len - 1] == off) { - return; - } + if (key->offset_len > 0 && key->offsets[key->offset_len - 1] == off) + return 0; REFTABLE_ALLOC_GROW(key->offsets, key->offset_len + 1, key->offset_cap); + if (!key->offsets) + return REFTABLE_OUT_OF_MEMORY_ERROR; key->offsets[key->offset_len++] = off; + + return 0; } static int writer_add_record(struct reftable_writer *w, @@ -230,8 +257,11 @@ static int writer_add_record(struct reftable_writer *w, strbuf_reset(&w->last_key); strbuf_addbuf(&w->last_key, &key); - if (!w->block_writer) - writer_reinit_block_writer(w, reftable_record_type(rec)); + if (!w->block_writer) { + err = writer_reinit_block_writer(w, reftable_record_type(rec)); + if (err < 0) + goto done; + } if (block_writer_type(w->block_writer) != reftable_record_type(rec)) BUG("record of type %d added to writer of type %d", @@ -254,7 +284,9 @@ static int writer_add_record(struct reftable_writer *w, err = writer_flush_block(w); if (err < 0) goto done; - writer_reinit_block_writer(w, reftable_record_type(rec)); + err = writer_reinit_block_writer(w, reftable_record_type(rec)); + if (err < 0) + goto done; /* * Try to add the record to the writer again. If this still fails then @@ -284,11 +316,11 @@ int reftable_writer_add_ref(struct reftable_writer *w, .ref = *ref }, }; - int err = 0; + struct strbuf buf = STRBUF_INIT; + int err; - if (!ref->refname) - return REFTABLE_API_ERROR; - if (ref->update_index < w->min_update_index || + if (!ref->refname || + ref->update_index < w->min_update_index || ref->update_index > w->max_update_index) return REFTABLE_API_ERROR; @@ -296,24 +328,32 @@ int reftable_writer_add_ref(struct reftable_writer *w, err = writer_add_record(w, &rec); if (err < 0) - return err; + goto out; if (!w->opts.skip_index_objects && reftable_ref_record_val1(ref)) { - struct strbuf h = STRBUF_INIT; - strbuf_add(&h, (char *)reftable_ref_record_val1(ref), + strbuf_add(&buf, (char *)reftable_ref_record_val1(ref), hash_size(w->opts.hash_id)); - writer_index_hash(w, &h); - strbuf_release(&h); + + err = writer_index_hash(w, &buf); + if (err < 0) + goto out; } if (!w->opts.skip_index_objects && reftable_ref_record_val2(ref)) { - struct strbuf h = STRBUF_INIT; - strbuf_add(&h, reftable_ref_record_val2(ref), + strbuf_reset(&buf); + strbuf_add(&buf, reftable_ref_record_val2(ref), hash_size(w->opts.hash_id)); - writer_index_hash(w, &h); - strbuf_release(&h); + + err = writer_index_hash(w, &buf); + if (err < 0) + goto out; } - return 0; + + err = 0; + +out: + strbuf_release(&buf); + return err; } int reftable_writer_add_refs(struct reftable_writer *w, @@ -436,7 +476,9 @@ static int writer_finish_section(struct reftable_writer *w) max_level++; index_start = w->next; - writer_reinit_block_writer(w, BLOCK_TYPE_INDEX); + err = writer_reinit_block_writer(w, BLOCK_TYPE_INDEX); + if (err < 0) + return err; idx = w->index; idx_len = w->index_len; @@ -530,7 +572,10 @@ static void write_object_record(void *void_arg, void *key) if (arg->err < 0) goto done; - writer_reinit_block_writer(arg->w, BLOCK_TYPE_OBJ); + arg->err = writer_reinit_block_writer(arg->w, BLOCK_TYPE_OBJ); + if (arg->err < 0) + goto done; + arg->err = block_writer_add(arg->w->block_writer, &rec); if (arg->err == 0) goto done; @@ -548,7 +593,7 @@ static void object_record_free(void *void_arg UNUSED, void *key) { struct obj_index_tree_node *entry = key; - FREE_AND_NULL(entry->offsets); + REFTABLE_FREE_AND_NULL(entry->offsets); strbuf_release(&entry->hash); reftable_free(entry); } @@ -559,16 +604,18 @@ static int writer_dump_object_index(struct reftable_writer *w) struct common_prefix_arg common = { .max = 1, /* obj_id_len should be >= 2. */ }; - if (w->obj_index_tree) { + int err; + + if (w->obj_index_tree) infix_walk(w->obj_index_tree, &update_common, &common); - } w->stats.object_id_len = common.max + 1; - writer_reinit_block_writer(w, BLOCK_TYPE_OBJ); + err = writer_reinit_block_writer(w, BLOCK_TYPE_OBJ); + if (err < 0) + return err; - if (w->obj_index_tree) { + if (w->obj_index_tree) infix_walk(w->obj_index_tree, &write_object_record, &closure); - } if (closure.err < 0) return closure.err; @@ -662,7 +709,7 @@ static void writer_clear_index(struct reftable_writer *w) { for (size_t i = 0; w->index && i < w->index_len; i++) strbuf_release(&w->index[i].last_key); - FREE_AND_NULL(w->index); + REFTABLE_FREE_AND_NULL(w->index); w->index_len = 0; w->index_cap = 0; } @@ -726,6 +773,9 @@ static int writer_flush_nonempty_block(struct reftable_writer *w) * case we will end up with a multi-level index. */ REFTABLE_ALLOC_GROW(w->index, w->index_len + 1, w->index_cap); + if (!w->index) + return REFTABLE_OUT_OF_MEMORY_ERROR; + index_record.offset = w->next; strbuf_reset(&index_record.last_key); strbuf_addbuf(&index_record.last_key, &w->block_writer->last_key); |
