From 8895abbc282edd5ea795f971b43b0a601a0b443d Mon Sep 17 00:00:00 2001 From: Gao Xiang Date: Fri, 9 Aug 2024 18:56:36 +0800 Subject: [PATCH] erofs-utils: fuse: fix partial decompression for libdeflate Actually, libdeflate doesn't support partial decompression; therefore, fix it by reallocating larger decompression buffers. Although a better approach would be to obtain the exact decompressed length instead for libdeflate decompressor, which requires more changes, a quick fix is needed. Fixes: 29b9e7140162 ("erofs-utils: fuse,fsck: add DEFLATE algorithm support") Signed-off-by: Gao Xiang Link: https://lore.kernel.org/r/20240809105636.3641536-1-hsiangkao@linux.alibaba.com --- lib/decompress.c | 42 +++++++++++++++++++++++++++++------------- 1 file changed, 29 insertions(+), 13 deletions(-) diff --git a/lib/decompress.c b/lib/decompress.c index 1b44a18..3f553a8 100644 --- a/lib/decompress.c +++ b/lib/decompress.c @@ -247,32 +247,47 @@ static int z_erofs_decompress_deflate(struct z_erofs_decompress_req *rq) unsigned int inputmargin; struct libdeflate_decompressor *inf; enum libdeflate_result ret; + unsigned int decodedcapacity; inputmargin = z_erofs_fixup_insize(src, rq->inputsize); if (inputmargin >= rq->inputsize) return -EFSCORRUPTED; - if (rq->decodedskip) { - buff = malloc(rq->decodedlength); + decodedcapacity = rq->decodedlength << (4 * rq->partial_decoding); + if (rq->decodedskip || rq->partial_decoding) { + buff = malloc(decodedcapacity); if (!buff) return -ENOMEM; dest = buff; } inf = libdeflate_alloc_decompressor(); - if (!inf) - return -ENOMEM; + if (!inf) { + ret = -ENOMEM; + goto out_free_mem; + } if (rq->partial_decoding) { - ret = libdeflate_deflate_decompress(inf, src + inputmargin, - rq->inputsize - inputmargin, dest, - rq->decodedlength, &actual_out); - if (ret && ret != LIBDEFLATE_INSUFFICIENT_SPACE) { - ret = -EIO; - goto out_inflate_end; + while (1) { + ret = libdeflate_deflate_decompress(inf, src + inputmargin, + rq->inputsize - inputmargin, dest, + decodedcapacity, &actual_out); + if (ret == LIBDEFLATE_SUCCESS) + break; + if (ret != LIBDEFLATE_INSUFFICIENT_SPACE) { + ret = -EIO; + goto out_inflate_end; + } + decodedcapacity = decodedcapacity << 1; + dest = realloc(buff, decodedcapacity); + if (!dest) { + ret = -ENOMEM; + goto out_inflate_end; + } + buff = dest; } - if (actual_out != rq->decodedlength) { + if (actual_out < rq->decodedlength) { ret = -EIO; goto out_inflate_end; } @@ -280,18 +295,19 @@ static int z_erofs_decompress_deflate(struct z_erofs_decompress_req *rq) ret = libdeflate_deflate_decompress(inf, src + inputmargin, rq->inputsize - inputmargin, dest, rq->decodedlength, NULL); - if (ret) { + if (ret != LIBDEFLATE_SUCCESS) { ret = -EIO; goto out_inflate_end; } } - if (rq->decodedskip) + if (rq->decodedskip || rq->partial_decoding) memcpy(rq->out, dest + rq->decodedskip, rq->decodedlength - rq->decodedskip); out_inflate_end: libdeflate_free_decompressor(inf); +out_free_mem: if (buff) free(buff); return ret; -- 2.34.1