181bb8debSPhillip Lougher /* 281bb8debSPhillip Lougher * Squashfs - a compressed read only filesystem for Linux 381bb8debSPhillip Lougher * 481bb8debSPhillip Lougher * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 581bb8debSPhillip Lougher * Phillip Lougher <phillip@lougher.demon.co.uk> 681bb8debSPhillip Lougher * 781bb8debSPhillip Lougher * This program is free software; you can redistribute it and/or 881bb8debSPhillip Lougher * modify it under the terms of the GNU General Public License 981bb8debSPhillip Lougher * as published by the Free Software Foundation; either version 2, 1081bb8debSPhillip Lougher * or (at your option) any later version. 1181bb8debSPhillip Lougher * 1281bb8debSPhillip Lougher * This program is distributed in the hope that it will be useful, 1381bb8debSPhillip Lougher * but WITHOUT ANY WARRANTY; without even the implied warranty of 1481bb8debSPhillip Lougher * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1581bb8debSPhillip Lougher * GNU General Public License for more details. 1681bb8debSPhillip Lougher * 1781bb8debSPhillip Lougher * You should have received a copy of the GNU General Public License 1881bb8debSPhillip Lougher * along with this program; if not, write to the Free Software 1981bb8debSPhillip Lougher * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 2081bb8debSPhillip Lougher * 2181bb8debSPhillip Lougher * xz_wrapper.c 2281bb8debSPhillip Lougher */ 2381bb8debSPhillip Lougher 2481bb8debSPhillip Lougher 2581bb8debSPhillip Lougher #include <linux/mutex.h> 2681bb8debSPhillip Lougher #include <linux/buffer_head.h> 2781bb8debSPhillip Lougher #include <linux/slab.h> 2881bb8debSPhillip Lougher #include <linux/xz.h> 2981bb8debSPhillip Lougher 3081bb8debSPhillip Lougher #include "squashfs_fs.h" 3181bb8debSPhillip Lougher #include "squashfs_fs_sb.h" 3281bb8debSPhillip Lougher #include "squashfs_fs_i.h" 3381bb8debSPhillip Lougher #include "squashfs.h" 3481bb8debSPhillip Lougher #include "decompressor.h" 3581bb8debSPhillip Lougher 3681bb8debSPhillip Lougher struct squashfs_xz { 3781bb8debSPhillip Lougher struct xz_dec *state; 3881bb8debSPhillip Lougher struct xz_buf buf; 3981bb8debSPhillip Lougher }; 4081bb8debSPhillip Lougher 4181bb8debSPhillip Lougher static void *squashfs_xz_init(struct squashfs_sb_info *msblk) 4281bb8debSPhillip Lougher { 4381bb8debSPhillip Lougher int block_size = max_t(int, msblk->block_size, SQUASHFS_METADATA_SIZE); 4481bb8debSPhillip Lougher 4581bb8debSPhillip Lougher struct squashfs_xz *stream = kmalloc(sizeof(*stream), GFP_KERNEL); 4681bb8debSPhillip Lougher if (stream == NULL) 4781bb8debSPhillip Lougher goto failed; 4881bb8debSPhillip Lougher 4981bb8debSPhillip Lougher stream->state = xz_dec_init(XZ_PREALLOC, block_size); 5081bb8debSPhillip Lougher if (stream->state == NULL) 5181bb8debSPhillip Lougher goto failed; 5281bb8debSPhillip Lougher 5381bb8debSPhillip Lougher return stream; 5481bb8debSPhillip Lougher 5581bb8debSPhillip Lougher failed: 5681bb8debSPhillip Lougher ERROR("Failed to allocate xz workspace\n"); 5781bb8debSPhillip Lougher kfree(stream); 5881bb8debSPhillip Lougher return NULL; 5981bb8debSPhillip Lougher } 6081bb8debSPhillip Lougher 6181bb8debSPhillip Lougher 6281bb8debSPhillip Lougher static void squashfs_xz_free(void *strm) 6381bb8debSPhillip Lougher { 6481bb8debSPhillip Lougher struct squashfs_xz *stream = strm; 6581bb8debSPhillip Lougher 6681bb8debSPhillip Lougher if (stream) { 6781bb8debSPhillip Lougher xz_dec_end(stream->state); 6881bb8debSPhillip Lougher kfree(stream); 6981bb8debSPhillip Lougher } 7081bb8debSPhillip Lougher } 7181bb8debSPhillip Lougher 7281bb8debSPhillip Lougher 7381bb8debSPhillip Lougher static int squashfs_xz_uncompress(struct squashfs_sb_info *msblk, void **buffer, 7481bb8debSPhillip Lougher struct buffer_head **bh, int b, int offset, int length, int srclength, 7581bb8debSPhillip Lougher int pages) 7681bb8debSPhillip Lougher { 7781bb8debSPhillip Lougher enum xz_ret xz_err; 7881bb8debSPhillip Lougher int avail, total = 0, k = 0, page = 0; 7981bb8debSPhillip Lougher struct squashfs_xz *stream = msblk->stream; 8081bb8debSPhillip Lougher 8181bb8debSPhillip Lougher mutex_lock(&msblk->read_data_mutex); 8281bb8debSPhillip Lougher 8381bb8debSPhillip Lougher xz_dec_reset(stream->state); 8481bb8debSPhillip Lougher stream->buf.in_pos = 0; 8581bb8debSPhillip Lougher stream->buf.in_size = 0; 8681bb8debSPhillip Lougher stream->buf.out_pos = 0; 8781bb8debSPhillip Lougher stream->buf.out_size = PAGE_CACHE_SIZE; 8881bb8debSPhillip Lougher stream->buf.out = buffer[page++]; 8981bb8debSPhillip Lougher 9081bb8debSPhillip Lougher do { 9181bb8debSPhillip Lougher if (stream->buf.in_pos == stream->buf.in_size && k < b) { 9281bb8debSPhillip Lougher avail = min(length, msblk->devblksize - offset); 9381bb8debSPhillip Lougher length -= avail; 9481bb8debSPhillip Lougher wait_on_buffer(bh[k]); 9581bb8debSPhillip Lougher if (!buffer_uptodate(bh[k])) 9681bb8debSPhillip Lougher goto release_mutex; 9781bb8debSPhillip Lougher 9881bb8debSPhillip Lougher if (avail == 0) { 9981bb8debSPhillip Lougher offset = 0; 10081bb8debSPhillip Lougher put_bh(bh[k++]); 10181bb8debSPhillip Lougher continue; 10281bb8debSPhillip Lougher } 10381bb8debSPhillip Lougher 10481bb8debSPhillip Lougher stream->buf.in = bh[k]->b_data + offset; 10581bb8debSPhillip Lougher stream->buf.in_size = avail; 10681bb8debSPhillip Lougher stream->buf.in_pos = 0; 10781bb8debSPhillip Lougher offset = 0; 10881bb8debSPhillip Lougher } 10981bb8debSPhillip Lougher 11081bb8debSPhillip Lougher if (stream->buf.out_pos == stream->buf.out_size 11181bb8debSPhillip Lougher && page < pages) { 11281bb8debSPhillip Lougher stream->buf.out = buffer[page++]; 11381bb8debSPhillip Lougher stream->buf.out_pos = 0; 11481bb8debSPhillip Lougher total += PAGE_CACHE_SIZE; 11581bb8debSPhillip Lougher } 11681bb8debSPhillip Lougher 11781bb8debSPhillip Lougher xz_err = xz_dec_run(stream->state, &stream->buf); 11881bb8debSPhillip Lougher 11981bb8debSPhillip Lougher if (stream->buf.in_pos == stream->buf.in_size && k < b) 12081bb8debSPhillip Lougher put_bh(bh[k++]); 12181bb8debSPhillip Lougher } while (xz_err == XZ_OK); 12281bb8debSPhillip Lougher 12381bb8debSPhillip Lougher if (xz_err != XZ_STREAM_END) { 12481bb8debSPhillip Lougher ERROR("xz_dec_run error, data probably corrupt\n"); 12581bb8debSPhillip Lougher goto release_mutex; 12681bb8debSPhillip Lougher } 12781bb8debSPhillip Lougher 12881bb8debSPhillip Lougher if (k < b) { 12981bb8debSPhillip Lougher ERROR("xz_uncompress error, input remaining\n"); 13081bb8debSPhillip Lougher goto release_mutex; 13181bb8debSPhillip Lougher } 13281bb8debSPhillip Lougher 13381bb8debSPhillip Lougher total += stream->buf.out_pos; 13481bb8debSPhillip Lougher mutex_unlock(&msblk->read_data_mutex); 13581bb8debSPhillip Lougher return total; 13681bb8debSPhillip Lougher 13781bb8debSPhillip Lougher release_mutex: 13881bb8debSPhillip Lougher mutex_unlock(&msblk->read_data_mutex); 13981bb8debSPhillip Lougher 14081bb8debSPhillip Lougher for (; k < b; k++) 14181bb8debSPhillip Lougher put_bh(bh[k]); 14281bb8debSPhillip Lougher 14381bb8debSPhillip Lougher return -EIO; 14481bb8debSPhillip Lougher } 14581bb8debSPhillip Lougher 14681bb8debSPhillip Lougher const struct squashfs_decompressor squashfs_xz_comp_ops = { 14781bb8debSPhillip Lougher .init = squashfs_xz_init, 14881bb8debSPhillip Lougher .free = squashfs_xz_free, 14981bb8debSPhillip Lougher .decompress = squashfs_xz_uncompress, 15081bb8debSPhillip Lougher .id = XZ_COMPRESSION, 15181bb8debSPhillip Lougher .name = "xz", 15281bb8debSPhillip Lougher .supported = 1 15381bb8debSPhillip Lougher }; 154