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