blob: cfd1153fd74a3de2a42575863b578d5ca15a063c [file] [log] [blame]
Joao Marcos Costa29da3742020-07-30 15:33:47 +02001// 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>
Joao Marcos Costa40a9fd52020-08-18 17:17:24 +020012
13#if IS_ENABLED(CONFIG_LZO)
14#include <linux/lzo.h>
15#endif
16
Joao Marcos Costa88f53332020-07-30 15:33:50 +020017#if IS_ENABLED(CONFIG_ZLIB)
18#include <u-boot/zlib.h>
19#endif
Joao Marcos Costa29da3742020-07-30 15:33:47 +020020
David Oberhollenzer1f064bc2023-11-06 11:14:03 +010021#if IS_ENABLED(CONFIG_LZ4)
22#include <u-boot/lz4.h>
23#endif
24
Joao Marcos Costab1fa6b82020-08-18 17:17:23 +020025#if IS_ENABLED(CONFIG_ZSTD)
26#include <linux/zstd.h>
27#endif
28
Joao Marcos Costa29da3742020-07-30 15:33:47 +020029#include "sqfs_decompressor.h"
Joao Marcos Costa29da3742020-07-30 15:33:47 +020030#include "sqfs_utils.h"
31
Joao Marcos Costa877576c2020-08-18 17:17:21 +020032int sqfs_decompressor_init(struct squashfs_ctxt *ctxt)
33{
34 u16 comp_type = get_unaligned_le16(&ctxt->sblk->compression);
35
36 switch (comp_type) {
Joao Marcos Costa40a9fd52020-08-18 17:17:24 +020037#if IS_ENABLED(CONFIG_LZO)
38 case SQFS_COMP_LZO:
39 break;
40#endif
Joao Marcos Costa877576c2020-08-18 17:17:21 +020041#if IS_ENABLED(CONFIG_ZLIB)
42 case SQFS_COMP_ZLIB:
43 break;
44#endif
David Oberhollenzer1f064bc2023-11-06 11:14:03 +010045#if IS_ENABLED(CONFIG_LZ4)
46 case SQFS_COMP_LZ4:
47 break;
48#endif
Joao Marcos Costab1fa6b82020-08-18 17:17:23 +020049#if IS_ENABLED(CONFIG_ZSTD)
50 case SQFS_COMP_ZSTD:
Brandon Maierdbe88da2023-01-12 10:27:45 -060051 ctxt->zstd_workspace = malloc(zstd_dctx_workspace_bound());
Joao Marcos Costab1fa6b82020-08-18 17:17:23 +020052 if (!ctxt->zstd_workspace)
53 return -ENOMEM;
54 break;
55#endif
Joao Marcos Costa877576c2020-08-18 17:17:21 +020056 default:
57 printf("Error: unknown compression type.\n");
58 return -EINVAL;
59 }
60
61 return 0;
62}
63
64void sqfs_decompressor_cleanup(struct squashfs_ctxt *ctxt)
65{
66 u16 comp_type = get_unaligned_le16(&ctxt->sblk->compression);
67
68 switch (comp_type) {
Joao Marcos Costa40a9fd52020-08-18 17:17:24 +020069#if IS_ENABLED(CONFIG_LZO)
70 case SQFS_COMP_LZO:
71 break;
72#endif
Joao Marcos Costa877576c2020-08-18 17:17:21 +020073#if IS_ENABLED(CONFIG_ZLIB)
74 case SQFS_COMP_ZLIB:
75 break;
76#endif
David Oberhollenzer1f064bc2023-11-06 11:14:03 +010077#if IS_ENABLED(CONFIG_LZ4)
78 case SQFS_COMP_LZ4:
79 break;
80#endif
Joao Marcos Costab1fa6b82020-08-18 17:17:23 +020081#if IS_ENABLED(CONFIG_ZSTD)
82 case SQFS_COMP_ZSTD:
83 free(ctxt->zstd_workspace);
84 break;
85#endif
Joao Marcos Costa877576c2020-08-18 17:17:21 +020086 }
87}
88
Joao Marcos Costa88f53332020-07-30 15:33:50 +020089#if IS_ENABLED(CONFIG_ZLIB)
90static 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
Joao Marcos Costab1fa6b82020-08-18 17:17:23 +0200106#if IS_ENABLED(CONFIG_ZSTD)
107static 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
Brandon Maierdbe88da2023-01-12 10:27:45 -0600114 wsize = zstd_dctx_workspace_bound();
Joao Marcos Costab1fa6b82020-08-18 17:17:23 +0200115
Brandon Maierdbe88da2023-01-12 10:27:45 -0600116 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);
Joao Marcos Costab1fa6b82020-08-18 17:17:23 +0200122}
123#endif /* CONFIG_ZSTD */
124
Joao Marcos Costab87fd012020-08-18 17:17:22 +0200125int sqfs_decompress(struct squashfs_ctxt *ctxt, void *dest,
126 unsigned long *dest_len, void *source, u32 src_len)
Joao Marcos Costa29da3742020-07-30 15:33:47 +0200127{
Joao Marcos Costab87fd012020-08-18 17:17:22 +0200128 u16 comp_type = get_unaligned_le16(&ctxt->sblk->compression);
Joao Marcos Costa29da3742020-07-30 15:33:47 +0200129 int ret = 0;
130
131 switch (comp_type) {
Joao Marcos Costa40a9fd52020-08-18 17:17:24 +0200132#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
Joao Marcos Costa88f53332020-07-30 15:33:50 +0200144#if IS_ENABLED(CONFIG_ZLIB)
145 case SQFS_COMP_ZLIB:
Joao Marcos Costa877576c2020-08-18 17:17:21 +0200146 ret = uncompress(dest, dest_len, source, src_len);
Joao Marcos Costa88f53332020-07-30 15:33:50 +0200147 if (ret) {
148 zlib_decompression_status(ret);
149 return -EINVAL;
150 }
151
152 break;
153#endif
David Oberhollenzer1f064bc2023-11-06 11:14:03 +0100154#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
Joao Marcos Costab1fa6b82020-08-18 17:17:23 +0200165#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) {
Brandon Maierdbe88da2023-01-12 10:27:45 -0600169 printf("ZSTD Error code: %d\n", zstd_get_error_code(ret));
Joao Marcos Costab1fa6b82020-08-18 17:17:23 +0200170 return -EINVAL;
171 }
172
173 break;
174#endif
Joao Marcos Costa29da3742020-07-30 15:33:47 +0200175 default:
176 printf("Error: unknown compression type.\n");
177 return -EINVAL;
178 }
179
180 return ret;
181}