fs/erofs: add lz4 decompression support
[platform/kernel/u-boot.git] / fs / erofs / decompress.c
1 // SPDX-License-Identifier: GPL-2.0+
2 #include "decompress.h"
3
4 #if IS_ENABLED(CONFIG_LZ4)
5 #include <u-boot/lz4.h>
6 static 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
18                 while (!src[inputmargin & ~PAGE_MASK])
19                         if (!(++inputmargin & ~PAGE_MASK))
20                                 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) {
43                 ret = -EIO;
44                 goto out;
45         }
46
47         if (rq->decodedskip)
48                 memcpy(rq->out, dest + rq->decodedskip,
49                        rq->decodedlength - rq->decodedskip);
50
51 out:
52         if (buff)
53                 free(buff);
54
55         return ret;
56 }
57 #endif
58
59 int z_erofs_decompress(struct z_erofs_decompress_req *rq)
60 {
61         if (rq->alg == Z_EROFS_COMPRESSION_SHIFTED) {
62                 if (rq->inputsize != EROFS_BLKSIZ)
63                         return -EFSCORRUPTED;
64
65                 DBG_BUGON(rq->decodedlength > EROFS_BLKSIZ);
66                 DBG_BUGON(rq->decodedlength < rq->decodedskip);
67
68                 memcpy(rq->out, rq->in + rq->decodedskip,
69                        rq->decodedlength - rq->decodedskip);
70                 return 0;
71         }
72
73 #if IS_ENABLED(CONFIG_LZ4)
74         if (rq->alg == Z_EROFS_COMPRESSION_LZ4)
75                 return z_erofs_decompress_lz4(rq);
76 #endif
77         return -EOPNOTSUPP;
78 }