]>
Commit | Line | Data |
---|---|---|
c5100613 JMC |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* | |
3 | * Copyright (C) 2020 Bootlin | |
4 | * | |
5 | * Author: Joao Marcos Costa <[email protected]> | |
6 | */ | |
7 | ||
8 | #include <errno.h> | |
9 | #include <stdint.h> | |
10 | #include <stdio.h> | |
11 | #include <stdlib.h> | |
6dfed163 JMC |
12 | |
13 | #if IS_ENABLED(CONFIG_LZO) | |
14 | #include <linux/lzo.h> | |
15 | #endif | |
16 | ||
3634b350 JMC |
17 | #if IS_ENABLED(CONFIG_ZLIB) |
18 | #include <u-boot/zlib.h> | |
19 | #endif | |
c5100613 | 20 | |
fa894a36 DO |
21 | #if IS_ENABLED(CONFIG_LZ4) |
22 | #include <u-boot/lz4.h> | |
23 | #endif | |
24 | ||
9c948f53 JMC |
25 | #if IS_ENABLED(CONFIG_ZSTD) |
26 | #include <linux/zstd.h> | |
27 | #endif | |
28 | ||
c5100613 | 29 | #include "sqfs_decompressor.h" |
c5100613 JMC |
30 | #include "sqfs_utils.h" |
31 | ||
10f7cf5f JMC |
32 | int sqfs_decompressor_init(struct squashfs_ctxt *ctxt) |
33 | { | |
34 | u16 comp_type = get_unaligned_le16(&ctxt->sblk->compression); | |
35 | ||
36 | switch (comp_type) { | |
6dfed163 JMC |
37 | #if IS_ENABLED(CONFIG_LZO) |
38 | case SQFS_COMP_LZO: | |
39 | break; | |
40 | #endif | |
10f7cf5f JMC |
41 | #if IS_ENABLED(CONFIG_ZLIB) |
42 | case SQFS_COMP_ZLIB: | |
43 | break; | |
9c948f53 | 44 | #endif |
fa894a36 DO |
45 | #if IS_ENABLED(CONFIG_LZ4) |
46 | case SQFS_COMP_LZ4: | |
47 | break; | |
48 | #endif | |
9c948f53 JMC |
49 | #if IS_ENABLED(CONFIG_ZSTD) |
50 | case SQFS_COMP_ZSTD: | |
4b9b25d9 | 51 | ctxt->zstd_workspace = malloc(zstd_dctx_workspace_bound()); |
9c948f53 JMC |
52 | if (!ctxt->zstd_workspace) |
53 | return -ENOMEM; | |
54 | break; | |
10f7cf5f JMC |
55 | #endif |
56 | default: | |
57 | printf("Error: unknown compression type.\n"); | |
58 | return -EINVAL; | |
59 | } | |
60 | ||
61 | return 0; | |
62 | } | |
63 | ||
64 | void sqfs_decompressor_cleanup(struct squashfs_ctxt *ctxt) | |
65 | { | |
66 | u16 comp_type = get_unaligned_le16(&ctxt->sblk->compression); | |
67 | ||
68 | switch (comp_type) { | |
6dfed163 JMC |
69 | #if IS_ENABLED(CONFIG_LZO) |
70 | case SQFS_COMP_LZO: | |
71 | break; | |
72 | #endif | |
10f7cf5f JMC |
73 | #if IS_ENABLED(CONFIG_ZLIB) |
74 | case SQFS_COMP_ZLIB: | |
75 | break; | |
9c948f53 | 76 | #endif |
fa894a36 DO |
77 | #if IS_ENABLED(CONFIG_LZ4) |
78 | case SQFS_COMP_LZ4: | |
79 | break; | |
80 | #endif | |
9c948f53 JMC |
81 | #if IS_ENABLED(CONFIG_ZSTD) |
82 | case SQFS_COMP_ZSTD: | |
83 | free(ctxt->zstd_workspace); | |
84 | break; | |
10f7cf5f JMC |
85 | #endif |
86 | } | |
87 | } | |
88 | ||
3634b350 JMC |
89 | #if IS_ENABLED(CONFIG_ZLIB) |
90 | static void zlib_decompression_status(int ret) | |
91 | { | |
92 | switch (ret) { | |
93 | case Z_BUF_ERROR: | |
94 | printf("Error: 'dest' buffer is not large enough.\n"); | |
95 | break; | |
96 | case Z_DATA_ERROR: | |
97 | printf("Error: corrupted compressed data.\n"); | |
98 | break; | |
99 | case Z_MEM_ERROR: | |
100 | printf("Error: insufficient memory.\n"); | |
101 | break; | |
102 | } | |
103 | } | |
104 | #endif | |
105 | ||
9c948f53 JMC |
106 | #if IS_ENABLED(CONFIG_ZSTD) |
107 | static int sqfs_zstd_decompress(struct squashfs_ctxt *ctxt, void *dest, | |
108 | unsigned long dest_len, void *source, u32 src_len) | |
109 | { | |
110 | ZSTD_DCtx *ctx; | |
111 | size_t wsize; | |
112 | int ret; | |
113 | ||
4b9b25d9 | 114 | wsize = zstd_dctx_workspace_bound(); |
9c948f53 | 115 | |
4b9b25d9 BM |
116 | ctx = zstd_init_dctx(ctxt->zstd_workspace, wsize); |
117 | if (!ctx) | |
118 | return -EINVAL; | |
119 | ret = zstd_decompress_dctx(ctx, dest, dest_len, source, src_len); | |
120 | ||
121 | return zstd_is_error(ret); | |
9c948f53 JMC |
122 | } |
123 | #endif /* CONFIG_ZSTD */ | |
124 | ||
cdc11441 JMC |
125 | int sqfs_decompress(struct squashfs_ctxt *ctxt, void *dest, |
126 | unsigned long *dest_len, void *source, u32 src_len) | |
c5100613 | 127 | { |
cdc11441 | 128 | u16 comp_type = get_unaligned_le16(&ctxt->sblk->compression); |
c5100613 JMC |
129 | int ret = 0; |
130 | ||
131 | switch (comp_type) { | |
6dfed163 JMC |
132 | #if IS_ENABLED(CONFIG_LZO) |
133 | case SQFS_COMP_LZO: { | |
134 | size_t lzo_dest_len = *dest_len; | |
135 | ret = lzo1x_decompress_safe(source, src_len, dest, &lzo_dest_len); | |
136 | if (ret) { | |
137 | printf("LZO decompression failed. Error code: %d\n", ret); | |
138 | return -EINVAL; | |
139 | } | |
140 | ||
141 | break; | |
142 | } | |
143 | #endif | |
3634b350 JMC |
144 | #if IS_ENABLED(CONFIG_ZLIB) |
145 | case SQFS_COMP_ZLIB: | |
10f7cf5f | 146 | ret = uncompress(dest, dest_len, source, src_len); |
3634b350 JMC |
147 | if (ret) { |
148 | zlib_decompression_status(ret); | |
149 | return -EINVAL; | |
150 | } | |
151 | ||
152 | break; | |
153 | #endif | |
fa894a36 DO |
154 | #if IS_ENABLED(CONFIG_LZ4) |
155 | case SQFS_COMP_LZ4: | |
156 | ret = LZ4_decompress_safe(source, dest, src_len, *dest_len); | |
157 | if (ret < 0) { | |
158 | printf("LZ4 decompression failed.\n"); | |
159 | return -EINVAL; | |
160 | } | |
161 | ||
162 | ret = 0; | |
163 | break; | |
164 | #endif | |
9c948f53 JMC |
165 | #if IS_ENABLED(CONFIG_ZSTD) |
166 | case SQFS_COMP_ZSTD: | |
167 | ret = sqfs_zstd_decompress(ctxt, dest, *dest_len, source, src_len); | |
168 | if (ret) { | |
4b9b25d9 | 169 | printf("ZSTD Error code: %d\n", zstd_get_error_code(ret)); |
9c948f53 JMC |
170 | return -EINVAL; |
171 | } | |
172 | ||
173 | break; | |
174 | #endif | |
c5100613 JMC |
175 | default: |
176 | printf("Error: unknown compression type.\n"); | |
177 | return -EINVAL; | |
178 | } | |
179 | ||
180 | return ret; | |
181 | } |