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