Merge tag 'u-boot-imx-20200825' of https://gitlab.denx.de/u-boot/custodians/u-boot-imx
[platform/kernel/u-boot.git] / fs / squashfs / sqfs_decompressor.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (C) 2020 Bootlin
4  *
5  * Author: Joao Marcos Costa <joaomarcos.costa@bootlin.com>
6  */
7
8 #include <errno.h>
9 #include <stdint.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12
13 #if IS_ENABLED(CONFIG_LZO)
14 #include <linux/lzo.h>
15 #endif
16
17 #if IS_ENABLED(CONFIG_ZLIB)
18 #include <u-boot/zlib.h>
19 #endif
20
21 #if IS_ENABLED(CONFIG_ZSTD)
22 #include <linux/zstd.h>
23 #endif
24
25 #include "sqfs_decompressor.h"
26 #include "sqfs_utils.h"
27
28 int sqfs_decompressor_init(struct squashfs_ctxt *ctxt)
29 {
30         u16 comp_type = get_unaligned_le16(&ctxt->sblk->compression);
31
32         switch (comp_type) {
33 #if IS_ENABLED(CONFIG_LZO)
34         case SQFS_COMP_LZO:
35                 break;
36 #endif
37 #if IS_ENABLED(CONFIG_ZLIB)
38         case SQFS_COMP_ZLIB:
39                 break;
40 #endif
41 #if IS_ENABLED(CONFIG_ZSTD)
42         case SQFS_COMP_ZSTD:
43                 ctxt->zstd_workspace = malloc(ZSTD_DCtxWorkspaceBound());
44                 if (!ctxt->zstd_workspace)
45                         return -ENOMEM;
46                 break;
47 #endif
48         default:
49                 printf("Error: unknown compression type.\n");
50                 return -EINVAL;
51         }
52
53         return 0;
54 }
55
56 void sqfs_decompressor_cleanup(struct squashfs_ctxt *ctxt)
57 {
58         u16 comp_type = get_unaligned_le16(&ctxt->sblk->compression);
59
60         switch (comp_type) {
61 #if IS_ENABLED(CONFIG_LZO)
62         case SQFS_COMP_LZO:
63                 break;
64 #endif
65 #if IS_ENABLED(CONFIG_ZLIB)
66         case SQFS_COMP_ZLIB:
67                 break;
68 #endif
69 #if IS_ENABLED(CONFIG_ZSTD)
70         case SQFS_COMP_ZSTD:
71                 free(ctxt->zstd_workspace);
72                 break;
73 #endif
74         }
75 }
76
77 #if IS_ENABLED(CONFIG_ZLIB)
78 static void zlib_decompression_status(int ret)
79 {
80         switch (ret) {
81         case Z_BUF_ERROR:
82                 printf("Error: 'dest' buffer is not large enough.\n");
83                 break;
84         case Z_DATA_ERROR:
85                 printf("Error: corrupted compressed data.\n");
86                 break;
87         case Z_MEM_ERROR:
88                 printf("Error: insufficient memory.\n");
89                 break;
90         }
91 }
92 #endif
93
94 #if IS_ENABLED(CONFIG_ZSTD)
95 static int sqfs_zstd_decompress(struct squashfs_ctxt *ctxt, void *dest,
96                                 unsigned long dest_len, void *source, u32 src_len)
97 {
98         ZSTD_DCtx *ctx;
99         size_t wsize;
100         int ret;
101
102         wsize = ZSTD_DCtxWorkspaceBound();
103         ctx = ZSTD_initDCtx(ctxt->zstd_workspace, wsize);
104         ret = ZSTD_decompressDCtx(ctx, dest, dest_len, source, src_len);
105
106         return ZSTD_isError(ret);
107 }
108 #endif /* CONFIG_ZSTD */
109
110 int sqfs_decompress(struct squashfs_ctxt *ctxt, void *dest,
111                     unsigned long *dest_len, void *source, u32 src_len)
112 {
113         u16 comp_type = get_unaligned_le16(&ctxt->sblk->compression);
114         int ret = 0;
115
116         switch (comp_type) {
117 #if IS_ENABLED(CONFIG_LZO)
118         case SQFS_COMP_LZO: {
119                 size_t lzo_dest_len = *dest_len;
120                 ret = lzo1x_decompress_safe(source, src_len, dest, &lzo_dest_len);
121                 if (ret) {
122                         printf("LZO decompression failed. Error code: %d\n", ret);
123                         return -EINVAL;
124                 }
125
126                 break;
127         }
128 #endif
129 #if IS_ENABLED(CONFIG_ZLIB)
130         case SQFS_COMP_ZLIB:
131                 ret = uncompress(dest, dest_len, source, src_len);
132                 if (ret) {
133                         zlib_decompression_status(ret);
134                         return -EINVAL;
135                 }
136
137                 break;
138 #endif
139 #if IS_ENABLED(CONFIG_ZSTD)
140         case SQFS_COMP_ZSTD:
141                 ret = sqfs_zstd_decompress(ctxt, dest, *dest_len, source, src_len);
142                 if (ret) {
143                         printf("ZSTD Error code: %d\n", ZSTD_getErrorCode(ret));
144                         return -EINVAL;
145                 }
146
147                 break;
148 #endif
149         default:
150                 printf("Error: unknown compression type.\n");
151                 return -EINVAL;
152         }
153
154         return ret;
155 }