block.c revision f6e22234d60d71a19b598a257de6355ffa1e999e
13cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher/*
23cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher * Squashfs - a compressed read only filesystem for Linux
33cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher *
43cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008
53cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher * Phillip Lougher <phillip@lougher.demon.co.uk>
63cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher *
73cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher * This program is free software; you can redistribute it and/or
83cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher * modify it under the terms of the GNU General Public License
93cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher * as published by the Free Software Foundation; either version 2,
103cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher * or (at your option) any later version.
113cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher *
123cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher * This program is distributed in the hope that it will be useful,
133cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher * but WITHOUT ANY WARRANTY; without even the implied warranty of
143cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
153cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher * GNU General Public License for more details.
163cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher *
173cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher * You should have received a copy of the GNU General Public License
183cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher * along with this program; if not, write to the Free Software
193cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
203cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher *
213cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher * block.c
223cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher */
233cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher
24c6893b04297e3a4c3eaaf4560563cfe87e9a6b56plougher#include <linux/fs.h>
25c6893b04297e3a4c3eaaf4560563cfe87e9a6b56plougher#include <linux/vfs.h>
26c6893b04297e3a4c3eaaf4560563cfe87e9a6b56plougher#include <linux/slab.h>
27c6893b04297e3a4c3eaaf4560563cfe87e9a6b56plougher#include <linux/mutex.h>
28c6893b04297e3a4c3eaaf4560563cfe87e9a6b56plougher#include <linux/string.h>
29e10248a420914a7c6092fc02b803cf3dac5b432dplougher#include <linux/buffer_head.h>
30c6893b04297e3a4c3eaaf4560563cfe87e9a6b56plougher#include <linux/zlib.h>
31e10248a420914a7c6092fc02b803cf3dac5b432dplougher#include <linux/squashfs_fs.h>
323cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher#include <linux/squashfs_fs_sb.h>
333cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher#include <linux/squashfs_fs_i.h>
343cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher
353cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher#include "squashfs.h"
36e10248a420914a7c6092fc02b803cf3dac5b432dplougher
373cb299277b04dfdb6fe21768b8f83dec1f4014b6plougherstatic struct buffer_head *get_block_length(struct super_block *s,
38f6e22234d60d71a19b598a257de6355ffa1e999eplougher			int *cur_index, int *offset, unsigned int *length)
393cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher{
403cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher	struct squashfs_sb_info *msblk = s->s_fs_info;
413cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher	struct buffer_head *bh;
423cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher
4356d24bf18e169cc9de1499e63a99809b8fed08fbplougher	bh = sb_bread(s, *cur_index);
4456d24bf18e169cc9de1499e63a99809b8fed08fbplougher	if (bh == NULL)
453cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher		goto out;
463cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher
473cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher	if (msblk->devblksize - *offset == 1) {
48f6e22234d60d71a19b598a257de6355ffa1e999eplougher		*length = (unsigned char) bh->b_data[*offset];
493cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher		brelse(bh);
5056d24bf18e169cc9de1499e63a99809b8fed08fbplougher		bh = sb_bread(s, ++(*cur_index));
5156d24bf18e169cc9de1499e63a99809b8fed08fbplougher		if (bh == NULL)
523cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher			goto out;
53f6e22234d60d71a19b598a257de6355ffa1e999eplougher		*length |= (unsigned char) bh->b_data[0] << 8;
543cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher		*offset = 1;
553cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher	} else {
56f6e22234d60d71a19b598a257de6355ffa1e999eplougher		*length = (unsigned char) bh->b_data[*offset] |
57f6e22234d60d71a19b598a257de6355ffa1e999eplougher			(unsigned char) bh->b_data[*offset + 1] << 8;
583cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher		*offset += 2;
593cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher	}
603cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher
613cb299277b04dfdb6fe21768b8f83dec1f4014b6plougherout:
62f6e22234d60d71a19b598a257de6355ffa1e999eplougher	return bh;
633cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher}
643cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher
653cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher
66f6e22234d60d71a19b598a257de6355ffa1e999eplougher
67283a23fa5fff9cab6eb5f04e5c9d876cec74d908plougherunsigned int squashfs_read_data(struct super_block *s, void *buffer,
683cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher			long long index, unsigned int length,
693cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher			long long *next_index, int srclength)
703cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher{
713cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher	struct squashfs_sb_info *msblk = s->s_fs_info;
723cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher	struct buffer_head **bh;
733cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher	unsigned int offset = index & ((1 << msblk->devblksize_log2) - 1);
743cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher	unsigned int cur_index = index >> msblk->devblksize_log2;
7556d24bf18e169cc9de1499e63a99809b8fed08fbplougher	int bytes, avail, b = 0, k = 0;
763cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher	unsigned int compressed;
773cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher	unsigned int c_byte = length;
783cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher
79b000fa80a6a742b279c61398287698f837cbb14aplougher	bh = kmalloc(((msblk->block_size >> msblk->devblksize_log2) + 1) *
8056d24bf18e169cc9de1499e63a99809b8fed08fbplougher				sizeof(struct buffer_head *), GFP_KERNEL);
813cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher	if (bh == NULL)
823cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher		goto read_failure;
833cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher
843cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher	if (c_byte) {
853cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher		bytes = -offset;
863cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher		compressed = SQUASHFS_COMPRESSED_BLOCK(c_byte);
873cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher		c_byte = SQUASHFS_COMPRESSED_SIZE_BLOCK(c_byte);
883cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher
8956d24bf18e169cc9de1499e63a99809b8fed08fbplougher		TRACE("Block @ 0x%llx, %scompressed size %d, src size %d\n",
90f6e22234d60d71a19b598a257de6355ffa1e999eplougher			index, compressed ? "" : "un", c_byte, srclength);
913cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher
9256d24bf18e169cc9de1499e63a99809b8fed08fbplougher		if (c_byte > srclength || index < 0 ||
9356d24bf18e169cc9de1499e63a99809b8fed08fbplougher				(index + c_byte) > msblk->bytes_used)
943cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher			goto read_failure;
953cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher
963cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher		for (b = 0; bytes < (int) c_byte; b++, cur_index++) {
973cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher			bh[b] = sb_getblk(s, cur_index);
983cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher			if (bh[b] == NULL)
993cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher				goto block_release;
1003cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher			bytes += msblk->devblksize;
1013cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher		}
1023cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher		ll_rw_block(READ, b, bh);
1033cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher	} else {
104b000fa80a6a742b279c61398287698f837cbb14aplougher		if (index < 0 || (index + 2) > msblk->bytes_used)
1053cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher			goto read_failure;
1063cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher
1073cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher		bh[0] = get_block_length(s, &cur_index, &offset, &c_byte);
1083cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher		if (bh[0] == NULL)
1093cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher			goto read_failure;
1103cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher		b = 1;
1113cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher
1123cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher		bytes = msblk->devblksize - offset;
1133cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher		compressed = SQUASHFS_COMPRESSED(c_byte);
1143cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher		c_byte = SQUASHFS_COMPRESSED_SIZE(c_byte);
1153cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher
11656d24bf18e169cc9de1499e63a99809b8fed08fbplougher		TRACE("Block @ 0x%llx, %scompressed size %d\n", index,
117f6e22234d60d71a19b598a257de6355ffa1e999eplougher				compressed ? "" : "un", c_byte);
1183cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher
119b000fa80a6a742b279c61398287698f837cbb14aplougher		if (c_byte > srclength || (index + c_byte) > msblk->bytes_used)
1203cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher			goto block_release;
1213cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher
1223cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher		for (; bytes < c_byte; b++) {
1233cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher			bh[b] = sb_getblk(s, ++cur_index);
1243cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher			if (bh[b] == NULL)
1253cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher				goto block_release;
1263cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher			bytes += msblk->devblksize;
1273cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher		}
1283cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher		ll_rw_block(READ, b - 1, bh + 1);
1293cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher	}
1303cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher
1313cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher	if (compressed) {
1323cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher		int zlib_err = 0;
1333cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher
1343cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher		/*
13556d24bf18e169cc9de1499e63a99809b8fed08fbplougher		 * uncompress block
13656d24bf18e169cc9de1499e63a99809b8fed08fbplougher		 */
1373cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher
1383cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher		mutex_lock(&msblk->read_data_mutex);
1393cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher
1403cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher		msblk->stream.next_out = buffer;
1413cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher		msblk->stream.avail_out = srclength;
1423cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher
1433cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher		for (bytes = 0; k < b; k++) {
14456d24bf18e169cc9de1499e63a99809b8fed08fbplougher			avail = min(c_byte - bytes, msblk->devblksize - offset);
1453cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher
1463cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher			wait_on_buffer(bh[k]);
1473cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher			if (!buffer_uptodate(bh[k]))
1483cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher				goto release_mutex;
1493cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher
1503cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher			msblk->stream.next_in = bh[k]->b_data + offset;
15156d24bf18e169cc9de1499e63a99809b8fed08fbplougher			msblk->stream.avail_in = avail;
1523cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher
1533cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher			if (k == 0) {
1543cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher				zlib_err = zlib_inflateInit(&msblk->stream);
1553cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher				if (zlib_err != Z_OK) {
15656d24bf18e169cc9de1499e63a99809b8fed08fbplougher					ERROR("zlib_inflateInit returned"
15756d24bf18e169cc9de1499e63a99809b8fed08fbplougher						" unexpected result 0x%x,"
15856d24bf18e169cc9de1499e63a99809b8fed08fbplougher						" srclength %d\n", zlib_err,
15956d24bf18e169cc9de1499e63a99809b8fed08fbplougher						srclength);
1603cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher					goto release_mutex;
1613cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher				}
1623cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher
16356d24bf18e169cc9de1499e63a99809b8fed08fbplougher				if (avail == 0) {
1643cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher					offset = 0;
1653cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher					brelse(bh[k]);
1663cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher					continue;
1673cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher				}
1683cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher			}
1693cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher
1703cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher			zlib_err = zlib_inflate(&msblk->stream, Z_NO_FLUSH);
1713cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher			if (zlib_err != Z_OK && zlib_err != Z_STREAM_END) {
17256d24bf18e169cc9de1499e63a99809b8fed08fbplougher				ERROR("zlib_inflate returned unexpected result"
17356d24bf18e169cc9de1499e63a99809b8fed08fbplougher					" 0x%x, srclength %d, avail_in %d,"
17456d24bf18e169cc9de1499e63a99809b8fed08fbplougher					" avail_out %d\n", zlib_err, srclength,
17556d24bf18e169cc9de1499e63a99809b8fed08fbplougher					msblk->stream.avail_in,
17656d24bf18e169cc9de1499e63a99809b8fed08fbplougher					msblk->stream.avail_out);
1773cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher				goto release_mutex;
1783cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher			}
1793cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher
18056d24bf18e169cc9de1499e63a99809b8fed08fbplougher			bytes += avail;
1813cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher			offset = 0;
1823cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher			brelse(bh[k]);
1833cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher		}
1843cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher
1853cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher		if (zlib_err != Z_STREAM_END)
1863cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher			goto release_mutex;
1873cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher
1883cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher		zlib_err = zlib_inflateEnd(&msblk->stream);
1893cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher		if (zlib_err != Z_OK) {
1903cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher			ERROR("zlib_inflateEnd returned unexpected result 0x%x,"
1913cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher				" srclength %d\n", zlib_err, srclength);
1923cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher			goto release_mutex;
1933cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher		}
1943cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher		bytes = msblk->stream.total_out;
1953cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher		mutex_unlock(&msblk->read_data_mutex);
1963cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher	} else {
1973cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher		int i;
1983cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher
19956d24bf18e169cc9de1499e63a99809b8fed08fbplougher		for (i = 0; i < b; i++) {
2003cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher			wait_on_buffer(bh[i]);
2013cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher			if (!buffer_uptodate(bh[i]))
2023cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher				goto block_release;
2033cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher		}
2043cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher
2053cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher		for (bytes = 0; k < b; k++) {
20656d24bf18e169cc9de1499e63a99809b8fed08fbplougher			avail = min(c_byte - bytes, msblk->devblksize - offset);
2073cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher
20856d24bf18e169cc9de1499e63a99809b8fed08fbplougher			memcpy(buffer + bytes, bh[k]->b_data + offset, avail);
20956d24bf18e169cc9de1499e63a99809b8fed08fbplougher			bytes += avail;
2103cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher			offset = 0;
2113cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher			brelse(bh[k]);
2123cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher		}
2133cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher	}
2143cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher
2153cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher	if (next_index)
216b000fa80a6a742b279c61398287698f837cbb14aplougher		*next_index = index + c_byte + (length ? 0 : 2);
2173cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher
2183cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher	kfree(bh);
2193cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher	return bytes;
2203cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher
2213cb299277b04dfdb6fe21768b8f83dec1f4014b6plougherrelease_mutex:
2223cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher	mutex_unlock(&msblk->read_data_mutex);
2233cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher
2243cb299277b04dfdb6fe21768b8f83dec1f4014b6plougherblock_release:
2253cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher	for (; k < b; k++)
2263cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher		brelse(bh[k]);
2273cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher
2283cb299277b04dfdb6fe21768b8f83dec1f4014b6plougherread_failure:
2293cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher	ERROR("sb_bread failed reading block 0x%x\n", cur_index);
2303cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher	kfree(bh);
2313cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher	return 0;
2323cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher}
2333cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher
2343cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher
2353cb299277b04dfdb6fe21768b8f83dec1f4014b6plougherint squashfs_get_cached_block(struct super_block *s, void *buffer,
2363cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher				long long block, unsigned int offset,
2373cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher				int length, long long *next_block,
2383cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher				unsigned int *next_offset)
2393cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher{
2403cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher	struct squashfs_sb_info *msblk = s->s_fs_info;
2413cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher	int bytes, return_length = length;
2423cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher	struct squashfs_cache_entry *entry;
2433cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher
2443cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher	TRACE("Entered squashfs_get_cached_block [%llx:%x]\n", block, offset);
2453cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher
2463cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher	while (1) {
2473cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher		entry = squashfs_cache_get(s, msblk->block_cache, block, 0);
2483cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher		bytes = entry->length - offset;
2493cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher
2503cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher		if (entry->error || bytes < 1) {
2513cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher			return_length = 0;
2523cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher			goto finish;
2533cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher		} else if (bytes >= length) {
2543cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher			if (buffer)
2553cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher				memcpy(buffer, entry->data + offset, length);
2563cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher			if (entry->length - offset == length) {
2573cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher				*next_block = entry->next_index;
2583cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher				*next_offset = 0;
2593cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher			} else {
2603cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher				*next_block = block;
2613cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher				*next_offset = offset + length;
2623cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher			}
2633cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher			goto finish;
2643cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher		} else {
2653cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher			if (buffer) {
2663cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher				memcpy(buffer, entry->data + offset, bytes);
267f6e22234d60d71a19b598a257de6355ffa1e999eplougher				buffer += bytes;
2683cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher			}
2693cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher			block = entry->next_index;
2703cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher			squashfs_cache_put(msblk->block_cache, entry);
2713cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher			length -= bytes;
2723cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher			offset = 0;
2733cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher		}
2743cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher	}
2753cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher
2763cb299277b04dfdb6fe21768b8f83dec1f4014b6plougherfinish:
2773cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher	squashfs_cache_put(msblk->block_cache, entry);
2783cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher	return return_length;
2793cb299277b04dfdb6fe21768b8f83dec1f4014b6plougher}
280