linux/fs/squashfs/zlib_wrapper.c
<<
>>
Prefs
   1/*
   2 * Squashfs - a compressed read only filesystem for Linux
   3 *
   4 * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
   5 * Phillip Lougher <phillip@lougher.demon.co.uk>
   6 *
   7 * This program is free software; you can redistribute it and/or
   8 * modify it under the terms of the GNU General Public License
   9 * as published by the Free Software Foundation; either version 2,
  10 * or (at your option) any later version.
  11 *
  12 * This program is distributed in the hope that it will be useful,
  13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15 * GNU General Public License for more details.
  16 *
  17 * You should have received a copy of the GNU General Public License
  18 * along with this program; if not, write to the Free Software
  19 * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  20 *
  21 * zlib_wrapper.c
  22 */
  23
  24
  25#include <linux/mutex.h>
  26#include <linux/buffer_head.h>
  27#include <linux/slab.h>
  28#include <linux/zlib.h>
  29
  30#include "squashfs_fs.h"
  31#include "squashfs_fs_sb.h"
  32#include "squashfs.h"
  33#include "decompressor.h"
  34
  35static void *zlib_init(struct squashfs_sb_info *dummy)
  36{
  37        z_stream *stream = kmalloc(sizeof(z_stream), GFP_KERNEL);
  38        if (stream == NULL)
  39                goto failed;
  40        stream->workspace = kmalloc(zlib_inflate_workspacesize(),
  41                GFP_KERNEL);
  42        if (stream->workspace == NULL)
  43                goto failed;
  44
  45        return stream;
  46
  47failed:
  48        ERROR("Failed to allocate zlib workspace\n");
  49        kfree(stream);
  50        return NULL;
  51}
  52
  53
  54static void zlib_free(void *strm)
  55{
  56        z_stream *stream = strm;
  57
  58        if (stream)
  59                kfree(stream->workspace);
  60        kfree(stream);
  61}
  62
  63
  64static int zlib_uncompress(struct squashfs_sb_info *msblk, void **buffer,
  65        struct buffer_head **bh, int b, int offset, int length, int srclength,
  66        int pages)
  67{
  68        int zlib_err, zlib_init = 0;
  69        int k = 0, page = 0;
  70        z_stream *stream = msblk->stream;
  71
  72        mutex_lock(&msblk->read_data_mutex);
  73
  74        stream->avail_out = 0;
  75        stream->avail_in = 0;
  76
  77        do {
  78                if (stream->avail_in == 0 && k < b) {
  79                        int avail = min(length, msblk->devblksize - offset);
  80                        length -= avail;
  81                        wait_on_buffer(bh[k]);
  82                        if (!buffer_uptodate(bh[k]))
  83                                goto release_mutex;
  84
  85                        stream->next_in = bh[k]->b_data + offset;
  86                        stream->avail_in = avail;
  87                        offset = 0;
  88                }
  89
  90                if (stream->avail_out == 0 && page < pages) {
  91                        stream->next_out = buffer[page++];
  92                        stream->avail_out = PAGE_CACHE_SIZE;
  93                }
  94
  95                if (!zlib_init) {
  96                        zlib_err = zlib_inflateInit(stream);
  97                        if (zlib_err != Z_OK) {
  98                                ERROR("zlib_inflateInit returned unexpected "
  99                                        "result 0x%x, srclength %d\n",
 100                                        zlib_err, srclength);
 101                                goto release_mutex;
 102                        }
 103                        zlib_init = 1;
 104                }
 105
 106                zlib_err = zlib_inflate(stream, Z_SYNC_FLUSH);
 107
 108                if (stream->avail_in == 0 && k < b)
 109                        put_bh(bh[k++]);
 110        } while (zlib_err == Z_OK);
 111
 112        if (zlib_err != Z_STREAM_END) {
 113                ERROR("zlib_inflate error, data probably corrupt\n");
 114                goto release_mutex;
 115        }
 116
 117        zlib_err = zlib_inflateEnd(stream);
 118        if (zlib_err != Z_OK) {
 119                ERROR("zlib_inflate error, data probably corrupt\n");
 120                goto release_mutex;
 121        }
 122
 123        if (k < b) {
 124                ERROR("zlib_uncompress error, data remaining\n");
 125                goto release_mutex;
 126        }
 127
 128        length = stream->total_out;
 129        mutex_unlock(&msblk->read_data_mutex);
 130        return length;
 131
 132release_mutex:
 133        mutex_unlock(&msblk->read_data_mutex);
 134
 135        for (; k < b; k++)
 136                put_bh(bh[k]);
 137
 138        return -EIO;
 139}
 140
 141const struct squashfs_decompressor squashfs_zlib_comp_ops = {
 142        .init = zlib_init,
 143        .free = zlib_free,
 144        .decompress = zlib_uncompress,
 145        .id = ZLIB_COMPRESSION,
 146        .name = "zlib",
 147        .supported = 1
 148};
 149
 150