decompressor.c (3332B)
1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * Squashfs - a compressed read only filesystem for Linux 4 * 5 * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 6 * Phillip Lougher <phillip@squashfs.org.uk> 7 * 8 * decompressor.c 9 */ 10 11#include <linux/types.h> 12#include <linux/mutex.h> 13#include <linux/slab.h> 14#include <linux/buffer_head.h> 15 16#include "squashfs_fs.h" 17#include "squashfs_fs_sb.h" 18#include "decompressor.h" 19#include "squashfs.h" 20#include "page_actor.h" 21 22/* 23 * This file (and decompressor.h) implements a decompressor framework for 24 * Squashfs, allowing multiple decompressors to be easily supported 25 */ 26 27static const struct squashfs_decompressor squashfs_lzma_unsupported_comp_ops = { 28 NULL, NULL, NULL, NULL, LZMA_COMPRESSION, "lzma", 0 29}; 30 31#ifndef CONFIG_SQUASHFS_LZ4 32static const struct squashfs_decompressor squashfs_lz4_comp_ops = { 33 NULL, NULL, NULL, NULL, LZ4_COMPRESSION, "lz4", 0 34}; 35#endif 36 37#ifndef CONFIG_SQUASHFS_LZO 38static const struct squashfs_decompressor squashfs_lzo_comp_ops = { 39 NULL, NULL, NULL, NULL, LZO_COMPRESSION, "lzo", 0 40}; 41#endif 42 43#ifndef CONFIG_SQUASHFS_XZ 44static const struct squashfs_decompressor squashfs_xz_comp_ops = { 45 NULL, NULL, NULL, NULL, XZ_COMPRESSION, "xz", 0 46}; 47#endif 48 49#ifndef CONFIG_SQUASHFS_ZLIB 50static const struct squashfs_decompressor squashfs_zlib_comp_ops = { 51 NULL, NULL, NULL, NULL, ZLIB_COMPRESSION, "zlib", 0 52}; 53#endif 54 55#ifndef CONFIG_SQUASHFS_ZSTD 56static const struct squashfs_decompressor squashfs_zstd_comp_ops = { 57 NULL, NULL, NULL, NULL, ZSTD_COMPRESSION, "zstd", 0 58}; 59#endif 60 61static const struct squashfs_decompressor squashfs_unknown_comp_ops = { 62 NULL, NULL, NULL, NULL, 0, "unknown", 0 63}; 64 65static const struct squashfs_decompressor *decompressor[] = { 66 &squashfs_zlib_comp_ops, 67 &squashfs_lz4_comp_ops, 68 &squashfs_lzo_comp_ops, 69 &squashfs_xz_comp_ops, 70 &squashfs_lzma_unsupported_comp_ops, 71 &squashfs_zstd_comp_ops, 72 &squashfs_unknown_comp_ops 73}; 74 75 76const struct squashfs_decompressor *squashfs_lookup_decompressor(int id) 77{ 78 int i; 79 80 for (i = 0; decompressor[i]->id; i++) 81 if (id == decompressor[i]->id) 82 break; 83 84 return decompressor[i]; 85} 86 87 88static void *get_comp_opts(struct super_block *sb, unsigned short flags) 89{ 90 struct squashfs_sb_info *msblk = sb->s_fs_info; 91 void *buffer = NULL, *comp_opts; 92 struct squashfs_page_actor *actor = NULL; 93 int length = 0; 94 95 /* 96 * Read decompressor specific options from file system if present 97 */ 98 if (SQUASHFS_COMP_OPTS(flags)) { 99 buffer = kmalloc(PAGE_SIZE, GFP_KERNEL); 100 if (buffer == NULL) { 101 comp_opts = ERR_PTR(-ENOMEM); 102 goto out; 103 } 104 105 actor = squashfs_page_actor_init(&buffer, 1, 0); 106 if (actor == NULL) { 107 comp_opts = ERR_PTR(-ENOMEM); 108 goto out; 109 } 110 111 length = squashfs_read_data(sb, 112 sizeof(struct squashfs_super_block), 0, NULL, actor); 113 114 if (length < 0) { 115 comp_opts = ERR_PTR(length); 116 goto out; 117 } 118 } 119 120 comp_opts = squashfs_comp_opts(msblk, buffer, length); 121 122out: 123 kfree(actor); 124 kfree(buffer); 125 return comp_opts; 126} 127 128 129void *squashfs_decompressor_setup(struct super_block *sb, unsigned short flags) 130{ 131 struct squashfs_sb_info *msblk = sb->s_fs_info; 132 void *stream, *comp_opts = get_comp_opts(sb, flags); 133 134 if (IS_ERR(comp_opts)) 135 return comp_opts; 136 137 stream = squashfs_decompressor_create(msblk, comp_opts); 138 if (IS_ERR(stream)) 139 kfree(comp_opts); 140 141 return stream; 142}