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 * zlib_wrapper.c 9 */ 10 11 12 #include <linux/mutex.h> 13 #include <linux/buffer_head.h> 14 #include <linux/slab.h> 15 #include <linux/zlib.h> 16 #include <linux/vmalloc.h> 17 18 #include "squashfs_fs.h" 19 #include "squashfs_fs_sb.h" 20 #include "squashfs.h" 21 #include "decompressor.h" 22 #include "page_actor.h" 23 24 static void *zlib_init(struct squashfs_sb_info *dummy, void *buff) 25 { 26 z_stream *stream = kmalloc(sizeof(z_stream), GFP_KERNEL); 27 if (stream == NULL) 28 goto failed; 29 stream->workspace = vmalloc(zlib_inflate_workspacesize()); 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); 38 return ERR_PTR(-ENOMEM); 39 } 40 41 42 static void zlib_free(void *strm) 43 { 44 z_stream *stream = strm; 45 46 if (stream) 47 vfree(stream->workspace); 48 kfree(stream); 49 } 50 51 52 static int zlib_uncompress(struct squashfs_sb_info *msblk, void *strm, 53 struct buffer_head **bh, int b, int offset, int length, 54 struct squashfs_page_actor *output) 55 { 56 int zlib_err, zlib_init = 0, k = 0; 57 z_stream *stream = strm; 58 59 stream->avail_out = PAGE_SIZE; 60 stream->next_out = squashfs_first_page(output); 61 stream->avail_in = 0; 62 63 do { 64 if (stream->avail_in == 0 && k < b) { 65 int avail = min(length, msblk->devblksize - offset); 66 length -= avail; 67 stream->next_in = bh[k]->b_data + offset; 68 stream->avail_in = avail; 69 offset = 0; 70 } 71 72 if (stream->avail_out == 0) { 73 stream->next_out = squashfs_next_page(output); 74 if (stream->next_out != NULL) 75 stream->avail_out = PAGE_SIZE; 76 } 77 78 if (!zlib_init) { 79 zlib_err = zlib_inflateInit(stream); 80 if (zlib_err != Z_OK) { 81 squashfs_finish_page(output); 82 goto out; 83 } 84 zlib_init = 1; 85 } 86 87 zlib_err = zlib_inflate(stream, Z_SYNC_FLUSH); 88 89 if (stream->avail_in == 0 && k < b) 90 put_bh(bh[k++]); 91 } while (zlib_err == Z_OK); 92 93 squashfs_finish_page(output); 94 95 if (zlib_err != Z_STREAM_END) 96 goto out; 97 98 zlib_err = zlib_inflateEnd(stream); 99 if (zlib_err != Z_OK) 100 goto out; 101 102 if (k < b) 103 goto out; 104 105 return stream->total_out; 106 107 out: 108 for (; k < b; k++) 109 put_bh(bh[k]); 110 111 return -EIO; 112 } 113 114 const struct squashfs_decompressor squashfs_zlib_comp_ops = { 115 .init = zlib_init, 116 .free = zlib_free, 117 .decompress = zlib_uncompress, 118 .id = ZLIB_COMPRESSION, 119 .name = "zlib", 120 .supported = 1 121 }; 122 123