2 * Copyright (c) 2019 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 "got_compat.h"
19 #include <sys/queue.h>
29 #include "got_error.h"
30 #include "got_object.h"
33 #include "got_lib_deflate.h"
34 #include "got_lib_hash.h"
35 #include "got_lib_poll.h"
38 #define MIN(_a,_b) ((_a) < (_b) ? (_a) : (_b))
41 static const struct got_error
*
42 wrap_deflate_error(int zerr
, const char *prefix
)
45 return got_error_from_errno(prefix
);
46 if (zerr
== Z_MEM_ERROR
)
47 return got_error_set_errno(ENOMEM
, prefix
);
49 return got_error(GOT_ERR_COMPRESSION
);
52 const struct got_error
*
53 got_deflate_init(struct got_deflate_buf
*zb
, uint8_t *outbuf
, size_t bufsize
)
55 const struct got_error
*err
= NULL
;
58 memset(zb
, 0, sizeof(*zb
));
60 zb
->z
.zalloc
= Z_NULL
;
62 zerr
= deflateInit(&zb
->z
, Z_DEFAULT_COMPRESSION
);
64 return wrap_deflate_error(zerr
, "deflateInit");
66 zb
->inlen
= zb
->outlen
= bufsize
;
68 zb
->inbuf
= calloc(1, zb
->inlen
);
69 if (zb
->inbuf
== NULL
) {
70 err
= got_error_from_errno("calloc");
76 zb
->outbuf
= calloc(1, zb
->outlen
);
77 if (zb
->outbuf
== NULL
) {
78 err
= got_error_from_errno("calloc");
81 zb
->flags
|= GOT_DEFLATE_F_OWN_OUTBUF
;
91 csum_output(struct got_deflate_checksum
*csum
, const uint8_t *buf
, size_t len
)
94 *csum
->output_crc
= crc32(*csum
->output_crc
, buf
, len
);
97 got_hash_update(csum
->output_ctx
, buf
, len
);
100 const struct got_error
*
101 got_deflate_read(struct got_deflate_buf
*zb
, FILE *f
, off_t len
,
102 size_t *outlenp
, off_t
*consumed
)
104 size_t last_total_out
= zb
->z
.total_out
;
105 z_stream
*z
= &zb
->z
;
108 z
->next_out
= zb
->outbuf
;
109 z
->avail_out
= zb
->outlen
;
114 size_t last_total_in
= z
->total_in
;
115 if (z
->avail_in
== 0) {
117 if (*consumed
< len
) {
118 n
= fread(zb
->inbuf
, 1,
119 MIN(zb
->inlen
, len
- *consumed
), f
);
123 return got_ferror(f
, GOT_ERR_IO
);
125 ret
= deflate(z
, Z_FINISH
);
128 z
->next_in
= zb
->inbuf
;
131 ret
= deflate(z
, Z_NO_FLUSH
);
132 *consumed
+= z
->total_in
- last_total_in
;
133 } while (ret
== Z_OK
&& z
->avail_out
> 0);
136 zb
->flags
|= GOT_DEFLATE_F_HAVE_MORE
;
138 if (ret
!= Z_STREAM_END
)
139 return wrap_deflate_error(ret
, "deflate");
140 zb
->flags
&= ~GOT_DEFLATE_F_HAVE_MORE
;
143 *outlenp
= z
->total_out
- last_total_out
;
147 static const struct got_error
*
148 deflate_read_mmap(struct got_deflate_buf
*zb
, uint8_t *map
, size_t offset
,
149 size_t len
, size_t *outlenp
, size_t *consumed
, int flush_on_eof
)
151 z_stream
*z
= &zb
->z
;
152 size_t last_total_out
= z
->total_out
;
155 z
->next_out
= zb
->outbuf
;
156 z
->avail_out
= zb
->outlen
;
161 size_t last_total_in
= z
->total_in
;
162 if (z
->avail_in
== 0) {
163 z
->next_in
= map
+ offset
+ *consumed
;
164 if (len
- *consumed
> UINT_MAX
)
165 z
->avail_in
= UINT_MAX
;
167 z
->avail_in
= len
- *consumed
;
168 if (z
->avail_in
== 0) {
171 ret
= deflate(z
, Z_FINISH
);
175 ret
= deflate(z
, Z_NO_FLUSH
);
176 *consumed
+= z
->total_in
- last_total_in
;
177 } while (ret
== Z_OK
&& z
->avail_out
> 0);
180 zb
->flags
|= GOT_DEFLATE_F_HAVE_MORE
;
182 if (ret
!= Z_STREAM_END
)
183 return wrap_deflate_error(ret
, "deflate");
184 zb
->flags
&= ~GOT_DEFLATE_F_HAVE_MORE
;
187 *outlenp
= z
->total_out
- last_total_out
;
191 const struct got_error
*
192 got_deflate_read_mmap(struct got_deflate_buf
*zb
, uint8_t *map
, size_t offset
,
193 size_t len
, size_t *outlenp
, size_t *consumed
)
195 return deflate_read_mmap(zb
, map
, offset
, len
, outlenp
, consumed
, 1);
198 const struct got_error
*
199 got_deflate_flush(struct got_deflate_buf
*zb
, FILE *outfile
,
200 struct got_deflate_checksum
*csum
, off_t
*outlenp
)
204 z_stream
*z
= &zb
->z
;
206 if (z
->avail_in
!= 0)
207 return got_error_msg(GOT_ERR_COMPRESSION
,
208 "cannot flush zb with pending input data");
211 size_t avail
, last_total_out
= zb
->z
.total_out
;
213 z
->next_out
= zb
->outbuf
;
214 z
->avail_out
= zb
->outlen
;
216 ret
= deflate(z
, Z_FINISH
);
217 if (ret
!= Z_STREAM_END
&& ret
!= Z_OK
)
218 return wrap_deflate_error(ret
, "deflate");
220 avail
= z
->total_out
- last_total_out
;
222 n
= fwrite(zb
->outbuf
, avail
, 1, outfile
);
224 return got_ferror(outfile
, GOT_ERR_IO
);
226 csum_output(csum
, zb
->outbuf
, avail
);
230 } while (ret
!= Z_STREAM_END
);
232 zb
->flags
&= ~GOT_DEFLATE_F_HAVE_MORE
;
237 got_deflate_end(struct got_deflate_buf
*zb
)
240 if (zb
->flags
& GOT_DEFLATE_F_OWN_OUTBUF
)
245 const struct got_error
*
246 got_deflate_to_fd(off_t
*outlen
, FILE *infile
, off_t len
, int outfd
,
247 struct got_deflate_checksum
*csum
)
249 const struct got_error
*err
;
252 struct got_deflate_buf zb
;
254 err
= got_deflate_init(&zb
, NULL
, GOT_DEFLATE_BUFSIZE
);
261 err
= got_deflate_read(&zb
, infile
, len
, &avail
, &consumed
);
266 err
= got_poll_write_full(outfd
, zb
.outbuf
, avail
);
270 csum_output(csum
, zb
.outbuf
, avail
);
273 } while (zb
.flags
& GOT_DEFLATE_F_HAVE_MORE
);
276 got_deflate_end(&zb
);
280 const struct got_error
*
281 got_deflate_to_fd_mmap(off_t
*outlen
, uint8_t *map
, size_t offset
,
282 size_t len
, int outfd
, struct got_deflate_checksum
*csum
)
284 const struct got_error
*err
;
285 size_t avail
, consumed
;
286 struct got_deflate_buf zb
;
288 err
= got_deflate_init(&zb
, NULL
, GOT_DEFLATE_BUFSIZE
);
294 err
= got_deflate_read_mmap(&zb
, map
, offset
, len
, &avail
,
301 err
= got_poll_write_full(outfd
, zb
.outbuf
, avail
);
305 csum_output(csum
, zb
.outbuf
, avail
);
308 } while (zb
.flags
& GOT_DEFLATE_F_HAVE_MORE
);
311 got_deflate_end(&zb
);
315 const struct got_error
*
316 got_deflate_to_file(off_t
*outlen
, FILE *infile
, off_t len
,
317 FILE *outfile
, struct got_deflate_checksum
*csum
)
319 const struct got_error
*err
;
322 struct got_deflate_buf zb
;
324 err
= got_deflate_init(&zb
, NULL
, GOT_DEFLATE_BUFSIZE
);
331 err
= got_deflate_read(&zb
, infile
, len
, &avail
, &consumed
);
337 n
= fwrite(zb
.outbuf
, avail
, 1, outfile
);
339 err
= got_ferror(outfile
, GOT_ERR_IO
);
343 csum_output(csum
, zb
.outbuf
, avail
);
346 } while (zb
.flags
& GOT_DEFLATE_F_HAVE_MORE
);
349 got_deflate_end(&zb
);
353 const struct got_error
*
354 got_deflate_to_file_mmap(off_t
*outlen
, uint8_t *map
, size_t offset
,
355 size_t len
, FILE *outfile
, struct got_deflate_checksum
*csum
)
357 const struct got_error
*err
;
358 size_t avail
, consumed
;
359 struct got_deflate_buf zb
;
361 err
= got_deflate_init(&zb
, NULL
, GOT_DEFLATE_BUFSIZE
);
367 err
= got_deflate_read_mmap(&zb
, map
, offset
, len
, &avail
,
375 n
= fwrite(zb
.outbuf
, avail
, 1, outfile
);
377 err
= got_ferror(outfile
, GOT_ERR_IO
);
381 csum_output(csum
, zb
.outbuf
, avail
);
384 } while (zb
.flags
& GOT_DEFLATE_F_HAVE_MORE
);
387 got_deflate_end(&zb
);
391 const struct got_error
*
392 got_deflate_append_to_file_mmap(struct got_deflate_buf
*zb
, off_t
*outlen
,
393 uint8_t *map
, size_t offset
, size_t len
, FILE *outfile
,
394 struct got_deflate_checksum
*csum
)
396 const struct got_error
*err
;
397 size_t avail
, consumed
;
400 err
= deflate_read_mmap(zb
, map
, offset
, len
, &avail
,
408 n
= fwrite(zb
->outbuf
, avail
, 1, outfile
);
410 err
= got_ferror(outfile
, GOT_ERR_IO
);
414 csum_output(csum
, zb
->outbuf
, avail
);
418 } while ((zb
->flags
& GOT_DEFLATE_F_HAVE_MORE
) && len
> 0);
423 const struct got_error
*
424 got_deflate_to_mem_mmap(uint8_t **outbuf
, size_t *outlen
,
425 size_t *consumed_total
, struct got_deflate_checksum
*csum
, uint8_t *map
,
426 size_t offset
, size_t len
)
428 const struct got_error
*err
;
429 size_t avail
, consumed
;
430 struct got_deflate_buf zb
;
435 *outbuf
= malloc(GOT_DEFLATE_BUFSIZE
);
437 return got_error_from_errno("malloc");
438 err
= got_deflate_init(&zb
, *outbuf
, GOT_DEFLATE_BUFSIZE
);
445 err
= got_deflate_init(&zb
, NULL
, GOT_DEFLATE_BUFSIZE
);
454 err
= got_deflate_read_mmap(&zb
, map
, offset
, len
, &avail
,
460 *consumed_total
+= consumed
;
462 if (avail
> 0 && csum
)
463 csum_output(csum
, zb
.outbuf
, avail
);
465 if ((zb
.flags
& GOT_DEFLATE_F_HAVE_MORE
) && outbuf
!= NULL
) {
466 newbuf
= reallocarray(*outbuf
, ++nbuf
,
467 GOT_DEFLATE_BUFSIZE
);
468 if (newbuf
== NULL
) {
469 err
= got_error_from_errno("reallocarray");
476 zb
.outbuf
= newbuf
+ *outlen
;
477 zb
.outlen
= (nbuf
* GOT_DEFLATE_BUFSIZE
) - *outlen
;
479 } while (zb
.flags
& GOT_DEFLATE_F_HAVE_MORE
);
481 got_deflate_end(&zb
);