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