[PATCH] erofs-utils: fix partial decompression for libdeflate
Gao Xiang
hsiangkao at linux.alibaba.com
Fri Aug 9 20:56:36 AEST 2024
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 <hsiangkao at 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.43.5
More information about the Linux-erofs
mailing list