From 2bdd00aa69b901e5230c9b8c24727011626ebeaa Mon Sep 17 00:00:00 2001 From: Sam Nystrom Date: Mon, 15 Jan 2024 13:35:27 -0500 Subject: init --- cdbmake.c | 126 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 126 insertions(+) create mode 100644 cdbmake.c (limited to 'cdbmake.c') diff --git a/cdbmake.c b/cdbmake.c new file mode 100644 index 0000000..c13420a --- /dev/null +++ b/cdbmake.c @@ -0,0 +1,126 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int +record_read(buffer *b, stralloc *key, stralloc *data, char **errmsg) +{ + char buf[sizeof("+4294967295,4294967295:")-1]; + size_t len = 0; + int r = getlnmax(b, buf, sizeof(buf), &len, ':'); + if (r <= 0) + return r; + if (buf[0] != '+') + return (*errmsg = "expected '+'", errno = EINVAL, -1); + + uint32_t keylen, datalen; + + size_t comma_pos = byte_chr(buf, len, ','); + if (comma_pos == len) + return (*errmsg = "expected ','", errno = EINVAL, -1); + buf[comma_pos] = 0; + if (!uint320_scan(buf + 1, &keylen)) + return (*errmsg = "could not parse key length", errno = EINVAL, -1); + buf[comma_pos] = ','; + + if (len < comma_pos + 1) + return (*errmsg = "expected data length after ','", errno = EINVAL, -1); + size_t colon_pos = byte_chr(buf, len, ':'); + if (colon_pos == len) + return (*errmsg = "expected ':'", errno = EINVAL, -1); + buf[colon_pos] = 0; + if (!uint320_scan(buf + comma_pos + 1, &datalen)) + return (*errmsg = "could not parse data length", errno = EINVAL, -1); + buf[colon_pos] = ':'; + + size_t w = 0; + if (!stralloc_ready(key, keylen)) + return (errno = ENOMEM, -1); + if ((r = buffer_getall(b, key->s, keylen, &w)) <= 0 && errno != EPIPE) + return -1; + if (w < keylen) + return (*errmsg = "unexpected EOF while reading key", errno = EINVAL, -1); + key->len = keylen; + w = 0; + if (buffer_getall(b, buf, 2, &w) <= 0 && errno != EPIPE) + return -1; + if (w < 2 || memcmp(buf, "->", 2)) + return (*errmsg = "expected '->'", errno = EINVAL, -1); + if (!stralloc_ready(data, datalen)) + return (errno = ENOMEM, -1); + w = 0; + if (buffer_getall(b, data->s, datalen, &w) <= 0 && errno != EPIPE) + return -1; + if (w < datalen) + return (*errmsg = "unexpected EOF while reading data", errno = EINVAL, -1); + data->len = datalen; + w = 0; + if (buffer_getall(b, buf, 1, &w) <= 0 && errno != EPIPE) + return -1; + if (w < 1 || buf[0] != '\n') + return (*errmsg = "expected '\\n'", errno = EINVAL, -1); + return 1; +} + +int +main(int argc, char *argv[]) +{ + PROG = "cdbmake"; + if (argc != 3) + strerr_dieusage(100, "cdbmake CDB TMP"); + char *cdb_path = argv[1]; + char *tmp_path = argv[2]; + + int tmp_fd = open_trunc(tmp_path); + if (tmp_fd < 0) + strerr_diefusys(111, "open ", tmp_path, " for writing"); + cdbmaker cm = CDBMAKER_ZERO; + if (!cdbmake_start(&cm, tmp_fd)) { + unlink_void(tmp_path); + strerr_diefusys(111, "cdbmake_start ", tmp_path); + } + + stralloc key = STRALLOC_ZERO; + stralloc data = STRALLOC_ZERO; + for (uint32_t record = 0;; ++record) { + char *errmsg = ""; + int r = record_read(buffer_0, &key, &data, &errmsg); + if (!r) break; + if (r < 0) { + unlink_void(tmp_path); + if (errno == EINVAL) { + char recordbuf[sizeof("4294967295")]; + recordbuf[uint32_fmt(recordbuf, record)] = 0; + strerr_dief(111, "syntax error on record ", recordbuf, ": ", errmsg); + } else { + strerr_diefusys(111, "read from stdin"); + } + } + if (!cdbmake_add(&cm, key.s, key.len, data.s, data.len)) { + unlink_void(tmp_path); + strerr_diefusys(111, "write cdb to ", tmp_path); + } + } + stralloc_free(&key); + stralloc_free(&data); + if (!cdbmake_finish(&cm)) { + unlink_void(tmp_path); + strerr_diefusys(111, "cdbmake_finish ", tmp_path); + } + if (fd_sync(tmp_fd) < 0) { + unlink_void(tmp_path); + strerr_diefusys(111, "fsync ", tmp_path); + } + if (rename(tmp_path, cdb_path) < 0) { + unlink_void(tmp_path); + strerr_diefusys(111, "rename ", tmp_path, " to ", cdb_path); + } + return 0; +} -- cgit v1.2.3