blob: e04e5c34a8d89210f8ddbb443339e61cbfc06912 [file] [log] [blame]
Huang Jianan65cb7302022-02-26 15:05:49 +08001// SPDX-License-Identifier: GPL-2.0+
2#include "decompress.h"
3
4#if IS_ENABLED(CONFIG_LZ4)
5#include <u-boot/lz4.h>
6static int z_erofs_decompress_lz4(struct z_erofs_decompress_req *rq)
7{
8 int ret = 0;
9 char *dest = rq->out;
10 char *src = rq->in;
11 char *buff = NULL;
12 bool support_0padding = false;
13 unsigned int inputmargin = 0;
14
15 if (erofs_sb_has_lz4_0padding()) {
16 support_0padding = true;
17
Yifan Zhao3a21e922023-07-07 23:52:12 +080018 while (!src[inputmargin & (erofs_blksiz() - 1)])
19 if (!(++inputmargin & (erofs_blksiz() - 1)))
Huang Jianan65cb7302022-02-26 15:05:49 +080020 break;
21
22 if (inputmargin >= rq->inputsize)
23 return -EIO;
24 }
25
26 if (rq->decodedskip) {
27 buff = malloc(rq->decodedlength);
28 if (!buff)
29 return -ENOMEM;
30 dest = buff;
31 }
32
33 if (rq->partial_decoding || !support_0padding)
34 ret = LZ4_decompress_safe_partial(src + inputmargin, dest,
35 rq->inputsize - inputmargin,
36 rq->decodedlength, rq->decodedlength);
37 else
38 ret = LZ4_decompress_safe(src + inputmargin, dest,
39 rq->inputsize - inputmargin,
40 rq->decodedlength);
41
42 if (ret != (int)rq->decodedlength) {
Yifan Zhao3a21e922023-07-07 23:52:12 +080043 erofs_err("failed to %s decompress %d in[%u, %u] out[%u]",
44 rq->partial_decoding ? "partial" : "full",
45 ret, rq->inputsize, inputmargin, rq->decodedlength);
Huang Jianan65cb7302022-02-26 15:05:49 +080046 ret = -EIO;
47 goto out;
48 }
49
50 if (rq->decodedskip)
51 memcpy(rq->out, dest + rq->decodedskip,
52 rq->decodedlength - rq->decodedskip);
53
54out:
55 if (buff)
56 free(buff);
57
58 return ret;
59}
60#endif
61
62int z_erofs_decompress(struct z_erofs_decompress_req *rq)
63{
Yifan Zhao3a21e922023-07-07 23:52:12 +080064 if (rq->alg == Z_EROFS_COMPRESSION_INTERLACED) {
65 unsigned int count, rightpart, skip;
66
67 /* XXX: should support inputsize >= erofs_blksiz() later */
68 if (rq->inputsize > erofs_blksiz())
Huang Jianan65cb7302022-02-26 15:05:49 +080069 return -EFSCORRUPTED;
70
Yifan Zhao3a21e922023-07-07 23:52:12 +080071 if (rq->decodedlength > erofs_blksiz())
72 return -EFSCORRUPTED;
Huang Jianan65cb7302022-02-26 15:05:49 +080073
Yifan Zhao3a21e922023-07-07 23:52:12 +080074 if (rq->decodedlength < rq->decodedskip)
75 return -EFSCORRUPTED;
76
77 count = rq->decodedlength - rq->decodedskip;
78 skip = erofs_blkoff(rq->interlaced_offset + rq->decodedskip);
79 rightpart = min(erofs_blksiz() - skip, count);
80 memcpy(rq->out, rq->in + skip, rightpart);
81 memcpy(rq->out + rightpart, rq->in, count - rightpart);
82 return 0;
83 } else if (rq->alg == Z_EROFS_COMPRESSION_SHIFTED) {
84 if (rq->decodedlength > rq->inputsize)
85 return -EFSCORRUPTED;
86
87 DBG_BUGON(rq->decodedlength < rq->decodedskip);
Huang Jianan65cb7302022-02-26 15:05:49 +080088 memcpy(rq->out, rq->in + rq->decodedskip,
89 rq->decodedlength - rq->decodedskip);
90 return 0;
91 }
92
93#if IS_ENABLED(CONFIG_LZ4)
94 if (rq->alg == Z_EROFS_COMPRESSION_LZ4)
95 return z_erofs_decompress_lz4(rq);
96#endif
97 return -EOPNOTSUPP;
98}