#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; }