Skip to content

Commit bf5cd0d

Browse files
committed
Refactor checksum parsing
Also fix number of chunks handling, it includes the first dictionary chunk.
1 parent c2b1951 commit bf5cd0d

1 file changed

Lines changed: 60 additions & 70 deletions

File tree

ext/solv_zchunk.c

Lines changed: 60 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,17 @@ struct solv_zchunk {
2828
unsigned int flags; /* header flags */
2929
unsigned int comp; /* compression type */
3030

31-
unsigned char *data_chk_ptr;
32-
int data_chk_len;
33-
Chksum *data_chk; /* for data checksum verification */
31+
unsigned int hdr_chk_type; /* header + data checksum */
32+
unsigned int hdr_chk_len;
33+
Id hdr_chk_id;
3434

3535
unsigned int chunk_chk_type; /* chunk checksum */
36-
int chunk_chk_len;
36+
unsigned int chunk_chk_len;
3737
Id chunk_chk_id;
3838

39+
Chksum *data_chk; /* for data checksum verification */
40+
unsigned char *data_chk_ptr;
41+
3942
unsigned int streamid; /* stream we are reading */
4043
unsigned int nchunks; /* chunks left */
4144
unsigned char *chunks;
@@ -83,31 +86,32 @@ getuint(unsigned char *p, unsigned char *endp, unsigned int *dp)
8386
return 0;
8487
}
8588

86-
static int
87-
chksum_len(unsigned int type)
88-
{
89-
if (type == 0)
90-
return 20;
91-
if (type == 1)
92-
return 32;
93-
if (type == 2)
94-
return 64;
95-
if (type == 3)
96-
return 16;
97-
return -1;
98-
}
99-
100-
static Id
101-
chksum_id(unsigned int type)
89+
static unsigned char *
90+
getchksum(unsigned char *p, unsigned char *endp, unsigned int *typep, unsigned int *lenp, Id *idp)
10291
{
103-
if (type == 0)
104-
return REPOKEY_TYPE_SHA1;
105-
if (type == 1)
106-
return REPOKEY_TYPE_SHA256;
107-
if (type == 2)
108-
return REPOKEY_TYPE_SHA512;
109-
if (type == 3)
110-
return REPOKEY_TYPE_SHA512;
92+
if ((p = getuint(p, endp, typep)) == 0)
93+
return 0;
94+
switch (*typep)
95+
{
96+
case 0:
97+
*lenp = 20;
98+
*idp = REPOKEY_TYPE_SHA1;
99+
return p;
100+
case 1:
101+
*lenp = 32;
102+
*idp = REPOKEY_TYPE_SHA256;
103+
return p;
104+
case 2:
105+
*lenp = 64;
106+
*idp = REPOKEY_TYPE_SHA512;
107+
return p;
108+
case 3:
109+
*lenp = 16;
110+
*idp = REPOKEY_TYPE_SHA512;
111+
return p;
112+
default:
113+
break;
114+
}
111115
return 0;
112116
}
113117

