Commit | Line | Data |
---|---|---|
68252eb5 | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
e6a6d379 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> |
e6a6d379 | 7 | * |
e6a6d379 PL |
8 | * zlib_wrapper.c |
9 | */ | |
10 | ||
11 | ||
12 | #include <linux/mutex.h> | |
93e72b3c | 13 | #include <linux/bio.h> |
5a0e3ad6 | 14 | #include <linux/slab.h> |
e6a6d379 | 15 | #include <linux/zlib.h> |
117a91e0 | 16 | #include <linux/vmalloc.h> |
e6a6d379 PL |
17 | |
18 | #include "squashfs_fs.h" | |
19 | #include "squashfs_fs_sb.h" | |
e6a6d379 | 20 | #include "squashfs.h" |
4c0f0bb2 | 21 | #include "decompressor.h" |
846b730e | 22 | #include "page_actor.h" |
e6a6d379 | 23 | |
9508c6b9 | 24 | static void *zlib_init(struct squashfs_sb_info *dummy, void *buff) |
f1a40359 PL |
25 | { |
26 | z_stream *stream = kmalloc(sizeof(z_stream), GFP_KERNEL); | |
27 | if (stream == NULL) | |
28 | goto failed; | |
117a91e0 | 29 | stream->workspace = vmalloc(zlib_inflate_workspacesize()); |
f1a40359 PL |
30 | if (stream->workspace == NULL) |
31 | goto failed; | |
32 | ||
33 | return stream; | |
34 | ||
35 | failed: | |
36 | ERROR("Failed to allocate zlib workspace\n"); | |
37 | kfree(stream); | |
b7fc0ff0 | 38 | return ERR_PTR(-ENOMEM); |
f1a40359 PL |
39 | } |
40 | ||
41 | ||
4c0f0bb2 | 42 | static void zlib_free(void *strm) |
f1a40359 PL |
43 | { |
44 | z_stream *stream = strm; | |
45 | ||
46 | if (stream) | |
117a91e0 | 47 | vfree(stream->workspace); |
f1a40359 PL |
48 | kfree(stream); |
49 | } | |
50 | ||
51 | ||
9508c6b9 | 52 | static int zlib_uncompress(struct squashfs_sb_info *msblk, void *strm, |
93e72b3c | 53 | struct bio *bio, int offset, int length, |
846b730e | 54 | struct squashfs_page_actor *output) |
e6a6d379 | 55 | { |
93e72b3c PL |
56 | struct bvec_iter_all iter_all = {}; |
57 | struct bio_vec *bvec = bvec_init_iter_all(&iter_all); | |
58 | int zlib_init = 0, error = 0; | |
9508c6b9 | 59 | z_stream *stream = strm; |
e6a6d379 | 60 | |
09cbfeaf | 61 | stream->avail_out = PAGE_SIZE; |
846b730e | 62 | stream->next_out = squashfs_first_page(output); |
f1a40359 | 63 | stream->avail_in = 0; |
e6a6d379 | 64 | |
f268eedd PL |
65 | if (IS_ERR(stream->next_out)) { |
66 | error = PTR_ERR(stream->next_out); | |
67 | goto finish; | |
68 | } | |
69 | ||
93e72b3c PL |
70 | for (;;) { |
71 | int zlib_err; | |
72 | ||
73 | if (stream->avail_in == 0) { | |
74 | const void *data; | |
75 | int avail; | |
76 | ||
77 | if (!bio_next_segment(bio, &iter_all)) { | |
78 | /* Z_STREAM_END must be reached. */ | |
79 | error = -EIO; | |
80 | break; | |
81 | } | |
82 | ||
83 | avail = min(length, ((int)bvec->bv_len) - offset); | |
fbc27241 | 84 | data = bvec_virt(bvec); |
170cf021 | 85 | length -= avail; |
93e72b3c | 86 | stream->next_in = data + offset; |
f1a40359 | 87 | stream->avail_in = avail; |
e6a6d379 PL |
88 | offset = 0; |
89 | } | |
90 | ||
846b730e PL |
91 | if (stream->avail_out == 0) { |
92 | stream->next_out = squashfs_next_page(output); | |
f268eedd PL |
93 | if (IS_ERR(stream->next_out)) { |
94 | error = PTR_ERR(stream->next_out); | |
95 | break; | |
96 | } else if (stream->next_out != NULL) | |
09cbfeaf | 97 | stream->avail_out = PAGE_SIZE; |
e6a6d379 PL |
98 | } |
99 | ||
100 | if (!zlib_init) { | |
f1a40359 | 101 | zlib_err = zlib_inflateInit(stream); |
846b730e | 102 | if (zlib_err != Z_OK) { |
93e72b3c PL |
103 | error = -EIO; |
104 | break; | |
846b730e | 105 | } |
e6a6d379 PL |
106 | zlib_init = 1; |
107 | } | |
108 | ||
f1a40359 | 109 | zlib_err = zlib_inflate(stream, Z_SYNC_FLUSH); |
93e72b3c PL |
110 | if (zlib_err == Z_STREAM_END) |
111 | break; | |
112 | if (zlib_err != Z_OK) { | |
113 | error = -EIO; | |
114 | break; | |
115 | } | |
116 | } | |
e6a6d379 | 117 | |
f268eedd | 118 | finish: |
846b730e PL |
119 | squashfs_finish_page(output); |
120 | ||
93e72b3c PL |
121 | if (!error) |
122 | if (zlib_inflateEnd(stream) != Z_OK) | |
123 | error = -EIO; | |
e6a6d379 | 124 | |
93e72b3c | 125 | return error ? error : stream->total_out; |
e6a6d379 | 126 | } |
4c0f0bb2 PL |
127 | |
128 | const struct squashfs_decompressor squashfs_zlib_comp_ops = { | |
129 | .init = zlib_init, | |
130 | .free = zlib_free, | |
131 | .decompress = zlib_uncompress, | |
132 | .id = ZLIB_COMPRESSION, | |
133 | .name = "zlib", | |
f268eedd | 134 | .alloc_buffer = 1, |
4c0f0bb2 PL |
135 | .supported = 1 |
136 | }; | |
137 |