// SPDX-License-Identifier: LGPL-3.0-or-later #include "impl.h" #ifdef FUZZING static const size_t hkvs_slab_sizes[HKVS_N_SLABS] = { 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, 78, 80, }; #else static const size_t hkvs_slab_sizes[HKVS_N_SLABS] = { (2 << 6), (3 << 6), (4 << 6), (5 << 6), (6 << 6), (7 << 6), (8 << 6), (9 << 6), (10 << 6), (11 << 6), (12 << 6), (14 << 6), (8 << 7), (9 << 7), (10 << 7), (11 << 7), (12 << 7), (14 << 7), (8 << 8), (9 << 8), (10 << 8), (11 << 8), (12 << 8), (14 << 8), (8 << 9), (9 << 9), (10 << 9), (11 << 9), (12 << 9), (14 << 9), (8 << 10), (9 << 10), (10 << 10), (11 << 10), (12 << 10), (14 << 10), (8 << 11), (9 << 11), (10 << 11), (11 << 11), }; #endif int hkvs_new(hkvs **pc, hkvs_io *io) { int r; bool created = false; hkvs *c = malloc(sizeof(*c)); if(!c) return -ENOMEM; c->io = io; r = io->open(io, 0, &c->root_param, &c->root_param_size); if(r < 0) { goto fail_free; } char *at = c->root_param; size_t param_size = c->root_param_size; if(param_size == 0) { r = io->resize(io, 0, &c->root_param, param_size, HKVS_POFF_TABLE); if(r < 0) goto fail_close; at = c->root_param; param_size = HKVS_POFF_TABLE; c->root_param_size = param_size; memset(at, 0, HKVS_POFF_TABLE); hkvs_write_u64(at + HKVS_PARAM_HEADER_MAGIC, HKVS_MAGIC); created = true; } else if(param_size < HKVS_PSIZE_HEADER || hkvs_read_u64(at + HKVS_PARAM_HEADER_MAGIC) != HKVS_MAGIC) { r = -EBADMSG; goto fail_close; } uint64_t version = hkvs_read_u64(at + HKVS_PARAM_HEADER_VERSION); if(version != 0) { r = -ENOTSUP; goto fail_close; } uint64_t n_tables_u64 = hkvs_read_u64(at + 16); at += HKVS_PSIZE_HEADER; if(param_size < HKVS_POFF_TABLE || n_tables_u64 > (param_size - HKVS_POFF_TABLE) / HKVS_PSIZE_TABLE) { r = -EBADMSG; goto fail_close; } size_t n_tables = (size_t)n_tables_u64; for(size_t i = 0; i < HKVS_N_SLABS; i++) { r = hkvs_slab_init(&c->slabs[i], io, at, hkvs_slab_sizes[i]); at += HKVS_PSIZE_SLAB; if(r < 0) goto fail_slabs; } hkvs_table **tables = calloc(n_tables, sizeof(hkvs_table*)); c->tables = tables; c->n_tables = n_tables; c->alloc_tables = n_tables; for(size_t i = 0; i < n_tables; i++) { r = hkvs_table_new(&tables[i], io, at); at += HKVS_PSIZE_TABLE; if(r < 0) goto fail_tables; } c->extfiles = NULL; c->n_extfiles = 0; c->alloc_extfiles = 0; c->extfile_gen = 0; *pc = c; return created; fail_tables: for(size_t i = 0; i < n_tables; i++) { hkvs_table *t = tables[i]; if(t) hkvs_table_free(t, io); } free(tables); fail_slabs:; size_t n_slabs = (size_t)(at - (char*)c->root_param) / HKVS_PSIZE_SLAB; if(n_slabs > HKVS_N_SLABS) n_slabs = HKVS_N_SLABS; while(n_slabs--) { hkvs_slab_destroy(&c->slabs[n_slabs], io); } fail_close: io->close(io, 0, c->root_param, c->root_param_size); fail_free: free(c); io->destroy(io); return r; } int hkvs_resize_param(hkvs *c) { if(c->n_tables > (SIZE_MAX - HKVS_POFF_TABLE) / HKVS_PSIZE_TABLE) return -EFBIG; size_t param_size = HKVS_POFF_TABLE + c->n_tables * HKVS_PSIZE_TABLE; int r = c->io->resize(c->io, 0, &c->root_param, c->root_param_size, param_size); if(r < 0) return r; c->root_param_size = param_size; char *at = c->root_param; if(hkvs_read_u64(at + HKVS_PARAM_HEADER_MAGIC) != HKVS_MAGIC || hkvs_read_u64(at + HKVS_PARAM_HEADER_VERSION) != 0) { hkvs_die("magic corrupted"); } hkvs_write_u64(at + 16, c->n_tables); at += HKVS_PSIZE_HEADER; for(size_t i = 0; i < HKVS_N_SLABS; i++) { c->slabs[i].param = at; at += HKVS_PSIZE_SLAB; } hkvs_table **tables = c->tables; size_t n_tables = c->n_tables; for(size_t i = 0; i < n_tables; i++) { hkvs_table *t = tables[i]; if(t) t->slab.param = at; at += HKVS_PSIZE_TABLE; } return 0; } void hkvs_free(hkvs *c) { hkvs_io *io = c->io; hkvs_extfile *ext = c->extfiles; size_t n_ext = c->n_extfiles; for(size_t i = 0; i < n_ext; i++) { io->close(io, ext[i].fi, ext[i].addr, ext[i].size); } free(ext); hkvs_table **tables = c->tables; size_t n_tables = c->n_tables; for(size_t i = 0; i < n_tables; i++) { hkvs_table *t = tables[i]; if(t) hkvs_table_free(t, io); } free(tables); for(size_t i = 0; i < HKVS_N_SLABS; i++) { hkvs_slab_destroy(&c->slabs[i], io); } io->close(io, 0, c->root_param, c->root_param_size); free(c); io->destroy(io); return; } uint8_t hkvs_slab_for_size(size_t data_size) { // TODO: faster for(uint8_t i = 0; i < HKVS_N_SLABS; i++) { if(data_size <= hkvs_slab_sizes[i]) return i; } return 255; }