18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Squashfs - a compressed read only filesystem for Linux 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 68c2ecf20Sopenharmony_ci * Phillip Lougher <phillip@squashfs.org.uk> 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * decompressor.c 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/types.h> 128c2ecf20Sopenharmony_ci#include <linux/mutex.h> 138c2ecf20Sopenharmony_ci#include <linux/slab.h> 148c2ecf20Sopenharmony_ci#include <linux/buffer_head.h> 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#include "squashfs_fs.h" 178c2ecf20Sopenharmony_ci#include "squashfs_fs_sb.h" 188c2ecf20Sopenharmony_ci#include "decompressor.h" 198c2ecf20Sopenharmony_ci#include "squashfs.h" 208c2ecf20Sopenharmony_ci#include "page_actor.h" 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci/* 238c2ecf20Sopenharmony_ci * This file (and decompressor.h) implements a decompressor framework for 248c2ecf20Sopenharmony_ci * Squashfs, allowing multiple decompressors to be easily supported 258c2ecf20Sopenharmony_ci */ 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_cistatic const struct squashfs_decompressor squashfs_lzma_unsupported_comp_ops = { 288c2ecf20Sopenharmony_ci NULL, NULL, NULL, NULL, LZMA_COMPRESSION, "lzma", 0 298c2ecf20Sopenharmony_ci}; 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci#ifndef CONFIG_SQUASHFS_LZ4 328c2ecf20Sopenharmony_cistatic const struct squashfs_decompressor squashfs_lz4_comp_ops = { 338c2ecf20Sopenharmony_ci NULL, NULL, NULL, NULL, LZ4_COMPRESSION, "lz4", 0 348c2ecf20Sopenharmony_ci}; 358c2ecf20Sopenharmony_ci#endif 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci#ifndef CONFIG_SQUASHFS_LZO 388c2ecf20Sopenharmony_cistatic const struct squashfs_decompressor squashfs_lzo_comp_ops = { 398c2ecf20Sopenharmony_ci NULL, NULL, NULL, NULL, LZO_COMPRESSION, "lzo", 0 408c2ecf20Sopenharmony_ci}; 418c2ecf20Sopenharmony_ci#endif 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci#ifndef CONFIG_SQUASHFS_XZ 448c2ecf20Sopenharmony_cistatic const struct squashfs_decompressor squashfs_xz_comp_ops = { 458c2ecf20Sopenharmony_ci NULL, NULL, NULL, NULL, XZ_COMPRESSION, "xz", 0 468c2ecf20Sopenharmony_ci}; 478c2ecf20Sopenharmony_ci#endif 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci#ifndef CONFIG_SQUASHFS_ZLIB 508c2ecf20Sopenharmony_cistatic const struct squashfs_decompressor squashfs_zlib_comp_ops = { 518c2ecf20Sopenharmony_ci NULL, NULL, NULL, NULL, ZLIB_COMPRESSION, "zlib", 0 528c2ecf20Sopenharmony_ci}; 538c2ecf20Sopenharmony_ci#endif 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci#ifndef CONFIG_SQUASHFS_ZSTD 568c2ecf20Sopenharmony_cistatic const struct squashfs_decompressor squashfs_zstd_comp_ops = { 578c2ecf20Sopenharmony_ci NULL, NULL, NULL, NULL, ZSTD_COMPRESSION, "zstd", 0 588c2ecf20Sopenharmony_ci}; 598c2ecf20Sopenharmony_ci#endif 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_cistatic const struct squashfs_decompressor squashfs_unknown_comp_ops = { 628c2ecf20Sopenharmony_ci NULL, NULL, NULL, NULL, 0, "unknown", 0 638c2ecf20Sopenharmony_ci}; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_cistatic const struct squashfs_decompressor *decompressor[] = { 668c2ecf20Sopenharmony_ci &squashfs_zlib_comp_ops, 678c2ecf20Sopenharmony_ci &squashfs_lz4_comp_ops, 688c2ecf20Sopenharmony_ci &squashfs_lzo_comp_ops, 698c2ecf20Sopenharmony_ci &squashfs_xz_comp_ops, 708c2ecf20Sopenharmony_ci &squashfs_lzma_unsupported_comp_ops, 718c2ecf20Sopenharmony_ci &squashfs_zstd_comp_ops, 728c2ecf20Sopenharmony_ci &squashfs_unknown_comp_ops 738c2ecf20Sopenharmony_ci}; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ciconst struct squashfs_decompressor *squashfs_lookup_decompressor(int id) 778c2ecf20Sopenharmony_ci{ 788c2ecf20Sopenharmony_ci int i; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci for (i = 0; decompressor[i]->id; i++) 818c2ecf20Sopenharmony_ci if (id == decompressor[i]->id) 828c2ecf20Sopenharmony_ci break; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci return decompressor[i]; 858c2ecf20Sopenharmony_ci} 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_cistatic void *get_comp_opts(struct super_block *sb, unsigned short flags) 898c2ecf20Sopenharmony_ci{ 908c2ecf20Sopenharmony_ci struct squashfs_sb_info *msblk = sb->s_fs_info; 918c2ecf20Sopenharmony_ci void *buffer = NULL, *comp_opts; 928c2ecf20Sopenharmony_ci struct squashfs_page_actor *actor = NULL; 938c2ecf20Sopenharmony_ci int length = 0; 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci /* 968c2ecf20Sopenharmony_ci * Read decompressor specific options from file system if present 978c2ecf20Sopenharmony_ci */ 988c2ecf20Sopenharmony_ci if (SQUASHFS_COMP_OPTS(flags)) { 998c2ecf20Sopenharmony_ci buffer = kmalloc(PAGE_SIZE, GFP_KERNEL); 1008c2ecf20Sopenharmony_ci if (buffer == NULL) { 1018c2ecf20Sopenharmony_ci comp_opts = ERR_PTR(-ENOMEM); 1028c2ecf20Sopenharmony_ci goto out; 1038c2ecf20Sopenharmony_ci } 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci actor = squashfs_page_actor_init(&buffer, 1, 0); 1068c2ecf20Sopenharmony_ci if (actor == NULL) { 1078c2ecf20Sopenharmony_ci comp_opts = ERR_PTR(-ENOMEM); 1088c2ecf20Sopenharmony_ci goto out; 1098c2ecf20Sopenharmony_ci } 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci length = squashfs_read_data(sb, 1128c2ecf20Sopenharmony_ci sizeof(struct squashfs_super_block), 0, NULL, actor); 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci if (length < 0) { 1158c2ecf20Sopenharmony_ci comp_opts = ERR_PTR(length); 1168c2ecf20Sopenharmony_ci goto out; 1178c2ecf20Sopenharmony_ci } 1188c2ecf20Sopenharmony_ci } 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci comp_opts = squashfs_comp_opts(msblk, buffer, length); 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ciout: 1238c2ecf20Sopenharmony_ci kfree(actor); 1248c2ecf20Sopenharmony_ci kfree(buffer); 1258c2ecf20Sopenharmony_ci return comp_opts; 1268c2ecf20Sopenharmony_ci} 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_civoid *squashfs_decompressor_setup(struct super_block *sb, unsigned short flags) 1308c2ecf20Sopenharmony_ci{ 1318c2ecf20Sopenharmony_ci struct squashfs_sb_info *msblk = sb->s_fs_info; 1328c2ecf20Sopenharmony_ci void *stream, *comp_opts = get_comp_opts(sb, flags); 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci if (IS_ERR(comp_opts)) 1358c2ecf20Sopenharmony_ci return comp_opts; 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci stream = squashfs_decompressor_create(msblk, comp_opts); 1388c2ecf20Sopenharmony_ci if (IS_ERR(stream)) 1398c2ecf20Sopenharmony_ci kfree(comp_opts); 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci return stream; 1428c2ecf20Sopenharmony_ci} 143