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
cute-signatures
Timo Teräs 2022-02-21 12:04:32 +02:00
parent 17f22530a5
commit fedaa44546
1 changed files with 15 additions and 12 deletions

View File

@ -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;