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-21 12:36:46 +0200 |
commit | fedaa44546af1b8c05131119752cc2f3f682ae7c (patch) | |
tree | 7553557f80d02cfa0a7ff900ed7074085077a621 | |
parent | 17f22530a5fdee33e1669a7b97d58d5a869dce26 (diff) | |
download | apk-tools-fedaa44546af1b8c05131119752cc2f3f682ae7c.tar.gz apk-tools-fedaa44546af1b8c05131119752cc2f3f682ae7c.tar.bz2 apk-tools-fedaa44546af1b8c05131119752cc2f3f682ae7c.tar.xz apk-tools-fedaa44546af1b8c05131119752cc2f3f682ae7c.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.c | 27 |
1 files changed, 15 insertions, 12 deletions
diff --git a/src/io_gunzip.c b/src/io_gunzip.c index ce29592..8731da2 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,17 +68,16 @@ static ssize_t gzi_read(struct apk_istream *is, void *ptr, size_t size) } r = apk_istream_get_all(gis->zis, &blob); gis->cbprev = blob.ptr; - gis->zs.avail_in = blob.len; - gis->zs.next_in = (void *) gis->cbprev; - if (r < 0) { - if (r == -APKE_EOF) { - gis->is.err = 1; - gis->cbarg = APK_BLOB_NULL; - gzi_boundary_change(gis); - } else { - gis->is.err = r; - } + + if (r == -APKE_EOF) { + gis->is.err = 1; + gis->cbarg = APK_BLOB_NULL; + } else if (r < 0) { + gis->is.err = r; goto ret; + } else { + gis->zs.avail_in = blob.len; + gis->zs.next_in = (void *) gis->cbprev; } } @@ -108,6 +107,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; |