1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
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;
}
|