blob: 6b3e01cdad76e2de4f00ec52fd0b9f6cfcd853e6 [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
Joao Marcos Costab1fa6b82020-08-18 17:17:23 +020021#if IS_ENABLED(CONFIG_ZSTD)
22#include <linux/zstd.h>
23#endif
24
Joao Marcos Costa29da3742020-07-30 15:33:47 +020025#include "sqfs_decompressor.h"
Joao Marcos Costa29da3742020-07-30 15:33:47 +020026#include "sqfs_utils.h"
27
Joao Marcos Costa877576c2020-08-18 17:17:21 +020028int sqfs_decompressor_init(struct squashfs_ctxt *ctxt)
29{
30 u16 comp_type = get_unaligned_le16(&ctxt->sblk->compression);
31
32 switch (comp_type) {
Joao Marcos Costa40a9fd52020-08-18 17:17:24 +020033#if IS_ENABLED(CONFIG_LZO)
34 case SQFS_COMP_LZO:
35 break;
36#endif
Joao Marcos Costa877576c2020-08-18 17:17:21 +020037#if IS_ENABLED(CONFIG_ZLIB)
38 case SQFS_COMP_ZLIB:
39 break;
40#endif
Joao Marcos Costab1fa6b82020-08-18 17:17:23 +020041#if IS_ENABLED(CONFIG_ZSTD)
42 case SQFS_COMP_ZSTD:
Brandon Maierdbe88da2023-01-12 10:27:45 -060043 ctxt->zstd_workspace = malloc(zstd_dctx_workspace_bound());
Joao Marcos Costab1fa6b82020-08-18 17:17:23 +020044 if (!ctxt->zstd_workspace)
45 return -ENOMEM;
46 break;
47#endif
Joao Marcos Costa877576c2020-08-18 17:17:21 +020048 default:
49 printf("Error: unknown compression type.\n");
50 return -EINVAL;
51 }
52
53 return 0;
54}
55
56void sqfs_decompressor_cleanup(struct squashfs_ctxt *ctxt)
57{
58 u16 comp_type = get_unaligned_le16(&ctxt->sblk->compression);
59
60 switch (comp_type) {
Joao Marcos Costa40a9fd52020-08-18 17:17:24 +020061#if IS_ENABLED(CONFIG_LZO)
62 case SQFS_COMP_LZO:
63 break;
64#endif
Joao Marcos Costa877576c2020-08-18 17:17:21 +020065#if IS_ENABLED(CONFIG_ZLIB)
66 case SQFS_COMP_ZLIB:
67 break;
68#endif
Joao Marcos Costab1fa6b82020-08-18 17:17:23 +020069#if IS_ENABLED(CONFIG_ZSTD)
70 case SQFS_COMP_ZSTD:
71 free(ctxt->zstd_workspace);
72 break;
73#endif
Joao Marcos Costa877576c2020-08-18 17:17:21 +020074 }
75}
76
Joao Marcos Costa88f53332020-07-30 15:33:50 +020077#if IS_ENABLED(CONFIG_ZLIB)
78static 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
Joao Marcos Costab1fa6b82020-08-18 17:17:23 +020094#if IS_ENABLED(CONFIG_ZSTD)
95static 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
Brandon Maierdbe88da2023-01-12 10:27:45 -0600102 wsize = zstd_dctx_workspace_bound();
Joao Marcos Costab1fa6b82020-08-18 17:17:23 +0200103
Brandon Maierdbe88da2023-01-12 10:27:45 -0600104 ctx = zstd_init_dctx(ctxt->zstd_workspace, wsize);
105 if (!ctx)
106 return -EINVAL;
107 ret = zstd_decompress_dctx(ctx, dest, dest_len, source, src_len);
108
109 return zstd_is_error(ret);
Joao Marcos Costab1fa6b82020-08-18 17:17:23 +0200110}
111#endif /* CONFIG_ZSTD */
112
Joao Marcos Costab87fd012020-08-18 17:17:22 +0200113int sqfs_decompress(struct squashfs_ctxt *ctxt, void *dest,
114 unsigned long *dest_len, void *source, u32 src_len)
Joao Marcos Costa29da3742020-07-30 15:33:47 +0200115{
Joao Marcos Costab87fd012020-08-18 17:17:22 +0200116 u16 comp_type = get_unaligned_le16(&ctxt->sblk->compression);
Joao Marcos Costa29da3742020-07-30 15:33:47 +0200117 int ret = 0;
118
119 switch (comp_type) {
Joao Marcos Costa40a9fd52020-08-18 17:17:24 +0200120#if IS_ENABLED(CONFIG_LZO)
121 case SQFS_COMP_LZO: {
122 size_t lzo_dest_len = *dest_len;
123 ret = lzo1x_decompress_safe(source, src_len, dest, &lzo_dest_len);
124 if (ret) {
125 printf("LZO decompression failed. Error code: %d\n", ret);
126 return -EINVAL;
127 }
128
129 break;
130 }
131#endif
Joao Marcos Costa88f53332020-07-30 15:33:50 +0200132#if IS_ENABLED(CONFIG_ZLIB)
133 case SQFS_COMP_ZLIB:
Joao Marcos Costa877576c2020-08-18 17:17:21 +0200134 ret = uncompress(dest, dest_len, source, src_len);
Joao Marcos Costa88f53332020-07-30 15:33:50 +0200135 if (ret) {
136 zlib_decompression_status(ret);
137 return -EINVAL;
138 }
139
140 break;
141#endif
Joao Marcos Costab1fa6b82020-08-18 17:17:23 +0200142#if IS_ENABLED(CONFIG_ZSTD)
143 case SQFS_COMP_ZSTD:
144 ret = sqfs_zstd_decompress(ctxt, dest, *dest_len, source, src_len);
145 if (ret) {
Brandon Maierdbe88da2023-01-12 10:27:45 -0600146 printf("ZSTD Error code: %d\n", zstd_get_error_code(ret));
Joao Marcos Costab1fa6b82020-08-18 17:17:23 +0200147 return -EINVAL;
148 }
149
150 break;
151#endif
Joao Marcos Costa29da3742020-07-30 15:33:47 +0200152 default:
153 printf("Error: unknown compression type.\n");
154 return -EINVAL;
155 }
156
157 return ret;
158}