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>
28 #include "got_error.h"
29 #include "got_object.h"
32 #include "got_lib_deflate.h"
33 #include "got_lib_hash.h"
34 #include "got_lib_poll.h"
37 #define MIN(_a,_b) ((_a) < (_b) ? (_a) : (_b))
40 static const struct got_error
*
41 wrap_deflate_error(int zerr
, const char *prefix
)
44 return got_error_from_errno(prefix
);
45 if (zerr
== Z_MEM_ERROR
)
46 return got_error_set_errno(ENOMEM
, prefix
);
48 return got_error(GOT_ERR_COMPRESSION
);
51 const struct got_error
*
52 got_deflate_init(struct got_deflate_buf
*zb
, uint8_t *outbuf
, size_t bufsize
)
54 const struct got_error
*err
= NULL
;
57 memset(zb
, 0, sizeof(*zb
));
59 zb
->z
.zalloc
= Z_NULL
;
61 zerr
= deflateInit(&zb
->z
, Z_DEFAULT_COMPRESSION
);
63 return wrap_deflate_error(zerr
, "deflateInit");
65 zb
->inlen
= zb
->outlen
= bufsize
;
67 zb
->inbuf
= calloc(1, zb
->inlen
);
68 if (zb
->inbuf
== NULL
) {
69 err
= got_error_from_errno("calloc");
75 zb
->outbuf
= calloc(1, zb
->outlen
);
76 if (zb
->outbuf
== NULL
) {
77 err
= got_error_from_errno("calloc");
80 zb
->flags
|= GOT_DEFLATE_F_OWN_OUTBUF
;
90 csum_output(struct got_deflate_checksum
*csum
, const uint8_t *buf
, size_t len
)
93 *csum
->output_crc
= crc32(*csum
->output_crc
, buf
, len
);
96 got_hash_update(csum
->output_ctx
, buf
, len
);
99 const struct got_error
*
100 got_deflate_read(struct got_deflate_buf
*zb
, FILE *f
, off_t len
,
101 size_t *outlenp
, off_t
*consumed
)
103 size_t last_total_out
= zb
->z
.total_out
;
104 z_stream
*z
= &zb
->z
;
107 z
->next_out
= zb
->outbuf
;
108 z
->avail_out
= zb
->outlen
;
113 size_t last_total_in
= z
->total_in
;
114 if (z
->avail_in
== 0) {
116 if (*consumed
< len
) {
117 n
= fread(zb
->inbuf
, 1,
118 MIN(zb
->inlen
, len
- *consumed
), f
);
122 return got_ferror(f
, GOT_ERR_IO
);
124 ret
= deflate(z
, Z_FINISH
);
127 z
->next_in
= zb
->inbuf
;
130 ret
= deflate(z
, Z_NO_FLUSH
);
131 *consumed
+= z
->total_in
- last_total_in
;
132 } while (ret
== Z_OK
&& z
->avail_out
> 0);
135 zb
->flags
|= GOT_DEFLATE_F_HAVE_MORE
;
137 if (ret
!= Z_STREAM_END
)
138 return wrap_deflate_error(ret
, "deflate");
139 zb
->flags
&= ~GOT_DEFLATE_F_HAVE_MORE
;
142 *outlenp
= z
->total_out
- last_total_out
;
146 static const struct got_error
*
147 deflate_read_mmap(struct got_deflate_buf
*zb
, uint8_t *map
, size_t offset
,
148 size_t len
, size_t *outlenp
, size_t *consumed
, int flush_on_eof
)
150 z_stream
*z
= &zb
->z
;
151 size_t last_total_out
= z
->total_out
;
154 z
->next_out
= zb
->outbuf
;
155 z
->avail_out
= zb
->outlen
;
160 size_t last_total_in
= z
->total_in
;
161 if (z
->avail_in
== 0) {
162 z
->next_in
= map
+ offset
+ *consumed
;
163 if (len
- *consumed
> UINT_MAX
)
164 z
->avail_in
= UINT_MAX
;
166 z
->avail_in
= len
- *consumed
;
167 if (z
->avail_in
== 0) {
170 ret
= deflate(z
, Z_FINISH
);
174 ret
= deflate(z
, Z_NO_FLUSH
);
175 *consumed
+= z
->total_in
- last_total_in
;
176 } while (ret
== Z_OK
&& z
->avail_out
> 0);
179 zb
->flags
|= GOT_DEFLATE_F_HAVE_MORE
;
181 if (ret
!= Z_STREAM_END
)
182 return wrap_deflate_error(ret
, "deflate");
183 zb
->flags
&= ~GOT_DEFLATE_F_HAVE_MORE
;
186 *outlenp
= z
->total_out
- last_total_out
;
190 const struct got_error
*
191 got_deflate_read_mmap(struct got_deflate_buf
*zb
, uint8_t *map
, size_t offset
,
192 size_t len
, size_t *outlenp
, size_t *consumed
)
194 return deflate_read_mmap(zb
, map
, offset
, len
, outlenp
, consumed
, 1);
197 const struct got_error
*
198 got_deflate_flush(struct got_deflate_buf
*zb
, FILE *outfile
,
199 struct got_deflate_checksum
*csum
, off_t
*outlenp
)
203 z_stream
*z
= &zb
->z
;
205 if (z
->avail_in
!= 0)
206 return got_error_msg(GOT_ERR_COMPRESSION
,
207 "cannot flush zb with pending input data");
210 size_t avail
, last_total_out
= zb
->z
.total_out
;
212 z
->next_out
= zb
->outbuf
;
213 z
->avail_out
= zb
->outlen
;
215 ret
= deflate(z
, Z_FINISH
);
216 if (ret
!= Z_STREAM_END
&& ret
!= Z_OK
)
217 return wrap_deflate_error(ret
, "deflate");
219 avail
= z
->total_out
- last_total_out
;
221 n
= fwrite(zb
->outbuf
, avail
, 1, outfile
);
223 return got_ferror(outfile
, GOT_ERR_IO
);
225 csum_output(csum
, zb
->outbuf
, avail
);
229 } while (ret
!= Z_STREAM_END
);
231 zb
->flags
&= ~GOT_DEFLATE_F_HAVE_MORE
;
236 got_deflate_end(struct got_deflate_buf
*zb
)
239 if (zb
->flags
& GOT_DEFLATE_F_OWN_OUTBUF
)
244 const struct got_error
*
245 got_deflate_to_fd(off_t
*outlen
, FILE *infile
, off_t len
, int outfd
,
246 struct got_deflate_checksum
*csum
)
248 const struct got_error
*err
;
251 struct got_deflate_buf zb
;
253 err
= got_deflate_init(&zb
, NULL
, GOT_DEFLATE_BUFSIZE
);
260 err
= got_deflate_read(&zb
, infile
, len
, &avail
, &consumed
);
265 err
= got_poll_write_full(outfd
, zb
.outbuf
, avail
);
269 csum_output(csum
, zb
.outbuf
, avail
);
272 } while (zb
.flags
& GOT_DEFLATE_F_HAVE_MORE
);
275 got_deflate_end(&zb
);
279 const struct got_error
*
280 got_deflate_to_fd_mmap(off_t
*outlen
, uint8_t *map
, size_t offset
,
281 size_t len
, int outfd
, struct got_deflate_checksum
*csum
)
283 const struct got_error
*err
;
284 size_t avail
, consumed
;
285 struct got_deflate_buf zb
;
287 err
= got_deflate_init(&zb
, NULL
, GOT_DEFLATE_BUFSIZE
);
293 err
= got_deflate_read_mmap(&zb
, map
, offset
, len
, &avail
,
300 err
= got_poll_write_full(outfd
, zb
.outbuf
, avail
);
304 csum_output(csum
, zb
.outbuf
, avail
);
307 } while (zb
.flags
& GOT_DEFLATE_F_HAVE_MORE
);
310 got_deflate_end(&zb
);
314 const struct got_error
*
315 got_deflate_to_file(off_t
*outlen
, FILE *infile
, off_t len
,
316 FILE *outfile
, struct got_deflate_checksum
*csum
)
318 const struct got_error
*err
;
321 struct got_deflate_buf zb
;
323 err
= got_deflate_init(&zb
, NULL
, GOT_DEFLATE_BUFSIZE
);
330 err
= got_deflate_read(&zb
, infile
, len
, &avail
, &consumed
);
336 n
= fwrite(zb
.outbuf
, avail
, 1, outfile
);
338 err
= got_ferror(outfile
, GOT_ERR_IO
);
342 csum_output(csum
, zb
.outbuf
, avail
);
345 } while (zb
.flags
& GOT_DEFLATE_F_HAVE_MORE
);
348 got_deflate_end(&zb
);
352 const struct got_error
*
353 got_deflate_to_file_mmap(off_t
*outlen
, uint8_t *map
, size_t offset
,
354 size_t len
, FILE *outfile
, struct got_deflate_checksum
*csum
)
356 const struct got_error
*err
;
357 size_t avail
, consumed
;
358 struct got_deflate_buf zb
;
360 err
= got_deflate_init(&zb
, NULL
, GOT_DEFLATE_BUFSIZE
);
366 err
= got_deflate_read_mmap(&zb
, map
, offset
, len
, &avail
,
374 n
= fwrite(zb
.outbuf
, avail
, 1, outfile
);
376 err
= got_ferror(outfile
, GOT_ERR_IO
);
380 csum_output(csum
, zb
.outbuf
, avail
);
383 } while (zb
.flags
& GOT_DEFLATE_F_HAVE_MORE
);
386 got_deflate_end(&zb
);
390 const struct got_error
*
391 got_deflate_append_to_file_mmap(struct got_deflate_buf
*zb
, off_t
*outlen
,
392 uint8_t *map
, size_t offset
, size_t len
, FILE *outfile
,
393 struct got_deflate_checksum
*csum
)
395 const struct got_error
*err
;
396 size_t avail
, consumed
;
399 err
= deflate_read_mmap(zb
, map
, offset
, len
, &avail
,
407 n
= fwrite(zb
->outbuf
, avail
, 1, outfile
);
409 err
= got_ferror(outfile
, GOT_ERR_IO
);
413 csum_output(csum
, zb
->outbuf
, avail
);
417 } while ((zb
->flags
& GOT_DEFLATE_F_HAVE_MORE
) && len
> 0);
422 const struct got_error
*
423 got_deflate_to_mem_mmap(uint8_t **outbuf
, size_t *outlen
,
424 size_t *consumed_total
, struct got_deflate_checksum
*csum
, uint8_t *map
,
425 size_t offset
, size_t len
)
427 const struct got_error
*err
;
428 size_t avail
, consumed
;
429 struct got_deflate_buf zb
;
434 *outbuf
= malloc(GOT_DEFLATE_BUFSIZE
);
436 return got_error_from_errno("malloc");
437 err
= got_deflate_init(&zb
, *outbuf
, GOT_DEFLATE_BUFSIZE
);
444 err
= got_deflate_init(&zb
, NULL
, GOT_DEFLATE_BUFSIZE
);
453 err
= got_deflate_read_mmap(&zb
, map
, offset
, len
, &avail
,
459 *consumed_total
+= consumed
;
461 if (avail
> 0 && csum
)
462 csum_output(csum
, zb
.outbuf
, avail
);
464 if ((zb
.flags
& GOT_DEFLATE_F_HAVE_MORE
) && outbuf
!= NULL
) {
465 newbuf
= reallocarray(*outbuf
, ++nbuf
,
466 GOT_DEFLATE_BUFSIZE
);
467 if (newbuf
== NULL
) {
468 err
= got_error_from_errno("reallocarray");
475 zb
.outbuf
= newbuf
+ *outlen
;
476 zb
.outlen
= (nbuf
* GOT_DEFLATE_BUFSIZE
) - *outlen
;
478 } while (zb
.flags
& GOT_DEFLATE_F_HAVE_MORE
);
480 got_deflate_end(&zb
);