Blob


1 /*
2 * Copyright (c) 2018 Stefan Sperling <stsp@openbsd.org>
3 *
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.
7 *
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.
15 */
17 #include <sys/queue.h>
19 #include <errno.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <sha1.h>
24 #include <sha2.h>
25 #include <poll.h>
26 #include <unistd.h>
27 #include <zlib.h>
28 #include <time.h>
30 #include "got_error.h"
31 #include "got_object.h"
32 #include "got_path.h"
34 #include "got_lib_hash.h"
35 #include "got_lib_inflate.h"
36 #include "got_lib_poll.h"
38 #ifndef MIN
39 #define MIN(_a,_b) ((_a) < (_b) ? (_a) : (_b))
40 #endif
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)
45 {
46 const struct got_error *err = NULL;
47 int zerr;
49 memset(zb, 0, sizeof(*zb));
51 zb->z.zalloc = Z_NULL;
52 zb->z.zfree = Z_NULL;
53 zerr = inflateInit(&zb->z);
54 if (zerr != Z_OK) {
55 if (zerr == Z_ERRNO)
56 return got_error_from_errno("inflateInit");
57 if (zerr == Z_MEM_ERROR) {
58 errno = ENOMEM;
59 return got_error_from_errno("inflateInit");
60 }
61 return got_error(GOT_ERR_DECOMPRESSION);
62 }
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");
69 goto done;
70 }
72 zb->flags = 0;
73 if (outbuf == NULL) {
74 zb->outbuf = calloc(1, zb->outlen);
75 if (zb->outbuf == NULL) {
76 err = got_error_from_errno("calloc");
77 goto done;
78 }
79 zb->flags |= GOT_INFLATE_F_OWN_OUTBUF;
80 } else
81 zb->outbuf = outbuf;
83 zb->csum = csum;
84 done:
85 if (err)
86 got_inflate_end(zb);
87 return err;
88 }
90 static void
91 csum_input(struct got_inflate_checksum *csum, const uint8_t *buf, size_t len)
92 {
93 if (csum->input_crc)
94 *csum->input_crc = crc32(*csum->input_crc, buf, len);
96 if (csum->input_sha1)
97 SHA1Update(csum->input_sha1, buf, len);
99 if (csum->input_ctx)
100 got_hash_update(csum->input_ctx, buf, len);
103 static void
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,
118 size_t *consumed)
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;
123 int ret = Z_ERRNO;
125 z->next_out = zb->outbuf;
126 z->avail_out = zb->outlen;
128 *outlenp = 0;
129 if (consumed)
130 *consumed = 0;
131 do {
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);
137 if (n == 0) {
138 if (ferror(f))
139 return got_ferror(f, GOT_ERR_IO);
140 /* EOF */
141 ret = Z_STREAM_END;
142 break;
144 z->next_in = zb->inbuf;
145 z->avail_in = n;
147 if (zb->csum) {
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);
154 if (zb->csum) {
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;
164 } else {
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;
171 if (consumed)
172 *consumed += z->total_in - last_total_in;
173 return NULL;
176 const struct got_error *
177 got_inflate_read_fd(struct got_inflate_buf *zb, int fd, size_t *outlenp,
178 size_t *consumed)
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;
184 int ret = Z_ERRNO;
186 z->next_out = zb->outbuf;
187 z->avail_out = zb->outlen;
189 *outlenp = 0;
190 if (consumed)
191 *consumed = 0;
192 do {
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) {
197 ssize_t n;
198 err = got_poll_fd(fd, POLLIN, INFTIM);
199 if (err) {
200 if (err->code == GOT_ERR_EOF) {
201 ret = Z_STREAM_END;
202 break;
204 return err;
206 n = read(fd, zb->inbuf, zb->inlen);
207 if (n < 0)
208 return got_error_from_errno("read");
209 else if (n == 0) {
210 /* EOF */
211 ret = Z_STREAM_END;
212 break;
214 z->next_in = zb->inbuf;
215 z->avail_in = n;
217 if (zb->csum) {
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);
224 if (zb->csum) {
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;
234 } else {
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;
241 if (consumed)
242 *consumed += z->total_in - last_total_in;
243 return NULL;
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;
252 int ret = Z_ERRNO;
254 z->next_out = zb->outbuf;
255 z->avail_out = zb->outlen;
257 *outlenp = 0;
258 *consumed = 0;
260 do {
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) {
266 if (len == 0) {
267 /* EOF */
268 ret = Z_STREAM_END;
269 break;
271 z->next_in = map + offset + *consumed;
272 if (len - *consumed > UINT_MAX)
273 z->avail_in = UINT_MAX;
274 else
275 z->avail_in = len - *consumed;
277 if (zb->csum) {
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);
284 if (zb->csum) {
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;
295 } else {
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;
302 return NULL;
305 void
306 got_inflate_end(struct got_inflate_buf *zb)
308 free(zb->inbuf);
309 if (zb->flags & GOT_INFLATE_F_OWN_OUTBUF)
310 free(zb->outbuf);
311 inflateEnd(&zb->z);
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;
321 void *newbuf;
322 int nbuf = 1;
324 if (outbuf) {
325 *outbuf = malloc(GOT_INFLATE_BUFSIZE);
326 if (*outbuf == NULL)
327 return got_error_from_errno("malloc");
328 err = got_inflate_init(&zb, *outbuf, GOT_INFLATE_BUFSIZE, csum);
329 } else
330 err = got_inflate_init(&zb, NULL, GOT_INFLATE_BUFSIZE, csum);
331 if (err)
332 return err;
334 *outlen = 0;
335 if (consumed_total)
336 *consumed_total = 0;
338 do {
339 err = got_inflate_read(&zb, f, &avail, &consumed);
340 if (err)
341 goto done;
342 *outlen += avail;
343 if (consumed_total)
344 *consumed_total += consumed;
345 if (zb.flags & GOT_INFLATE_F_HAVE_MORE) {
346 if (outbuf == NULL)
347 continue;
348 newbuf = reallocarray(*outbuf, ++nbuf,
349 GOT_INFLATE_BUFSIZE);
350 if (newbuf == NULL) {
351 err = got_error_from_errno("reallocarray");
352 free(*outbuf);
353 *outbuf = NULL;
354 *outlen = 0;
355 goto done;
357 *outbuf = newbuf;
358 zb.outbuf = newbuf + *outlen;
359 zb.outlen = (nbuf * GOT_INFLATE_BUFSIZE) - *outlen;
361 } while (zb.flags & GOT_INFLATE_F_HAVE_MORE);
363 done:
364 got_inflate_end(&zb);
365 return err;
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;
376 void *newbuf;
377 int nbuf = 1;
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;
384 if (outbuf) {
385 *outbuf = malloc(bufsize);
386 if (*outbuf == NULL)
387 return got_error_from_errno("malloc");
388 err = got_inflate_init(&zb, *outbuf, GOT_INFLATE_BUFSIZE, csum);
389 } else
390 err = got_inflate_init(&zb, NULL, bufsize, csum);
391 if (err)
392 goto done;
394 *outlen = 0;
395 if (consumed_total)
396 *consumed_total = 0;
398 do {
399 err = got_inflate_read_fd(&zb, infd, &avail, &consumed);
400 if (err)
401 goto done;
402 *outlen += avail;
403 if (consumed_total)
404 *consumed_total += consumed;
405 if (zb.flags & GOT_INFLATE_F_HAVE_MORE) {
406 if (outbuf == NULL)
407 continue;
408 newbuf = reallocarray(*outbuf, ++nbuf,
409 GOT_INFLATE_BUFSIZE);
410 if (newbuf == NULL) {
411 err = got_error_from_errno("reallocarray");
412 free(*outbuf);
413 *outbuf = NULL;
414 *outlen = 0;
415 goto done;
417 *outbuf = newbuf;
418 zb.outbuf = newbuf + *outlen;
419 zb.outlen = (nbuf * GOT_INFLATE_BUFSIZE) - *outlen;
421 } while (zb.flags & GOT_INFLATE_F_HAVE_MORE);
423 done:
424 got_inflate_end(&zb);
425 return err;
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;
436 void *newbuf;
437 int nbuf = 1;
439 if (outbuf) {
440 *outbuf = malloc(GOT_INFLATE_BUFSIZE);
441 if (*outbuf == NULL)
442 return got_error_from_errno("malloc");
443 err = got_inflate_init(&zb, *outbuf, GOT_INFLATE_BUFSIZE, csum);
444 if (err) {
445 free(*outbuf);
446 *outbuf = NULL;
447 return err;
449 } else {
450 err = got_inflate_init(&zb, NULL, GOT_INFLATE_BUFSIZE, csum);
451 if (err)
452 return err;
455 *outlen = 0;
456 if (consumed_total)
457 *consumed_total = 0;
458 do {
459 err = got_inflate_read_mmap(&zb, map, offset, len, &avail,
460 &consumed);
461 if (err)
462 goto done;
463 offset += consumed;
464 if (consumed_total)
465 *consumed_total += consumed;
466 len -= consumed;
467 *outlen += avail;
468 if (len == 0)
469 break;
470 if (zb.flags & GOT_INFLATE_F_HAVE_MORE) {
471 if (outbuf == NULL)
472 continue;
473 newbuf = reallocarray(*outbuf, ++nbuf,
474 GOT_INFLATE_BUFSIZE);
475 if (newbuf == NULL) {
476 err = got_error_from_errno("reallocarray");
477 free(*outbuf);
478 *outbuf = NULL;
479 *outlen = 0;
480 goto done;
482 *outbuf = newbuf;
483 zb.outbuf = newbuf + *outlen;
484 zb.outlen = (nbuf * GOT_INFLATE_BUFSIZE) - *outlen;
486 } while (zb.flags & GOT_INFLATE_F_HAVE_MORE);
487 done:
488 got_inflate_end(&zb);
489 return err;
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;
497 size_t avail;
498 struct got_inflate_buf zb;
500 err = got_inflate_init(&zb, NULL, GOT_INFLATE_BUFSIZE, csum);
501 if (err)
502 goto done;
504 *outlen = 0;
506 do {
507 err = got_inflate_read(&zb, infile, &avail, NULL);
508 if (err)
509 goto done;
510 if (avail > 0) {
511 ssize_t n;
512 n = write(outfd, zb.outbuf, avail);
513 if (n != avail) {
514 err = got_error_from_errno("write");
515 goto done;
517 *outlen += avail;
519 } while (zb.flags & GOT_INFLATE_F_HAVE_MORE);
521 done:
522 if (err == NULL) {
523 if (lseek(outfd, SEEK_SET, 0) == -1)
524 err = got_error_from_errno("lseek");
526 got_inflate_end(&zb);
527 return err;
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;
535 size_t avail;
536 struct got_inflate_buf zb;
538 err = got_inflate_init(&zb, NULL, GOT_INFLATE_BUFSIZE, csum);
539 if (err)
540 goto done;
542 *outlen = 0;
544 do {
545 err = got_inflate_read(&zb, infile, &avail, NULL);
546 if (err)
547 goto done;
548 if (avail > 0) {
549 size_t n;
550 n = fwrite(zb.outbuf, avail, 1, outfile);
551 if (n != 1) {
552 err = got_ferror(outfile, GOT_ERR_IO);
553 goto done;
555 *outlen += avail;
557 } while (zb.flags & GOT_INFLATE_F_HAVE_MORE);
559 done:
560 if (err == NULL)
561 rewind(outfile);
562 got_inflate_end(&zb);
563 return err;
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);
575 if (err)
576 goto done;
578 *outlen = 0;
579 if (consumed_total)
580 *consumed_total = 0;
581 do {
582 err = got_inflate_read_fd(&zb, infd, &avail, &consumed);
583 if (err)
584 goto done;
585 if (avail > 0) {
586 size_t n;
587 n = fwrite(zb.outbuf, avail, 1, outfile);
588 if (n != 1) {
589 err = got_ferror(outfile, GOT_ERR_IO);
590 goto done;
592 *outlen += avail;
593 if (consumed_total)
594 *consumed_total += consumed;
596 } while (zb.flags & GOT_INFLATE_F_HAVE_MORE);
598 done:
599 if (err == NULL)
600 rewind(outfile);
601 got_inflate_end(&zb);
602 return err;
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);
615 if (err)
616 goto done;
618 *outlen = 0;
619 if (consumed_total)
620 *consumed_total = 0;
621 do {
622 err = got_inflate_read_mmap(&zb, map, offset, len, &avail,
623 &consumed);
624 if (err)
625 goto done;
626 offset += consumed;
627 if (consumed_total)
628 *consumed_total += consumed;
629 len -= consumed;
630 if (avail > 0) {
631 size_t n;
632 n = fwrite(zb.outbuf, avail, 1, outfile);
633 if (n != 1) {
634 err = got_ferror(outfile, GOT_ERR_IO);
635 goto done;
637 *outlen += avail;
639 } while (zb.flags & GOT_INFLATE_F_HAVE_MORE);
641 done:
642 if (err == NULL)
643 rewind(outfile);
644 got_inflate_end(&zb);
645 return err;