2 * Copyright (c) 2018 Stefan Sperling <stsp@openbsd.org>
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 #include <sys/queue.h>
30 #include "got_error.h"
31 #include "got_object.h"
34 #include "got_lib_inflate.h"
35 #include "got_lib_poll.h"
38 #define MIN(_a,_b) ((_a) < (_b) ? (_a) : (_b))
41 const struct got_error *
42 got_inflate_init(struct got_inflate_buf *zb, uint8_t *outbuf, size_t bufsize,
43 struct got_inflate_checksum *csum)
45 const struct got_error *err = NULL;
48 memset(zb, 0, sizeof(*zb));
50 zb->z.zalloc = Z_NULL;
52 zerr = inflateInit(&zb->z);
55 return got_error_from_errno("inflateInit");
56 if (zerr == Z_MEM_ERROR) {
58 return got_error_from_errno("inflateInit");
60 return got_error(GOT_ERR_DECOMPRESSION);
63 zb->inlen = zb->outlen = bufsize;
65 zb->inbuf = calloc(1, zb->inlen);
66 if (zb->inbuf == NULL) {
67 err = got_error_from_errno("calloc");
73 zb->outbuf = calloc(1, zb->outlen);
74 if (zb->outbuf == NULL) {
75 err = got_error_from_errno("calloc");
78 zb->flags |= GOT_INFLATE_F_OWN_OUTBUF;
90 csum_input(struct got_inflate_checksum *csum, const uint8_t *buf, size_t len)
93 *csum->input_crc = crc32(*csum->input_crc, buf, len);
96 SHA1Update(csum->input_sha1, buf, len);
98 if (csum->input_sha256)
99 SHA256Update(csum->input_sha256, buf, len);
103 csum_output(struct got_inflate_checksum *csum, const uint8_t *buf, size_t len)
105 if (csum->output_crc)
106 *csum->output_crc = crc32(*csum->output_crc, buf, len);
108 if (csum->output_sha1)
109 SHA1Update(csum->output_sha1, buf, len);
111 if (csum->output_sha256)
112 SHA256Update(csum->output_sha256, buf, len);
115 const struct got_error *
116 got_inflate_read(struct got_inflate_buf *zb, FILE *f, size_t *outlenp,
119 size_t last_total_out = zb->z.total_out;
120 size_t last_total_in = zb->z.total_in;
121 z_stream *z = &zb->z;
124 z->next_out = zb->outbuf;
125 z->avail_out = zb->outlen;
131 uint8_t *csum_in = NULL, *csum_out = NULL;
132 size_t csum_avail_in = 0, csum_avail_out = 0;
134 if (z->avail_in == 0) {
135 size_t n = fread(zb->inbuf, 1, zb->inlen, f);
138 return got_ferror(f, GOT_ERR_IO);
143 z->next_in = zb->inbuf;
147 csum_in = z->next_in;
148 csum_avail_in = z->avail_in;
149 csum_out = z->next_out;
150 csum_avail_out = z->avail_out;
152 ret = inflate(z, Z_SYNC_FLUSH);
154 csum_input(zb->csum, csum_in,
155 csum_avail_in - z->avail_in);
156 csum_output(zb->csum, csum_out,
157 csum_avail_out - z->avail_out);
159 } while (ret == Z_OK && z->avail_out > 0);
161 if (ret == Z_OK || ret == Z_BUF_ERROR) {
162 zb->flags |= GOT_INFLATE_F_HAVE_MORE;
164 if (ret != Z_STREAM_END)
165 return got_error(GOT_ERR_DECOMPRESSION);
166 zb->flags &= ~GOT_INFLATE_F_HAVE_MORE;
169 *outlenp = z->total_out - last_total_out;
171 *consumed += z->total_in - last_total_in;
175 const struct got_error *
176 got_inflate_read_fd(struct got_inflate_buf *zb, int fd, size_t *outlenp,
179 const struct got_error *err = NULL;
180 size_t last_total_out = zb->z.total_out;
181 size_t last_total_in = zb->z.total_in;
182 z_stream *z = &zb->z;
185 z->next_out = zb->outbuf;
186 z->avail_out = zb->outlen;
192 uint8_t *csum_in = NULL, *csum_out = NULL;
193 size_t csum_avail_in = 0, csum_avail_out = 0;
195 if (z->avail_in == 0) {
197 err = got_poll_fd(fd, POLLIN, INFTIM);
199 if (err->code == GOT_ERR_EOF) {
205 n = read(fd, zb->inbuf, zb->inlen);
207 return got_error_from_errno("read");
213 z->next_in = zb->inbuf;
217 csum_in = z->next_in;
218 csum_avail_in = z->avail_in;
219 csum_out = z->next_out;
220 csum_avail_out = z->avail_out;
222 ret = inflate(z, Z_SYNC_FLUSH);
224 csum_input(zb->csum, csum_in,
225 csum_avail_in - z->avail_in);
226 csum_output(zb->csum, csum_out,
227 csum_avail_out - z->avail_out);
229 } while (ret == Z_OK && z->avail_out > 0);
231 if (ret == Z_OK || ret == Z_BUF_ERROR) {
232 zb->flags |= GOT_INFLATE_F_HAVE_MORE;
234 if (ret != Z_STREAM_END)
235 return got_error(GOT_ERR_DECOMPRESSION);
236 zb->flags &= ~GOT_INFLATE_F_HAVE_MORE;
239 *outlenp = z->total_out - last_total_out;
241 *consumed += z->total_in - last_total_in;
245 const struct got_error *
246 got_inflate_read_mmap(struct got_inflate_buf *zb, uint8_t *map, size_t offset,
247 size_t len, size_t *outlenp, size_t *consumed)
249 size_t last_total_out = zb->z.total_out;
250 z_stream *z = &zb->z;
253 z->next_out = zb->outbuf;
254 z->avail_out = zb->outlen;
260 uint8_t *csum_in = NULL, *csum_out = NULL;
261 size_t csum_avail_in = 0, csum_avail_out = 0;
262 size_t last_total_in = zb->z.total_in;
264 if (z->avail_in == 0) {
270 z->next_in = map + offset + *consumed;
271 if (len - *consumed > UINT_MAX)
272 z->avail_in = UINT_MAX;
274 z->avail_in = len - *consumed;
277 csum_in = z->next_in;
278 csum_avail_in = z->avail_in;
279 csum_out = z->next_out;
280 csum_avail_out = z->avail_out;
282 ret = inflate(z, Z_SYNC_FLUSH);
284 csum_input(zb->csum, csum_in,
285 csum_avail_in - z->avail_in);
286 csum_output(zb->csum, csum_out,
287 csum_avail_out - z->avail_out);
289 *consumed += z->total_in - last_total_in;
290 } while (ret == Z_OK && z->avail_out > 0);
292 if (ret == Z_OK || ret == Z_BUF_ERROR) {
293 zb->flags |= GOT_INFLATE_F_HAVE_MORE;
295 if (ret != Z_STREAM_END)
296 return got_error(GOT_ERR_DECOMPRESSION);
297 zb->flags &= ~GOT_INFLATE_F_HAVE_MORE;
300 *outlenp = z->total_out - last_total_out;
305 got_inflate_end(struct got_inflate_buf *zb)
308 if (zb->flags & GOT_INFLATE_F_OWN_OUTBUF)
313 const struct got_error *
314 got_inflate_to_mem(uint8_t **outbuf, size_t *outlen,
315 size_t *consumed_total, struct got_inflate_checksum *csum, FILE *f)
317 const struct got_error *err;
318 size_t avail, consumed;
319 struct got_inflate_buf zb;
324 *outbuf = malloc(GOT_INFLATE_BUFSIZE);
326 return got_error_from_errno("malloc");
327 err = got_inflate_init(&zb, *outbuf, GOT_INFLATE_BUFSIZE, csum);
329 err = got_inflate_init(&zb, NULL, GOT_INFLATE_BUFSIZE, csum);
338 err = got_inflate_read(&zb, f, &avail, &consumed);
343 *consumed_total += consumed;
344 if (zb.flags & GOT_INFLATE_F_HAVE_MORE) {
347 newbuf = reallocarray(*outbuf, ++nbuf,
348 GOT_INFLATE_BUFSIZE);
349 if (newbuf == NULL) {
350 err = got_error_from_errno("reallocarray");
357 zb.outbuf = newbuf + *outlen;
358 zb.outlen = (nbuf * GOT_INFLATE_BUFSIZE) - *outlen;
360 } while (zb.flags & GOT_INFLATE_F_HAVE_MORE);
363 got_inflate_end(&zb);
367 const struct got_error *
368 got_inflate_to_mem_fd(uint8_t **outbuf, size_t *outlen,
369 size_t *consumed_total, struct got_inflate_checksum *csum,
370 size_t expected_size, int infd)
372 const struct got_error *err;
373 size_t avail, consumed;
374 struct got_inflate_buf zb;
377 size_t bufsize = GOT_INFLATE_BUFSIZE;
379 /* Optimize buffer size in case short reads should suffice. */
380 if (expected_size > 0 && expected_size < bufsize)
381 bufsize = expected_size;
384 *outbuf = malloc(bufsize);
386 return got_error_from_errno("malloc");
387 err = got_inflate_init(&zb, *outbuf, GOT_INFLATE_BUFSIZE, csum);
389 err = got_inflate_init(&zb, NULL, bufsize, csum);
398 err = got_inflate_read_fd(&zb, infd, &avail, &consumed);
403 *consumed_total += consumed;
404 if (zb.flags & GOT_INFLATE_F_HAVE_MORE) {
407 newbuf = reallocarray(*outbuf, ++nbuf,
408 GOT_INFLATE_BUFSIZE);
409 if (newbuf == NULL) {
410 err = got_error_from_errno("reallocarray");
417 zb.outbuf = newbuf + *outlen;
418 zb.outlen = (nbuf * GOT_INFLATE_BUFSIZE) - *outlen;
420 } while (zb.flags & GOT_INFLATE_F_HAVE_MORE);
423 got_inflate_end(&zb);
427 const struct got_error *
428 got_inflate_to_mem_mmap(uint8_t **outbuf, size_t *outlen,
429 size_t *consumed_total, struct got_inflate_checksum *csum, uint8_t *map,
430 size_t offset, size_t len)
432 const struct got_error *err;
433 size_t avail, consumed;
434 struct got_inflate_buf zb;
439 *outbuf = malloc(GOT_INFLATE_BUFSIZE);
441 return got_error_from_errno("malloc");
442 err = got_inflate_init(&zb, *outbuf, GOT_INFLATE_BUFSIZE, csum);
449 err = got_inflate_init(&zb, NULL, GOT_INFLATE_BUFSIZE, csum);
458 err = got_inflate_read_mmap(&zb, map, offset, len, &avail,
464 *consumed_total += consumed;
469 if (zb.flags & GOT_INFLATE_F_HAVE_MORE) {
472 newbuf = reallocarray(*outbuf, ++nbuf,
473 GOT_INFLATE_BUFSIZE);
474 if (newbuf == NULL) {
475 err = got_error_from_errno("reallocarray");
482 zb.outbuf = newbuf + *outlen;
483 zb.outlen = (nbuf * GOT_INFLATE_BUFSIZE) - *outlen;
485 } while (zb.flags & GOT_INFLATE_F_HAVE_MORE);
487 got_inflate_end(&zb);
491 const struct got_error *
492 got_inflate_to_fd(size_t *outlen, FILE *infile,
493 struct got_inflate_checksum *csum, int outfd)
495 const struct got_error *err = NULL;
497 struct got_inflate_buf zb;
499 err = got_inflate_init(&zb, NULL, GOT_INFLATE_BUFSIZE, csum);
506 err = got_inflate_read(&zb, infile, &avail, NULL);
511 n = write(outfd, zb.outbuf, avail);
513 err = got_error_from_errno("write");
518 } while (zb.flags & GOT_INFLATE_F_HAVE_MORE);
522 if (lseek(outfd, SEEK_SET, 0) == -1)
523 err = got_error_from_errno("lseek");
525 got_inflate_end(&zb);
529 const struct got_error *
530 got_inflate_to_file(size_t *outlen, FILE *infile,
531 struct got_inflate_checksum *csum, FILE *outfile)
533 const struct got_error *err;
535 struct got_inflate_buf zb;
537 err = got_inflate_init(&zb, NULL, GOT_INFLATE_BUFSIZE, csum);
544 err = got_inflate_read(&zb, infile, &avail, NULL);
549 n = fwrite(zb.outbuf, avail, 1, outfile);
551 err = got_ferror(outfile, GOT_ERR_IO);
556 } while (zb.flags & GOT_INFLATE_F_HAVE_MORE);
561 got_inflate_end(&zb);
565 const struct got_error *
566 got_inflate_to_file_fd(size_t *outlen, size_t *consumed_total,
567 struct got_inflate_checksum *csum, int infd, FILE *outfile)
569 const struct got_error *err;
570 size_t avail, consumed;
571 struct got_inflate_buf zb;
573 err = got_inflate_init(&zb, NULL, GOT_INFLATE_BUFSIZE, csum);
581 err = got_inflate_read_fd(&zb, infd, &avail, &consumed);
586 n = fwrite(zb.outbuf, avail, 1, outfile);
588 err = got_ferror(outfile, GOT_ERR_IO);
593 *consumed_total += consumed;
595 } while (zb.flags & GOT_INFLATE_F_HAVE_MORE);
600 got_inflate_end(&zb);
604 const struct got_error *
605 got_inflate_to_file_mmap(size_t *outlen, size_t *consumed_total,
606 struct got_inflate_checksum *csum, uint8_t *map, size_t offset,
607 size_t len, FILE *outfile)
609 const struct got_error *err;
610 size_t avail, consumed;
611 struct got_inflate_buf zb;
613 err = got_inflate_init(&zb, NULL, GOT_INFLATE_BUFSIZE, csum);
621 err = got_inflate_read_mmap(&zb, map, offset, len, &avail,
627 *consumed_total += consumed;
631 n = fwrite(zb.outbuf, avail, 1, outfile);
633 err = got_ferror(outfile, GOT_ERR_IO);
638 } while (zb.flags & GOT_INFLATE_F_HAVE_MORE);
643 got_inflate_end(&zb);