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> 29ff750311SPhillip Lougher #include <linux/bitops.h> 3081bb8debSPhillip Lougher 3181bb8debSPhillip Lougher #include "squashfs_fs.h" 3281bb8debSPhillip Lougher #include "squashfs_fs_sb.h" 3381bb8debSPhillip Lougher #include "squashfs_fs_i.h" 3481bb8debSPhillip Lougher #include "squashfs.h" 3581bb8debSPhillip Lougher #include "decompressor.h" 3681bb8debSPhillip Lougher 3781bb8debSPhillip Lougher struct squashfs_xz { 3881bb8debSPhillip Lougher struct xz_dec *state; 3981bb8debSPhillip Lougher struct xz_buf buf; 4081bb8debSPhillip Lougher }; 4181bb8debSPhillip Lougher 42ff750311SPhillip Lougher struct comp_opts { 43ff750311SPhillip Lougher __le32 dictionary_size; 44ff750311SPhillip Lougher __le32 flags; 45ff750311SPhillip Lougher }; 46ff750311SPhillip Lougher 47b7fc0ff0SPhillip Lougher static void *squashfs_xz_init(struct squashfs_sb_info *msblk, void *buff, 48b7fc0ff0SPhillip Lougher int len) 4981bb8debSPhillip Lougher { 50ff750311SPhillip Lougher struct comp_opts *comp_opts = buff; 51ff750311SPhillip Lougher struct squashfs_xz *stream; 52ff750311SPhillip Lougher int dict_size = msblk->block_size; 53ff750311SPhillip Lougher int err, n; 5481bb8debSPhillip Lougher 55ff750311SPhillip Lougher if (comp_opts) { 56ff750311SPhillip Lougher /* check compressor options are the expected length */ 57ff750311SPhillip Lougher if (len < sizeof(*comp_opts)) { 58ff750311SPhillip Lougher err = -EIO; 5981bb8debSPhillip Lougher goto failed; 60ff750311SPhillip Lougher } 6181bb8debSPhillip Lougher 62ff750311SPhillip Lougher dict_size = le32_to_cpu(comp_opts->dictionary_size); 63ff750311SPhillip Lougher 64ff750311SPhillip Lougher /* the dictionary size should be 2^n or 2^n+2^(n+1) */ 65ff750311SPhillip Lougher n = ffs(dict_size) - 1; 66ff750311SPhillip Lougher if (dict_size != (1 << n) && dict_size != (1 << n) + 67ff750311SPhillip Lougher (1 << (n + 1))) { 68ff750311SPhillip Lougher err = -EIO; 6981bb8debSPhillip Lougher goto failed; 70ff750311SPhillip Lougher } 71ff750311SPhillip Lougher } 72ff750311SPhillip Lougher 73ff750311SPhillip Lougher dict_size = max_t(int, dict_size, SQUASHFS_METADATA_SIZE); 74ff750311SPhillip Lougher 75ff750311SPhillip Lougher stream = kmalloc(sizeof(*stream), GFP_KERNEL); 76ff750311SPhillip Lougher if (stream == NULL) { 77ff750311SPhillip Lougher err = -ENOMEM; 78ff750311SPhillip Lougher goto failed; 79ff750311SPhillip Lougher } 80ff750311SPhillip Lougher 81ff750311SPhillip Lougher stream->state = xz_dec_init(XZ_PREALLOC, dict_size); 82ff750311SPhillip Lougher if (stream->state == NULL) { 83ff750311SPhillip Lougher kfree(stream); 84ff750311SPhillip Lougher err = -ENOMEM; 85ff750311SPhillip Lougher goto failed; 86ff750311SPhillip Lougher } 8781bb8debSPhillip Lougher 8881bb8debSPhillip Lougher return stream; 8981bb8debSPhillip Lougher 9081bb8debSPhillip Lougher failed: 91ff750311SPhillip Lougher ERROR("Failed to initialise xz decompressor\n"); 92ff750311SPhillip Lougher return ERR_PTR(err); 9381bb8debSPhillip Lougher } 9481bb8debSPhillip Lougher 9581bb8debSPhillip Lougher 9681bb8debSPhillip Lougher static void squashfs_xz_free(void *strm) 9781bb8debSPhillip Lougher { 9881bb8debSPhillip Lougher struct squashfs_xz *stream = strm; 9981bb8debSPhillip Lougher 10081bb8debSPhillip Lougher if (stream) { 10181bb8debSPhillip Lougher xz_dec_end(stream->state); 10281bb8debSPhillip Lougher kfree(stream); 10381bb8debSPhillip Lougher } 10481bb8debSPhillip Lougher } 10581bb8debSPhillip Lougher 10681bb8debSPhillip Lougher 10781bb8debSPhillip Lougher static int squashfs_xz_uncompress(struct squashfs_sb_info *msblk, void **buffer, 10881bb8debSPhillip Lougher struct buffer_head **bh, int b, int offset, int length, int srclength, 10981bb8debSPhillip Lougher int pages) 11081bb8debSPhillip Lougher { 11181bb8debSPhillip Lougher enum xz_ret xz_err; 11281bb8debSPhillip Lougher int avail, total = 0, k = 0, page = 0; 11381bb8debSPhillip Lougher struct squashfs_xz *stream = msblk->stream; 11481bb8debSPhillip Lougher 11581bb8debSPhillip Lougher mutex_lock(&msblk->read_data_mutex); 11681bb8debSPhillip Lougher 11781bb8debSPhillip Lougher xz_dec_reset(stream->state); 11881bb8debSPhillip Lougher stream->buf.in_pos = 0; 11981bb8debSPhillip Lougher stream->buf.in_size = 0; 12081bb8debSPhillip Lougher stream->buf.out_pos = 0; 12181bb8debSPhillip Lougher stream->buf.out_size = PAGE_CACHE_SIZE; 12281bb8debSPhillip Lougher stream->buf.out = buffer[page++]; 12381bb8debSPhillip Lougher 12481bb8debSPhillip Lougher do { 12581bb8debSPhillip Lougher if (stream->buf.in_pos == stream->buf.in_size && k < b) { 12681bb8debSPhillip Lougher avail = min(length, msblk->devblksize - offset); 12781bb8debSPhillip Lougher length -= avail; 12881bb8debSPhillip Lougher wait_on_buffer(bh[k]); 12981bb8debSPhillip Lougher if (!buffer_uptodate(bh[k])) 13081bb8debSPhillip Lougher goto release_mutex; 13181bb8debSPhillip Lougher 13281bb8debSPhillip Lougher stream->buf.in = bh[k]->b_data + offset; 13381bb8debSPhillip Lougher stream->buf.in_size = avail; 13481bb8debSPhillip Lougher stream->buf.in_pos = 0; 13581bb8debSPhillip Lougher offset = 0; 13681bb8debSPhillip Lougher } 13781bb8debSPhillip Lougher 13881bb8debSPhillip Lougher if (stream->buf.out_pos == stream->buf.out_size 13981bb8debSPhillip Lougher && page < pages) { 14081bb8debSPhillip Lougher stream->buf.out = buffer[page++]; 14181bb8debSPhillip Lougher stream->buf.out_pos = 0; 14281bb8debSPhillip Lougher total += PAGE_CACHE_SIZE; 14381bb8debSPhillip Lougher } 14481bb8debSPhillip Lougher 14581bb8debSPhillip Lougher xz_err = xz_dec_run(stream->state, &stream->buf); 14681bb8debSPhillip Lougher 14781bb8debSPhillip Lougher if (stream->buf.in_pos == stream->buf.in_size && k < b) 14881bb8debSPhillip Lougher put_bh(bh[k++]); 14981bb8debSPhillip Lougher } while (xz_err == XZ_OK); 15081bb8debSPhillip Lougher 15181bb8debSPhillip Lougher if (xz_err != XZ_STREAM_END) { 15281bb8debSPhillip Lougher ERROR("xz_dec_run error, data probably corrupt\n"); 15381bb8debSPhillip Lougher goto release_mutex; 15481bb8debSPhillip Lougher } 15581bb8debSPhillip Lougher 15681bb8debSPhillip Lougher if (k < b) { 15781bb8debSPhillip Lougher ERROR("xz_uncompress error, input remaining\n"); 15881bb8debSPhillip Lougher goto release_mutex; 15981bb8debSPhillip Lougher } 16081bb8debSPhillip Lougher 16181bb8debSPhillip Lougher total += stream->buf.out_pos; 16281bb8debSPhillip Lougher mutex_unlock(&msblk->read_data_mutex); 16381bb8debSPhillip Lougher return total; 16481bb8debSPhillip Lougher 16581bb8debSPhillip Lougher release_mutex: 16681bb8debSPhillip Lougher mutex_unlock(&msblk->read_data_mutex); 16781bb8debSPhillip Lougher 16881bb8debSPhillip Lougher for (; k < b; k++) 16981bb8debSPhillip Lougher put_bh(bh[k]); 17081bb8debSPhillip Lougher 17181bb8debSPhillip Lougher return -EIO; 17281bb8debSPhillip Lougher } 17381bb8debSPhillip Lougher 17481bb8debSPhillip Lougher const struct squashfs_decompressor squashfs_xz_comp_ops = { 17581bb8debSPhillip Lougher .init = squashfs_xz_init, 17681bb8debSPhillip Lougher .free = squashfs_xz_free, 17781bb8debSPhillip Lougher .decompress = squashfs_xz_uncompress, 17881bb8debSPhillip Lougher .id = XZ_COMPRESSION, 17981bb8debSPhillip Lougher .name = "xz", 18081bb8debSPhillip Lougher .supported = 1 18181bb8debSPhillip Lougher }; 182