@@ -131,7 +135,7 @@ static int
131135
nextchunk(struct solv_zchunk *zck, unsigned int streamid)
132136
{
133137
unsigned char *p = zck->chunks;
134-
unsigned char *chunk_chksum;
138+
unsigned char *chunk_chk_ptr;
135139
unsigned int sid, chunk_len, uncompressed_len;
136140
unsigned char *cbuf;
137141

@@ -153,7 +157,7 @@ nextchunk(struct solv_zchunk *zck, unsigned int streamid)
153157
/* check if this is the correct stream */
154158
if ((zck->flags & 1) != 0 && (p = getuint(p, zck->hdr_end, &sid)) == 0)
155159
return 0;
156-
chunk_chksum = p;
160+
chunk_chk_ptr = p; /* remember for verification */
157161
p += zck->chunk_chk_len;
158162
if (p >= zck->hdr_end)
159163
return 0;
@@ -182,7 +186,7 @@ nextchunk(struct solv_zchunk *zck, unsigned int streamid)
182186
if (zck->data_chk)
183187
solv_chksum_add(zck->data_chk, cbuf, chunk_len);
184188

185-
/* verify the checksum */
189+
/* verify the chunk checksum */
186190
if (zck->chunk_chk_id)
187191
{
188192
Chksum *chk = solv_chksum_create(zck->chunk_chk_id);
@@ -192,7 +196,7 @@ nextchunk(struct solv_zchunk *zck, unsigned int streamid)
192196
return 0;
193197
}
194198
solv_chksum_add(chk, cbuf, chunk_len);
195-
if (memcmp(solv_chksum_get(chk, 0), chunk_chksum, zck->chunk_chk_len) != 0)
199+
if (memcmp(solv_chksum_get(chk, 0), chunk_chk_ptr, zck->chunk_chk_len) != 0)
196200
{
197201
solv_chksum_free(chk, 0);
198202
solv_free(cbuf);
@@ -218,7 +222,7 @@ nextchunk(struct solv_zchunk *zck, unsigned int streamid)
218222
{
219223
/* zstd compressed */
220224
size_t r;
221-
zck->buf = solv_malloc(uncompressed_len + 1);
225+
zck->buf = solv_malloc(uncompressed_len + 1); /* +1 so we can detect too large frames */
222226
if (zck->ddict)
223227
r = ZSTD_decompress_usingDDict(zck->dctx, zck->buf, uncompressed_len + 1, cbuf, chunk_len, zck->ddict);
224228
else
@@ -245,9 +249,6 @@ solv_zchunk_open(FILE *fp, unsigned int streamid)
245249
{
246250
struct solv_zchunk *zck;
247251
unsigned char *p;
248-
unsigned int hdr_chk_type;
249-
int hdr_chk_len;
250-
Id hdr_chk_id;
251252
unsigned int hdr_size; /* preface + index + signatures */
252253
unsigned int lead_size;
253254
unsigned int preface_size;
@@ -256,72 +257,64 @@ solv_zchunk_open(FILE *fp, unsigned int streamid)
256257

257258
zck = solv_calloc(1, sizeof(*zck));
258259

259-
/* read the header */
260+
/* read and parse the lead, read the complete header */
260261
zck->hdr = solv_calloc(15, 1);
262+
zck->hdr_end = zck->hdr + 15;
261263
if (fread(zck->hdr, 15, 1, fp) != 1 || memcmp(zck->hdr, "\000ZCK1", 5) != 0)
262264
return open_error(zck);
263265
p = zck->hdr + 5;
264-
if ((p = getuint(p, zck->hdr + 15, &hdr_chk_type)) == 0)
266+
if ((p = getchksum(p, zck->hdr_end, &zck->hdr_chk_type, &zck->hdr_chk_len, &zck->hdr_chk_id)) == 0)
265267
return open_error(zck);
266-
hdr_chk_len = chksum_len(hdr_chk_type);
267-
if (hdr_chk_len < 0)
268+
if ((p = getuint(p, zck->hdr_end, &hdr_size)) == 0 || hdr_size > MAX_HDR_SIZE)
268269
return open_error(zck);
269-
hdr_chk_id = chksum_id(hdr_chk_type);
270-
if ((p = getuint(p, zck->hdr + 15, &hdr_size)) == 0 || hdr_size > MAX_HDR_SIZE)
271-
return open_error(zck);
272-
lead_size = p - zck->hdr + hdr_chk_len;
270+
lead_size = p - zck->hdr + zck->hdr_chk_len;
273271
zck->hdr = solv_realloc(zck->hdr, lead_size + hdr_size);
274272
zck->hdr_end = zck->hdr + lead_size + hdr_size;
275273
if (fread(zck->hdr + 15, lead_size + hdr_size - 15, 1, fp) != 1)
276274
return open_error(zck);
277275

278276
/* verify header checksum to guard against corrupt files */
279-
if (hdr_chk_id)
277+
if (zck->hdr_chk_id)
280278
{
281-
Chksum *chk = solv_chksum_create(hdr_chk_id);
279+
Chksum *chk = solv_chksum_create(zck->hdr_chk_id);
282280
if (!chk)
283281
return open_error(zck);
284-
solv_chksum_add(chk, zck->hdr, lead_size - hdr_chk_len);
282+
solv_chksum_add(chk, zck->hdr, lead_size - zck->hdr_chk_len);
285283
solv_chksum_add(chk, zck->hdr + lead_size, hdr_size);
286-
if (memcmp(solv_chksum_get(chk, 0), zck->hdr + (lead_size - hdr_chk_len), hdr_chk_len) != 0)
284+
if (memcmp(solv_chksum_get(chk, 0), zck->hdr + (lead_size - zck->hdr_chk_len), zck->hdr_chk_len) != 0)
287285
{
288286
solv_chksum_free(chk, 0);
289287
return open_error(zck);
290288
}
291289
solv_chksum_free(chk, 0);
292290
}
293291

294-
/* parse preface */
292+
/* parse preface: data chksum, flags, compression */
295293
p = zck->hdr + lead_size;
296-
if (p + hdr_chk_len + 4 > zck->hdr_end)
294+
if (p + zck->hdr_chk_len > zck->hdr_end)
297295
return open_error(zck);
296+
zck->data_chk_ptr = p;
297+
p += zck->hdr_chk_len;
298298
#ifdef VERIFY_DATA_CHKSUM
299-
if (hdr_chk_id && (zck->data_chk = solv_chksum_create(hdr_chk_id)) == 0)
299+
if (zck->hdr_chk_id && (zck->data_chk = solv_chksum_create(zck->hdr_chk_id)) == 0)
300300
return open_error(zck);
301-
zck->data_chk_ptr = zck->hdr + lead_size;
302-
zck->data_chk_len = hdr_chk_len;
303301
#endif
304-
p += hdr_chk_len; /* skip data checksum */
305302
if ((p = getuint(p, zck->hdr_end, &zck->flags)) == 0)
306303
return open_error(zck);
307304
if ((zck->flags & ~(1)) != 0)
308305
return open_error(zck);
309306
if ((p = getuint(p, zck->hdr_end, &zck->comp)) == 0 || (zck->comp != 0 && zck->comp != 2))
310-
return open_error(zck); /* only uncompressed + zstd */
307+
return open_error(zck); /* only uncompressed + zstd supported */
311308
preface_size = p - (zck->hdr + lead_size);
312309

313-
/* parse index */
310+
/* parse index: index size, index chksum type, num chunks, chunk data */
314311
if ((p = getuint(p, zck->hdr_end, &index_size)) == 0)
315312
return open_error(zck);
316313
if (hdr_size < preface_size + index_size)
317314
return open_error(zck);
318-
if ((p = getuint(p, zck->hdr_end, &zck->chunk_chk_type)) == 0)
319-
return open_error(zck);
320-
zck->chunk_chk_len = chksum_len(zck->chunk_chk_type);
321-
if (zck->chunk_chk_len < 0)
315+
if ((p = getchksum(p, zck->hdr_end, &zck->chunk_chk_type, &zck->chunk_chk_len, &zck->chunk_chk_id)) == 0)
322316
return open_error(zck);
323-
324-
if ((p = getuint(p, zck->hdr_end, &nchunks)) == 0 || nchunks > MAX_CHUNK_CNT)
317+
if ((p = getuint(p, zck->hdr_end, &nchunks)) == 0 || nchunks < 1 || nchunks > MAX_CHUNK_CNT)
325318
return open_error(zck);
326319

327320
/* setup decompressor */
@@ -358,27 +351,25 @@ solv_zchunk_open(FILE *fp, unsigned int streamid)
358351
zck->buf_avail = 0;
359352

360353
/* ready to read the rest of the chunks */
361-
zck->nchunks = nchunks;
354+
zck->nchunks = nchunks - 1; /* subtract 1 for the dict stream */
362355
return zck;
363356
}
364357

365358
ssize_t
366359
solv_zchunk_read(struct solv_zchunk *zck, char *buf, size_t len)
367360
{
368361
size_t n = 0;
369-
unsigned int bite;
370362
if (!zck || zck->eof == 2)
371363
return -1;
372-
if (!len || zck->eof)
373-
return 0;
374-
for (;;)
364+
while (n < len && !zck->eof)
375365
{
366+
unsigned int bite;
376367
while (!zck->buf_avail)
377368
{
378369
if (!zck->nchunks)
379370
{
380371
/* verify data checksum if requested */
381-
if (zck->streamid != 0 && zck->data_chk && memcmp(solv_chksum_get(zck->data_chk, 0), zck->data_chk_ptr, zck->data_chk_len) != 0) {
372+
if (zck->streamid != 0 && zck->data_chk && memcmp(solv_chksum_get(zck->data_chk, 0), zck->data_chk_ptr, zck->hdr_chk_len) != 0) {
382373
zck->eof = 2;
383374
return -1;
384375
}
@@ -396,9 +387,8 @@ solv_zchunk_read(struct solv_zchunk *zck, char *buf, size_t len)
396387
n += bite;
397388
zck->buf_used += bite;
398389
zck->buf_avail -= bite;
399-
if (n == len)
400-
return n;
401390
}
391+
return n;
402392
}
403393

404394
int

0 commit comments

Comments
 (0)