Skip to content

Commit 5673005

Browse files
jltoblergitster
authored andcommitted
archive: flush deflate stream until Z_STREAM_END
In `archive-zip.c:write_zip_entry()` when using a stream as input for deflating a file, the call to `git_deflate()` with Z_FINISH always expects Z_STREAM_END to be returned. Per zlib documentation[1]: If the parameter flush is set to Z_FINISH, pending input is processed, pending output is flushed and deflate returns with Z_STREAM_END if there was enough output space. If deflate returns with Z_OK or Z_BUF_ERROR, this function must be called again with Z_FINISH and more output space (updated avail_out) but no more input data, until it returns with Z_STREAM_END or an error. After deflate has returned Z_STREAM_END, the only possible operations on the stream are deflateReset or deflateEnd. In scenarios where the output buffer is not large enough to write all the compressed data, it is perfectly valid for the underlying `deflate()` to return Z_OK. Thus, expecting a single pass of `deflate()` here to always return Z_STREAM_END is a bug. Update the code to flush the deflate stream until Z_STREAM_END is returned. [1]: https://zlib.net/manual.html Helped-by: Toon Claes <[email protected]> Signed-off-by: Justin Tobler <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 112648d commit 5673005

File tree

1 file changed

+14
-6
lines changed

1 file changed

+14
-6
lines changed

archive-zip.c

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -492,14 +492,22 @@ static int write_zip_entry(struct archiver_args *args,
492492

493493
zstream.next_in = buf;
494494
zstream.avail_in = 0;
495-
result = git_deflate(&zstream, Z_FINISH);
496-
if (result != Z_STREAM_END)
497-
die("deflate error (%d)", result);
495+
496+
do {
497+
result = git_deflate(&zstream, Z_FINISH);
498+
if (result != Z_OK && result != Z_STREAM_END)
499+
die("deflate error (%d)", result);
500+
501+
out_len = zstream.next_out - compressed;
502+
if (out_len > 0) {
503+
write_or_die(1, compressed, out_len);
504+
compressed_size += out_len;
505+
zstream.next_out = compressed;
506+
zstream.avail_out = sizeof(compressed);
507+
}
508+
} while (result != Z_STREAM_END);
498509

499510
git_deflate_end(&zstream);
500-
out_len = zstream.next_out - compressed;
501-
write_or_die(1, compressed, out_len);
502-
compressed_size += out_len;
503511
zip_offset += compressed_size;
504512

505513
write_zip_data_desc(size, compressed_size, crc);

0 commit comments

Comments
 (0)