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_LZ4) 22#include <u-boot/lz4.h> 23#endif 24 25#if IS_ENABLED(CONFIG_ZSTD) 26#include <linux/zstd.h> 27#endif 28 29#include "sqfs_decompressor.h" 30#include "sqfs_utils.h" 31 32int sqfs_decompressor_init(struct squashfs_ctxt *ctxt) 33{ 34 u16 comp_type = get_unaligned_le16(&ctxt->sblk->compression); 35 36 switch (comp_type) { 37#if IS_ENABLED(CONFIG_LZO) 38 case SQFS_COMP_LZO: 39 break; 40#endif 41#if IS_ENABLED(CONFIG_ZLIB) 42 case SQFS_COMP_ZLIB: 43 break; 44#endif 45#if IS_ENABLED(CONFIG_LZ4) 46 case SQFS_COMP_LZ4: 47 break; 48#endif 49#if IS_ENABLED(CONFIG_ZSTD) 50 case SQFS_COMP_ZSTD: 51 ctxt->zstd_workspace = malloc(zstd_dctx_workspace_bound()); 52 if (!ctxt->zstd_workspace) 53 return -ENOMEM; 54 break; 55#endif 56 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) { 69#if IS_ENABLED(CONFIG_LZO) 70 case SQFS_COMP_LZO: 71 break; 72#endif 73#if IS_ENABLED(CONFIG_ZLIB) 74 case SQFS_COMP_ZLIB: 75 break; 76#endif 77#if IS_ENABLED(CONFIG_LZ4) 78 case SQFS_COMP_LZ4: 79 break; 80#endif 81#if IS_ENABLED(CONFIG_ZSTD) 82 case SQFS_COMP_ZSTD: 83 free(ctxt->zstd_workspace); 84 break; 85#endif 86 } 87} 88 89#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 106#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 114 wsize = zstd_dctx_workspace_bound(); 115 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); 122} 123#endif /* CONFIG_ZSTD */ 124 125int sqfs_decompress(struct squashfs_ctxt *ctxt, void *dest, 126 unsigned long *dest_len, void *source, u32 src_len) 127{ 128 u16 comp_type = get_unaligned_le16(&ctxt->sblk->compression); 129 int ret = 0; 130 131 switch (comp_type) { 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 144#if IS_ENABLED(CONFIG_ZLIB) 145 case SQFS_COMP_ZLIB: 146 ret = uncompress(dest, dest_len, source, src_len); 147 if (ret) { 148 zlib_decompression_status(ret); 149 return -EINVAL; 150 } 151 152 break; 153#endif 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 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) { 169 printf("ZSTD Error code: %d\n", zstd_get_error_code(ret)); 170 return -EINVAL; 171 } 172 173 break; 174#endif 175 default: 176 printf("Error: unknown compression type.\n"); 177 return -EINVAL; 178 } 179 180 return ret; 181} 182