1e2780ab1SPhillip Lougher /* 2e2780ab1SPhillip Lougher * Squashfs - a compressed read only filesystem for Linux 3e2780ab1SPhillip Lougher * 4e2780ab1SPhillip Lougher * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008 5e2780ab1SPhillip Lougher * Phillip Lougher <phillip@lougher.demon.co.uk> 6e2780ab1SPhillip Lougher * 7e2780ab1SPhillip Lougher * This program is free software; you can redistribute it and/or 8e2780ab1SPhillip Lougher * modify it under the terms of the GNU General Public License 9e2780ab1SPhillip Lougher * as published by the Free Software Foundation; either version 2, 10e2780ab1SPhillip Lougher * or (at your option) any later version. 11e2780ab1SPhillip Lougher * 12e2780ab1SPhillip Lougher * This program is distributed in the hope that it will be useful, 13e2780ab1SPhillip Lougher * but WITHOUT ANY WARRANTY; without even the implied warranty of 14e2780ab1SPhillip Lougher * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15e2780ab1SPhillip Lougher * GNU General Public License for more details. 16e2780ab1SPhillip Lougher * 17e2780ab1SPhillip Lougher * You should have received a copy of the GNU General Public License 18e2780ab1SPhillip Lougher * along with this program; if not, write to the Free Software 19e2780ab1SPhillip Lougher * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 20e2780ab1SPhillip Lougher * 21e2780ab1SPhillip Lougher * block.c 22e2780ab1SPhillip Lougher */ 23e2780ab1SPhillip Lougher 24e2780ab1SPhillip Lougher /* 25e2780ab1SPhillip Lougher * This file implements the low-level routines to read and decompress 26e2780ab1SPhillip Lougher * datablocks and metadata blocks. 27e2780ab1SPhillip Lougher */ 28e2780ab1SPhillip Lougher 29e2780ab1SPhillip Lougher #include <linux/fs.h> 30e2780ab1SPhillip Lougher #include <linux/vfs.h> 31e2780ab1SPhillip Lougher #include <linux/slab.h> 32e2780ab1SPhillip Lougher #include <linux/mutex.h> 33e2780ab1SPhillip Lougher #include <linux/string.h> 34e2780ab1SPhillip Lougher #include <linux/buffer_head.h> 35e2780ab1SPhillip Lougher #include <linux/zlib.h> 36e2780ab1SPhillip Lougher 37e2780ab1SPhillip Lougher #include "squashfs_fs.h" 38e2780ab1SPhillip Lougher #include "squashfs_fs_sb.h" 39e2780ab1SPhillip Lougher #include "squashfs_fs_i.h" 40e2780ab1SPhillip Lougher #include "squashfs.h" 41e2780ab1SPhillip Lougher 42e2780ab1SPhillip Lougher /* 43e2780ab1SPhillip Lougher * Read the metadata block length, this is stored in the first two 44e2780ab1SPhillip Lougher * bytes of the metadata block. 45e2780ab1SPhillip Lougher */ 46e2780ab1SPhillip Lougher static struct buffer_head *get_block_length(struct super_block *sb, 47e2780ab1SPhillip Lougher u64 *cur_index, int *offset, int *length) 48e2780ab1SPhillip Lougher { 49e2780ab1SPhillip Lougher struct squashfs_sb_info *msblk = sb->s_fs_info; 50e2780ab1SPhillip Lougher struct buffer_head *bh; 51e2780ab1SPhillip Lougher 52e2780ab1SPhillip Lougher bh = sb_bread(sb, *cur_index); 53e2780ab1SPhillip Lougher if (bh == NULL) 54e2780ab1SPhillip Lougher return NULL; 55e2780ab1SPhillip Lougher 56e2780ab1SPhillip Lougher if (msblk->devblksize - *offset == 1) { 57e2780ab1SPhillip Lougher *length = (unsigned char) bh->b_data[*offset]; 58e2780ab1SPhillip Lougher put_bh(bh); 59e2780ab1SPhillip Lougher bh = sb_bread(sb, ++(*cur_index)); 60e2780ab1SPhillip Lougher if (bh == NULL) 61e2780ab1SPhillip Lougher return NULL; 62e2780ab1SPhillip Lougher *length |= (unsigned char) bh->b_data[0] << 8; 63e2780ab1SPhillip Lougher *offset = 1; 64e2780ab1SPhillip Lougher } else { 65e2780ab1SPhillip Lougher *length = (unsigned char) bh->b_data[*offset] | 66e2780ab1SPhillip Lougher (unsigned char) bh->b_data[*offset + 1] << 8; 67e2780ab1SPhillip Lougher *offset += 2; 68e2780ab1SPhillip Lougher } 69e2780ab1SPhillip Lougher 70e2780ab1SPhillip Lougher return bh; 71e2780ab1SPhillip Lougher } 72e2780ab1SPhillip Lougher 73e2780ab1SPhillip Lougher 74e2780ab1SPhillip Lougher /* 75e2780ab1SPhillip Lougher * Read and decompress a metadata block or datablock. Length is non-zero 76e2780ab1SPhillip Lougher * if a datablock is being read (the size is stored elsewhere in the 77e2780ab1SPhillip Lougher * filesystem), otherwise the length is obtained from the first two bytes of 78e2780ab1SPhillip Lougher * the metadata block. A bit in the length field indicates if the block 79e2780ab1SPhillip Lougher * is stored uncompressed in the filesystem (usually because compression 80e2780ab1SPhillip Lougher * generated a larger block - this does occasionally happen with zlib). 81e2780ab1SPhillip Lougher */ 82e2780ab1SPhillip Lougher int squashfs_read_data(struct super_block *sb, void **buffer, u64 index, 83e2780ab1SPhillip Lougher int length, u64 *next_index, int srclength) 84e2780ab1SPhillip Lougher { 85e2780ab1SPhillip Lougher struct squashfs_sb_info *msblk = sb->s_fs_info; 86e2780ab1SPhillip Lougher struct buffer_head **bh; 87e2780ab1SPhillip Lougher int offset = index & ((1 << msblk->devblksize_log2) - 1); 88e2780ab1SPhillip Lougher u64 cur_index = index >> msblk->devblksize_log2; 89e2780ab1SPhillip Lougher int bytes, compressed, b = 0, k = 0, page = 0, avail; 90e2780ab1SPhillip Lougher 91e2780ab1SPhillip Lougher 92e2780ab1SPhillip Lougher bh = kcalloc((msblk->block_size >> msblk->devblksize_log2) + 1, 93e2780ab1SPhillip Lougher sizeof(*bh), GFP_KERNEL); 94e2780ab1SPhillip Lougher if (bh == NULL) 95e2780ab1SPhillip Lougher return -ENOMEM; 96e2780ab1SPhillip Lougher 97e2780ab1SPhillip Lougher if (length) { 98e2780ab1SPhillip Lougher /* 99e2780ab1SPhillip Lougher * Datablock. 100e2780ab1SPhillip Lougher */ 101e2780ab1SPhillip Lougher bytes = -offset; 102e2780ab1SPhillip Lougher compressed = SQUASHFS_COMPRESSED_BLOCK(length); 103e2780ab1SPhillip Lougher length = SQUASHFS_COMPRESSED_SIZE_BLOCK(length); 104e2780ab1SPhillip Lougher if (next_index) 105e2780ab1SPhillip Lougher *next_index = index + length; 106e2780ab1SPhillip Lougher 107e2780ab1SPhillip Lougher TRACE("Block @ 0x%llx, %scompressed size %d, src size %d\n", 108e2780ab1SPhillip Lougher index, compressed ? "" : "un", length, srclength); 109e2780ab1SPhillip Lougher 110e2780ab1SPhillip Lougher if (length < 0 || length > srclength || 111e2780ab1SPhillip Lougher (index + length) > msblk->bytes_used) 112e2780ab1SPhillip Lougher goto read_failure; 113e2780ab1SPhillip Lougher 114e2780ab1SPhillip Lougher for (b = 0; bytes < length; b++, cur_index++) { 115e2780ab1SPhillip Lougher bh[b] = sb_getblk(sb, cur_index); 116e2780ab1SPhillip Lougher if (bh[b] == NULL) 117e2780ab1SPhillip Lougher goto block_release; 118e2780ab1SPhillip Lougher bytes += msblk->devblksize; 119e2780ab1SPhillip Lougher } 120e2780ab1SPhillip Lougher ll_rw_block(READ, b, bh); 121e2780ab1SPhillip Lougher } else { 122e2780ab1SPhillip Lougher /* 123e2780ab1SPhillip Lougher * Metadata block. 124e2780ab1SPhillip Lougher */ 125e2780ab1SPhillip Lougher if ((index + 2) > msblk->bytes_used) 126e2780ab1SPhillip Lougher goto read_failure; 127e2780ab1SPhillip Lougher 128e2780ab1SPhillip Lougher bh[0] = get_block_length(sb, &cur_index, &offset, &length); 129e2780ab1SPhillip Lougher if (bh[0] == NULL) 130e2780ab1SPhillip Lougher goto read_failure; 131e2780ab1SPhillip Lougher b = 1; 132e2780ab1SPhillip Lougher 133e2780ab1SPhillip Lougher bytes = msblk->devblksize - offset; 134e2780ab1SPhillip Lougher compressed = SQUASHFS_COMPRESSED(length); 135e2780ab1SPhillip Lougher length = SQUASHFS_COMPRESSED_SIZE(length); 136e2780ab1SPhillip Lougher if (next_index) 137e2780ab1SPhillip Lougher *next_index = index + length + 2; 138e2780ab1SPhillip Lougher 139e2780ab1SPhillip Lougher TRACE("Block @ 0x%llx, %scompressed size %d\n", index, 140e2780ab1SPhillip Lougher compressed ? "" : "un", length); 141e2780ab1SPhillip Lougher 142e2780ab1SPhillip Lougher if (length < 0 || length > srclength || 143e2780ab1SPhillip Lougher (index + length) > msblk->bytes_used) 144e2780ab1SPhillip Lougher goto block_release; 145e2780ab1SPhillip Lougher 146e2780ab1SPhillip Lougher for (; bytes < length; b++) { 147e2780ab1SPhillip Lougher bh[b] = sb_getblk(sb, ++cur_index); 148e2780ab1SPhillip Lougher if (bh[b] == NULL) 149e2780ab1SPhillip Lougher goto block_release; 150e2780ab1SPhillip Lougher bytes += msblk->devblksize; 151e2780ab1SPhillip Lougher } 152e2780ab1SPhillip Lougher ll_rw_block(READ, b - 1, bh + 1); 153e2780ab1SPhillip Lougher } 154e2780ab1SPhillip Lougher 155e2780ab1SPhillip Lougher if (compressed) { 156e2780ab1SPhillip Lougher int zlib_err = 0, zlib_init = 0; 157e2780ab1SPhillip Lougher 158e2780ab1SPhillip Lougher /* 159e2780ab1SPhillip Lougher * Uncompress block. 160e2780ab1SPhillip Lougher */ 161e2780ab1SPhillip Lougher 162e2780ab1SPhillip Lougher mutex_lock(&msblk->read_data_mutex); 163e2780ab1SPhillip Lougher 164e2780ab1SPhillip Lougher msblk->stream.avail_out = 0; 165e2780ab1SPhillip Lougher msblk->stream.avail_in = 0; 166e2780ab1SPhillip Lougher 167e2780ab1SPhillip Lougher bytes = length; 168e2780ab1SPhillip Lougher do { 169e2780ab1SPhillip Lougher if (msblk->stream.avail_in == 0 && k < b) { 170e2780ab1SPhillip Lougher avail = min(bytes, msblk->devblksize - offset); 171e2780ab1SPhillip Lougher bytes -= avail; 172e2780ab1SPhillip Lougher wait_on_buffer(bh[k]); 173e2780ab1SPhillip Lougher if (!buffer_uptodate(bh[k])) 174e2780ab1SPhillip Lougher goto release_mutex; 175e2780ab1SPhillip Lougher 176e2780ab1SPhillip Lougher if (avail == 0) { 177e2780ab1SPhillip Lougher offset = 0; 178e2780ab1SPhillip Lougher put_bh(bh[k++]); 179e2780ab1SPhillip Lougher continue; 180e2780ab1SPhillip Lougher } 181e2780ab1SPhillip Lougher 182e2780ab1SPhillip Lougher msblk->stream.next_in = bh[k]->b_data + offset; 183e2780ab1SPhillip Lougher msblk->stream.avail_in = avail; 184e2780ab1SPhillip Lougher offset = 0; 185e2780ab1SPhillip Lougher } 186e2780ab1SPhillip Lougher 187e2780ab1SPhillip Lougher if (msblk->stream.avail_out == 0) { 188e2780ab1SPhillip Lougher msblk->stream.next_out = buffer[page++]; 189e2780ab1SPhillip Lougher msblk->stream.avail_out = PAGE_CACHE_SIZE; 190e2780ab1SPhillip Lougher } 191e2780ab1SPhillip Lougher 192e2780ab1SPhillip Lougher if (!zlib_init) { 193e2780ab1SPhillip Lougher zlib_err = zlib_inflateInit(&msblk->stream); 194e2780ab1SPhillip Lougher if (zlib_err != Z_OK) { 195e2780ab1SPhillip Lougher ERROR("zlib_inflateInit returned" 196e2780ab1SPhillip Lougher " unexpected result 0x%x," 197e2780ab1SPhillip Lougher " srclength %d\n", zlib_err, 198e2780ab1SPhillip Lougher srclength); 199e2780ab1SPhillip Lougher goto release_mutex; 200e2780ab1SPhillip Lougher } 201e2780ab1SPhillip Lougher zlib_init = 1; 202e2780ab1SPhillip Lougher } 203e2780ab1SPhillip Lougher 204e2780ab1SPhillip Lougher zlib_err = zlib_inflate(&msblk->stream, Z_NO_FLUSH); 205e2780ab1SPhillip Lougher 206e2780ab1SPhillip Lougher if (msblk->stream.avail_in == 0 && k < b) 207e2780ab1SPhillip Lougher put_bh(bh[k++]); 208e2780ab1SPhillip Lougher } while (zlib_err == Z_OK); 209e2780ab1SPhillip Lougher 210e2780ab1SPhillip Lougher if (zlib_err != Z_STREAM_END) { 211e2780ab1SPhillip Lougher ERROR("zlib_inflate returned unexpected result" 212e2780ab1SPhillip Lougher " 0x%x, srclength %d, avail_in %d," 213e2780ab1SPhillip Lougher " avail_out %d\n", zlib_err, srclength, 214e2780ab1SPhillip Lougher msblk->stream.avail_in, 215e2780ab1SPhillip Lougher msblk->stream.avail_out); 216e2780ab1SPhillip Lougher goto release_mutex; 217e2780ab1SPhillip Lougher } 218e2780ab1SPhillip Lougher 219e2780ab1SPhillip Lougher zlib_err = zlib_inflateEnd(&msblk->stream); 220e2780ab1SPhillip Lougher if (zlib_err != Z_OK) { 221e2780ab1SPhillip Lougher ERROR("zlib_inflateEnd returned unexpected result 0x%x," 222e2780ab1SPhillip Lougher " srclength %d\n", zlib_err, srclength); 223e2780ab1SPhillip Lougher goto release_mutex; 224e2780ab1SPhillip Lougher } 225e2780ab1SPhillip Lougher length = msblk->stream.total_out; 226e2780ab1SPhillip Lougher mutex_unlock(&msblk->read_data_mutex); 227e2780ab1SPhillip Lougher } else { 228e2780ab1SPhillip Lougher /* 229e2780ab1SPhillip Lougher * Block is uncompressed. 230e2780ab1SPhillip Lougher */ 231e2780ab1SPhillip Lougher int i, in, pg_offset = 0; 232e2780ab1SPhillip Lougher 233e2780ab1SPhillip Lougher for (i = 0; i < b; i++) { 234e2780ab1SPhillip Lougher wait_on_buffer(bh[i]); 235e2780ab1SPhillip Lougher if (!buffer_uptodate(bh[i])) 236e2780ab1SPhillip Lougher goto block_release; 237e2780ab1SPhillip Lougher } 238e2780ab1SPhillip Lougher 239e2780ab1SPhillip Lougher for (bytes = length; k < b; k++) { 240e2780ab1SPhillip Lougher in = min(bytes, msblk->devblksize - offset); 241e2780ab1SPhillip Lougher bytes -= in; 242e2780ab1SPhillip Lougher while (in) { 243e2780ab1SPhillip Lougher if (pg_offset == PAGE_CACHE_SIZE) { 244e2780ab1SPhillip Lougher page++; 245e2780ab1SPhillip Lougher pg_offset = 0; 246e2780ab1SPhillip Lougher } 247e2780ab1SPhillip Lougher avail = min_t(int, in, PAGE_CACHE_SIZE - 248e2780ab1SPhillip Lougher pg_offset); 249e2780ab1SPhillip Lougher memcpy(buffer[page] + pg_offset, 250e2780ab1SPhillip Lougher bh[k]->b_data + offset, avail); 251e2780ab1SPhillip Lougher in -= avail; 252e2780ab1SPhillip Lougher pg_offset += avail; 253e2780ab1SPhillip Lougher offset += avail; 254e2780ab1SPhillip Lougher } 255e2780ab1SPhillip Lougher offset = 0; 256e2780ab1SPhillip Lougher put_bh(bh[k]); 257e2780ab1SPhillip Lougher } 258e2780ab1SPhillip Lougher } 259e2780ab1SPhillip Lougher 260e2780ab1SPhillip Lougher kfree(bh); 261e2780ab1SPhillip Lougher return length; 262e2780ab1SPhillip Lougher 263e2780ab1SPhillip Lougher release_mutex: 264e2780ab1SPhillip Lougher mutex_unlock(&msblk->read_data_mutex); 265e2780ab1SPhillip Lougher 266e2780ab1SPhillip Lougher block_release: 267e2780ab1SPhillip Lougher for (; k < b; k++) 268e2780ab1SPhillip Lougher put_bh(bh[k]); 269e2780ab1SPhillip Lougher 270e2780ab1SPhillip Lougher read_failure: 271e2780ab1SPhillip Lougher ERROR("sb_bread failed reading block 0x%llx\n", cur_index); 272e2780ab1SPhillip Lougher kfree(bh); 273e2780ab1SPhillip Lougher return -EIO; 274e2780ab1SPhillip Lougher } 275