1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * uncompress.c |
4 | * |
5 | * (C) Copyright 1999 Linus Torvalds |
6 | * |
7 | * cramfs interfaces to the uncompression library. There's really just |
8 | * three entrypoints: |
9 | * |
10 | * - cramfs_uncompress_init() - called to initialize the thing. |
11 | * - cramfs_uncompress_exit() - tell me when you're done |
12 | * - cramfs_uncompress_block() - uncompress a block. |
13 | * |
14 | * NOTE NOTE NOTE! The uncompression is entirely single-threaded. We |
15 | * only have one stream, and we'll initialize it only once even if it |
16 | * then is used by multiple filesystems. |
17 | */ |
18 | |
19 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
20 | |
21 | #include <linux/kernel.h> |
22 | #include <linux/errno.h> |
23 | #include <linux/vmalloc.h> |
24 | #include <linux/zlib.h> |
25 | #include "internal.h" |
26 | |
27 | static z_stream stream; |
28 | static int initialized; |
29 | |
30 | /* Returns length of decompressed data. */ |
31 | int cramfs_uncompress_block(void *dst, int dstlen, void *src, int srclen) |
32 | { |
33 | int err; |
34 | |
35 | stream.next_in = src; |
36 | stream.avail_in = srclen; |
37 | |
38 | stream.next_out = dst; |
39 | stream.avail_out = dstlen; |
40 | |
41 | err = zlib_inflateReset(strm: &stream); |
42 | if (err != Z_OK) { |
43 | pr_err("zlib_inflateReset error %d\n" , err); |
44 | zlib_inflateEnd(strm: &stream); |
45 | zlib_inflateInit(&stream); |
46 | } |
47 | |
48 | err = zlib_inflate(strm: &stream, Z_FINISH); |
49 | if (err != Z_STREAM_END) |
50 | goto err; |
51 | return stream.total_out; |
52 | |
53 | err: |
54 | pr_err("Error %d while decompressing!\n" , err); |
55 | pr_err("%p(%d)->%p(%d)\n" , src, srclen, dst, dstlen); |
56 | return -EIO; |
57 | } |
58 | |
59 | int cramfs_uncompress_init(void) |
60 | { |
61 | if (!initialized++) { |
62 | stream.workspace = vmalloc(size: zlib_inflate_workspacesize()); |
63 | if (!stream.workspace) { |
64 | initialized = 0; |
65 | return -ENOMEM; |
66 | } |
67 | stream.next_in = NULL; |
68 | stream.avail_in = 0; |
69 | zlib_inflateInit(&stream); |
70 | } |
71 | return 0; |
72 | } |
73 | |
74 | void cramfs_uncompress_exit(void) |
75 | { |
76 | if (!--initialized) { |
77 | zlib_inflateEnd(strm: &stream); |
78 | vfree(addr: stream.workspace); |
79 | } |
80 | } |
81 | |