// SPDX-License-Identifier: LGPL-3.0-or-later #include "internal.h" #include #include #include typedef struct hkvs_iomem_file hkvs_iomem_file; struct hkvs_iomem_file { uintptr_t data_mode; size_t size; }; typedef struct hkvs_iomem hkvs_iomem; struct hkvs_iomem { hkvs_io base; uint64_t rand_ctr; char rand_key[16]; size_t n_files; struct hkvs_iomem_file *files; }; static void hkvs_iomem_destroy(hkvs_io *iov) { hkvs_iomem *io = (hkvs_iomem*)iov; size_t n = io->n_files; for(size_t i = 0; i < n; i++) { struct hkvs_iomem_file *f = io->files + i; uintptr_t mode = f->data_mode & 3; char *p = (char*)(f->data_mode - mode); free(p); } free(io->files); free(io); } static int hkvs_iomem_random(hkvs_io *iov, char *buf, size_t n) { hkvs_iomem *io = (hkvs_iomem*)iov; while(true) { uint64_t h = hkvs_hash(io->rand_key, (const char*)&io->rand_ctr, sizeof(io->rand_ctr)); io->rand_ctr++; if(n > 8) { memcpy(buf, &h, 8); buf += 8; n -= 8; } else { memcpy(buf, &h, n); return 0; } } } static int hkvs_iomem_open(hkvs_io *iov, uint64_t fi, char **pmem, size_t *psz) { hkvs_iomem *io = (hkvs_iomem*)iov; if(fi >= io->n_files) return -ENOENT; hkvs_iomem_file *f = io->files + (size_t)fi; uintptr_t mode = f->data_mode & 3; char *p = (char*)(f->data_mode - mode); if(mode == 0) { if(fi != 0) return -ENOENT; } else if(mode != 1) { hkvs_die("bad file state"); } f->data_mode = (uintptr_t)p + 2; *pmem = p; *psz = f->size; return 0; } static int hkvs_iomem_create(hkvs_io *iov, uint64_t *pfi, char **pmem, size_t sz) { hkvs_iomem *io = (hkvs_iomem*)iov; hkvs_iomem_file *f = io->files; size_t n = io->n_files; for(size_t i = 1; i < n; i++) { if(!f[i].data_mode) { n = i; f += n; goto done; } } f = realloc(f, (n + 1) * sizeof(hkvs_iomem_file)); if(!f) return -ENOMEM; io->files = f; io->n_files = n + 1; f += n; f->data_mode = 0; done:; char *p = malloc(sz); if(!p) return -ENOMEM; memset(p, 0, sz); f->data_mode = (uintptr_t)p + 2; f->size = sz; *pfi = n; *pmem = p; return 0; } static int hkvs_iomem_resize(hkvs_io *iov, uint64_t fi, char **pmem, size_t old_sz, size_t new_sz) { hkvs_iomem *io = (hkvs_iomem*)iov; if(fi > io->n_files) hkvs_die("bad file index"); hkvs_iomem_file *f = io->files + (size_t)fi; uintptr_t mode = f->data_mode & 3; char *p = (char*)(f->data_mode - mode); if(mode != 2) hkvs_die("bad file state"); if(*pmem != p) hkvs_die("bad file mem"); if(old_sz != f->size) hkvs_die("bad file old_size"); p = realloc(p, new_sz); if(new_sz && !p) return -ENOMEM; f->data_mode = (uintptr_t)p + 2; f->size = new_sz; *pmem = p; return 0; } static void hkvs_iomem_close(hkvs_io *iov, uint64_t fi, char *mem, size_t sz) { hkvs_iomem *io = (hkvs_iomem*)iov; if(fi > io->n_files) hkvs_die("bad file index"); hkvs_iomem_file *f = io->files + (size_t)fi; uintptr_t mode = f->data_mode & 3; char *p = (char*)(f->data_mode - mode); if(mode != 2) hkvs_die("bad file state"); if(mem != p) hkvs_die("bad file mem"); if(sz != f->size) hkvs_die("bad file size"); f->data_mode = (uintptr_t)p + 1; } static void hkvs_iomem_unlink(hkvs_io *iov, uint64_t fi) { hkvs_iomem *io = (hkvs_iomem*)iov; if(fi > io->n_files) hkvs_die("bad file index"); hkvs_iomem_file *f = io->files + (size_t)fi; uintptr_t mode = f->data_mode & 3; char *p = (char*)(f->data_mode - mode); if(mode != 1) hkvs_die("bad file state"); free(p); f->data_mode = 0; f->size = 0; } hkvs_io *hkvs_io_new_mem(uint64_t rand_seed) { hkvs_iomem_file *files = malloc(sizeof(hkvs_iomem_file)); if(!files) return NULL; files[0].data_mode = 0; files[0].size = 0; hkvs_iomem *io = malloc(sizeof(*io)); if(!io) { free(files); return NULL; } io->base = (hkvs_io){ .destroy = &hkvs_iomem_destroy, .random = &hkvs_iomem_random, .open = &hkvs_iomem_open, .create = &hkvs_iomem_create, .close = &hkvs_iomem_close, .resize = &hkvs_iomem_resize, .unlink = &hkvs_iomem_unlink, }; hkvs_write_u64(io->rand_key, rand_seed); hkvs_write_u64(io->rand_key + 8, rand_seed); io->rand_ctr = 0; io->n_files = 1; io->files = files; return &io->base; }