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_hash.h"
35 #include "got_lib_inflate.h"
36 #include "got_lib_poll.h"
39 #define MIN(_a,_b) ((_a) < (_b) ? (_a) : (_b))
42 const struct got_error *
43 got_inflate_init(struct got_inflate_buf *zb, uint8_t *outbuf, size_t bufsize,
44 struct got_inflate_checksum *csum)
46 const struct got_error *err = NULL;
49 memset(zb, 0, sizeof(*zb));
51 zb->z.zalloc = Z_NULL;
53 zerr = inflateInit(&zb->z);
56 return got_error_from_errno("inflateInit");
57 if (zerr == Z_MEM_ERROR) {
59 return got_error_from_errno("inflateInit");
61 return got_error(GOT_ERR_DECOMPRESSION);
64 zb->inlen = zb->outlen = bufsize;
66 zb->inbuf = calloc(1, zb->inlen);
67 if (zb->inbuf == NULL) {
68 err = got_error_from_errno("calloc");
74 zb->outbuf = calloc(1, zb->outlen);
75 if (zb->outbuf == NULL) {
76 err = got_error_from_errno("calloc");
79 zb->flags |= GOT_INFLATE_F_OWN_OUTBUF;
91 csum_input(struct got_inflate_checksum *csum, const uint8_t *buf, size_t len)
94 *csum->input_crc = crc32(*csum->input_crc, buf, len);
97 SHA1Update(csum->input_sha1, buf, len);
100 got_hash_update(csum->input_ctx, buf, len);
104 csum_output(struct got_inflate_checksum *csum, const uint8_t *buf, size_t len)
106 if (csum->output_crc)
107 *csum->output_crc = crc32(*csum->output_crc, buf, len);
109 if (csum->output_sha1)
110 SHA1Update(csum->output_sha1, buf, len);
112 if (csum->output_ctx)
113 got_hash_update(csum->output_ctx, buf, len);
116 const struct got_error *
117 got_inflate_read(struct got_inflate_buf *zb, FILE *f, size_t *outlenp,
120 size_t last_total_out = zb->z.total_out;
121 size_t last_total_in = zb->z.total_in;
122 z_stream *z = &zb->z;
125 z->next_out = zb->outbuf;
126 z->avail_out = zb->outlen;
132 uint8_t *csum_in = NULL, *csum_out = NULL;
133 size_t csum_avail_in = 0, csum_avail_out = 0;
135 if (z->avail_in == 0) {
136 size_t n = fread(zb->inbuf, 1, zb->inlen, f);
139 return got_ferror(f, GOT_ERR_IO);
144 z->next_in = zb->inbuf;
148 csum_in = z->next_in;
149 csum_avail_in = z->avail_in;
150 csum_out = z->next_out;
151 csum_avail_out = z->avail_out;
153 ret = inflate(z, Z_SYNC_FLUSH);
155 csum_input(zb->csum, csum_in,
156 csum_avail_in - z->avail_in);
157 csum_output(zb->csum, csum_out,
158 csum_avail_out - z->avail_out);
160 } while (ret == Z_OK && z->avail_out > 0);
162 if (ret == Z_OK || ret == Z_BUF_ERROR) {
163 zb->flags |= GOT_INFLATE_F_HAVE_MORE;
165 if (ret != Z_STREAM_END)
166 return got_error(GOT_ERR_DECOMPRESSION);
167 zb->flags &= ~GOT_INFLATE_F_HAVE_MORE;
170 *outlenp = z->total_out - last_total_out;
172 *consumed += z->total_in - last_total_in;
176 const struct got_error *
177 got_inflate_read_fd(struct got_inflate_buf *zb, int fd, size_t *outlenp,
180 const struct got_error *err = NULL;
181 size_t last_total_out = zb->z.total_out;
182 size_t last_total_in = zb->z.total_in;
183 z_stream *z = &zb->z;
186 z->next_out = zb->outbuf;
187 z->avail_out = zb->outlen;
193 uint8_t *csum_in = NULL, *csum_out = NULL;
194 size_t csum_avail_in = 0, csum_avail_out = 0;
196 if (z->avail_in == 0) {
198 err = got_poll_fd(fd, POLLIN, INFTIM);
200 if (err->code == GOT_ERR_EOF) {
206 n = read(fd, zb->inbuf, zb->inlen);
208 return got_error_from_errno("read");
214 z->next_in = zb->inbuf;
218 csum_in = z->next_in;
219 csum_avail_in = z->avail_in;
220 csum_out = z->next_out;
221 csum_avail_out = z->avail_out;
223 ret = inflate(z, Z_SYNC_FLUSH);
225 csum_input(zb->csum, csum_in,
226 csum_avail_in - z->avail_in);
227 csum_output(zb->csum, csum_out,
228 csum_avail_out - z->avail_out);
230 } while (ret == Z_OK && z->avail_out > 0);
232 if (ret == Z_OK || ret == Z_BUF_ERROR) {
233 zb->flags |= GOT_INFLATE_F_HAVE_MORE;
235 if (ret != Z_STREAM_END)
236 return got_error(GOT_ERR_DECOMPRESSION);
237 zb->flags &= ~GOT_INFLATE_F_HAVE_MORE;
240 *outlenp = z->total_out - last_total_out;
242 *consumed += z->total_in - last_total_in;
246 const struct got_error *
247 got_inflate_read_mmap(struct got_inflate_buf *zb, uint8_t *map, size_t offset,
248 size_t len, size_t *outlenp, size_t *consumed)
250 size_t last_total_out = zb->z.total_out;
251 z_stream *z = &zb->z;
254 z->next_out = zb->outbuf;
255 z->avail_out = zb->outlen;
261 uint8_t *csum_in = NULL, *csum_out = NULL;
262 size_t csum_avail_in = 0, csum_avail_out = 0;
263 size_t last_total_in = zb->z.total_in;
265 if (z->avail_in == 0) {
271 z->next_in = map + offset + *consumed;
272 if (len - *consumed > UINT_MAX)
273 z->avail_in = UINT_MAX;
275 z->avail_in = len - *consumed;
278 csum_in = z->next_in;
279 csum_avail_in = z->avail_in;
280 csum_out = z->next_out;
281 csum_avail_out = z->avail_out;
283 ret = inflate(z, Z_SYNC_FLUSH);
285 csum_input(zb->csum, csum_in,
286 csum_avail_in - z->avail_in);
287 csum_output(zb->csum, csum_out,
288 csum_avail_out - z->avail_out);
290 *consumed += z->total_in - last_total_in;
291 } while (ret == Z_OK && z->avail_out > 0);
293 if (ret == Z_OK || ret == Z_BUF_ERROR) {
294 zb->flags |= GOT_INFLATE_F_HAVE_MORE;
296 if (ret != Z_STREAM_END)
297 return got_error(GOT_ERR_DECOMPRESSION);
298 zb->flags &= ~GOT_INFLATE_F_HAVE_MORE;
301 *outlenp = z->total_out - last_total_out;
306 got_inflate_end(struct got_inflate_buf *zb)
309 if (zb->flags & GOT_INFLATE_F_OWN_OUTBUF)
314 const struct got_error *
315 got_inflate_to_mem(uint8_t **outbuf, size_t *outlen,
316 size_t *consumed_total, struct got_inflate_checksum *csum, FILE *f)
318 const struct got_error *err;
319 size_t avail, consumed;
320 struct got_inflate_buf zb;
325 *outbuf = malloc(GOT_INFLATE_BUFSIZE);
327 return got_error_from_errno("malloc");
328 err = got_inflate_init(&zb, *outbuf, GOT_INFLATE_BUFSIZE, csum);
330 err = got_inflate_init(&zb, NULL, GOT_INFLATE_BUFSIZE, csum);
339 err = got_inflate_read(&zb, f, &avail, &consumed);
344 *consumed_total += consumed;
345 if (zb.flags & GOT_INFLATE_F_HAVE_MORE) {
348 newbuf = reallocarray(*outbuf, ++nbuf,
349 GOT_INFLATE_BUFSIZE);
350 if (newbuf == NULL) {
351 err = got_error_from_errno("reallocarray");
358 zb.outbuf = newbuf + *outlen;
359 zb.outlen = (nbuf * GOT_INFLATE_BUFSIZE) - *outlen;
361 } while (zb.flags & GOT_INFLATE_F_HAVE_MORE);
364 got_inflate_end(&zb);
368 const struct got_error *
369 got_inflate_to_mem_fd(uint8_t **outbuf, size_t *outlen,
370 size_t *consumed_total, struct got_inflate_checksum *csum,
371 size_t expected_size, int infd)
373 const struct got_error *err;
374 size_t avail, consumed;
375 struct got_inflate_buf zb;
378 size_t bufsize = GOT_INFLATE_BUFSIZE;
380 /* Optimize buffer size in case short reads should suffice. */
381 if (expected_size > 0 && expected_size < bufsize)
382 bufsize = expected_size;
385 *outbuf = malloc(bufsize);
387 return got_error_from_errno("malloc");
388 err = got_inflate_init(&zb, *outbuf, GOT_INFLATE_BUFSIZE, csum);
390 err = got_inflate_init(&zb, NULL, bufsize, csum);
399 err = got_inflate_read_fd(&zb, infd, &avail, &consumed);
404 *consumed_total += consumed;
405 if (zb.flags & GOT_INFLATE_F_HAVE_MORE) {
408 newbuf = reallocarray(*outbuf, ++nbuf,
409 GOT_INFLATE_BUFSIZE);
410 if (newbuf == NULL) {
411 err = got_error_from_errno("reallocarray");
418 zb.outbuf = newbuf + *outlen;
419 zb.outlen = (nbuf * GOT_INFLATE_BUFSIZE) - *outlen;
421 } while (zb.flags & GOT_INFLATE_F_HAVE_MORE);
424 got_inflate_end(&zb);
428 const struct got_error *
429 got_inflate_to_mem_mmap(uint8_t **outbuf, size_t *outlen,
430 size_t *consumed_total, struct got_inflate_checksum *csum, uint8_t *map,
431 size_t offset, size_t len)
433 const struct got_error *err;
434 size_t avail, consumed;
435 struct got_inflate_buf zb;
440 *outbuf = malloc(GOT_INFLATE_BUFSIZE);
442 return got_error_from_errno("malloc");
443 err = got_inflate_init(&zb, *outbuf, GOT_INFLATE_BUFSIZE, csum);
450 err = got_inflate_init(&zb, NULL, GOT_INFLATE_BUFSIZE, csum);
459 err = got_inflate_read_mmap(&zb, map, offset, len, &avail,
465 *consumed_total += consumed;
470 if (zb.flags & GOT_INFLATE_F_HAVE_MORE) {
473 newbuf = reallocarray(*outbuf, ++nbuf,
474 GOT_INFLATE_BUFSIZE);
475 if (newbuf == NULL) {
476 err = got_error_from_errno("reallocarray");
483 zb.outbuf = newbuf + *outlen;
484 zb.outlen = (nbuf * GOT_INFLATE_BUFSIZE) - *outlen;
486 } while (zb.flags & GOT_INFLATE_F_HAVE_MORE);
488 got_inflate_end(&zb);
492 const struct got_error *
493 got_inflate_to_fd(size_t *outlen, FILE *infile,
494 struct got_inflate_checksum *csum, int outfd)
496 const struct got_error *err = NULL;
498 struct got_inflate_buf zb;
500 err = got_inflate_init(&zb, NULL, GOT_INFLATE_BUFSIZE, csum);
507 err = got_inflate_read(&zb, infile, &avail, NULL);
512 n = write(outfd, zb.outbuf, avail);
514 err = got_error_from_errno("write");
519 } while (zb.flags & GOT_INFLATE_F_HAVE_MORE);
523 if (lseek(outfd, SEEK_SET, 0) == -1)
524 err = got_error_from_errno("lseek");
526 got_inflate_end(&zb);
530 const struct got_error *
531 got_inflate_to_file(size_t *outlen, FILE *infile,
532 struct got_inflate_checksum *csum, FILE *outfile)
534 const struct got_error *err;
536 struct got_inflate_buf zb;
538 err = got_inflate_init(&zb, NULL, GOT_INFLATE_BUFSIZE, csum);
545 err = got_inflate_read(&zb, infile, &avail, NULL);
550 n = fwrite(zb.outbuf, avail, 1, outfile);
552 err = got_ferror(outfile, GOT_ERR_IO);
557 } while (zb.flags & GOT_INFLATE_F_HAVE_MORE);
562 got_inflate_end(&zb);
566 const struct got_error *
567 got_inflate_to_file_fd(size_t *outlen, size_t *consumed_total,
568 struct got_inflate_checksum *csum, int infd, FILE *outfile)
570 const struct got_error *err;
571 size_t avail, consumed;
572 struct got_inflate_buf zb;
574 err = got_inflate_init(&zb, NULL, GOT_INFLATE_BUFSIZE, csum);
582 err = got_inflate_read_fd(&zb, infd, &avail, &consumed);
587 n = fwrite(zb.outbuf, avail, 1, outfile);
589 err = got_ferror(outfile, GOT_ERR_IO);
594 *consumed_total += consumed;
596 } while (zb.flags & GOT_INFLATE_F_HAVE_MORE);
601 got_inflate_end(&zb);
605 const struct got_error *
606 got_inflate_to_file_mmap(size_t *outlen, size_t *consumed_total,
607 struct got_inflate_checksum *csum, uint8_t *map, size_t offset,
608 size_t len, FILE *outfile)
610 const struct got_error *err;
611 size_t avail, consumed;
612 struct got_inflate_buf zb;
614 err = got_inflate_init(&zb, NULL, GOT_INFLATE_BUFSIZE, csum);
622 err = got_inflate_read_mmap(&zb, map, offset, len, &avail,
628 *consumed_total += consumed;
632 n = fwrite(zb.outbuf, avail, 1, outfile);
634 err = got_ferror(outfile, GOT_ERR_IO);
639 } while (zb.flags & GOT_INFLATE_F_HAVE_MORE);
644 got_inflate_end(&zb);