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 27 static 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 32 static 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 38 static 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 44 static 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 50 static 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 56 static const struct squashfs_decompressor squashfs_zstd_comp_ops = { 57 NULL, NULL, NULL, NULL, ZSTD_COMPRESSION, "zstd", 0 58 }; 59 #endif 60 61 static const struct squashfs_decompressor squashfs_unknown_comp_ops = { 62 NULL, NULL, NULL, NULL, 0, "unknown", 0 63 }; 64 65 static 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 76 const 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 88 static 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 122 out: 123 kfree(actor); 124 kfree(buffer); 125 return comp_opts; 126 } 127 128 129 void *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 = msblk->thread_ops->create(msblk, comp_opts); 138 if (IS_ERR(stream)) 139 kfree(comp_opts); 140 141 return stream; 142 } 143