| 1 | |
| 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 <[email protected]>
|
| 7 | *
|
| 8 | * zlib_wrapper.c
|
| 9 |
|
| 10 |
|
| 11 |
|
| 12 | #include <linux/mutex.h>
|
| 13 | #include <linux/bio.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_obj(z_stream);
|
| 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 bio *bio, int offset, int length,
|
| 54 | struct squashfs_page_actor *output)
|
| 55 | {
|
| 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;
|
| 59 | z_stream *stream = strm;
|
| 60 |
|
| 61 | stream->avail_out = PAGE_SIZE;
|
| 62 | stream->next_out = squashfs_first_page(output);
|
| 63 | stream->avail_in = 0;
|
| 64 |
|
| 65 | if (IS_ERR(stream->next_out)) {
|
| 66 | error = PTR_ERR(stream->next_out);
|
| 67 | goto finish;
|
| 68 | }
|
| 69 |
|
| 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 |
|
| 79 | error = -EIO;
|
| 80 | break;
|
| 81 | }
|
| 82 |
|
| 83 | avail = min(length, ((int)bvec->bv_len) - offset);
|
| 84 | data = bvec_virt(bvec);
|
| 85 | length -= avail;
|
| 86 | stream->next_in = data + offset;
|
| 87 | stream->avail_in = avail;
|
| 88 | offset = 0;
|
| 89 | }
|
| 90 |
|
| 91 | if (stream->avail_out == 0) {
|
| 92 | stream->next_out = squashfs_next_page(output);
|
| 93 | if (IS_ERR(stream->next_out)) {
|
| 94 | error = PTR_ERR(stream->next_out);
|
| 95 | break;
|
| 96 | } else if (stream->next_out != NULL)
|
| 97 | stream->avail_out = PAGE_SIZE;
|
| 98 | }
|
| 99 |
|
| 100 | if (!zlib_init) {
|
| 101 | zlib_err = zlib_inflateInit(stream);
|
| 102 | if (zlib_err != Z_OK) {
|
| 103 | error = -EIO;
|
| 104 | break;
|
| 105 | }
|
| 106 | zlib_init = 1;
|
| 107 | }
|
| 108 |
|
| 109 | zlib_err = zlib_inflate(stream, Z_SYNC_FLUSH);
|
| 110 | if (zlib_err == Z_STREAM_END)
|
| 111 | break;
|
| 112 | if (zlib_err != Z_OK) {
|
| 113 | error = -EIO;
|
| 114 | break;
|
| 115 | }
|
| 116 | }
|
| 117 |
|
| 118 | finish:
|
| 119 | squashfs_finish_page(output);
|
| 120 |
|
| 121 | if (!error)
|
| 122 | if (zlib_inflateEnd(stream) != Z_OK)
|
| 123 | error = -EIO;
|
| 124 |
|
| 125 | return error ? error : stream->total_out;
|
| 126 | }
|
| 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",
|
| 134 | .alloc_buffer = 1,
|
| 135 | .supported = 1
|
| 136 | };
|
| 137 |
|