summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTimo Teräs <timo.teras@iki.fi>2022-02-21 12:04:32 +0200
committerTimo Teräs <timo.teras@iki.fi>2022-02-25 10:42:35 +0200
commita920d3e4a5a7e13d47bd20e79d3898824f61e85f (patch)
tree5b499946aba2338987a999bbd97304d9ddb76c38
parent9e824cf3dbfca9c2575b17f9f45ca89b86aa43c6 (diff)
downloadapk-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
-rw-r--r--src/io_gunzip.c21
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;