diff options
author | Timo Teräs <timo.teras@iki.fi> | 2022-02-21 12:04:32 +0200 |
---|---|---|
committer | Timo Teräs <timo.teras@iki.fi> | 2022-02-25 10:42:35 +0200 |
commit | a920d3e4a5a7e13d47bd20e79d3898824f61e85f (patch) | |
tree | 5b499946aba2338987a999bbd97304d9ddb76c38 /src/io_gunzip.c | |
parent | 9e824cf3dbfca9c2575b17f9f45ca89b86aa43c6 (diff) | |
download | apk-tools-a920d3e4a5a7e13d47bd20e79d3898824f61e85f.tar.gz apk-tools-a920d3e4a5a7e13d47bd20e79d3898824f61e85f.tar.bz2 apk-tools-a920d3e4a5a7e13d47bd20e79d3898824f61e85f.tar.xz apk-tools-a920d3e4a5a7e13d47bd20e79d3898824f61e85f.zip |
io_gunzip: fix handling short reads near end-of-file
The gzip library can drain all of the input to internal buffers
and still keep providing data even if avail_in is zero. Previously
it was assumed that avail_in != 0 if there is still data expected out,
but this logic breaks near end-of-file for multiple short reads.
Adjust logic to not process end-of-file event too early.
fixes #10809
Diffstat (limited to 'src/io_gunzip.c')
-rw-r--r-- | src/io_gunzip.c | 21 |
1 files changed, 13 insertions, 8 deletions
diff --git a/src/io_gunzip.c b/src/io_gunzip.c index 9ffc060..8e92ae4 100644 --- a/src/io_gunzip.c +++ b/src/io_gunzip.c @@ -51,13 +51,13 @@ static ssize_t gzi_read(struct apk_istream *is, void *ptr, size_t size) gis->zs.avail_out = size; gis->zs.next_out = ptr; - while (gis->zs.avail_out != 0 && gis->is.err == 0) { + while (gis->zs.avail_out != 0 && gis->is.err >= 0) { if (!APK_BLOB_IS_NULL(gis->cbarg)) { if (gzi_boundary_change(gis)) goto ret; gis->cbarg = APK_BLOB_NULL; } - if (gis->zs.avail_in == 0) { + if (gis->zs.avail_in == 0 && gis->is.err == 0) { apk_blob_t blob; if (gis->cb != NULL && gis->cbprev != NULL && @@ -68,16 +68,17 @@ static ssize_t gzi_read(struct apk_istream *is, void *ptr, size_t size) } blob = apk_istream_get_all(gis->zis); gis->cbprev = blob.ptr; - gis->zs.avail_in = blob.len; - gis->zs.next_in = (void *) gis->cbprev; - if (blob.len < 0) { - gis->is.err = blob.len; - goto ret; - } else if (gis->zs.avail_in == 0) { + + if (blob.len == 0) { gis->is.err = 1; gis->cbarg = APK_BLOB_NULL; gzi_boundary_change(gis); + } else if (blob.len < 0) { + gis->is.err = blob.len; goto ret; + } else { + gis->zs.avail_in = blob.len; + gis->zs.next_in = (void *) blob.ptr; } } @@ -107,6 +108,10 @@ static ssize_t gzi_read(struct apk_istream *is, void *ptr, size_t size) break; case Z_OK: break; + case Z_BUF_ERROR: + /* Happens when input stream is EOF, input buffer is empty, + * and we just tried reading a new header. */ + goto ret; default: gis->is.err = -EIO; break; |