summaryrefslogtreecommitdiff
path: root/cdbmake.c
diff options
context:
space:
mode:
Diffstat (limited to 'cdbmake.c')
-rw-r--r--cdbmake.c126
1 files changed, 126 insertions, 0 deletions
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 <errno.h>
+#include <stdio.h>
+#include <skalibs/bytestr.h>
+#include <skalibs/buffer.h>
+#include <skalibs/cdbmake.h>
+#include <skalibs/djbunix.h>
+#include <skalibs/posixplz.h>
+#include <skalibs/skamisc.h>
+#include <skalibs/strerr.h>
+#include <skalibs/uint32.h>
+
+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;
+}