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-21 12:36:46 +0200
commitfedaa44546af1b8c05131119752cc2f3f682ae7c (patch)
tree7553557f80d02cfa0a7ff900ed7074085077a621
parent17f22530a5fdee33e1669a7b97d58d5a869dce26 (diff)
downloadapk-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.c27
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;