xref: /aosp_15_r20/external/squashfs-tools/kernel-2.4/fs/squashfs/inode.c (revision 79398b2563bcbbbab54656397863972d8fa68df1)
1*79398b25SAndroid Build Coastguard Worker /*
2*79398b25SAndroid Build Coastguard Worker  * Squashfs - a compressed read only filesystem for Linux
3*79398b25SAndroid Build Coastguard Worker  *
4*79398b25SAndroid Build Coastguard Worker  * Copyright (c) 2002, 2003, 2004, 2005, 2006
5*79398b25SAndroid Build Coastguard Worker  * Phillip Lougher <[email protected]>
6*79398b25SAndroid Build Coastguard Worker  *
7*79398b25SAndroid Build Coastguard Worker  * This program is free software; you can redistribute it and/or
8*79398b25SAndroid Build Coastguard Worker  * modify it under the terms of the GNU General Public License
9*79398b25SAndroid Build Coastguard Worker  * as published by the Free Software Foundation; either version 2,
10*79398b25SAndroid Build Coastguard Worker  * or (at your option) any later version.
11*79398b25SAndroid Build Coastguard Worker  *
12*79398b25SAndroid Build Coastguard Worker  * This program is distributed in the hope that it will be useful,
13*79398b25SAndroid Build Coastguard Worker  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14*79398b25SAndroid Build Coastguard Worker  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15*79398b25SAndroid Build Coastguard Worker  * GNU General Public License for more details.
16*79398b25SAndroid Build Coastguard Worker  *
17*79398b25SAndroid Build Coastguard Worker  * You should have received a copy of the GNU General Public License
18*79398b25SAndroid Build Coastguard Worker  * along with this program; if not, write to the Free Software
19*79398b25SAndroid Build Coastguard Worker  * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20*79398b25SAndroid Build Coastguard Worker  *
21*79398b25SAndroid Build Coastguard Worker  * inode.c
22*79398b25SAndroid Build Coastguard Worker  */
23*79398b25SAndroid Build Coastguard Worker 
24*79398b25SAndroid Build Coastguard Worker #include <linux/types.h>
25*79398b25SAndroid Build Coastguard Worker #include <linux/squashfs_fs.h>
26*79398b25SAndroid Build Coastguard Worker #include <linux/module.h>
27*79398b25SAndroid Build Coastguard Worker #include <linux/errno.h>
28*79398b25SAndroid Build Coastguard Worker #include <linux/slab.h>
29*79398b25SAndroid Build Coastguard Worker #include <linux/zlib.h>
30*79398b25SAndroid Build Coastguard Worker #include <linux/fs.h>
31*79398b25SAndroid Build Coastguard Worker #include <linux/smp_lock.h>
32*79398b25SAndroid Build Coastguard Worker #include <linux/locks.h>
33*79398b25SAndroid Build Coastguard Worker #include <linux/init.h>
34*79398b25SAndroid Build Coastguard Worker #include <linux/dcache.h>
35*79398b25SAndroid Build Coastguard Worker #include <linux/wait.h>
36*79398b25SAndroid Build Coastguard Worker #include <linux/blkdev.h>
37*79398b25SAndroid Build Coastguard Worker #include <linux/vmalloc.h>
38*79398b25SAndroid Build Coastguard Worker #include <asm/uaccess.h>
39*79398b25SAndroid Build Coastguard Worker #include <asm/semaphore.h>
40*79398b25SAndroid Build Coastguard Worker 
41*79398b25SAndroid Build Coastguard Worker #include "squashfs.h"
42*79398b25SAndroid Build Coastguard Worker 
43*79398b25SAndroid Build Coastguard Worker static struct super_block *squashfs_read_super(struct super_block *, void *, int);
44*79398b25SAndroid Build Coastguard Worker static void squashfs_put_super(struct super_block *);
45*79398b25SAndroid Build Coastguard Worker static int squashfs_statfs(struct super_block *, struct statfs *);
46*79398b25SAndroid Build Coastguard Worker static int squashfs_symlink_readpage(struct file *file, struct page *page);
47*79398b25SAndroid Build Coastguard Worker static int squashfs_readpage(struct file *file, struct page *page);
48*79398b25SAndroid Build Coastguard Worker static int squashfs_readpage4K(struct file *file, struct page *page);
49*79398b25SAndroid Build Coastguard Worker static int squashfs_readdir(struct file *, void *, filldir_t);
50*79398b25SAndroid Build Coastguard Worker static struct dentry *squashfs_lookup(struct inode *, struct dentry *);
51*79398b25SAndroid Build Coastguard Worker static struct inode *squashfs_iget(struct super_block *s, squashfs_inode_t inode);
52*79398b25SAndroid Build Coastguard Worker static long long read_blocklist(struct inode *inode, int index,
53*79398b25SAndroid Build Coastguard Worker 				int readahead_blks, char *block_list,
54*79398b25SAndroid Build Coastguard Worker 				unsigned short **block_p, unsigned int *bsize);
55*79398b25SAndroid Build Coastguard Worker 
56*79398b25SAndroid Build Coastguard Worker static DECLARE_FSTYPE_DEV(squashfs_fs_type, "squashfs", squashfs_read_super);
57*79398b25SAndroid Build Coastguard Worker 
58*79398b25SAndroid Build Coastguard Worker static unsigned char squashfs_filetype_table[] = {
59*79398b25SAndroid Build Coastguard Worker 	DT_UNKNOWN, DT_DIR, DT_REG, DT_LNK, DT_BLK, DT_CHR, DT_FIFO, DT_SOCK
60*79398b25SAndroid Build Coastguard Worker };
61*79398b25SAndroid Build Coastguard Worker 
62*79398b25SAndroid Build Coastguard Worker static struct super_operations squashfs_ops = {
63*79398b25SAndroid Build Coastguard Worker 	.statfs = squashfs_statfs,
64*79398b25SAndroid Build Coastguard Worker 	.put_super = squashfs_put_super,
65*79398b25SAndroid Build Coastguard Worker };
66*79398b25SAndroid Build Coastguard Worker 
67*79398b25SAndroid Build Coastguard Worker SQSH_EXTERN struct address_space_operations squashfs_symlink_aops = {
68*79398b25SAndroid Build Coastguard Worker 	.readpage = squashfs_symlink_readpage
69*79398b25SAndroid Build Coastguard Worker };
70*79398b25SAndroid Build Coastguard Worker 
71*79398b25SAndroid Build Coastguard Worker SQSH_EXTERN struct address_space_operations squashfs_aops = {
72*79398b25SAndroid Build Coastguard Worker 	.readpage = squashfs_readpage
73*79398b25SAndroid Build Coastguard Worker };
74*79398b25SAndroid Build Coastguard Worker 
75*79398b25SAndroid Build Coastguard Worker SQSH_EXTERN struct address_space_operations squashfs_aops_4K = {
76*79398b25SAndroid Build Coastguard Worker 	.readpage = squashfs_readpage4K
77*79398b25SAndroid Build Coastguard Worker };
78*79398b25SAndroid Build Coastguard Worker 
79*79398b25SAndroid Build Coastguard Worker static struct file_operations squashfs_dir_ops = {
80*79398b25SAndroid Build Coastguard Worker 	.read = generic_read_dir,
81*79398b25SAndroid Build Coastguard Worker 	.readdir = squashfs_readdir
82*79398b25SAndroid Build Coastguard Worker };
83*79398b25SAndroid Build Coastguard Worker 
84*79398b25SAndroid Build Coastguard Worker static struct inode_operations squashfs_dir_inode_ops = {
85*79398b25SAndroid Build Coastguard Worker 	.lookup = squashfs_lookup
86*79398b25SAndroid Build Coastguard Worker };
87*79398b25SAndroid Build Coastguard Worker 
get_block_length(struct super_block * s,int * cur_index,int * offset,int * c_byte)88*79398b25SAndroid Build Coastguard Worker static struct buffer_head *get_block_length(struct super_block *s,
89*79398b25SAndroid Build Coastguard Worker 				int *cur_index, int *offset, int *c_byte)
90*79398b25SAndroid Build Coastguard Worker {
91*79398b25SAndroid Build Coastguard Worker 	struct squashfs_sb_info *msblk = &s->u.squashfs_sb;
92*79398b25SAndroid Build Coastguard Worker 	unsigned short temp;
93*79398b25SAndroid Build Coastguard Worker 	struct buffer_head *bh;
94*79398b25SAndroid Build Coastguard Worker 
95*79398b25SAndroid Build Coastguard Worker 	if (!(bh = sb_bread(s, *cur_index)))
96*79398b25SAndroid Build Coastguard Worker 		goto out;
97*79398b25SAndroid Build Coastguard Worker 
98*79398b25SAndroid Build Coastguard Worker 	if (msblk->devblksize - *offset == 1) {
99*79398b25SAndroid Build Coastguard Worker 		if (msblk->swap)
100*79398b25SAndroid Build Coastguard Worker 			((unsigned char *) &temp)[1] = *((unsigned char *)
101*79398b25SAndroid Build Coastguard Worker 				(bh->b_data + *offset));
102*79398b25SAndroid Build Coastguard Worker 		else
103*79398b25SAndroid Build Coastguard Worker 			((unsigned char *) &temp)[0] = *((unsigned char *)
104*79398b25SAndroid Build Coastguard Worker 				(bh->b_data + *offset));
105*79398b25SAndroid Build Coastguard Worker 		brelse(bh);
106*79398b25SAndroid Build Coastguard Worker 		if (!(bh = sb_bread(s, ++(*cur_index))))
107*79398b25SAndroid Build Coastguard Worker 			goto out;
108*79398b25SAndroid Build Coastguard Worker 		if (msblk->swap)
109*79398b25SAndroid Build Coastguard Worker 			((unsigned char *) &temp)[0] = *((unsigned char *)
110*79398b25SAndroid Build Coastguard Worker 				bh->b_data);
111*79398b25SAndroid Build Coastguard Worker 		else
112*79398b25SAndroid Build Coastguard Worker 			((unsigned char *) &temp)[1] = *((unsigned char *)
113*79398b25SAndroid Build Coastguard Worker 				bh->b_data);
114*79398b25SAndroid Build Coastguard Worker 		*c_byte = temp;
115*79398b25SAndroid Build Coastguard Worker 		*offset = 1;
116*79398b25SAndroid Build Coastguard Worker 	} else {
117*79398b25SAndroid Build Coastguard Worker 		if (msblk->swap) {
118*79398b25SAndroid Build Coastguard Worker 			((unsigned char *) &temp)[1] = *((unsigned char *)
119*79398b25SAndroid Build Coastguard Worker 				(bh->b_data + *offset));
120*79398b25SAndroid Build Coastguard Worker 			((unsigned char *) &temp)[0] = *((unsigned char *)
121*79398b25SAndroid Build Coastguard Worker 				(bh->b_data + *offset + 1));
122*79398b25SAndroid Build Coastguard Worker 		} else {
123*79398b25SAndroid Build Coastguard Worker 			((unsigned char *) &temp)[0] = *((unsigned char *)
124*79398b25SAndroid Build Coastguard Worker 				(bh->b_data + *offset));
125*79398b25SAndroid Build Coastguard Worker 			((unsigned char *) &temp)[1] = *((unsigned char *)
126*79398b25SAndroid Build Coastguard Worker 				(bh->b_data + *offset + 1));
127*79398b25SAndroid Build Coastguard Worker 		}
128*79398b25SAndroid Build Coastguard Worker 		*c_byte = temp;
129*79398b25SAndroid Build Coastguard Worker 		*offset += 2;
130*79398b25SAndroid Build Coastguard Worker 	}
131*79398b25SAndroid Build Coastguard Worker 
132*79398b25SAndroid Build Coastguard Worker 	if (SQUASHFS_CHECK_DATA(msblk->sblk.flags)) {
133*79398b25SAndroid Build Coastguard Worker 		if (*offset == msblk->devblksize) {
134*79398b25SAndroid Build Coastguard Worker 			brelse(bh);
135*79398b25SAndroid Build Coastguard Worker 			if (!(bh = sb_bread(s, ++(*cur_index))))
136*79398b25SAndroid Build Coastguard Worker 				goto out;
137*79398b25SAndroid Build Coastguard Worker 			*offset = 0;
138*79398b25SAndroid Build Coastguard Worker 		}
139*79398b25SAndroid Build Coastguard Worker 		if (*((unsigned char *) (bh->b_data + *offset)) !=
140*79398b25SAndroid Build Coastguard Worker 						SQUASHFS_MARKER_BYTE) {
141*79398b25SAndroid Build Coastguard Worker 			ERROR("Metadata block marker corrupt @ %x\n",
142*79398b25SAndroid Build Coastguard Worker 						*cur_index);
143*79398b25SAndroid Build Coastguard Worker 			brelse(bh);
144*79398b25SAndroid Build Coastguard Worker 			goto out;
145*79398b25SAndroid Build Coastguard Worker 		}
146*79398b25SAndroid Build Coastguard Worker 		(*offset)++;
147*79398b25SAndroid Build Coastguard Worker 	}
148*79398b25SAndroid Build Coastguard Worker 	return bh;
149*79398b25SAndroid Build Coastguard Worker 
150*79398b25SAndroid Build Coastguard Worker out:
151*79398b25SAndroid Build Coastguard Worker 	return NULL;
152*79398b25SAndroid Build Coastguard Worker }
153*79398b25SAndroid Build Coastguard Worker 
154*79398b25SAndroid Build Coastguard Worker 
squashfs_read_data(struct super_block * s,char * buffer,long long index,unsigned int length,long long * next_index)155*79398b25SAndroid Build Coastguard Worker SQSH_EXTERN unsigned int squashfs_read_data(struct super_block *s, char *buffer,
156*79398b25SAndroid Build Coastguard Worker 			long long index, unsigned int length,
157*79398b25SAndroid Build Coastguard Worker 			long long *next_index)
158*79398b25SAndroid Build Coastguard Worker {
159*79398b25SAndroid Build Coastguard Worker 	struct squashfs_sb_info *msblk = &s->u.squashfs_sb;
160*79398b25SAndroid Build Coastguard Worker 	struct buffer_head *bh[((SQUASHFS_FILE_MAX_SIZE - 1) >>
161*79398b25SAndroid Build Coastguard Worker 			msblk->devblksize_log2) + 2];
162*79398b25SAndroid Build Coastguard Worker 	unsigned int offset = index & ((1 << msblk->devblksize_log2) - 1);
163*79398b25SAndroid Build Coastguard Worker 	unsigned int cur_index = index >> msblk->devblksize_log2;
164*79398b25SAndroid Build Coastguard Worker 	int bytes, avail_bytes, b = 0, k;
165*79398b25SAndroid Build Coastguard Worker 	char *c_buffer;
166*79398b25SAndroid Build Coastguard Worker 	unsigned int compressed;
167*79398b25SAndroid Build Coastguard Worker 	unsigned int c_byte = length;
168*79398b25SAndroid Build Coastguard Worker 
169*79398b25SAndroid Build Coastguard Worker 	if (c_byte) {
170*79398b25SAndroid Build Coastguard Worker 		bytes = msblk->devblksize - offset;
171*79398b25SAndroid Build Coastguard Worker 		compressed = SQUASHFS_COMPRESSED_BLOCK(c_byte);
172*79398b25SAndroid Build Coastguard Worker 		c_buffer = compressed ? msblk->read_data : buffer;
173*79398b25SAndroid Build Coastguard Worker 		c_byte = SQUASHFS_COMPRESSED_SIZE_BLOCK(c_byte);
174*79398b25SAndroid Build Coastguard Worker 
175*79398b25SAndroid Build Coastguard Worker 		TRACE("Block @ 0x%llx, %scompressed size %d\n", index, compressed
176*79398b25SAndroid Build Coastguard Worker 					? "" : "un", (unsigned int) c_byte);
177*79398b25SAndroid Build Coastguard Worker 
178*79398b25SAndroid Build Coastguard Worker 		if (!(bh[0] = sb_getblk(s, cur_index)))
179*79398b25SAndroid Build Coastguard Worker 			goto block_release;
180*79398b25SAndroid Build Coastguard Worker 
181*79398b25SAndroid Build Coastguard Worker 		for (b = 1; bytes < c_byte; b++) {
182*79398b25SAndroid Build Coastguard Worker 			if (!(bh[b] = sb_getblk(s, ++cur_index)))
183*79398b25SAndroid Build Coastguard Worker 				goto block_release;
184*79398b25SAndroid Build Coastguard Worker 			bytes += msblk->devblksize;
185*79398b25SAndroid Build Coastguard Worker 		}
186*79398b25SAndroid Build Coastguard Worker 		ll_rw_block(READ, b, bh);
187*79398b25SAndroid Build Coastguard Worker 	} else {
188*79398b25SAndroid Build Coastguard Worker 		if (!(bh[0] = get_block_length(s, &cur_index, &offset,
189*79398b25SAndroid Build Coastguard Worker 								&c_byte)))
190*79398b25SAndroid Build Coastguard Worker 			goto read_failure;
191*79398b25SAndroid Build Coastguard Worker 
192*79398b25SAndroid Build Coastguard Worker 		bytes = msblk->devblksize - offset;
193*79398b25SAndroid Build Coastguard Worker 		compressed = SQUASHFS_COMPRESSED(c_byte);
194*79398b25SAndroid Build Coastguard Worker 		c_buffer = compressed ? msblk->read_data : buffer;
195*79398b25SAndroid Build Coastguard Worker 		c_byte = SQUASHFS_COMPRESSED_SIZE(c_byte);
196*79398b25SAndroid Build Coastguard Worker 
197*79398b25SAndroid Build Coastguard Worker 		TRACE("Block @ 0x%llx, %scompressed size %d\n", index, compressed
198*79398b25SAndroid Build Coastguard Worker 					? "" : "un", (unsigned int) c_byte);
199*79398b25SAndroid Build Coastguard Worker 
200*79398b25SAndroid Build Coastguard Worker 		for (b = 1; bytes < c_byte; b++) {
201*79398b25SAndroid Build Coastguard Worker 			if (!(bh[b] = sb_getblk(s, ++cur_index)))
202*79398b25SAndroid Build Coastguard Worker 				goto block_release;
203*79398b25SAndroid Build Coastguard Worker 			bytes += msblk->devblksize;
204*79398b25SAndroid Build Coastguard Worker 		}
205*79398b25SAndroid Build Coastguard Worker 		ll_rw_block(READ, b - 1, bh + 1);
206*79398b25SAndroid Build Coastguard Worker 	}
207*79398b25SAndroid Build Coastguard Worker 
208*79398b25SAndroid Build Coastguard Worker 	if (compressed)
209*79398b25SAndroid Build Coastguard Worker 		down(&msblk->read_data_mutex);
210*79398b25SAndroid Build Coastguard Worker 
211*79398b25SAndroid Build Coastguard Worker 	for (bytes = 0, k = 0; k < b; k++) {
212*79398b25SAndroid Build Coastguard Worker 		avail_bytes = (c_byte - bytes) > (msblk->devblksize - offset) ?
213*79398b25SAndroid Build Coastguard Worker 					msblk->devblksize - offset :
214*79398b25SAndroid Build Coastguard Worker 					c_byte - bytes;
215*79398b25SAndroid Build Coastguard Worker 		wait_on_buffer(bh[k]);
216*79398b25SAndroid Build Coastguard Worker 		if (!buffer_uptodate(bh[k]))
217*79398b25SAndroid Build Coastguard Worker 			goto block_release;
218*79398b25SAndroid Build Coastguard Worker 		memcpy(c_buffer + bytes, bh[k]->b_data + offset, avail_bytes);
219*79398b25SAndroid Build Coastguard Worker 		bytes += avail_bytes;
220*79398b25SAndroid Build Coastguard Worker 		offset = 0;
221*79398b25SAndroid Build Coastguard Worker 		brelse(bh[k]);
222*79398b25SAndroid Build Coastguard Worker 	}
223*79398b25SAndroid Build Coastguard Worker 
224*79398b25SAndroid Build Coastguard Worker 	/*
225*79398b25SAndroid Build Coastguard Worker 	 * uncompress block
226*79398b25SAndroid Build Coastguard Worker 	 */
227*79398b25SAndroid Build Coastguard Worker 	if (compressed) {
228*79398b25SAndroid Build Coastguard Worker 		int zlib_err;
229*79398b25SAndroid Build Coastguard Worker 
230*79398b25SAndroid Build Coastguard Worker 		msblk->stream.next_in = c_buffer;
231*79398b25SAndroid Build Coastguard Worker 		msblk->stream.avail_in = c_byte;
232*79398b25SAndroid Build Coastguard Worker 		msblk->stream.next_out = buffer;
233*79398b25SAndroid Build Coastguard Worker 		msblk->stream.avail_out = msblk->read_size;
234*79398b25SAndroid Build Coastguard Worker 
235*79398b25SAndroid Build Coastguard Worker 		if (((zlib_err = zlib_inflateInit(&msblk->stream)) != Z_OK) ||
236*79398b25SAndroid Build Coastguard Worker 				((zlib_err = zlib_inflate(&msblk->stream, Z_FINISH))
237*79398b25SAndroid Build Coastguard Worker 				 != Z_STREAM_END) || ((zlib_err =
238*79398b25SAndroid Build Coastguard Worker 				zlib_inflateEnd(&msblk->stream)) != Z_OK)) {
239*79398b25SAndroid Build Coastguard Worker 			ERROR("zlib_fs returned unexpected result 0x%x\n",
240*79398b25SAndroid Build Coastguard Worker 				zlib_err);
241*79398b25SAndroid Build Coastguard Worker 			bytes = 0;
242*79398b25SAndroid Build Coastguard Worker 		} else
243*79398b25SAndroid Build Coastguard Worker 			bytes = msblk->stream.total_out;
244*79398b25SAndroid Build Coastguard Worker 
245*79398b25SAndroid Build Coastguard Worker 		up(&msblk->read_data_mutex);
246*79398b25SAndroid Build Coastguard Worker 	}
247*79398b25SAndroid Build Coastguard Worker 
248*79398b25SAndroid Build Coastguard Worker 	if (next_index)
249*79398b25SAndroid Build Coastguard Worker 		*next_index = index + c_byte + (length ? 0 :
250*79398b25SAndroid Build Coastguard Worker 				(SQUASHFS_CHECK_DATA(msblk->sblk.flags)
251*79398b25SAndroid Build Coastguard Worker 				 ? 3 : 2));
252*79398b25SAndroid Build Coastguard Worker 	return bytes;
253*79398b25SAndroid Build Coastguard Worker 
254*79398b25SAndroid Build Coastguard Worker block_release:
255*79398b25SAndroid Build Coastguard Worker 	while (--b >= 0)
256*79398b25SAndroid Build Coastguard Worker 		brelse(bh[b]);
257*79398b25SAndroid Build Coastguard Worker 
258*79398b25SAndroid Build Coastguard Worker read_failure:
259*79398b25SAndroid Build Coastguard Worker 	ERROR("sb_bread failed reading block 0x%x\n", cur_index);
260*79398b25SAndroid Build Coastguard Worker 	return 0;
261*79398b25SAndroid Build Coastguard Worker }
262*79398b25SAndroid Build Coastguard Worker 
263*79398b25SAndroid Build Coastguard Worker 
squashfs_get_cached_block(struct super_block * s,char * buffer,long long block,unsigned int offset,int length,long long * next_block,unsigned int * next_offset)264*79398b25SAndroid Build Coastguard Worker SQSH_EXTERN int squashfs_get_cached_block(struct super_block *s, char *buffer,
265*79398b25SAndroid Build Coastguard Worker 				long long block, unsigned int offset,
266*79398b25SAndroid Build Coastguard Worker 				int length, long long *next_block,
267*79398b25SAndroid Build Coastguard Worker 				unsigned int *next_offset)
268*79398b25SAndroid Build Coastguard Worker {
269*79398b25SAndroid Build Coastguard Worker 	struct squashfs_sb_info *msblk = &s->u.squashfs_sb;
270*79398b25SAndroid Build Coastguard Worker 	int n, i, bytes, return_length = length;
271*79398b25SAndroid Build Coastguard Worker 	long long next_index;
272*79398b25SAndroid Build Coastguard Worker 
273*79398b25SAndroid Build Coastguard Worker 	TRACE("Entered squashfs_get_cached_block [%llx:%x]\n", block, offset);
274*79398b25SAndroid Build Coastguard Worker 
275*79398b25SAndroid Build Coastguard Worker 	while ( 1 ) {
276*79398b25SAndroid Build Coastguard Worker 		for (i = 0; i < SQUASHFS_CACHED_BLKS; i++)
277*79398b25SAndroid Build Coastguard Worker 			if (msblk->block_cache[i].block == block)
278*79398b25SAndroid Build Coastguard Worker 				break;
279*79398b25SAndroid Build Coastguard Worker 
280*79398b25SAndroid Build Coastguard Worker 		down(&msblk->block_cache_mutex);
281*79398b25SAndroid Build Coastguard Worker 
282*79398b25SAndroid Build Coastguard Worker 		if (i == SQUASHFS_CACHED_BLKS) {
283*79398b25SAndroid Build Coastguard Worker 			/* read inode header block */
284*79398b25SAndroid Build Coastguard Worker 			for (i = msblk->next_cache, n = SQUASHFS_CACHED_BLKS;
285*79398b25SAndroid Build Coastguard Worker 					n ; n --, i = (i + 1) %
286*79398b25SAndroid Build Coastguard Worker 					SQUASHFS_CACHED_BLKS)
287*79398b25SAndroid Build Coastguard Worker 				if (msblk->block_cache[i].block !=
288*79398b25SAndroid Build Coastguard Worker 							SQUASHFS_USED_BLK)
289*79398b25SAndroid Build Coastguard Worker 					break;
290*79398b25SAndroid Build Coastguard Worker 
291*79398b25SAndroid Build Coastguard Worker 			if (n == 0) {
292*79398b25SAndroid Build Coastguard Worker 				wait_queue_t wait;
293*79398b25SAndroid Build Coastguard Worker 
294*79398b25SAndroid Build Coastguard Worker 				init_waitqueue_entry(&wait, current);
295*79398b25SAndroid Build Coastguard Worker 				add_wait_queue(&msblk->waitq, &wait);
296*79398b25SAndroid Build Coastguard Worker 				set_current_state(TASK_UNINTERRUPTIBLE);
297*79398b25SAndroid Build Coastguard Worker  				up(&msblk->block_cache_mutex);
298*79398b25SAndroid Build Coastguard Worker 				schedule();
299*79398b25SAndroid Build Coastguard Worker 				set_current_state(TASK_RUNNING);
300*79398b25SAndroid Build Coastguard Worker 				remove_wait_queue(&msblk->waitq, &wait);
301*79398b25SAndroid Build Coastguard Worker 				continue;
302*79398b25SAndroid Build Coastguard Worker 			}
303*79398b25SAndroid Build Coastguard Worker 			msblk->next_cache = (i + 1) % SQUASHFS_CACHED_BLKS;
304*79398b25SAndroid Build Coastguard Worker 
305*79398b25SAndroid Build Coastguard Worker 			if (msblk->block_cache[i].block ==
306*79398b25SAndroid Build Coastguard Worker 							SQUASHFS_INVALID_BLK) {
307*79398b25SAndroid Build Coastguard Worker 				if (!(msblk->block_cache[i].data =
308*79398b25SAndroid Build Coastguard Worker 						kmalloc(SQUASHFS_METADATA_SIZE,
309*79398b25SAndroid Build Coastguard Worker 						GFP_KERNEL))) {
310*79398b25SAndroid Build Coastguard Worker 					ERROR("Failed to allocate cache"
311*79398b25SAndroid Build Coastguard Worker 							"block\n");
312*79398b25SAndroid Build Coastguard Worker 					up(&msblk->block_cache_mutex);
313*79398b25SAndroid Build Coastguard Worker 					goto out;
314*79398b25SAndroid Build Coastguard Worker 				}
315*79398b25SAndroid Build Coastguard Worker 			}
316*79398b25SAndroid Build Coastguard Worker 
317*79398b25SAndroid Build Coastguard Worker 			msblk->block_cache[i].block = SQUASHFS_USED_BLK;
318*79398b25SAndroid Build Coastguard Worker 			up(&msblk->block_cache_mutex);
319*79398b25SAndroid Build Coastguard Worker 
320*79398b25SAndroid Build Coastguard Worker 			if (!(msblk->block_cache[i].length =
321*79398b25SAndroid Build Coastguard Worker 						squashfs_read_data(s,
322*79398b25SAndroid Build Coastguard Worker 						msblk->block_cache[i].data,
323*79398b25SAndroid Build Coastguard Worker 						block, 0, &next_index))) {
324*79398b25SAndroid Build Coastguard Worker 				ERROR("Unable to read cache block [%llx:%x]\n",
325*79398b25SAndroid Build Coastguard Worker 						block, offset);
326*79398b25SAndroid Build Coastguard Worker 				goto out;
327*79398b25SAndroid Build Coastguard Worker 			}
328*79398b25SAndroid Build Coastguard Worker 
329*79398b25SAndroid Build Coastguard Worker 			down(&msblk->block_cache_mutex);
330*79398b25SAndroid Build Coastguard Worker 			wake_up(&msblk->waitq);
331*79398b25SAndroid Build Coastguard Worker 			msblk->block_cache[i].block = block;
332*79398b25SAndroid Build Coastguard Worker 			msblk->block_cache[i].next_index = next_index;
333*79398b25SAndroid Build Coastguard Worker 			TRACE("Read cache block [%llx:%x]\n", block, offset);
334*79398b25SAndroid Build Coastguard Worker 		}
335*79398b25SAndroid Build Coastguard Worker 
336*79398b25SAndroid Build Coastguard Worker 		if (msblk->block_cache[i].block != block) {
337*79398b25SAndroid Build Coastguard Worker 			up(&msblk->block_cache_mutex);
338*79398b25SAndroid Build Coastguard Worker 			continue;
339*79398b25SAndroid Build Coastguard Worker 		}
340*79398b25SAndroid Build Coastguard Worker 
341*79398b25SAndroid Build Coastguard Worker 		if ((bytes = msblk->block_cache[i].length - offset) >= length) {
342*79398b25SAndroid Build Coastguard Worker 			if (buffer)
343*79398b25SAndroid Build Coastguard Worker 				memcpy(buffer, msblk->block_cache[i].data +
344*79398b25SAndroid Build Coastguard Worker 						offset, length);
345*79398b25SAndroid Build Coastguard Worker 			if (msblk->block_cache[i].length - offset == length) {
346*79398b25SAndroid Build Coastguard Worker 				*next_block = msblk->block_cache[i].next_index;
347*79398b25SAndroid Build Coastguard Worker 				*next_offset = 0;
348*79398b25SAndroid Build Coastguard Worker 			} else {
349*79398b25SAndroid Build Coastguard Worker 				*next_block = block;
350*79398b25SAndroid Build Coastguard Worker 				*next_offset = offset + length;
351*79398b25SAndroid Build Coastguard Worker 			}
352*79398b25SAndroid Build Coastguard Worker 			up(&msblk->block_cache_mutex);
353*79398b25SAndroid Build Coastguard Worker 			goto finish;
354*79398b25SAndroid Build Coastguard Worker 		} else {
355*79398b25SAndroid Build Coastguard Worker 			if (buffer) {
356*79398b25SAndroid Build Coastguard Worker 				memcpy(buffer, msblk->block_cache[i].data +
357*79398b25SAndroid Build Coastguard Worker 						offset, bytes);
358*79398b25SAndroid Build Coastguard Worker 				buffer += bytes;
359*79398b25SAndroid Build Coastguard Worker 			}
360*79398b25SAndroid Build Coastguard Worker 			block = msblk->block_cache[i].next_index;
361*79398b25SAndroid Build Coastguard Worker 			up(&msblk->block_cache_mutex);
362*79398b25SAndroid Build Coastguard Worker 			length -= bytes;
363*79398b25SAndroid Build Coastguard Worker 			offset = 0;
364*79398b25SAndroid Build Coastguard Worker 		}
365*79398b25SAndroid Build Coastguard Worker 	}
366*79398b25SAndroid Build Coastguard Worker 
367*79398b25SAndroid Build Coastguard Worker finish:
368*79398b25SAndroid Build Coastguard Worker 	return return_length;
369*79398b25SAndroid Build Coastguard Worker out:
370*79398b25SAndroid Build Coastguard Worker 	return 0;
371*79398b25SAndroid Build Coastguard Worker }
372*79398b25SAndroid Build Coastguard Worker 
373*79398b25SAndroid Build Coastguard Worker 
get_fragment_location(struct super_block * s,unsigned int fragment,long long * fragment_start_block,unsigned int * fragment_size)374*79398b25SAndroid Build Coastguard Worker static int get_fragment_location(struct super_block *s, unsigned int fragment,
375*79398b25SAndroid Build Coastguard Worker 				long long *fragment_start_block,
376*79398b25SAndroid Build Coastguard Worker 				unsigned int *fragment_size)
377*79398b25SAndroid Build Coastguard Worker {
378*79398b25SAndroid Build Coastguard Worker 	struct squashfs_sb_info *msblk = &s->u.squashfs_sb;
379*79398b25SAndroid Build Coastguard Worker 	long long start_block =
380*79398b25SAndroid Build Coastguard Worker 		msblk->fragment_index[SQUASHFS_FRAGMENT_INDEX(fragment)];
381*79398b25SAndroid Build Coastguard Worker 	int offset = SQUASHFS_FRAGMENT_INDEX_OFFSET(fragment);
382*79398b25SAndroid Build Coastguard Worker 	struct squashfs_fragment_entry fragment_entry;
383*79398b25SAndroid Build Coastguard Worker 
384*79398b25SAndroid Build Coastguard Worker 	if (msblk->swap) {
385*79398b25SAndroid Build Coastguard Worker 		struct squashfs_fragment_entry sfragment_entry;
386*79398b25SAndroid Build Coastguard Worker 
387*79398b25SAndroid Build Coastguard Worker 		if (!squashfs_get_cached_block(s, (char *) &sfragment_entry,
388*79398b25SAndroid Build Coastguard Worker 					start_block, offset,
389*79398b25SAndroid Build Coastguard Worker 					sizeof(sfragment_entry), &start_block,
390*79398b25SAndroid Build Coastguard Worker 					&offset))
391*79398b25SAndroid Build Coastguard Worker 			goto out;
392*79398b25SAndroid Build Coastguard Worker 		SQUASHFS_SWAP_FRAGMENT_ENTRY(&fragment_entry, &sfragment_entry);
393*79398b25SAndroid Build Coastguard Worker 	} else
394*79398b25SAndroid Build Coastguard Worker 		if (!squashfs_get_cached_block(s, (char *) &fragment_entry,
395*79398b25SAndroid Build Coastguard Worker 					start_block, offset,
396*79398b25SAndroid Build Coastguard Worker 					sizeof(fragment_entry), &start_block,
397*79398b25SAndroid Build Coastguard Worker 					&offset))
398*79398b25SAndroid Build Coastguard Worker 			goto out;
399*79398b25SAndroid Build Coastguard Worker 
400*79398b25SAndroid Build Coastguard Worker 	*fragment_start_block = fragment_entry.start_block;
401*79398b25SAndroid Build Coastguard Worker 	*fragment_size = fragment_entry.size;
402*79398b25SAndroid Build Coastguard Worker 
403*79398b25SAndroid Build Coastguard Worker 	return 1;
404*79398b25SAndroid Build Coastguard Worker 
405*79398b25SAndroid Build Coastguard Worker out:
406*79398b25SAndroid Build Coastguard Worker 	return 0;
407*79398b25SAndroid Build Coastguard Worker }
408*79398b25SAndroid Build Coastguard Worker 
409*79398b25SAndroid Build Coastguard Worker 
release_cached_fragment(struct squashfs_sb_info * msblk,struct squashfs_fragment_cache * fragment)410*79398b25SAndroid Build Coastguard Worker SQSH_EXTERN void release_cached_fragment(struct squashfs_sb_info *msblk, struct
411*79398b25SAndroid Build Coastguard Worker 					squashfs_fragment_cache *fragment)
412*79398b25SAndroid Build Coastguard Worker {
413*79398b25SAndroid Build Coastguard Worker 	down(&msblk->fragment_mutex);
414*79398b25SAndroid Build Coastguard Worker 	fragment->locked --;
415*79398b25SAndroid Build Coastguard Worker 	wake_up(&msblk->fragment_wait_queue);
416*79398b25SAndroid Build Coastguard Worker 	up(&msblk->fragment_mutex);
417*79398b25SAndroid Build Coastguard Worker }
418*79398b25SAndroid Build Coastguard Worker 
419*79398b25SAndroid Build Coastguard Worker 
get_cached_fragment(struct super_block * s,long long start_block,int length)420*79398b25SAndroid Build Coastguard Worker SQSH_EXTERN struct squashfs_fragment_cache *get_cached_fragment(struct super_block
421*79398b25SAndroid Build Coastguard Worker 					*s, long long start_block,
422*79398b25SAndroid Build Coastguard Worker 					int length)
423*79398b25SAndroid Build Coastguard Worker {
424*79398b25SAndroid Build Coastguard Worker 	int i, n;
425*79398b25SAndroid Build Coastguard Worker 	struct squashfs_sb_info *msblk = &s->u.squashfs_sb;
426*79398b25SAndroid Build Coastguard Worker 
427*79398b25SAndroid Build Coastguard Worker 	while ( 1 ) {
428*79398b25SAndroid Build Coastguard Worker 		down(&msblk->fragment_mutex);
429*79398b25SAndroid Build Coastguard Worker 
430*79398b25SAndroid Build Coastguard Worker 		for (i = 0; i < SQUASHFS_CACHED_FRAGMENTS &&
431*79398b25SAndroid Build Coastguard Worker 				msblk->fragment[i].block != start_block; i++);
432*79398b25SAndroid Build Coastguard Worker 
433*79398b25SAndroid Build Coastguard Worker 		if (i == SQUASHFS_CACHED_FRAGMENTS) {
434*79398b25SAndroid Build Coastguard Worker 			for (i = msblk->next_fragment, n =
435*79398b25SAndroid Build Coastguard Worker 				SQUASHFS_CACHED_FRAGMENTS; n &&
436*79398b25SAndroid Build Coastguard Worker 				msblk->fragment[i].locked; n--, i = (i + 1) %
437*79398b25SAndroid Build Coastguard Worker 				SQUASHFS_CACHED_FRAGMENTS);
438*79398b25SAndroid Build Coastguard Worker 
439*79398b25SAndroid Build Coastguard Worker 			if (n == 0) {
440*79398b25SAndroid Build Coastguard Worker 				wait_queue_t wait;
441*79398b25SAndroid Build Coastguard Worker 
442*79398b25SAndroid Build Coastguard Worker 				init_waitqueue_entry(&wait, current);
443*79398b25SAndroid Build Coastguard Worker 				add_wait_queue(&msblk->fragment_wait_queue,
444*79398b25SAndroid Build Coastguard Worker 									&wait);
445*79398b25SAndroid Build Coastguard Worker 				set_current_state(TASK_UNINTERRUPTIBLE);
446*79398b25SAndroid Build Coastguard Worker 				up(&msblk->fragment_mutex);
447*79398b25SAndroid Build Coastguard Worker 				schedule();
448*79398b25SAndroid Build Coastguard Worker 				set_current_state(TASK_RUNNING);
449*79398b25SAndroid Build Coastguard Worker 				remove_wait_queue(&msblk->fragment_wait_queue,
450*79398b25SAndroid Build Coastguard Worker 									&wait);
451*79398b25SAndroid Build Coastguard Worker 				continue;
452*79398b25SAndroid Build Coastguard Worker 			}
453*79398b25SAndroid Build Coastguard Worker 			msblk->next_fragment = (msblk->next_fragment + 1) %
454*79398b25SAndroid Build Coastguard Worker 				SQUASHFS_CACHED_FRAGMENTS;
455*79398b25SAndroid Build Coastguard Worker 
456*79398b25SAndroid Build Coastguard Worker 			if (msblk->fragment[i].data == NULL)
457*79398b25SAndroid Build Coastguard Worker 				if (!(msblk->fragment[i].data = SQUASHFS_ALLOC
458*79398b25SAndroid Build Coastguard Worker 						(SQUASHFS_FILE_MAX_SIZE))) {
459*79398b25SAndroid Build Coastguard Worker 					ERROR("Failed to allocate fragment "
460*79398b25SAndroid Build Coastguard Worker 							"cache block\n");
461*79398b25SAndroid Build Coastguard Worker 					up(&msblk->fragment_mutex);
462*79398b25SAndroid Build Coastguard Worker 					goto out;
463*79398b25SAndroid Build Coastguard Worker 				}
464*79398b25SAndroid Build Coastguard Worker 
465*79398b25SAndroid Build Coastguard Worker 			msblk->fragment[i].block = SQUASHFS_INVALID_BLK;
466*79398b25SAndroid Build Coastguard Worker 			msblk->fragment[i].locked = 1;
467*79398b25SAndroid Build Coastguard Worker 			up(&msblk->fragment_mutex);
468*79398b25SAndroid Build Coastguard Worker 
469*79398b25SAndroid Build Coastguard Worker 			if (!(msblk->fragment[i].length = squashfs_read_data(s,
470*79398b25SAndroid Build Coastguard Worker 						msblk->fragment[i].data,
471*79398b25SAndroid Build Coastguard Worker 						start_block, length, NULL))) {
472*79398b25SAndroid Build Coastguard Worker 				ERROR("Unable to read fragment cache block "
473*79398b25SAndroid Build Coastguard Worker 							"[%llx]\n", start_block);
474*79398b25SAndroid Build Coastguard Worker 				msblk->fragment[i].locked = 0;
475*79398b25SAndroid Build Coastguard Worker 				goto out;
476*79398b25SAndroid Build Coastguard Worker 			}
477*79398b25SAndroid Build Coastguard Worker 
478*79398b25SAndroid Build Coastguard Worker 			msblk->fragment[i].block = start_block;
479*79398b25SAndroid Build Coastguard Worker 			TRACE("New fragment %d, start block %lld, locked %d\n",
480*79398b25SAndroid Build Coastguard Worker 						i, msblk->fragment[i].block,
481*79398b25SAndroid Build Coastguard Worker 						msblk->fragment[i].locked);
482*79398b25SAndroid Build Coastguard Worker 			break;
483*79398b25SAndroid Build Coastguard Worker 		}
484*79398b25SAndroid Build Coastguard Worker 
485*79398b25SAndroid Build Coastguard Worker 		msblk->fragment[i].locked++;
486*79398b25SAndroid Build Coastguard Worker 		up(&msblk->fragment_mutex);
487*79398b25SAndroid Build Coastguard Worker 		TRACE("Got fragment %d, start block %lld, locked %d\n", i,
488*79398b25SAndroid Build Coastguard Worker 						msblk->fragment[i].block,
489*79398b25SAndroid Build Coastguard Worker 						msblk->fragment[i].locked);
490*79398b25SAndroid Build Coastguard Worker 		break;
491*79398b25SAndroid Build Coastguard Worker 	}
492*79398b25SAndroid Build Coastguard Worker 
493*79398b25SAndroid Build Coastguard Worker 	return &msblk->fragment[i];
494*79398b25SAndroid Build Coastguard Worker 
495*79398b25SAndroid Build Coastguard Worker out:
496*79398b25SAndroid Build Coastguard Worker 	return NULL;
497*79398b25SAndroid Build Coastguard Worker }
498*79398b25SAndroid Build Coastguard Worker 
499*79398b25SAndroid Build Coastguard Worker 
squashfs_new_inode(struct super_block * s,struct squashfs_base_inode_header * inodeb)500*79398b25SAndroid Build Coastguard Worker static struct inode *squashfs_new_inode(struct super_block *s,
501*79398b25SAndroid Build Coastguard Worker 		struct squashfs_base_inode_header *inodeb)
502*79398b25SAndroid Build Coastguard Worker {
503*79398b25SAndroid Build Coastguard Worker 	struct squashfs_sb_info *msblk = &s->u.squashfs_sb;
504*79398b25SAndroid Build Coastguard Worker 	struct inode *i = new_inode(s);
505*79398b25SAndroid Build Coastguard Worker 
506*79398b25SAndroid Build Coastguard Worker 	if (i) {
507*79398b25SAndroid Build Coastguard Worker 		i->i_ino = inodeb->inode_number;
508*79398b25SAndroid Build Coastguard Worker 		i->i_mtime = inodeb->mtime;
509*79398b25SAndroid Build Coastguard Worker 		i->i_atime = inodeb->mtime;
510*79398b25SAndroid Build Coastguard Worker 		i->i_ctime = inodeb->mtime;
511*79398b25SAndroid Build Coastguard Worker 		i->i_uid = msblk->uid[inodeb->uid];
512*79398b25SAndroid Build Coastguard Worker 		i->i_mode = inodeb->mode;
513*79398b25SAndroid Build Coastguard Worker 		i->i_size = 0;
514*79398b25SAndroid Build Coastguard Worker 		if (inodeb->guid == SQUASHFS_GUIDS)
515*79398b25SAndroid Build Coastguard Worker 			i->i_gid = i->i_uid;
516*79398b25SAndroid Build Coastguard Worker 		else
517*79398b25SAndroid Build Coastguard Worker 			i->i_gid = msblk->guid[inodeb->guid];
518*79398b25SAndroid Build Coastguard Worker 	}
519*79398b25SAndroid Build Coastguard Worker 
520*79398b25SAndroid Build Coastguard Worker 	return i;
521*79398b25SAndroid Build Coastguard Worker }
522*79398b25SAndroid Build Coastguard Worker 
523*79398b25SAndroid Build Coastguard Worker 
squashfs_iget(struct super_block * s,squashfs_inode_t inode)524*79398b25SAndroid Build Coastguard Worker static struct inode *squashfs_iget(struct super_block *s, squashfs_inode_t inode)
525*79398b25SAndroid Build Coastguard Worker {
526*79398b25SAndroid Build Coastguard Worker 	struct inode *i;
527*79398b25SAndroid Build Coastguard Worker 	struct squashfs_sb_info *msblk = &s->u.squashfs_sb;
528*79398b25SAndroid Build Coastguard Worker 	struct squashfs_super_block *sblk = &msblk->sblk;
529*79398b25SAndroid Build Coastguard Worker 	long long block = SQUASHFS_INODE_BLK(inode) +
530*79398b25SAndroid Build Coastguard Worker 		sblk->inode_table_start;
531*79398b25SAndroid Build Coastguard Worker 	unsigned int offset = SQUASHFS_INODE_OFFSET(inode);
532*79398b25SAndroid Build Coastguard Worker 	long long next_block;
533*79398b25SAndroid Build Coastguard Worker 	unsigned int next_offset;
534*79398b25SAndroid Build Coastguard Worker 	union squashfs_inode_header id, sid;
535*79398b25SAndroid Build Coastguard Worker 	struct squashfs_base_inode_header *inodeb = &id.base,
536*79398b25SAndroid Build Coastguard Worker 					  *sinodeb = &sid.base;
537*79398b25SAndroid Build Coastguard Worker 
538*79398b25SAndroid Build Coastguard Worker 	TRACE("Entered squashfs_iget\n");
539*79398b25SAndroid Build Coastguard Worker 
540*79398b25SAndroid Build Coastguard Worker 	if (msblk->swap) {
541*79398b25SAndroid Build Coastguard Worker 		if (!squashfs_get_cached_block(s, (char *) sinodeb, block,
542*79398b25SAndroid Build Coastguard Worker 					offset, sizeof(*sinodeb), &next_block,
543*79398b25SAndroid Build Coastguard Worker 					&next_offset))
544*79398b25SAndroid Build Coastguard Worker 			goto failed_read;
545*79398b25SAndroid Build Coastguard Worker 		SQUASHFS_SWAP_BASE_INODE_HEADER(inodeb, sinodeb,
546*79398b25SAndroid Build Coastguard Worker 					sizeof(*sinodeb));
547*79398b25SAndroid Build Coastguard Worker 	} else
548*79398b25SAndroid Build Coastguard Worker 		if (!squashfs_get_cached_block(s, (char *) inodeb, block,
549*79398b25SAndroid Build Coastguard Worker 					offset, sizeof(*inodeb), &next_block,
550*79398b25SAndroid Build Coastguard Worker 					&next_offset))
551*79398b25SAndroid Build Coastguard Worker 			goto failed_read;
552*79398b25SAndroid Build Coastguard Worker 
553*79398b25SAndroid Build Coastguard Worker 	switch(inodeb->inode_type) {
554*79398b25SAndroid Build Coastguard Worker 		case SQUASHFS_FILE_TYPE: {
555*79398b25SAndroid Build Coastguard Worker 			unsigned int frag_size;
556*79398b25SAndroid Build Coastguard Worker 			long long frag_blk;
557*79398b25SAndroid Build Coastguard Worker 			struct squashfs_reg_inode_header *inodep = &id.reg;
558*79398b25SAndroid Build Coastguard Worker 			struct squashfs_reg_inode_header *sinodep = &sid.reg;
559*79398b25SAndroid Build Coastguard Worker 
560*79398b25SAndroid Build Coastguard Worker 			if (msblk->swap) {
561*79398b25SAndroid Build Coastguard Worker 				if (!squashfs_get_cached_block(s, (char *)
562*79398b25SAndroid Build Coastguard Worker 						sinodep, block, offset,
563*79398b25SAndroid Build Coastguard Worker 						sizeof(*sinodep), &next_block,
564*79398b25SAndroid Build Coastguard Worker 						&next_offset))
565*79398b25SAndroid Build Coastguard Worker 					goto failed_read;
566*79398b25SAndroid Build Coastguard Worker 				SQUASHFS_SWAP_REG_INODE_HEADER(inodep, sinodep);
567*79398b25SAndroid Build Coastguard Worker 			} else
568*79398b25SAndroid Build Coastguard Worker 				if (!squashfs_get_cached_block(s, (char *)
569*79398b25SAndroid Build Coastguard Worker 						inodep, block, offset,
570*79398b25SAndroid Build Coastguard Worker 						sizeof(*inodep), &next_block,
571*79398b25SAndroid Build Coastguard Worker 						&next_offset))
572*79398b25SAndroid Build Coastguard Worker 					goto failed_read;
573*79398b25SAndroid Build Coastguard Worker 
574*79398b25SAndroid Build Coastguard Worker 			frag_blk = SQUASHFS_INVALID_BLK;
575*79398b25SAndroid Build Coastguard Worker 			if (inodep->fragment != SQUASHFS_INVALID_FRAG &&
576*79398b25SAndroid Build Coastguard Worker 					!get_fragment_location(s,
577*79398b25SAndroid Build Coastguard Worker 					inodep->fragment, &frag_blk, &frag_size))
578*79398b25SAndroid Build Coastguard Worker 				goto failed_read;
579*79398b25SAndroid Build Coastguard Worker 
580*79398b25SAndroid Build Coastguard Worker 			if((i = squashfs_new_inode(s, inodeb)) == NULL)
581*79398b25SAndroid Build Coastguard Worker 				goto failed_read1;
582*79398b25SAndroid Build Coastguard Worker 
583*79398b25SAndroid Build Coastguard Worker 			i->i_nlink = 1;
584*79398b25SAndroid Build Coastguard Worker 			i->i_size = inodep->file_size;
585*79398b25SAndroid Build Coastguard Worker 			i->i_fop = &generic_ro_fops;
586*79398b25SAndroid Build Coastguard Worker 			i->i_mode |= S_IFREG;
587*79398b25SAndroid Build Coastguard Worker 			i->i_blocks = ((i->i_size - 1) >> 9) + 1;
588*79398b25SAndroid Build Coastguard Worker 			i->i_blksize = PAGE_CACHE_SIZE;
589*79398b25SAndroid Build Coastguard Worker 			SQUASHFS_I(i)->u.s1.fragment_start_block = frag_blk;
590*79398b25SAndroid Build Coastguard Worker 			SQUASHFS_I(i)->u.s1.fragment_size = frag_size;
591*79398b25SAndroid Build Coastguard Worker 			SQUASHFS_I(i)->u.s1.fragment_offset = inodep->offset;
592*79398b25SAndroid Build Coastguard Worker 			SQUASHFS_I(i)->start_block = inodep->start_block;
593*79398b25SAndroid Build Coastguard Worker 			SQUASHFS_I(i)->u.s1.block_list_start = next_block;
594*79398b25SAndroid Build Coastguard Worker 			SQUASHFS_I(i)->offset = next_offset;
595*79398b25SAndroid Build Coastguard Worker 			if (sblk->block_size > 4096)
596*79398b25SAndroid Build Coastguard Worker 				i->i_data.a_ops = &squashfs_aops;
597*79398b25SAndroid Build Coastguard Worker 			else
598*79398b25SAndroid Build Coastguard Worker 				i->i_data.a_ops = &squashfs_aops_4K;
599*79398b25SAndroid Build Coastguard Worker 
600*79398b25SAndroid Build Coastguard Worker 			TRACE("File inode %x:%x, start_block %llx, "
601*79398b25SAndroid Build Coastguard Worker 					"block_list_start %llx, offset %x\n",
602*79398b25SAndroid Build Coastguard Worker 					SQUASHFS_INODE_BLK(inode), offset,
603*79398b25SAndroid Build Coastguard Worker 					inodep->start_block, next_block,
604*79398b25SAndroid Build Coastguard Worker 					next_offset);
605*79398b25SAndroid Build Coastguard Worker 			break;
606*79398b25SAndroid Build Coastguard Worker 		}
607*79398b25SAndroid Build Coastguard Worker 		case SQUASHFS_LREG_TYPE: {
608*79398b25SAndroid Build Coastguard Worker 			unsigned int frag_size;
609*79398b25SAndroid Build Coastguard Worker 			long long frag_blk;
610*79398b25SAndroid Build Coastguard Worker 			struct squashfs_lreg_inode_header *inodep = &id.lreg;
611*79398b25SAndroid Build Coastguard Worker 			struct squashfs_lreg_inode_header *sinodep = &sid.lreg;
612*79398b25SAndroid Build Coastguard Worker 
613*79398b25SAndroid Build Coastguard Worker 			if (msblk->swap) {
614*79398b25SAndroid Build Coastguard Worker 				if (!squashfs_get_cached_block(s, (char *)
615*79398b25SAndroid Build Coastguard Worker 						sinodep, block, offset,
616*79398b25SAndroid Build Coastguard Worker 						sizeof(*sinodep), &next_block,
617*79398b25SAndroid Build Coastguard Worker 						&next_offset))
618*79398b25SAndroid Build Coastguard Worker 					goto failed_read;
619*79398b25SAndroid Build Coastguard Worker 				SQUASHFS_SWAP_LREG_INODE_HEADER(inodep, sinodep);
620*79398b25SAndroid Build Coastguard Worker 			} else
621*79398b25SAndroid Build Coastguard Worker 				if (!squashfs_get_cached_block(s, (char *)
622*79398b25SAndroid Build Coastguard Worker 						inodep, block, offset,
623*79398b25SAndroid Build Coastguard Worker 						sizeof(*inodep), &next_block,
624*79398b25SAndroid Build Coastguard Worker 						&next_offset))
625*79398b25SAndroid Build Coastguard Worker 					goto failed_read;
626*79398b25SAndroid Build Coastguard Worker 
627*79398b25SAndroid Build Coastguard Worker 			frag_blk = SQUASHFS_INVALID_BLK;
628*79398b25SAndroid Build Coastguard Worker 			if (inodep->fragment != SQUASHFS_INVALID_FRAG &&
629*79398b25SAndroid Build Coastguard Worker 					!get_fragment_location(s,
630*79398b25SAndroid Build Coastguard Worker 					inodep->fragment, &frag_blk, &frag_size))
631*79398b25SAndroid Build Coastguard Worker 				goto failed_read;
632*79398b25SAndroid Build Coastguard Worker 
633*79398b25SAndroid Build Coastguard Worker 			if((i = squashfs_new_inode(s, inodeb)) == NULL)
634*79398b25SAndroid Build Coastguard Worker 				goto failed_read1;
635*79398b25SAndroid Build Coastguard Worker 
636*79398b25SAndroid Build Coastguard Worker 			i->i_nlink = inodep->nlink;
637*79398b25SAndroid Build Coastguard Worker 			i->i_size = inodep->file_size;
638*79398b25SAndroid Build Coastguard Worker 			i->i_fop = &generic_ro_fops;
639*79398b25SAndroid Build Coastguard Worker 			i->i_mode |= S_IFREG;
640*79398b25SAndroid Build Coastguard Worker 			i->i_blocks = ((i->i_size - 1) >> 9) + 1;
641*79398b25SAndroid Build Coastguard Worker 			i->i_blksize = PAGE_CACHE_SIZE;
642*79398b25SAndroid Build Coastguard Worker 			SQUASHFS_I(i)->u.s1.fragment_start_block = frag_blk;
643*79398b25SAndroid Build Coastguard Worker 			SQUASHFS_I(i)->u.s1.fragment_size = frag_size;
644*79398b25SAndroid Build Coastguard Worker 			SQUASHFS_I(i)->u.s1.fragment_offset = inodep->offset;
645*79398b25SAndroid Build Coastguard Worker 			SQUASHFS_I(i)->start_block = inodep->start_block;
646*79398b25SAndroid Build Coastguard Worker 			SQUASHFS_I(i)->u.s1.block_list_start = next_block;
647*79398b25SAndroid Build Coastguard Worker 			SQUASHFS_I(i)->offset = next_offset;
648*79398b25SAndroid Build Coastguard Worker 			if (sblk->block_size > 4096)
649*79398b25SAndroid Build Coastguard Worker 				i->i_data.a_ops = &squashfs_aops;
650*79398b25SAndroid Build Coastguard Worker 			else
651*79398b25SAndroid Build Coastguard Worker 				i->i_data.a_ops = &squashfs_aops_4K;
652*79398b25SAndroid Build Coastguard Worker 
653*79398b25SAndroid Build Coastguard Worker 			TRACE("File inode %x:%x, start_block %llx, "
654*79398b25SAndroid Build Coastguard Worker 					"block_list_start %llx, offset %x\n",
655*79398b25SAndroid Build Coastguard Worker 					SQUASHFS_INODE_BLK(inode), offset,
656*79398b25SAndroid Build Coastguard Worker 					inodep->start_block, next_block,
657*79398b25SAndroid Build Coastguard Worker 					next_offset);
658*79398b25SAndroid Build Coastguard Worker 			break;
659*79398b25SAndroid Build Coastguard Worker 		}
660*79398b25SAndroid Build Coastguard Worker 		case SQUASHFS_DIR_TYPE: {
661*79398b25SAndroid Build Coastguard Worker 			struct squashfs_dir_inode_header *inodep = &id.dir;
662*79398b25SAndroid Build Coastguard Worker 			struct squashfs_dir_inode_header *sinodep = &sid.dir;
663*79398b25SAndroid Build Coastguard Worker 
664*79398b25SAndroid Build Coastguard Worker 			if (msblk->swap) {
665*79398b25SAndroid Build Coastguard Worker 				if (!squashfs_get_cached_block(s, (char *)
666*79398b25SAndroid Build Coastguard Worker 						sinodep, block, offset,
667*79398b25SAndroid Build Coastguard Worker 						sizeof(*sinodep), &next_block,
668*79398b25SAndroid Build Coastguard Worker 						&next_offset))
669*79398b25SAndroid Build Coastguard Worker 					goto failed_read;
670*79398b25SAndroid Build Coastguard Worker 				SQUASHFS_SWAP_DIR_INODE_HEADER(inodep, sinodep);
671*79398b25SAndroid Build Coastguard Worker 			} else
672*79398b25SAndroid Build Coastguard Worker 				if (!squashfs_get_cached_block(s, (char *)
673*79398b25SAndroid Build Coastguard Worker 						inodep, block, offset,
674*79398b25SAndroid Build Coastguard Worker 						sizeof(*inodep), &next_block,
675*79398b25SAndroid Build Coastguard Worker 						&next_offset))
676*79398b25SAndroid Build Coastguard Worker 					goto failed_read;
677*79398b25SAndroid Build Coastguard Worker 
678*79398b25SAndroid Build Coastguard Worker 			if((i = squashfs_new_inode(s, inodeb)) == NULL)
679*79398b25SAndroid Build Coastguard Worker 				goto failed_read1;
680*79398b25SAndroid Build Coastguard Worker 
681*79398b25SAndroid Build Coastguard Worker 			i->i_nlink = inodep->nlink;
682*79398b25SAndroid Build Coastguard Worker 			i->i_size = inodep->file_size;
683*79398b25SAndroid Build Coastguard Worker 			i->i_op = &squashfs_dir_inode_ops;
684*79398b25SAndroid Build Coastguard Worker 			i->i_fop = &squashfs_dir_ops;
685*79398b25SAndroid Build Coastguard Worker 			i->i_mode |= S_IFDIR;
686*79398b25SAndroid Build Coastguard Worker 			SQUASHFS_I(i)->start_block = inodep->start_block;
687*79398b25SAndroid Build Coastguard Worker 			SQUASHFS_I(i)->offset = inodep->offset;
688*79398b25SAndroid Build Coastguard Worker 			SQUASHFS_I(i)->u.s2.directory_index_count = 0;
689*79398b25SAndroid Build Coastguard Worker 			SQUASHFS_I(i)->u.s2.parent_inode = inodep->parent_inode;
690*79398b25SAndroid Build Coastguard Worker 
691*79398b25SAndroid Build Coastguard Worker 			TRACE("Directory inode %x:%x, start_block %x, offset "
692*79398b25SAndroid Build Coastguard Worker 					"%x\n", SQUASHFS_INODE_BLK(inode),
693*79398b25SAndroid Build Coastguard Worker 					offset, inodep->start_block,
694*79398b25SAndroid Build Coastguard Worker 					inodep->offset);
695*79398b25SAndroid Build Coastguard Worker 			break;
696*79398b25SAndroid Build Coastguard Worker 		}
697*79398b25SAndroid Build Coastguard Worker 		case SQUASHFS_LDIR_TYPE: {
698*79398b25SAndroid Build Coastguard Worker 			struct squashfs_ldir_inode_header *inodep = &id.ldir;
699*79398b25SAndroid Build Coastguard Worker 			struct squashfs_ldir_inode_header *sinodep = &sid.ldir;
700*79398b25SAndroid Build Coastguard Worker 
701*79398b25SAndroid Build Coastguard Worker 			if (msblk->swap) {
702*79398b25SAndroid Build Coastguard Worker 				if (!squashfs_get_cached_block(s, (char *)
703*79398b25SAndroid Build Coastguard Worker 						sinodep, block, offset,
704*79398b25SAndroid Build Coastguard Worker 						sizeof(*sinodep), &next_block,
705*79398b25SAndroid Build Coastguard Worker 						&next_offset))
706*79398b25SAndroid Build Coastguard Worker 					goto failed_read;
707*79398b25SAndroid Build Coastguard Worker 				SQUASHFS_SWAP_LDIR_INODE_HEADER(inodep,
708*79398b25SAndroid Build Coastguard Worker 						sinodep);
709*79398b25SAndroid Build Coastguard Worker 			} else
710*79398b25SAndroid Build Coastguard Worker 				if (!squashfs_get_cached_block(s, (char *)
711*79398b25SAndroid Build Coastguard Worker 						inodep, block, offset,
712*79398b25SAndroid Build Coastguard Worker 						sizeof(*inodep), &next_block,
713*79398b25SAndroid Build Coastguard Worker 						&next_offset))
714*79398b25SAndroid Build Coastguard Worker 					goto failed_read;
715*79398b25SAndroid Build Coastguard Worker 
716*79398b25SAndroid Build Coastguard Worker 			if((i = squashfs_new_inode(s, inodeb)) == NULL)
717*79398b25SAndroid Build Coastguard Worker 				goto failed_read1;
718*79398b25SAndroid Build Coastguard Worker 
719*79398b25SAndroid Build Coastguard Worker 			i->i_nlink = inodep->nlink;
720*79398b25SAndroid Build Coastguard Worker 			i->i_size = inodep->file_size;
721*79398b25SAndroid Build Coastguard Worker 			i->i_op = &squashfs_dir_inode_ops;
722*79398b25SAndroid Build Coastguard Worker 			i->i_fop = &squashfs_dir_ops;
723*79398b25SAndroid Build Coastguard Worker 			i->i_mode |= S_IFDIR;
724*79398b25SAndroid Build Coastguard Worker 			SQUASHFS_I(i)->start_block = inodep->start_block;
725*79398b25SAndroid Build Coastguard Worker 			SQUASHFS_I(i)->offset = inodep->offset;
726*79398b25SAndroid Build Coastguard Worker 			SQUASHFS_I(i)->u.s2.directory_index_start = next_block;
727*79398b25SAndroid Build Coastguard Worker 			SQUASHFS_I(i)->u.s2.directory_index_offset =
728*79398b25SAndroid Build Coastguard Worker 								next_offset;
729*79398b25SAndroid Build Coastguard Worker 			SQUASHFS_I(i)->u.s2.directory_index_count =
730*79398b25SAndroid Build Coastguard Worker 								inodep->i_count;
731*79398b25SAndroid Build Coastguard Worker 			SQUASHFS_I(i)->u.s2.parent_inode = inodep->parent_inode;
732*79398b25SAndroid Build Coastguard Worker 
733*79398b25SAndroid Build Coastguard Worker 			TRACE("Long directory inode %x:%x, start_block %x, "
734*79398b25SAndroid Build Coastguard Worker 					"offset %x\n",
735*79398b25SAndroid Build Coastguard Worker 					SQUASHFS_INODE_BLK(inode), offset,
736*79398b25SAndroid Build Coastguard Worker 					inodep->start_block, inodep->offset);
737*79398b25SAndroid Build Coastguard Worker 			break;
738*79398b25SAndroid Build Coastguard Worker 		}
739*79398b25SAndroid Build Coastguard Worker 		case SQUASHFS_SYMLINK_TYPE: {
740*79398b25SAndroid Build Coastguard Worker 			struct squashfs_symlink_inode_header *inodep =
741*79398b25SAndroid Build Coastguard Worker 								&id.symlink;
742*79398b25SAndroid Build Coastguard Worker 			struct squashfs_symlink_inode_header *sinodep =
743*79398b25SAndroid Build Coastguard Worker 								&sid.symlink;
744*79398b25SAndroid Build Coastguard Worker 
745*79398b25SAndroid Build Coastguard Worker 			if (msblk->swap) {
746*79398b25SAndroid Build Coastguard Worker 				if (!squashfs_get_cached_block(s, (char *)
747*79398b25SAndroid Build Coastguard Worker 						sinodep, block, offset,
748*79398b25SAndroid Build Coastguard Worker 						sizeof(*sinodep), &next_block,
749*79398b25SAndroid Build Coastguard Worker 						&next_offset))
750*79398b25SAndroid Build Coastguard Worker 					goto failed_read;
751*79398b25SAndroid Build Coastguard Worker 				SQUASHFS_SWAP_SYMLINK_INODE_HEADER(inodep,
752*79398b25SAndroid Build Coastguard Worker 								sinodep);
753*79398b25SAndroid Build Coastguard Worker 			} else
754*79398b25SAndroid Build Coastguard Worker 				if (!squashfs_get_cached_block(s, (char *)
755*79398b25SAndroid Build Coastguard Worker 						inodep, block, offset,
756*79398b25SAndroid Build Coastguard Worker 						sizeof(*inodep), &next_block,
757*79398b25SAndroid Build Coastguard Worker 						&next_offset))
758*79398b25SAndroid Build Coastguard Worker 					goto failed_read;
759*79398b25SAndroid Build Coastguard Worker 
760*79398b25SAndroid Build Coastguard Worker 			if((i = squashfs_new_inode(s, inodeb)) == NULL)
761*79398b25SAndroid Build Coastguard Worker 				goto failed_read1;
762*79398b25SAndroid Build Coastguard Worker 
763*79398b25SAndroid Build Coastguard Worker 			i->i_nlink = inodep->nlink;
764*79398b25SAndroid Build Coastguard Worker 			i->i_size = inodep->symlink_size;
765*79398b25SAndroid Build Coastguard Worker 			i->i_op = &page_symlink_inode_operations;
766*79398b25SAndroid Build Coastguard Worker 			i->i_data.a_ops = &squashfs_symlink_aops;
767*79398b25SAndroid Build Coastguard Worker 			i->i_mode |= S_IFLNK;
768*79398b25SAndroid Build Coastguard Worker 			SQUASHFS_I(i)->start_block = next_block;
769*79398b25SAndroid Build Coastguard Worker 			SQUASHFS_I(i)->offset = next_offset;
770*79398b25SAndroid Build Coastguard Worker 
771*79398b25SAndroid Build Coastguard Worker 			TRACE("Symbolic link inode %x:%x, start_block %llx, "
772*79398b25SAndroid Build Coastguard Worker 					"offset %x\n",
773*79398b25SAndroid Build Coastguard Worker 					SQUASHFS_INODE_BLK(inode), offset,
774*79398b25SAndroid Build Coastguard Worker 					next_block, next_offset);
775*79398b25SAndroid Build Coastguard Worker 			break;
776*79398b25SAndroid Build Coastguard Worker 		 }
777*79398b25SAndroid Build Coastguard Worker 		 case SQUASHFS_BLKDEV_TYPE:
778*79398b25SAndroid Build Coastguard Worker 		 case SQUASHFS_CHRDEV_TYPE: {
779*79398b25SAndroid Build Coastguard Worker 			struct squashfs_dev_inode_header *inodep = &id.dev;
780*79398b25SAndroid Build Coastguard Worker 			struct squashfs_dev_inode_header *sinodep = &sid.dev;
781*79398b25SAndroid Build Coastguard Worker 
782*79398b25SAndroid Build Coastguard Worker 			if (msblk->swap) {
783*79398b25SAndroid Build Coastguard Worker 				if (!squashfs_get_cached_block(s, (char *)
784*79398b25SAndroid Build Coastguard Worker 						sinodep, block, offset,
785*79398b25SAndroid Build Coastguard Worker 						sizeof(*sinodep), &next_block,
786*79398b25SAndroid Build Coastguard Worker 						&next_offset))
787*79398b25SAndroid Build Coastguard Worker 					goto failed_read;
788*79398b25SAndroid Build Coastguard Worker 				SQUASHFS_SWAP_DEV_INODE_HEADER(inodep, sinodep);
789*79398b25SAndroid Build Coastguard Worker 			} else
790*79398b25SAndroid Build Coastguard Worker 				if (!squashfs_get_cached_block(s, (char *)
791*79398b25SAndroid Build Coastguard Worker 						inodep, block, offset,
792*79398b25SAndroid Build Coastguard Worker 						sizeof(*inodep), &next_block,
793*79398b25SAndroid Build Coastguard Worker 						&next_offset))
794*79398b25SAndroid Build Coastguard Worker 					goto failed_read;
795*79398b25SAndroid Build Coastguard Worker 
796*79398b25SAndroid Build Coastguard Worker 			if ((i = squashfs_new_inode(s, inodeb)) == NULL)
797*79398b25SAndroid Build Coastguard Worker 				goto failed_read1;
798*79398b25SAndroid Build Coastguard Worker 
799*79398b25SAndroid Build Coastguard Worker 			i->i_nlink = inodep->nlink;
800*79398b25SAndroid Build Coastguard Worker 			i->i_mode |= (inodeb->inode_type ==
801*79398b25SAndroid Build Coastguard Worker 					SQUASHFS_CHRDEV_TYPE) ?  S_IFCHR :
802*79398b25SAndroid Build Coastguard Worker 					S_IFBLK;
803*79398b25SAndroid Build Coastguard Worker 			init_special_inode(i, i->i_mode, inodep->rdev);
804*79398b25SAndroid Build Coastguard Worker 
805*79398b25SAndroid Build Coastguard Worker 			TRACE("Device inode %x:%x, rdev %x\n",
806*79398b25SAndroid Build Coastguard Worker 					SQUASHFS_INODE_BLK(inode), offset,
807*79398b25SAndroid Build Coastguard Worker 					inodep->rdev);
808*79398b25SAndroid Build Coastguard Worker 			break;
809*79398b25SAndroid Build Coastguard Worker 		 }
810*79398b25SAndroid Build Coastguard Worker 		 case SQUASHFS_FIFO_TYPE:
811*79398b25SAndroid Build Coastguard Worker 		 case SQUASHFS_SOCKET_TYPE: {
812*79398b25SAndroid Build Coastguard Worker 			struct squashfs_ipc_inode_header *inodep = &id.ipc;
813*79398b25SAndroid Build Coastguard Worker 			struct squashfs_ipc_inode_header *sinodep = &sid.ipc;
814*79398b25SAndroid Build Coastguard Worker 
815*79398b25SAndroid Build Coastguard Worker 			if (msblk->swap) {
816*79398b25SAndroid Build Coastguard Worker 				if (!squashfs_get_cached_block(s, (char *)
817*79398b25SAndroid Build Coastguard Worker 						sinodep, block, offset,
818*79398b25SAndroid Build Coastguard Worker 						sizeof(*sinodep), &next_block,
819*79398b25SAndroid Build Coastguard Worker 						&next_offset))
820*79398b25SAndroid Build Coastguard Worker 					goto failed_read;
821*79398b25SAndroid Build Coastguard Worker 				SQUASHFS_SWAP_IPC_INODE_HEADER(inodep, sinodep);
822*79398b25SAndroid Build Coastguard Worker 			} else
823*79398b25SAndroid Build Coastguard Worker 				if (!squashfs_get_cached_block(s, (char *)
824*79398b25SAndroid Build Coastguard Worker 						inodep, block, offset,
825*79398b25SAndroid Build Coastguard Worker 						sizeof(*inodep), &next_block,
826*79398b25SAndroid Build Coastguard Worker 						&next_offset))
827*79398b25SAndroid Build Coastguard Worker 					goto failed_read;
828*79398b25SAndroid Build Coastguard Worker 
829*79398b25SAndroid Build Coastguard Worker 			if ((i = squashfs_new_inode(s, inodeb)) == NULL)
830*79398b25SAndroid Build Coastguard Worker 				goto failed_read1;
831*79398b25SAndroid Build Coastguard Worker 
832*79398b25SAndroid Build Coastguard Worker 			i->i_nlink = inodep->nlink;
833*79398b25SAndroid Build Coastguard Worker 			i->i_mode |= (inodeb->inode_type == SQUASHFS_FIFO_TYPE)
834*79398b25SAndroid Build Coastguard Worker 							? S_IFIFO : S_IFSOCK;
835*79398b25SAndroid Build Coastguard Worker 			init_special_inode(i, i->i_mode, 0);
836*79398b25SAndroid Build Coastguard Worker 			break;
837*79398b25SAndroid Build Coastguard Worker 		 }
838*79398b25SAndroid Build Coastguard Worker 		 default:
839*79398b25SAndroid Build Coastguard Worker 			ERROR("Unknown inode type %d in squashfs_iget!\n",
840*79398b25SAndroid Build Coastguard Worker 					inodeb->inode_type);
841*79398b25SAndroid Build Coastguard Worker 			goto failed_read1;
842*79398b25SAndroid Build Coastguard Worker 	}
843*79398b25SAndroid Build Coastguard Worker 
844*79398b25SAndroid Build Coastguard Worker 	insert_inode_hash(i);
845*79398b25SAndroid Build Coastguard Worker 	return i;
846*79398b25SAndroid Build Coastguard Worker 
847*79398b25SAndroid Build Coastguard Worker failed_read:
848*79398b25SAndroid Build Coastguard Worker 	ERROR("Unable to read inode [%llx:%x]\n", block, offset);
849*79398b25SAndroid Build Coastguard Worker 
850*79398b25SAndroid Build Coastguard Worker failed_read1:
851*79398b25SAndroid Build Coastguard Worker 	return NULL;
852*79398b25SAndroid Build Coastguard Worker }
853*79398b25SAndroid Build Coastguard Worker 
854*79398b25SAndroid Build Coastguard Worker 
read_fragment_index_table(struct super_block * s)855*79398b25SAndroid Build Coastguard Worker int read_fragment_index_table(struct super_block *s)
856*79398b25SAndroid Build Coastguard Worker {
857*79398b25SAndroid Build Coastguard Worker 	struct squashfs_sb_info *msblk = &s->u.squashfs_sb;
858*79398b25SAndroid Build Coastguard Worker 	struct squashfs_super_block *sblk = &msblk->sblk;
859*79398b25SAndroid Build Coastguard Worker 
860*79398b25SAndroid Build Coastguard Worker 	if (!(msblk->fragment_index = kmalloc(SQUASHFS_FRAGMENT_INDEX_BYTES
861*79398b25SAndroid Build Coastguard Worker 					(sblk->fragments), GFP_KERNEL))) {
862*79398b25SAndroid Build Coastguard Worker 		ERROR("Failed to allocate uid/gid table\n");
863*79398b25SAndroid Build Coastguard Worker 		return 0;
864*79398b25SAndroid Build Coastguard Worker 	}
865*79398b25SAndroid Build Coastguard Worker 
866*79398b25SAndroid Build Coastguard Worker 	if (SQUASHFS_FRAGMENT_INDEX_BYTES(sblk->fragments) &&
867*79398b25SAndroid Build Coastguard Worker 					!squashfs_read_data(s, (char *)
868*79398b25SAndroid Build Coastguard Worker 					msblk->fragment_index,
869*79398b25SAndroid Build Coastguard Worker 					sblk->fragment_table_start,
870*79398b25SAndroid Build Coastguard Worker 					SQUASHFS_FRAGMENT_INDEX_BYTES
871*79398b25SAndroid Build Coastguard Worker 					(sblk->fragments) |
872*79398b25SAndroid Build Coastguard Worker 					SQUASHFS_COMPRESSED_BIT_BLOCK, NULL)) {
873*79398b25SAndroid Build Coastguard Worker 		ERROR("unable to read fragment index table\n");
874*79398b25SAndroid Build Coastguard Worker 		return 0;
875*79398b25SAndroid Build Coastguard Worker 	}
876*79398b25SAndroid Build Coastguard Worker 
877*79398b25SAndroid Build Coastguard Worker 	if (msblk->swap) {
878*79398b25SAndroid Build Coastguard Worker 		int i;
879*79398b25SAndroid Build Coastguard Worker 		long long fragment;
880*79398b25SAndroid Build Coastguard Worker 
881*79398b25SAndroid Build Coastguard Worker 		for (i = 0; i < SQUASHFS_FRAGMENT_INDEXES(sblk->fragments);
882*79398b25SAndroid Build Coastguard Worker 									i++) {
883*79398b25SAndroid Build Coastguard Worker 			SQUASHFS_SWAP_FRAGMENT_INDEXES((&fragment),
884*79398b25SAndroid Build Coastguard Worker 						&msblk->fragment_index[i], 1);
885*79398b25SAndroid Build Coastguard Worker 			msblk->fragment_index[i] = fragment;
886*79398b25SAndroid Build Coastguard Worker 		}
887*79398b25SAndroid Build Coastguard Worker 	}
888*79398b25SAndroid Build Coastguard Worker 
889*79398b25SAndroid Build Coastguard Worker 	return 1;
890*79398b25SAndroid Build Coastguard Worker }
891*79398b25SAndroid Build Coastguard Worker 
892*79398b25SAndroid Build Coastguard Worker 
supported_squashfs_filesystem(struct squashfs_sb_info * msblk,int silent)893*79398b25SAndroid Build Coastguard Worker static int supported_squashfs_filesystem(struct squashfs_sb_info *msblk, int silent)
894*79398b25SAndroid Build Coastguard Worker {
895*79398b25SAndroid Build Coastguard Worker 	struct squashfs_super_block *sblk = &msblk->sblk;
896*79398b25SAndroid Build Coastguard Worker 
897*79398b25SAndroid Build Coastguard Worker 	msblk->iget = squashfs_iget;
898*79398b25SAndroid Build Coastguard Worker 	msblk->read_blocklist = read_blocklist;
899*79398b25SAndroid Build Coastguard Worker 	msblk->read_fragment_index_table = read_fragment_index_table;
900*79398b25SAndroid Build Coastguard Worker 
901*79398b25SAndroid Build Coastguard Worker 	if (sblk->s_major == 1) {
902*79398b25SAndroid Build Coastguard Worker 		if (!squashfs_1_0_supported(msblk)) {
903*79398b25SAndroid Build Coastguard Worker 			SERROR("Major/Minor mismatch, Squashfs 1.0 filesystems "
904*79398b25SAndroid Build Coastguard Worker 				"are unsupported\n");
905*79398b25SAndroid Build Coastguard Worker 			SERROR("Please recompile with "
906*79398b25SAndroid Build Coastguard Worker 				"Squashfs 1.0 support enabled\n");
907*79398b25SAndroid Build Coastguard Worker 			return 0;
908*79398b25SAndroid Build Coastguard Worker 		}
909*79398b25SAndroid Build Coastguard Worker 	} else if (sblk->s_major == 2) {
910*79398b25SAndroid Build Coastguard Worker 		if (!squashfs_2_0_supported(msblk)) {
911*79398b25SAndroid Build Coastguard Worker 			SERROR("Major/Minor mismatch, Squashfs 2.0 filesystems "
912*79398b25SAndroid Build Coastguard Worker 				"are unsupported\n");
913*79398b25SAndroid Build Coastguard Worker 			SERROR("Please recompile with "
914*79398b25SAndroid Build Coastguard Worker 				"Squashfs 2.0 support enabled\n");
915*79398b25SAndroid Build Coastguard Worker 			return 0;
916*79398b25SAndroid Build Coastguard Worker 		}
917*79398b25SAndroid Build Coastguard Worker 	} else if(sblk->s_major != SQUASHFS_MAJOR || sblk->s_minor >
918*79398b25SAndroid Build Coastguard Worker 			SQUASHFS_MINOR) {
919*79398b25SAndroid Build Coastguard Worker 		SERROR("Major/Minor mismatch, trying to mount newer %d.%d "
920*79398b25SAndroid Build Coastguard Worker 				"filesystem\n", sblk->s_major, sblk->s_minor);
921*79398b25SAndroid Build Coastguard Worker 		SERROR("Please update your kernel\n");
922*79398b25SAndroid Build Coastguard Worker 		return 0;
923*79398b25SAndroid Build Coastguard Worker 	}
924*79398b25SAndroid Build Coastguard Worker 
925*79398b25SAndroid Build Coastguard Worker 	return 1;
926*79398b25SAndroid Build Coastguard Worker }
927*79398b25SAndroid Build Coastguard Worker 
928*79398b25SAndroid Build Coastguard Worker 
squashfs_read_super(struct super_block * s,void * data,int silent)929*79398b25SAndroid Build Coastguard Worker static struct super_block *squashfs_read_super(struct super_block *s,
930*79398b25SAndroid Build Coastguard Worker 		void *data, int silent)
931*79398b25SAndroid Build Coastguard Worker {
932*79398b25SAndroid Build Coastguard Worker 	kdev_t dev = s->s_dev;
933*79398b25SAndroid Build Coastguard Worker 	struct squashfs_sb_info *msblk = &s->u.squashfs_sb;
934*79398b25SAndroid Build Coastguard Worker 	struct squashfs_super_block *sblk = &msblk->sblk;
935*79398b25SAndroid Build Coastguard Worker 	int i;
936*79398b25SAndroid Build Coastguard Worker 	struct inode *root;
937*79398b25SAndroid Build Coastguard Worker 
938*79398b25SAndroid Build Coastguard Worker 	if (!(msblk->stream.workspace = vmalloc(zlib_inflate_workspacesize()))) {
939*79398b25SAndroid Build Coastguard Worker 		ERROR("Failed to allocate zlib workspace\n");
940*79398b25SAndroid Build Coastguard Worker 		goto failed_mount;
941*79398b25SAndroid Build Coastguard Worker 	}
942*79398b25SAndroid Build Coastguard Worker 
943*79398b25SAndroid Build Coastguard Worker 	msblk->devblksize = get_hardsect_size(dev);
944*79398b25SAndroid Build Coastguard Worker 	if(msblk->devblksize < BLOCK_SIZE)
945*79398b25SAndroid Build Coastguard Worker 		msblk->devblksize = BLOCK_SIZE;
946*79398b25SAndroid Build Coastguard Worker 	msblk->devblksize_log2 = ffz(~msblk->devblksize);
947*79398b25SAndroid Build Coastguard Worker         set_blocksize(dev, msblk->devblksize);
948*79398b25SAndroid Build Coastguard Worker 	s->s_blocksize = msblk->devblksize;
949*79398b25SAndroid Build Coastguard Worker 	s->s_blocksize_bits = msblk->devblksize_log2;
950*79398b25SAndroid Build Coastguard Worker 
951*79398b25SAndroid Build Coastguard Worker 	init_MUTEX(&msblk->read_data_mutex);
952*79398b25SAndroid Build Coastguard Worker 	init_MUTEX(&msblk->read_page_mutex);
953*79398b25SAndroid Build Coastguard Worker 	init_MUTEX(&msblk->block_cache_mutex);
954*79398b25SAndroid Build Coastguard Worker 	init_MUTEX(&msblk->fragment_mutex);
955*79398b25SAndroid Build Coastguard Worker 
956*79398b25SAndroid Build Coastguard Worker 	init_waitqueue_head(&msblk->waitq);
957*79398b25SAndroid Build Coastguard Worker 	init_waitqueue_head(&msblk->fragment_wait_queue);
958*79398b25SAndroid Build Coastguard Worker 
959*79398b25SAndroid Build Coastguard Worker 	if (!squashfs_read_data(s, (char *) sblk, SQUASHFS_START,
960*79398b25SAndroid Build Coastguard Worker 					sizeof(struct squashfs_super_block) |
961*79398b25SAndroid Build Coastguard Worker 					SQUASHFS_COMPRESSED_BIT_BLOCK, NULL)) {
962*79398b25SAndroid Build Coastguard Worker 		SERROR("unable to read superblock\n");
963*79398b25SAndroid Build Coastguard Worker 		goto failed_mount;
964*79398b25SAndroid Build Coastguard Worker 	}
965*79398b25SAndroid Build Coastguard Worker 
966*79398b25SAndroid Build Coastguard Worker 	/* Check it is a SQUASHFS superblock */
967*79398b25SAndroid Build Coastguard Worker 	msblk->swap = 0;
968*79398b25SAndroid Build Coastguard Worker 	if ((s->s_magic = sblk->s_magic) != SQUASHFS_MAGIC) {
969*79398b25SAndroid Build Coastguard Worker 		if (sblk->s_magic == SQUASHFS_MAGIC_SWAP) {
970*79398b25SAndroid Build Coastguard Worker 			struct squashfs_super_block ssblk;
971*79398b25SAndroid Build Coastguard Worker 
972*79398b25SAndroid Build Coastguard Worker 			WARNING("Mounting a different endian SQUASHFS "
973*79398b25SAndroid Build Coastguard Worker 				"filesystem on %s\n", bdevname(dev));
974*79398b25SAndroid Build Coastguard Worker 
975*79398b25SAndroid Build Coastguard Worker 			SQUASHFS_SWAP_SUPER_BLOCK(&ssblk, sblk);
976*79398b25SAndroid Build Coastguard Worker 			memcpy(sblk, &ssblk, sizeof(struct squashfs_super_block));
977*79398b25SAndroid Build Coastguard Worker 			msblk->swap = 1;
978*79398b25SAndroid Build Coastguard Worker 		} else  {
979*79398b25SAndroid Build Coastguard Worker 			SERROR("Can't find a SQUASHFS superblock on %s\n",
980*79398b25SAndroid Build Coastguard Worker 							bdevname(dev));
981*79398b25SAndroid Build Coastguard Worker 			goto failed_mount;
982*79398b25SAndroid Build Coastguard Worker 		}
983*79398b25SAndroid Build Coastguard Worker 	}
984*79398b25SAndroid Build Coastguard Worker 
985*79398b25SAndroid Build Coastguard Worker 	/* Check the MAJOR & MINOR versions */
986*79398b25SAndroid Build Coastguard Worker 	if(!supported_squashfs_filesystem(msblk, silent))
987*79398b25SAndroid Build Coastguard Worker 		goto failed_mount;
988*79398b25SAndroid Build Coastguard Worker 
989*79398b25SAndroid Build Coastguard Worker 	TRACE("Found valid superblock on %s\n", bdevname(dev));
990*79398b25SAndroid Build Coastguard Worker 	TRACE("Inodes are %scompressed\n",
991*79398b25SAndroid Build Coastguard Worker 					SQUASHFS_UNCOMPRESSED_INODES
992*79398b25SAndroid Build Coastguard Worker 					(sblk->flags) ? "un" : "");
993*79398b25SAndroid Build Coastguard Worker 	TRACE("Data is %scompressed\n",
994*79398b25SAndroid Build Coastguard Worker 					SQUASHFS_UNCOMPRESSED_DATA(sblk->flags)
995*79398b25SAndroid Build Coastguard Worker 					? "un" : "");
996*79398b25SAndroid Build Coastguard Worker 	TRACE("Check data is %s present in the filesystem\n",
997*79398b25SAndroid Build Coastguard Worker 					SQUASHFS_CHECK_DATA(sblk->flags) ?
998*79398b25SAndroid Build Coastguard Worker 					"" : "not");
999*79398b25SAndroid Build Coastguard Worker 	TRACE("Filesystem size %lld bytes\n", sblk->bytes_used);
1000*79398b25SAndroid Build Coastguard Worker 	TRACE("Block size %d\n", sblk->block_size);
1001*79398b25SAndroid Build Coastguard Worker 	TRACE("Number of inodes %d\n", sblk->inodes);
1002*79398b25SAndroid Build Coastguard Worker 	if (sblk->s_major > 1)
1003*79398b25SAndroid Build Coastguard Worker 		TRACE("Number of fragments %d\n", sblk->fragments);
1004*79398b25SAndroid Build Coastguard Worker 	TRACE("Number of uids %d\n", sblk->no_uids);
1005*79398b25SAndroid Build Coastguard Worker 	TRACE("Number of gids %d\n", sblk->no_guids);
1006*79398b25SAndroid Build Coastguard Worker 	TRACE("sblk->inode_table_start %llx\n", sblk->inode_table_start);
1007*79398b25SAndroid Build Coastguard Worker 	TRACE("sblk->directory_table_start %llx\n", sblk->directory_table_start);
1008*79398b25SAndroid Build Coastguard Worker 	if (sblk->s_major > 1)
1009*79398b25SAndroid Build Coastguard Worker 		TRACE("sblk->fragment_table_start %llx\n",
1010*79398b25SAndroid Build Coastguard Worker 					sblk->fragment_table_start);
1011*79398b25SAndroid Build Coastguard Worker 	TRACE("sblk->uid_start %llx\n", sblk->uid_start);
1012*79398b25SAndroid Build Coastguard Worker 
1013*79398b25SAndroid Build Coastguard Worker 	s->s_flags |= MS_RDONLY;
1014*79398b25SAndroid Build Coastguard Worker 	s->s_op = &squashfs_ops;
1015*79398b25SAndroid Build Coastguard Worker 
1016*79398b25SAndroid Build Coastguard Worker 	/* Init inode_table block pointer array */
1017*79398b25SAndroid Build Coastguard Worker 	if (!(msblk->block_cache = kmalloc(sizeof(struct squashfs_cache) *
1018*79398b25SAndroid Build Coastguard Worker 					SQUASHFS_CACHED_BLKS, GFP_KERNEL))) {
1019*79398b25SAndroid Build Coastguard Worker 		ERROR("Failed to allocate block cache\n");
1020*79398b25SAndroid Build Coastguard Worker 		goto failed_mount;
1021*79398b25SAndroid Build Coastguard Worker 	}
1022*79398b25SAndroid Build Coastguard Worker 
1023*79398b25SAndroid Build Coastguard Worker 	for (i = 0; i < SQUASHFS_CACHED_BLKS; i++)
1024*79398b25SAndroid Build Coastguard Worker 		msblk->block_cache[i].block = SQUASHFS_INVALID_BLK;
1025*79398b25SAndroid Build Coastguard Worker 
1026*79398b25SAndroid Build Coastguard Worker 	msblk->next_cache = 0;
1027*79398b25SAndroid Build Coastguard Worker 
1028*79398b25SAndroid Build Coastguard Worker 	/* Allocate read_data block */
1029*79398b25SAndroid Build Coastguard Worker 	msblk->read_size = (sblk->block_size < SQUASHFS_METADATA_SIZE) ?
1030*79398b25SAndroid Build Coastguard Worker 					SQUASHFS_METADATA_SIZE :
1031*79398b25SAndroid Build Coastguard Worker 					sblk->block_size;
1032*79398b25SAndroid Build Coastguard Worker 
1033*79398b25SAndroid Build Coastguard Worker 	if (!(msblk->read_data = kmalloc(msblk->read_size, GFP_KERNEL))) {
1034*79398b25SAndroid Build Coastguard Worker 		ERROR("Failed to allocate read_data block\n");
1035*79398b25SAndroid Build Coastguard Worker 		goto failed_mount;
1036*79398b25SAndroid Build Coastguard Worker 	}
1037*79398b25SAndroid Build Coastguard Worker 
1038*79398b25SAndroid Build Coastguard Worker 	/* Allocate read_page block */
1039*79398b25SAndroid Build Coastguard Worker 	if (!(msblk->read_page = kmalloc(sblk->block_size, GFP_KERNEL))) {
1040*79398b25SAndroid Build Coastguard Worker 		ERROR("Failed to allocate read_page block\n");
1041*79398b25SAndroid Build Coastguard Worker 		goto failed_mount;
1042*79398b25SAndroid Build Coastguard Worker 	}
1043*79398b25SAndroid Build Coastguard Worker 
1044*79398b25SAndroid Build Coastguard Worker 	/* Allocate uid and gid tables */
1045*79398b25SAndroid Build Coastguard Worker 	if (!(msblk->uid = kmalloc((sblk->no_uids + sblk->no_guids) *
1046*79398b25SAndroid Build Coastguard Worker 					sizeof(unsigned int), GFP_KERNEL))) {
1047*79398b25SAndroid Build Coastguard Worker 		ERROR("Failed to allocate uid/gid table\n");
1048*79398b25SAndroid Build Coastguard Worker 		goto failed_mount;
1049*79398b25SAndroid Build Coastguard Worker 	}
1050*79398b25SAndroid Build Coastguard Worker 	msblk->guid = msblk->uid + sblk->no_uids;
1051*79398b25SAndroid Build Coastguard Worker 
1052*79398b25SAndroid Build Coastguard Worker 	if (msblk->swap) {
1053*79398b25SAndroid Build Coastguard Worker 		unsigned int suid[sblk->no_uids + sblk->no_guids];
1054*79398b25SAndroid Build Coastguard Worker 
1055*79398b25SAndroid Build Coastguard Worker 		if (!squashfs_read_data(s, (char *) &suid, sblk->uid_start,
1056*79398b25SAndroid Build Coastguard Worker 					((sblk->no_uids + sblk->no_guids) *
1057*79398b25SAndroid Build Coastguard Worker 					 sizeof(unsigned int)) |
1058*79398b25SAndroid Build Coastguard Worker 					SQUASHFS_COMPRESSED_BIT_BLOCK, NULL)) {
1059*79398b25SAndroid Build Coastguard Worker 			ERROR("unable to read uid/gid table\n");
1060*79398b25SAndroid Build Coastguard Worker 			goto failed_mount;
1061*79398b25SAndroid Build Coastguard Worker 		}
1062*79398b25SAndroid Build Coastguard Worker 
1063*79398b25SAndroid Build Coastguard Worker 		SQUASHFS_SWAP_DATA(msblk->uid, suid, (sblk->no_uids +
1064*79398b25SAndroid Build Coastguard Worker 			sblk->no_guids), (sizeof(unsigned int) * 8));
1065*79398b25SAndroid Build Coastguard Worker 	} else
1066*79398b25SAndroid Build Coastguard Worker 		if (!squashfs_read_data(s, (char *) msblk->uid, sblk->uid_start,
1067*79398b25SAndroid Build Coastguard Worker 					((sblk->no_uids + sblk->no_guids) *
1068*79398b25SAndroid Build Coastguard Worker 					 sizeof(unsigned int)) |
1069*79398b25SAndroid Build Coastguard Worker 					SQUASHFS_COMPRESSED_BIT_BLOCK, NULL)) {
1070*79398b25SAndroid Build Coastguard Worker 			ERROR("unable to read uid/gid table\n");
1071*79398b25SAndroid Build Coastguard Worker 			goto failed_mount;
1072*79398b25SAndroid Build Coastguard Worker 		}
1073*79398b25SAndroid Build Coastguard Worker 
1074*79398b25SAndroid Build Coastguard Worker 
1075*79398b25SAndroid Build Coastguard Worker 	if (sblk->s_major == 1 && squashfs_1_0_supported(msblk))
1076*79398b25SAndroid Build Coastguard Worker 		goto allocate_root;
1077*79398b25SAndroid Build Coastguard Worker 
1078*79398b25SAndroid Build Coastguard Worker 	if (!(msblk->fragment = kmalloc(sizeof(struct squashfs_fragment_cache) *
1079*79398b25SAndroid Build Coastguard Worker 				SQUASHFS_CACHED_FRAGMENTS, GFP_KERNEL))) {
1080*79398b25SAndroid Build Coastguard Worker 		ERROR("Failed to allocate fragment block cache\n");
1081*79398b25SAndroid Build Coastguard Worker 		goto failed_mount;
1082*79398b25SAndroid Build Coastguard Worker 	}
1083*79398b25SAndroid Build Coastguard Worker 
1084*79398b25SAndroid Build Coastguard Worker 	for (i = 0; i < SQUASHFS_CACHED_FRAGMENTS; i++) {
1085*79398b25SAndroid Build Coastguard Worker 		msblk->fragment[i].locked = 0;
1086*79398b25SAndroid Build Coastguard Worker 		msblk->fragment[i].block = SQUASHFS_INVALID_BLK;
1087*79398b25SAndroid Build Coastguard Worker 		msblk->fragment[i].data = NULL;
1088*79398b25SAndroid Build Coastguard Worker 	}
1089*79398b25SAndroid Build Coastguard Worker 
1090*79398b25SAndroid Build Coastguard Worker 	msblk->next_fragment = 0;
1091*79398b25SAndroid Build Coastguard Worker 
1092*79398b25SAndroid Build Coastguard Worker 	/* Allocate fragment index table */
1093*79398b25SAndroid Build Coastguard Worker 	if(msblk->read_fragment_index_table(s) == 0)
1094*79398b25SAndroid Build Coastguard Worker 		goto failed_mount;
1095*79398b25SAndroid Build Coastguard Worker 
1096*79398b25SAndroid Build Coastguard Worker allocate_root:
1097*79398b25SAndroid Build Coastguard Worker 	if ((root = (msblk->iget)(s, sblk->root_inode)) == NULL)
1098*79398b25SAndroid Build Coastguard Worker 		goto failed_mount;
1099*79398b25SAndroid Build Coastguard Worker 
1100*79398b25SAndroid Build Coastguard Worker 	if ((s->s_root = d_alloc_root(root)) == NULL) {
1101*79398b25SAndroid Build Coastguard Worker 		ERROR("Root inode create failed\n");
1102*79398b25SAndroid Build Coastguard Worker 		iput(root);
1103*79398b25SAndroid Build Coastguard Worker 		goto failed_mount;
1104*79398b25SAndroid Build Coastguard Worker 	}
1105*79398b25SAndroid Build Coastguard Worker 
1106*79398b25SAndroid Build Coastguard Worker 	TRACE("Leaving squashfs_read_super\n");
1107*79398b25SAndroid Build Coastguard Worker 	return s;
1108*79398b25SAndroid Build Coastguard Worker 
1109*79398b25SAndroid Build Coastguard Worker failed_mount:
1110*79398b25SAndroid Build Coastguard Worker 	kfree(msblk->fragment_index);
1111*79398b25SAndroid Build Coastguard Worker 	kfree(msblk->fragment);
1112*79398b25SAndroid Build Coastguard Worker 	kfree(msblk->uid);
1113*79398b25SAndroid Build Coastguard Worker 	kfree(msblk->read_page);
1114*79398b25SAndroid Build Coastguard Worker 	kfree(msblk->read_data);
1115*79398b25SAndroid Build Coastguard Worker 	kfree(msblk->block_cache);
1116*79398b25SAndroid Build Coastguard Worker 	kfree(msblk->fragment_index_2);
1117*79398b25SAndroid Build Coastguard Worker 	vfree(msblk->stream.workspace);
1118*79398b25SAndroid Build Coastguard Worker 	return NULL;
1119*79398b25SAndroid Build Coastguard Worker }
1120*79398b25SAndroid Build Coastguard Worker 
1121*79398b25SAndroid Build Coastguard Worker 
squashfs_statfs(struct super_block * s,struct statfs * buf)1122*79398b25SAndroid Build Coastguard Worker static int squashfs_statfs(struct super_block *s, struct statfs *buf)
1123*79398b25SAndroid Build Coastguard Worker {
1124*79398b25SAndroid Build Coastguard Worker 	struct squashfs_sb_info *msblk = &s->u.squashfs_sb;
1125*79398b25SAndroid Build Coastguard Worker 	struct squashfs_super_block *sblk = &msblk->sblk;
1126*79398b25SAndroid Build Coastguard Worker 
1127*79398b25SAndroid Build Coastguard Worker 	TRACE("Entered squashfs_statfs\n");
1128*79398b25SAndroid Build Coastguard Worker 
1129*79398b25SAndroid Build Coastguard Worker 	buf->f_type = SQUASHFS_MAGIC;
1130*79398b25SAndroid Build Coastguard Worker 	buf->f_bsize = sblk->block_size;
1131*79398b25SAndroid Build Coastguard Worker 	buf->f_blocks = ((sblk->bytes_used - 1) >> sblk->block_log) + 1;
1132*79398b25SAndroid Build Coastguard Worker 	buf->f_bfree = buf->f_bavail = 0;
1133*79398b25SAndroid Build Coastguard Worker 	buf->f_files = sblk->inodes;
1134*79398b25SAndroid Build Coastguard Worker 	buf->f_ffree = 0;
1135*79398b25SAndroid Build Coastguard Worker 	buf->f_namelen = SQUASHFS_NAME_LEN;
1136*79398b25SAndroid Build Coastguard Worker 
1137*79398b25SAndroid Build Coastguard Worker 	return 0;
1138*79398b25SAndroid Build Coastguard Worker }
1139*79398b25SAndroid Build Coastguard Worker 
1140*79398b25SAndroid Build Coastguard Worker 
squashfs_symlink_readpage(struct file * file,struct page * page)1141*79398b25SAndroid Build Coastguard Worker static int squashfs_symlink_readpage(struct file *file, struct page *page)
1142*79398b25SAndroid Build Coastguard Worker {
1143*79398b25SAndroid Build Coastguard Worker 	struct inode *inode = page->mapping->host;
1144*79398b25SAndroid Build Coastguard Worker 	int index = page->index << PAGE_CACHE_SHIFT, length, bytes;
1145*79398b25SAndroid Build Coastguard Worker 	long long block = SQUASHFS_I(inode)->start_block;
1146*79398b25SAndroid Build Coastguard Worker 	int offset = SQUASHFS_I(inode)->offset;
1147*79398b25SAndroid Build Coastguard Worker 	void *pageaddr = kmap(page);
1148*79398b25SAndroid Build Coastguard Worker 
1149*79398b25SAndroid Build Coastguard Worker 	TRACE("Entered squashfs_symlink_readpage, page index %ld, start block "
1150*79398b25SAndroid Build Coastguard Worker 				"%llx, offset %x\n", page->index,
1151*79398b25SAndroid Build Coastguard Worker 				SQUASHFS_I(inode)->start_block,
1152*79398b25SAndroid Build Coastguard Worker 				SQUASHFS_I(inode)->offset);
1153*79398b25SAndroid Build Coastguard Worker 
1154*79398b25SAndroid Build Coastguard Worker 	for (length = 0; length < index; length += bytes) {
1155*79398b25SAndroid Build Coastguard Worker 		if (!(bytes = squashfs_get_cached_block(inode->i_sb, NULL,
1156*79398b25SAndroid Build Coastguard Worker 				block, offset, PAGE_CACHE_SIZE, &block,
1157*79398b25SAndroid Build Coastguard Worker 				&offset))) {
1158*79398b25SAndroid Build Coastguard Worker 			ERROR("Unable to read symbolic link [%llx:%x]\n", block,
1159*79398b25SAndroid Build Coastguard Worker 					offset);
1160*79398b25SAndroid Build Coastguard Worker 			goto skip_read;
1161*79398b25SAndroid Build Coastguard Worker 		}
1162*79398b25SAndroid Build Coastguard Worker 	}
1163*79398b25SAndroid Build Coastguard Worker 
1164*79398b25SAndroid Build Coastguard Worker 	if (length != index) {
1165*79398b25SAndroid Build Coastguard Worker 		ERROR("(squashfs_symlink_readpage) length != index\n");
1166*79398b25SAndroid Build Coastguard Worker 		bytes = 0;
1167*79398b25SAndroid Build Coastguard Worker 		goto skip_read;
1168*79398b25SAndroid Build Coastguard Worker 	}
1169*79398b25SAndroid Build Coastguard Worker 
1170*79398b25SAndroid Build Coastguard Worker 	bytes = (i_size_read(inode) - length) > PAGE_CACHE_SIZE ? PAGE_CACHE_SIZE :
1171*79398b25SAndroid Build Coastguard Worker 					i_size_read(inode) - length;
1172*79398b25SAndroid Build Coastguard Worker 
1173*79398b25SAndroid Build Coastguard Worker 	if (!(bytes = squashfs_get_cached_block(inode->i_sb, pageaddr, block,
1174*79398b25SAndroid Build Coastguard Worker 					offset, bytes, &block, &offset)))
1175*79398b25SAndroid Build Coastguard Worker 		ERROR("Unable to read symbolic link [%llx:%x]\n", block, offset);
1176*79398b25SAndroid Build Coastguard Worker 
1177*79398b25SAndroid Build Coastguard Worker skip_read:
1178*79398b25SAndroid Build Coastguard Worker 	memset(pageaddr + bytes, 0, PAGE_CACHE_SIZE - bytes);
1179*79398b25SAndroid Build Coastguard Worker 	kunmap(page);
1180*79398b25SAndroid Build Coastguard Worker 	SetPageUptodate(page);
1181*79398b25SAndroid Build Coastguard Worker 	UnlockPage(page);
1182*79398b25SAndroid Build Coastguard Worker 
1183*79398b25SAndroid Build Coastguard Worker 	return 0;
1184*79398b25SAndroid Build Coastguard Worker }
1185*79398b25SAndroid Build Coastguard Worker 
1186*79398b25SAndroid Build Coastguard Worker 
locate_meta_index(struct inode * inode,int index,int offset)1187*79398b25SAndroid Build Coastguard Worker struct meta_index *locate_meta_index(struct inode *inode, int index, int offset)
1188*79398b25SAndroid Build Coastguard Worker {
1189*79398b25SAndroid Build Coastguard Worker 	struct meta_index *meta = NULL;
1190*79398b25SAndroid Build Coastguard Worker 	struct squashfs_sb_info *msblk = &inode->i_sb->u.squashfs_sb;
1191*79398b25SAndroid Build Coastguard Worker 	int i;
1192*79398b25SAndroid Build Coastguard Worker 
1193*79398b25SAndroid Build Coastguard Worker 	down(&msblk->meta_index_mutex);
1194*79398b25SAndroid Build Coastguard Worker 
1195*79398b25SAndroid Build Coastguard Worker 	TRACE("locate_meta_index: index %d, offset %d\n", index, offset);
1196*79398b25SAndroid Build Coastguard Worker 
1197*79398b25SAndroid Build Coastguard Worker 	if(msblk->meta_index == NULL)
1198*79398b25SAndroid Build Coastguard Worker 		goto not_allocated;
1199*79398b25SAndroid Build Coastguard Worker 
1200*79398b25SAndroid Build Coastguard Worker 	for (i = 0; i < SQUASHFS_META_NUMBER; i ++)
1201*79398b25SAndroid Build Coastguard Worker 		if (msblk->meta_index[i].inode_number == inode->i_ino &&
1202*79398b25SAndroid Build Coastguard Worker 				msblk->meta_index[i].offset >= offset &&
1203*79398b25SAndroid Build Coastguard Worker 				msblk->meta_index[i].offset <= index &&
1204*79398b25SAndroid Build Coastguard Worker 				msblk->meta_index[i].locked == 0) {
1205*79398b25SAndroid Build Coastguard Worker 			TRACE("locate_meta_index: entry %d, offset %d\n", i,
1206*79398b25SAndroid Build Coastguard Worker 					msblk->meta_index[i].offset);
1207*79398b25SAndroid Build Coastguard Worker 			meta = &msblk->meta_index[i];
1208*79398b25SAndroid Build Coastguard Worker 			offset = meta->offset;
1209*79398b25SAndroid Build Coastguard Worker 		}
1210*79398b25SAndroid Build Coastguard Worker 
1211*79398b25SAndroid Build Coastguard Worker 	if (meta)
1212*79398b25SAndroid Build Coastguard Worker 		meta->locked = 1;
1213*79398b25SAndroid Build Coastguard Worker 
1214*79398b25SAndroid Build Coastguard Worker not_allocated:
1215*79398b25SAndroid Build Coastguard Worker 	up(&msblk->meta_index_mutex);
1216*79398b25SAndroid Build Coastguard Worker 
1217*79398b25SAndroid Build Coastguard Worker 	return meta;
1218*79398b25SAndroid Build Coastguard Worker }
1219*79398b25SAndroid Build Coastguard Worker 
1220*79398b25SAndroid Build Coastguard Worker 
empty_meta_index(struct inode * inode,int offset,int skip)1221*79398b25SAndroid Build Coastguard Worker struct meta_index *empty_meta_index(struct inode *inode, int offset, int skip)
1222*79398b25SAndroid Build Coastguard Worker {
1223*79398b25SAndroid Build Coastguard Worker 	struct squashfs_sb_info *msblk = &inode->i_sb->u.squashfs_sb;
1224*79398b25SAndroid Build Coastguard Worker 	struct meta_index *meta = NULL;
1225*79398b25SAndroid Build Coastguard Worker 	int i;
1226*79398b25SAndroid Build Coastguard Worker 
1227*79398b25SAndroid Build Coastguard Worker 	down(&msblk->meta_index_mutex);
1228*79398b25SAndroid Build Coastguard Worker 
1229*79398b25SAndroid Build Coastguard Worker 	TRACE("empty_meta_index: offset %d, skip %d\n", offset, skip);
1230*79398b25SAndroid Build Coastguard Worker 
1231*79398b25SAndroid Build Coastguard Worker 	if(msblk->meta_index == NULL) {
1232*79398b25SAndroid Build Coastguard Worker 		if (!(msblk->meta_index = kmalloc(sizeof(struct meta_index) *
1233*79398b25SAndroid Build Coastguard Worker 					SQUASHFS_META_NUMBER, GFP_KERNEL))) {
1234*79398b25SAndroid Build Coastguard Worker 			ERROR("Failed to allocate meta_index\n");
1235*79398b25SAndroid Build Coastguard Worker 			goto failed;
1236*79398b25SAndroid Build Coastguard Worker 		}
1237*79398b25SAndroid Build Coastguard Worker 		for(i = 0; i < SQUASHFS_META_NUMBER; i++) {
1238*79398b25SAndroid Build Coastguard Worker 			msblk->meta_index[i].inode_number = 0;
1239*79398b25SAndroid Build Coastguard Worker 			msblk->meta_index[i].locked = 0;
1240*79398b25SAndroid Build Coastguard Worker 		}
1241*79398b25SAndroid Build Coastguard Worker 		msblk->next_meta_index = 0;
1242*79398b25SAndroid Build Coastguard Worker 	}
1243*79398b25SAndroid Build Coastguard Worker 
1244*79398b25SAndroid Build Coastguard Worker 	for(i = SQUASHFS_META_NUMBER; i &&
1245*79398b25SAndroid Build Coastguard Worker 			msblk->meta_index[msblk->next_meta_index].locked; i --)
1246*79398b25SAndroid Build Coastguard Worker 		msblk->next_meta_index = (msblk->next_meta_index + 1) %
1247*79398b25SAndroid Build Coastguard Worker 			SQUASHFS_META_NUMBER;
1248*79398b25SAndroid Build Coastguard Worker 
1249*79398b25SAndroid Build Coastguard Worker 	if(i == 0) {
1250*79398b25SAndroid Build Coastguard Worker 		TRACE("empty_meta_index: failed!\n");
1251*79398b25SAndroid Build Coastguard Worker 		goto failed;
1252*79398b25SAndroid Build Coastguard Worker 	}
1253*79398b25SAndroid Build Coastguard Worker 
1254*79398b25SAndroid Build Coastguard Worker 	TRACE("empty_meta_index: returned meta entry %d, %p\n",
1255*79398b25SAndroid Build Coastguard Worker 			msblk->next_meta_index,
1256*79398b25SAndroid Build Coastguard Worker 			&msblk->meta_index[msblk->next_meta_index]);
1257*79398b25SAndroid Build Coastguard Worker 
1258*79398b25SAndroid Build Coastguard Worker 	meta = &msblk->meta_index[msblk->next_meta_index];
1259*79398b25SAndroid Build Coastguard Worker 	msblk->next_meta_index = (msblk->next_meta_index + 1) %
1260*79398b25SAndroid Build Coastguard Worker 			SQUASHFS_META_NUMBER;
1261*79398b25SAndroid Build Coastguard Worker 
1262*79398b25SAndroid Build Coastguard Worker 	meta->inode_number = inode->i_ino;
1263*79398b25SAndroid Build Coastguard Worker 	meta->offset = offset;
1264*79398b25SAndroid Build Coastguard Worker 	meta->skip = skip;
1265*79398b25SAndroid Build Coastguard Worker 	meta->entries = 0;
1266*79398b25SAndroid Build Coastguard Worker 	meta->locked = 1;
1267*79398b25SAndroid Build Coastguard Worker 
1268*79398b25SAndroid Build Coastguard Worker failed:
1269*79398b25SAndroid Build Coastguard Worker 	up(&msblk->meta_index_mutex);
1270*79398b25SAndroid Build Coastguard Worker 	return meta;
1271*79398b25SAndroid Build Coastguard Worker }
1272*79398b25SAndroid Build Coastguard Worker 
1273*79398b25SAndroid Build Coastguard Worker 
release_meta_index(struct inode * inode,struct meta_index * meta)1274*79398b25SAndroid Build Coastguard Worker void release_meta_index(struct inode *inode, struct meta_index *meta)
1275*79398b25SAndroid Build Coastguard Worker {
1276*79398b25SAndroid Build Coastguard Worker 	meta->locked = 0;
1277*79398b25SAndroid Build Coastguard Worker }
1278*79398b25SAndroid Build Coastguard Worker 
1279*79398b25SAndroid Build Coastguard Worker 
read_block_index(struct super_block * s,int blocks,char * block_list,long long * start_block,int * offset)1280*79398b25SAndroid Build Coastguard Worker static int read_block_index(struct super_block *s, int blocks, char *block_list,
1281*79398b25SAndroid Build Coastguard Worker 		long long *start_block, int *offset)
1282*79398b25SAndroid Build Coastguard Worker {
1283*79398b25SAndroid Build Coastguard Worker 	struct squashfs_sb_info *msblk = &s->u.squashfs_sb;
1284*79398b25SAndroid Build Coastguard Worker 	unsigned int *block_listp;
1285*79398b25SAndroid Build Coastguard Worker 	int block = 0;
1286*79398b25SAndroid Build Coastguard Worker 
1287*79398b25SAndroid Build Coastguard Worker 	if (msblk->swap) {
1288*79398b25SAndroid Build Coastguard Worker 		char sblock_list[blocks << 2];
1289*79398b25SAndroid Build Coastguard Worker 
1290*79398b25SAndroid Build Coastguard Worker 		if (!squashfs_get_cached_block(s, sblock_list, *start_block,
1291*79398b25SAndroid Build Coastguard Worker 				*offset, blocks << 2, start_block, offset)) {
1292*79398b25SAndroid Build Coastguard Worker 			ERROR("Unable to read block list [%llx:%x]\n",
1293*79398b25SAndroid Build Coastguard Worker 				*start_block, *offset);
1294*79398b25SAndroid Build Coastguard Worker 			goto failure;
1295*79398b25SAndroid Build Coastguard Worker 		}
1296*79398b25SAndroid Build Coastguard Worker 		SQUASHFS_SWAP_INTS(((unsigned int *)block_list),
1297*79398b25SAndroid Build Coastguard Worker 				((unsigned int *)sblock_list), blocks);
1298*79398b25SAndroid Build Coastguard Worker 	} else
1299*79398b25SAndroid Build Coastguard Worker 		if (!squashfs_get_cached_block(s, block_list, *start_block,
1300*79398b25SAndroid Build Coastguard Worker 				*offset, blocks << 2, start_block, offset)) {
1301*79398b25SAndroid Build Coastguard Worker 			ERROR("Unable to read block list [%llx:%x]\n",
1302*79398b25SAndroid Build Coastguard Worker 				*start_block, *offset);
1303*79398b25SAndroid Build Coastguard Worker 			goto failure;
1304*79398b25SAndroid Build Coastguard Worker 		}
1305*79398b25SAndroid Build Coastguard Worker 
1306*79398b25SAndroid Build Coastguard Worker 	for (block_listp = (unsigned int *) block_list; blocks;
1307*79398b25SAndroid Build Coastguard Worker 				block_listp++, blocks --)
1308*79398b25SAndroid Build Coastguard Worker 		block += SQUASHFS_COMPRESSED_SIZE_BLOCK(*block_listp);
1309*79398b25SAndroid Build Coastguard Worker 
1310*79398b25SAndroid Build Coastguard Worker 	return block;
1311*79398b25SAndroid Build Coastguard Worker 
1312*79398b25SAndroid Build Coastguard Worker failure:
1313*79398b25SAndroid Build Coastguard Worker 	return -1;
1314*79398b25SAndroid Build Coastguard Worker }
1315*79398b25SAndroid Build Coastguard Worker 
1316*79398b25SAndroid Build Coastguard Worker 
1317*79398b25SAndroid Build Coastguard Worker #define SIZE 256
1318*79398b25SAndroid Build Coastguard Worker 
calculate_skip(int blocks)1319*79398b25SAndroid Build Coastguard Worker static inline int calculate_skip(int blocks) {
1320*79398b25SAndroid Build Coastguard Worker 	int skip = (blocks - 1) / ((SQUASHFS_SLOTS * SQUASHFS_META_ENTRIES + 1) * SQUASHFS_META_INDEXES);
1321*79398b25SAndroid Build Coastguard Worker 	return skip >= 7 ? 7 : skip + 1;
1322*79398b25SAndroid Build Coastguard Worker }
1323*79398b25SAndroid Build Coastguard Worker 
1324*79398b25SAndroid Build Coastguard Worker 
get_meta_index(struct inode * inode,int index,long long * index_block,int * index_offset,long long * data_block,char * block_list)1325*79398b25SAndroid Build Coastguard Worker static int get_meta_index(struct inode *inode, int index,
1326*79398b25SAndroid Build Coastguard Worker 		long long *index_block, int *index_offset,
1327*79398b25SAndroid Build Coastguard Worker 		long long *data_block, char *block_list)
1328*79398b25SAndroid Build Coastguard Worker {
1329*79398b25SAndroid Build Coastguard Worker 	struct squashfs_sb_info *msblk = &inode->i_sb->u.squashfs_sb;
1330*79398b25SAndroid Build Coastguard Worker 	struct squashfs_super_block *sblk = &msblk->sblk;
1331*79398b25SAndroid Build Coastguard Worker 	int skip = calculate_skip(i_size_read(inode) >> sblk->block_log);
1332*79398b25SAndroid Build Coastguard Worker 	int offset = 0;
1333*79398b25SAndroid Build Coastguard Worker 	struct meta_index *meta;
1334*79398b25SAndroid Build Coastguard Worker 	struct meta_entry *meta_entry;
1335*79398b25SAndroid Build Coastguard Worker 	long long cur_index_block = SQUASHFS_I(inode)->u.s1.block_list_start;
1336*79398b25SAndroid Build Coastguard Worker 	int cur_offset = SQUASHFS_I(inode)->offset;
1337*79398b25SAndroid Build Coastguard Worker 	long long cur_data_block = SQUASHFS_I(inode)->start_block;
1338*79398b25SAndroid Build Coastguard Worker 	int i;
1339*79398b25SAndroid Build Coastguard Worker 
1340*79398b25SAndroid Build Coastguard Worker 	index /= SQUASHFS_META_INDEXES * skip;
1341*79398b25SAndroid Build Coastguard Worker 
1342*79398b25SAndroid Build Coastguard Worker 	while ( offset < index ) {
1343*79398b25SAndroid Build Coastguard Worker 		meta = locate_meta_index(inode, index, offset + 1);
1344*79398b25SAndroid Build Coastguard Worker 
1345*79398b25SAndroid Build Coastguard Worker 		if (meta == NULL) {
1346*79398b25SAndroid Build Coastguard Worker 			if ((meta = empty_meta_index(inode, offset + 1,
1347*79398b25SAndroid Build Coastguard Worker 							skip)) == NULL)
1348*79398b25SAndroid Build Coastguard Worker 				goto all_done;
1349*79398b25SAndroid Build Coastguard Worker 		} else {
1350*79398b25SAndroid Build Coastguard Worker 			offset = index < meta->offset + meta->entries ? index :
1351*79398b25SAndroid Build Coastguard Worker 				meta->offset + meta->entries - 1;
1352*79398b25SAndroid Build Coastguard Worker 			meta_entry = &meta->meta_entry[offset - meta->offset];
1353*79398b25SAndroid Build Coastguard Worker 			cur_index_block = meta_entry->index_block + sblk->inode_table_start;
1354*79398b25SAndroid Build Coastguard Worker 			cur_offset = meta_entry->offset;
1355*79398b25SAndroid Build Coastguard Worker 			cur_data_block = meta_entry->data_block;
1356*79398b25SAndroid Build Coastguard Worker 			TRACE("get_meta_index: offset %d, meta->offset %d, "
1357*79398b25SAndroid Build Coastguard Worker 				"meta->entries %d\n", offset, meta->offset,
1358*79398b25SAndroid Build Coastguard Worker 				meta->entries);
1359*79398b25SAndroid Build Coastguard Worker 			TRACE("get_meta_index: index_block 0x%llx, offset 0x%x"
1360*79398b25SAndroid Build Coastguard Worker 				" data_block 0x%llx\n", cur_index_block,
1361*79398b25SAndroid Build Coastguard Worker 				cur_offset, cur_data_block);
1362*79398b25SAndroid Build Coastguard Worker 		}
1363*79398b25SAndroid Build Coastguard Worker 
1364*79398b25SAndroid Build Coastguard Worker 		for (i = meta->offset + meta->entries; i <= index &&
1365*79398b25SAndroid Build Coastguard Worker 				i < meta->offset + SQUASHFS_META_ENTRIES; i++) {
1366*79398b25SAndroid Build Coastguard Worker 			int blocks = skip * SQUASHFS_META_INDEXES;
1367*79398b25SAndroid Build Coastguard Worker 
1368*79398b25SAndroid Build Coastguard Worker 			while (blocks) {
1369*79398b25SAndroid Build Coastguard Worker 				int block = blocks > (SIZE >> 2) ? (SIZE >> 2) :
1370*79398b25SAndroid Build Coastguard Worker 					blocks;
1371*79398b25SAndroid Build Coastguard Worker 				int res = read_block_index(inode->i_sb, block,
1372*79398b25SAndroid Build Coastguard Worker 					block_list, &cur_index_block,
1373*79398b25SAndroid Build Coastguard Worker 					&cur_offset);
1374*79398b25SAndroid Build Coastguard Worker 
1375*79398b25SAndroid Build Coastguard Worker 				if (res == -1)
1376*79398b25SAndroid Build Coastguard Worker 					goto failed;
1377*79398b25SAndroid Build Coastguard Worker 
1378*79398b25SAndroid Build Coastguard Worker 				cur_data_block += res;
1379*79398b25SAndroid Build Coastguard Worker 				blocks -= block;
1380*79398b25SAndroid Build Coastguard Worker 			}
1381*79398b25SAndroid Build Coastguard Worker 
1382*79398b25SAndroid Build Coastguard Worker 			meta_entry = &meta->meta_entry[i - meta->offset];
1383*79398b25SAndroid Build Coastguard Worker 			meta_entry->index_block = cur_index_block - sblk->inode_table_start;
1384*79398b25SAndroid Build Coastguard Worker 			meta_entry->offset = cur_offset;
1385*79398b25SAndroid Build Coastguard Worker 			meta_entry->data_block = cur_data_block;
1386*79398b25SAndroid Build Coastguard Worker 			meta->entries ++;
1387*79398b25SAndroid Build Coastguard Worker 			offset ++;
1388*79398b25SAndroid Build Coastguard Worker 		}
1389*79398b25SAndroid Build Coastguard Worker 
1390*79398b25SAndroid Build Coastguard Worker 		TRACE("get_meta_index: meta->offset %d, meta->entries %d\n",
1391*79398b25SAndroid Build Coastguard Worker 				meta->offset, meta->entries);
1392*79398b25SAndroid Build Coastguard Worker 
1393*79398b25SAndroid Build Coastguard Worker 		release_meta_index(inode, meta);
1394*79398b25SAndroid Build Coastguard Worker 	}
1395*79398b25SAndroid Build Coastguard Worker 
1396*79398b25SAndroid Build Coastguard Worker all_done:
1397*79398b25SAndroid Build Coastguard Worker 	*index_block = cur_index_block;
1398*79398b25SAndroid Build Coastguard Worker 	*index_offset = cur_offset;
1399*79398b25SAndroid Build Coastguard Worker 	*data_block = cur_data_block;
1400*79398b25SAndroid Build Coastguard Worker 
1401*79398b25SAndroid Build Coastguard Worker 	return offset * SQUASHFS_META_INDEXES * skip;
1402*79398b25SAndroid Build Coastguard Worker 
1403*79398b25SAndroid Build Coastguard Worker failed:
1404*79398b25SAndroid Build Coastguard Worker 	release_meta_index(inode, meta);
1405*79398b25SAndroid Build Coastguard Worker 	return -1;
1406*79398b25SAndroid Build Coastguard Worker }
1407*79398b25SAndroid Build Coastguard Worker 
1408*79398b25SAndroid Build Coastguard Worker 
read_blocklist(struct inode * inode,int index,int readahead_blks,char * block_list,unsigned short ** block_p,unsigned int * bsize)1409*79398b25SAndroid Build Coastguard Worker static long long read_blocklist(struct inode *inode, int index,
1410*79398b25SAndroid Build Coastguard Worker 				int readahead_blks, char *block_list,
1411*79398b25SAndroid Build Coastguard Worker 				unsigned short **block_p, unsigned int *bsize)
1412*79398b25SAndroid Build Coastguard Worker {
1413*79398b25SAndroid Build Coastguard Worker 	long long block_ptr;
1414*79398b25SAndroid Build Coastguard Worker 	int offset;
1415*79398b25SAndroid Build Coastguard Worker 	long long block;
1416*79398b25SAndroid Build Coastguard Worker 	int res = get_meta_index(inode, index, &block_ptr, &offset, &block,
1417*79398b25SAndroid Build Coastguard Worker 		block_list);
1418*79398b25SAndroid Build Coastguard Worker 
1419*79398b25SAndroid Build Coastguard Worker 	TRACE("read_blocklist: res %d, index %d, block_ptr 0x%llx, offset"
1420*79398b25SAndroid Build Coastguard Worker 		       " 0x%x, block 0x%llx\n", res, index, block_ptr, offset,
1421*79398b25SAndroid Build Coastguard Worker 		       block);
1422*79398b25SAndroid Build Coastguard Worker 
1423*79398b25SAndroid Build Coastguard Worker 	if(res == -1)
1424*79398b25SAndroid Build Coastguard Worker 		goto failure;
1425*79398b25SAndroid Build Coastguard Worker 
1426*79398b25SAndroid Build Coastguard Worker 	index -= res;
1427*79398b25SAndroid Build Coastguard Worker 
1428*79398b25SAndroid Build Coastguard Worker 	while ( index ) {
1429*79398b25SAndroid Build Coastguard Worker 		int blocks = index > (SIZE >> 2) ? (SIZE >> 2) : index;
1430*79398b25SAndroid Build Coastguard Worker 		int res = read_block_index(inode->i_sb, blocks, block_list,
1431*79398b25SAndroid Build Coastguard Worker 			&block_ptr, &offset);
1432*79398b25SAndroid Build Coastguard Worker 		if (res == -1)
1433*79398b25SAndroid Build Coastguard Worker 			goto failure;
1434*79398b25SAndroid Build Coastguard Worker 		block += res;
1435*79398b25SAndroid Build Coastguard Worker 		index -= blocks;
1436*79398b25SAndroid Build Coastguard Worker 	}
1437*79398b25SAndroid Build Coastguard Worker 
1438*79398b25SAndroid Build Coastguard Worker 	if (read_block_index(inode->i_sb, 1, block_list,
1439*79398b25SAndroid Build Coastguard Worker 			&block_ptr, &offset) == -1)
1440*79398b25SAndroid Build Coastguard Worker 		goto failure;
1441*79398b25SAndroid Build Coastguard Worker 	*bsize = *((unsigned int *) block_list);
1442*79398b25SAndroid Build Coastguard Worker 
1443*79398b25SAndroid Build Coastguard Worker 	return block;
1444*79398b25SAndroid Build Coastguard Worker 
1445*79398b25SAndroid Build Coastguard Worker failure:
1446*79398b25SAndroid Build Coastguard Worker 	return 0;
1447*79398b25SAndroid Build Coastguard Worker }
1448*79398b25SAndroid Build Coastguard Worker 
1449*79398b25SAndroid Build Coastguard Worker 
squashfs_readpage(struct file * file,struct page * page)1450*79398b25SAndroid Build Coastguard Worker static int squashfs_readpage(struct file *file, struct page *page)
1451*79398b25SAndroid Build Coastguard Worker {
1452*79398b25SAndroid Build Coastguard Worker 	struct inode *inode = page->mapping->host;
1453*79398b25SAndroid Build Coastguard Worker 	struct squashfs_sb_info *msblk = &inode->i_sb->u.squashfs_sb;
1454*79398b25SAndroid Build Coastguard Worker 	struct squashfs_super_block *sblk = &msblk->sblk;
1455*79398b25SAndroid Build Coastguard Worker 	unsigned char block_list[SIZE];
1456*79398b25SAndroid Build Coastguard Worker 	long long block;
1457*79398b25SAndroid Build Coastguard Worker 	unsigned int bsize, i = 0, bytes = 0, byte_offset = 0;
1458*79398b25SAndroid Build Coastguard Worker 	int index = page->index >> (sblk->block_log - PAGE_CACHE_SHIFT);
1459*79398b25SAndroid Build Coastguard Worker  	void *pageaddr;
1460*79398b25SAndroid Build Coastguard Worker 	struct squashfs_fragment_cache *fragment = NULL;
1461*79398b25SAndroid Build Coastguard Worker 	char *data_ptr = msblk->read_page;
1462*79398b25SAndroid Build Coastguard Worker 
1463*79398b25SAndroid Build Coastguard Worker 	int mask = (1 << (sblk->block_log - PAGE_CACHE_SHIFT)) - 1;
1464*79398b25SAndroid Build Coastguard Worker 	int start_index = page->index & ~mask;
1465*79398b25SAndroid Build Coastguard Worker 	int end_index = start_index | mask;
1466*79398b25SAndroid Build Coastguard Worker 
1467*79398b25SAndroid Build Coastguard Worker 	TRACE("Entered squashfs_readpage, page index %lx, start block %llx\n",
1468*79398b25SAndroid Build Coastguard Worker 					page->index,
1469*79398b25SAndroid Build Coastguard Worker 					SQUASHFS_I(inode)->start_block);
1470*79398b25SAndroid Build Coastguard Worker 
1471*79398b25SAndroid Build Coastguard Worker 	if (page->index >= ((i_size_read(inode) + PAGE_CACHE_SIZE - 1) >>
1472*79398b25SAndroid Build Coastguard Worker 					PAGE_CACHE_SHIFT))
1473*79398b25SAndroid Build Coastguard Worker 		goto skip_read;
1474*79398b25SAndroid Build Coastguard Worker 
1475*79398b25SAndroid Build Coastguard Worker 	if (SQUASHFS_I(inode)->u.s1.fragment_start_block == SQUASHFS_INVALID_BLK
1476*79398b25SAndroid Build Coastguard Worker 					|| index < (i_size_read(inode) >>
1477*79398b25SAndroid Build Coastguard Worker 					sblk->block_log)) {
1478*79398b25SAndroid Build Coastguard Worker 		if ((block = (msblk->read_blocklist)(inode, index, 1,
1479*79398b25SAndroid Build Coastguard Worker 					block_list, NULL, &bsize)) == 0)
1480*79398b25SAndroid Build Coastguard Worker 			goto skip_read;
1481*79398b25SAndroid Build Coastguard Worker 
1482*79398b25SAndroid Build Coastguard Worker 		down(&msblk->read_page_mutex);
1483*79398b25SAndroid Build Coastguard Worker 
1484*79398b25SAndroid Build Coastguard Worker 		if (!(bytes = squashfs_read_data(inode->i_sb, msblk->read_page,
1485*79398b25SAndroid Build Coastguard Worker 					block, bsize, NULL))) {
1486*79398b25SAndroid Build Coastguard Worker 			ERROR("Unable to read page, block %llx, size %x\n", block,
1487*79398b25SAndroid Build Coastguard Worker 					bsize);
1488*79398b25SAndroid Build Coastguard Worker 			up(&msblk->read_page_mutex);
1489*79398b25SAndroid Build Coastguard Worker 			goto skip_read;
1490*79398b25SAndroid Build Coastguard Worker 		}
1491*79398b25SAndroid Build Coastguard Worker 	} else {
1492*79398b25SAndroid Build Coastguard Worker 		if ((fragment = get_cached_fragment(inode->i_sb,
1493*79398b25SAndroid Build Coastguard Worker 					SQUASHFS_I(inode)->
1494*79398b25SAndroid Build Coastguard Worker 					u.s1.fragment_start_block,
1495*79398b25SAndroid Build Coastguard Worker 					SQUASHFS_I(inode)->u.s1.fragment_size))
1496*79398b25SAndroid Build Coastguard Worker 					== NULL) {
1497*79398b25SAndroid Build Coastguard Worker 			ERROR("Unable to read page, block %llx, size %x\n",
1498*79398b25SAndroid Build Coastguard Worker 					SQUASHFS_I(inode)->
1499*79398b25SAndroid Build Coastguard Worker 					u.s1.fragment_start_block,
1500*79398b25SAndroid Build Coastguard Worker 					(int) SQUASHFS_I(inode)->
1501*79398b25SAndroid Build Coastguard Worker 					u.s1.fragment_size);
1502*79398b25SAndroid Build Coastguard Worker 			goto skip_read;
1503*79398b25SAndroid Build Coastguard Worker 		}
1504*79398b25SAndroid Build Coastguard Worker 		bytes = SQUASHFS_I(inode)->u.s1.fragment_offset +
1505*79398b25SAndroid Build Coastguard Worker 					(i_size_read(inode) & (sblk->block_size
1506*79398b25SAndroid Build Coastguard Worker 					- 1));
1507*79398b25SAndroid Build Coastguard Worker 		byte_offset = SQUASHFS_I(inode)->u.s1.fragment_offset;
1508*79398b25SAndroid Build Coastguard Worker 		data_ptr = fragment->data;
1509*79398b25SAndroid Build Coastguard Worker 	}
1510*79398b25SAndroid Build Coastguard Worker 
1511*79398b25SAndroid Build Coastguard Worker 	for (i = start_index; i <= end_index && byte_offset < bytes;
1512*79398b25SAndroid Build Coastguard Worker 					i++, byte_offset += PAGE_CACHE_SIZE) {
1513*79398b25SAndroid Build Coastguard Worker 		struct page *push_page;
1514*79398b25SAndroid Build Coastguard Worker 		int available_bytes = (bytes - byte_offset) > PAGE_CACHE_SIZE ?
1515*79398b25SAndroid Build Coastguard Worker 					PAGE_CACHE_SIZE : bytes - byte_offset;
1516*79398b25SAndroid Build Coastguard Worker 
1517*79398b25SAndroid Build Coastguard Worker 		TRACE("bytes %d, i %d, byte_offset %d, available_bytes %d\n",
1518*79398b25SAndroid Build Coastguard Worker 					bytes, i, byte_offset, available_bytes);
1519*79398b25SAndroid Build Coastguard Worker 
1520*79398b25SAndroid Build Coastguard Worker 		if (i == page->index)  {
1521*79398b25SAndroid Build Coastguard Worker 			pageaddr = kmap_atomic(page, KM_USER0);
1522*79398b25SAndroid Build Coastguard Worker 			memcpy(pageaddr, data_ptr + byte_offset,
1523*79398b25SAndroid Build Coastguard Worker 					available_bytes);
1524*79398b25SAndroid Build Coastguard Worker 			memset(pageaddr + available_bytes, 0,
1525*79398b25SAndroid Build Coastguard Worker 					PAGE_CACHE_SIZE - available_bytes);
1526*79398b25SAndroid Build Coastguard Worker 			kunmap_atomic(pageaddr, KM_USER0);
1527*79398b25SAndroid Build Coastguard Worker 			flush_dcache_page(page);
1528*79398b25SAndroid Build Coastguard Worker 			SetPageUptodate(page);
1529*79398b25SAndroid Build Coastguard Worker 			UnlockPage(page);
1530*79398b25SAndroid Build Coastguard Worker 		} else if ((push_page =
1531*79398b25SAndroid Build Coastguard Worker 				grab_cache_page_nowait(page->mapping, i))) {
1532*79398b25SAndroid Build Coastguard Worker  			pageaddr = kmap_atomic(push_page, KM_USER0);
1533*79398b25SAndroid Build Coastguard Worker 
1534*79398b25SAndroid Build Coastguard Worker 			memcpy(pageaddr, data_ptr + byte_offset,
1535*79398b25SAndroid Build Coastguard Worker 					available_bytes);
1536*79398b25SAndroid Build Coastguard Worker 			memset(pageaddr + available_bytes, 0,
1537*79398b25SAndroid Build Coastguard Worker 					PAGE_CACHE_SIZE - available_bytes);
1538*79398b25SAndroid Build Coastguard Worker 			kunmap_atomic(pageaddr, KM_USER0);
1539*79398b25SAndroid Build Coastguard Worker 			flush_dcache_page(push_page);
1540*79398b25SAndroid Build Coastguard Worker 			SetPageUptodate(push_page);
1541*79398b25SAndroid Build Coastguard Worker 			UnlockPage(push_page);
1542*79398b25SAndroid Build Coastguard Worker 			page_cache_release(push_page);
1543*79398b25SAndroid Build Coastguard Worker 		}
1544*79398b25SAndroid Build Coastguard Worker 	}
1545*79398b25SAndroid Build Coastguard Worker 
1546*79398b25SAndroid Build Coastguard Worker 	if (SQUASHFS_I(inode)->u.s1.fragment_start_block == SQUASHFS_INVALID_BLK
1547*79398b25SAndroid Build Coastguard Worker 					|| index < (i_size_read(inode) >>
1548*79398b25SAndroid Build Coastguard Worker 					sblk->block_log))
1549*79398b25SAndroid Build Coastguard Worker 		up(&msblk->read_page_mutex);
1550*79398b25SAndroid Build Coastguard Worker 	else
1551*79398b25SAndroid Build Coastguard Worker 		release_cached_fragment(msblk, fragment);
1552*79398b25SAndroid Build Coastguard Worker 
1553*79398b25SAndroid Build Coastguard Worker 	return 0;
1554*79398b25SAndroid Build Coastguard Worker 
1555*79398b25SAndroid Build Coastguard Worker skip_read:
1556*79398b25SAndroid Build Coastguard Worker 	pageaddr = kmap_atomic(page, KM_USER0);
1557*79398b25SAndroid Build Coastguard Worker 	memset(pageaddr + bytes, 0, PAGE_CACHE_SIZE - bytes);
1558*79398b25SAndroid Build Coastguard Worker 	kunmap_atomic(pageaddr, KM_USER0);
1559*79398b25SAndroid Build Coastguard Worker 	flush_dcache_page(page);
1560*79398b25SAndroid Build Coastguard Worker 	SetPageUptodate(page);
1561*79398b25SAndroid Build Coastguard Worker 	UnlockPage(page);
1562*79398b25SAndroid Build Coastguard Worker 
1563*79398b25SAndroid Build Coastguard Worker 	return 0;
1564*79398b25SAndroid Build Coastguard Worker }
1565*79398b25SAndroid Build Coastguard Worker 
1566*79398b25SAndroid Build Coastguard Worker 
squashfs_readpage4K(struct file * file,struct page * page)1567*79398b25SAndroid Build Coastguard Worker static int squashfs_readpage4K(struct file *file, struct page *page)
1568*79398b25SAndroid Build Coastguard Worker {
1569*79398b25SAndroid Build Coastguard Worker 	struct inode *inode = page->mapping->host;
1570*79398b25SAndroid Build Coastguard Worker 	struct squashfs_sb_info *msblk = &inode->i_sb->u.squashfs_sb;
1571*79398b25SAndroid Build Coastguard Worker 	struct squashfs_super_block *sblk = &msblk->sblk;
1572*79398b25SAndroid Build Coastguard Worker 	unsigned char block_list[SIZE];
1573*79398b25SAndroid Build Coastguard Worker 	long long block;
1574*79398b25SAndroid Build Coastguard Worker 	unsigned int bsize, bytes = 0;
1575*79398b25SAndroid Build Coastguard Worker  	void *pageaddr;
1576*79398b25SAndroid Build Coastguard Worker 
1577*79398b25SAndroid Build Coastguard Worker 	TRACE("Entered squashfs_readpage4K, page index %lx, start block %llx\n",
1578*79398b25SAndroid Build Coastguard Worker 					page->index,
1579*79398b25SAndroid Build Coastguard Worker 					SQUASHFS_I(inode)->start_block);
1580*79398b25SAndroid Build Coastguard Worker 
1581*79398b25SAndroid Build Coastguard Worker 	if (page->index >= ((i_size_read(inode) + PAGE_CACHE_SIZE - 1) >>
1582*79398b25SAndroid Build Coastguard Worker 					PAGE_CACHE_SHIFT)) {
1583*79398b25SAndroid Build Coastguard Worker 		pageaddr = kmap_atomic(page, KM_USER0);
1584*79398b25SAndroid Build Coastguard Worker 		goto skip_read;
1585*79398b25SAndroid Build Coastguard Worker 	}
1586*79398b25SAndroid Build Coastguard Worker 
1587*79398b25SAndroid Build Coastguard Worker 	if (SQUASHFS_I(inode)->u.s1.fragment_start_block == SQUASHFS_INVALID_BLK
1588*79398b25SAndroid Build Coastguard Worker 					|| page->index < (i_size_read(inode) >>
1589*79398b25SAndroid Build Coastguard Worker 					sblk->block_log)) {
1590*79398b25SAndroid Build Coastguard Worker 		block = (msblk->read_blocklist)(inode, page->index, 1,
1591*79398b25SAndroid Build Coastguard Worker 					block_list, NULL, &bsize);
1592*79398b25SAndroid Build Coastguard Worker 
1593*79398b25SAndroid Build Coastguard Worker 		down(&msblk->read_page_mutex);
1594*79398b25SAndroid Build Coastguard Worker 		bytes = squashfs_read_data(inode->i_sb, msblk->read_page, block,
1595*79398b25SAndroid Build Coastguard Worker 					bsize, NULL);
1596*79398b25SAndroid Build Coastguard Worker 		pageaddr = kmap_atomic(page, KM_USER0);
1597*79398b25SAndroid Build Coastguard Worker 		if (bytes)
1598*79398b25SAndroid Build Coastguard Worker 			memcpy(pageaddr, msblk->read_page, bytes);
1599*79398b25SAndroid Build Coastguard Worker 		else
1600*79398b25SAndroid Build Coastguard Worker 			ERROR("Unable to read page, block %llx, size %x\n",
1601*79398b25SAndroid Build Coastguard Worker 					block, bsize);
1602*79398b25SAndroid Build Coastguard Worker 		up(&msblk->read_page_mutex);
1603*79398b25SAndroid Build Coastguard Worker 	} else {
1604*79398b25SAndroid Build Coastguard Worker 		struct squashfs_fragment_cache *fragment =
1605*79398b25SAndroid Build Coastguard Worker 			get_cached_fragment(inode->i_sb,
1606*79398b25SAndroid Build Coastguard Worker 					SQUASHFS_I(inode)->
1607*79398b25SAndroid Build Coastguard Worker 					u.s1.fragment_start_block,
1608*79398b25SAndroid Build Coastguard Worker 					SQUASHFS_I(inode)-> u.s1.fragment_size);
1609*79398b25SAndroid Build Coastguard Worker 		pageaddr = kmap_atomic(page, KM_USER0);
1610*79398b25SAndroid Build Coastguard Worker 		if (fragment) {
1611*79398b25SAndroid Build Coastguard Worker 			bytes = i_size_read(inode) & (sblk->block_size - 1);
1612*79398b25SAndroid Build Coastguard Worker 			memcpy(pageaddr, fragment->data + SQUASHFS_I(inode)->
1613*79398b25SAndroid Build Coastguard Worker 					u.s1.fragment_offset, bytes);
1614*79398b25SAndroid Build Coastguard Worker 			release_cached_fragment(msblk, fragment);
1615*79398b25SAndroid Build Coastguard Worker 		} else
1616*79398b25SAndroid Build Coastguard Worker 			ERROR("Unable to read page, block %llx, size %x\n",
1617*79398b25SAndroid Build Coastguard Worker 					SQUASHFS_I(inode)->
1618*79398b25SAndroid Build Coastguard Worker 					u.s1.fragment_start_block, (int)
1619*79398b25SAndroid Build Coastguard Worker 					SQUASHFS_I(inode)-> u.s1.fragment_size);
1620*79398b25SAndroid Build Coastguard Worker 	}
1621*79398b25SAndroid Build Coastguard Worker 
1622*79398b25SAndroid Build Coastguard Worker skip_read:
1623*79398b25SAndroid Build Coastguard Worker 	memset(pageaddr + bytes, 0, PAGE_CACHE_SIZE - bytes);
1624*79398b25SAndroid Build Coastguard Worker 	kunmap_atomic(pageaddr, KM_USER0);
1625*79398b25SAndroid Build Coastguard Worker 	flush_dcache_page(page);
1626*79398b25SAndroid Build Coastguard Worker 	SetPageUptodate(page);
1627*79398b25SAndroid Build Coastguard Worker 	UnlockPage(page);
1628*79398b25SAndroid Build Coastguard Worker 
1629*79398b25SAndroid Build Coastguard Worker 	return 0;
1630*79398b25SAndroid Build Coastguard Worker }
1631*79398b25SAndroid Build Coastguard Worker 
1632*79398b25SAndroid Build Coastguard Worker 
get_dir_index_using_offset(struct super_block * s,long long * next_block,unsigned int * next_offset,long long index_start,unsigned int index_offset,int i_count,long long f_pos)1633*79398b25SAndroid Build Coastguard Worker static int get_dir_index_using_offset(struct super_block *s, long long
1634*79398b25SAndroid Build Coastguard Worker 				*next_block, unsigned int *next_offset,
1635*79398b25SAndroid Build Coastguard Worker 				long long index_start,
1636*79398b25SAndroid Build Coastguard Worker 				unsigned int index_offset, int i_count,
1637*79398b25SAndroid Build Coastguard Worker 				long long f_pos)
1638*79398b25SAndroid Build Coastguard Worker {
1639*79398b25SAndroid Build Coastguard Worker 	struct squashfs_sb_info *msblk = &s->u.squashfs_sb;
1640*79398b25SAndroid Build Coastguard Worker 	struct squashfs_super_block *sblk = &msblk->sblk;
1641*79398b25SAndroid Build Coastguard Worker 	int i, length = 0;
1642*79398b25SAndroid Build Coastguard Worker 	struct squashfs_dir_index index;
1643*79398b25SAndroid Build Coastguard Worker 
1644*79398b25SAndroid Build Coastguard Worker 	TRACE("Entered get_dir_index_using_offset, i_count %d, f_pos %d\n",
1645*79398b25SAndroid Build Coastguard Worker 					i_count, (unsigned int) f_pos);
1646*79398b25SAndroid Build Coastguard Worker 
1647*79398b25SAndroid Build Coastguard Worker 	f_pos -= 3;
1648*79398b25SAndroid Build Coastguard Worker 	if (f_pos == 0)
1649*79398b25SAndroid Build Coastguard Worker 		goto finish;
1650*79398b25SAndroid Build Coastguard Worker 
1651*79398b25SAndroid Build Coastguard Worker 	for (i = 0; i < i_count; i++) {
1652*79398b25SAndroid Build Coastguard Worker 		if (msblk->swap) {
1653*79398b25SAndroid Build Coastguard Worker 			struct squashfs_dir_index sindex;
1654*79398b25SAndroid Build Coastguard Worker 			squashfs_get_cached_block(s, (char *) &sindex,
1655*79398b25SAndroid Build Coastguard Worker 					index_start, index_offset,
1656*79398b25SAndroid Build Coastguard Worker 					sizeof(sindex), &index_start,
1657*79398b25SAndroid Build Coastguard Worker 					&index_offset);
1658*79398b25SAndroid Build Coastguard Worker 			SQUASHFS_SWAP_DIR_INDEX(&index, &sindex);
1659*79398b25SAndroid Build Coastguard Worker 		} else
1660*79398b25SAndroid Build Coastguard Worker 			squashfs_get_cached_block(s, (char *) &index,
1661*79398b25SAndroid Build Coastguard Worker 					index_start, index_offset,
1662*79398b25SAndroid Build Coastguard Worker 					sizeof(index), &index_start,
1663*79398b25SAndroid Build Coastguard Worker 					&index_offset);
1664*79398b25SAndroid Build Coastguard Worker 
1665*79398b25SAndroid Build Coastguard Worker 		if (index.index > f_pos)
1666*79398b25SAndroid Build Coastguard Worker 			break;
1667*79398b25SAndroid Build Coastguard Worker 
1668*79398b25SAndroid Build Coastguard Worker 		squashfs_get_cached_block(s, NULL, index_start, index_offset,
1669*79398b25SAndroid Build Coastguard Worker 					index.size + 1, &index_start,
1670*79398b25SAndroid Build Coastguard Worker 					&index_offset);
1671*79398b25SAndroid Build Coastguard Worker 
1672*79398b25SAndroid Build Coastguard Worker 		length = index.index;
1673*79398b25SAndroid Build Coastguard Worker 		*next_block = index.start_block + sblk->directory_table_start;
1674*79398b25SAndroid Build Coastguard Worker 	}
1675*79398b25SAndroid Build Coastguard Worker 
1676*79398b25SAndroid Build Coastguard Worker 	*next_offset = (length + *next_offset) % SQUASHFS_METADATA_SIZE;
1677*79398b25SAndroid Build Coastguard Worker 
1678*79398b25SAndroid Build Coastguard Worker finish:
1679*79398b25SAndroid Build Coastguard Worker 	return length + 3;
1680*79398b25SAndroid Build Coastguard Worker }
1681*79398b25SAndroid Build Coastguard Worker 
1682*79398b25SAndroid Build Coastguard Worker 
get_dir_index_using_name(struct super_block * s,long long * next_block,unsigned int * next_offset,long long index_start,unsigned int index_offset,int i_count,const char * name,int size)1683*79398b25SAndroid Build Coastguard Worker static int get_dir_index_using_name(struct super_block *s, long long
1684*79398b25SAndroid Build Coastguard Worker 				*next_block, unsigned int *next_offset,
1685*79398b25SAndroid Build Coastguard Worker 				long long index_start,
1686*79398b25SAndroid Build Coastguard Worker 				unsigned int index_offset, int i_count,
1687*79398b25SAndroid Build Coastguard Worker 				const char *name, int size)
1688*79398b25SAndroid Build Coastguard Worker {
1689*79398b25SAndroid Build Coastguard Worker 	struct squashfs_sb_info *msblk = &s->u.squashfs_sb;
1690*79398b25SAndroid Build Coastguard Worker 	struct squashfs_super_block *sblk = &msblk->sblk;
1691*79398b25SAndroid Build Coastguard Worker 	int i, length = 0;
1692*79398b25SAndroid Build Coastguard Worker 	char buffer[sizeof(struct squashfs_dir_index) + SQUASHFS_NAME_LEN + 1];
1693*79398b25SAndroid Build Coastguard Worker 	struct squashfs_dir_index *index = (struct squashfs_dir_index *) buffer;
1694*79398b25SAndroid Build Coastguard Worker 	char str[SQUASHFS_NAME_LEN + 1];
1695*79398b25SAndroid Build Coastguard Worker 
1696*79398b25SAndroid Build Coastguard Worker 	TRACE("Entered get_dir_index_using_name, i_count %d\n", i_count);
1697*79398b25SAndroid Build Coastguard Worker 
1698*79398b25SAndroid Build Coastguard Worker 	strncpy(str, name, size);
1699*79398b25SAndroid Build Coastguard Worker 	str[size] = '\0';
1700*79398b25SAndroid Build Coastguard Worker 
1701*79398b25SAndroid Build Coastguard Worker 	for (i = 0; i < i_count; i++) {
1702*79398b25SAndroid Build Coastguard Worker 		if (msblk->swap) {
1703*79398b25SAndroid Build Coastguard Worker 			struct squashfs_dir_index sindex;
1704*79398b25SAndroid Build Coastguard Worker 			squashfs_get_cached_block(s, (char *) &sindex,
1705*79398b25SAndroid Build Coastguard Worker 					index_start, index_offset,
1706*79398b25SAndroid Build Coastguard Worker 					sizeof(sindex), &index_start,
1707*79398b25SAndroid Build Coastguard Worker 					&index_offset);
1708*79398b25SAndroid Build Coastguard Worker 			SQUASHFS_SWAP_DIR_INDEX(index, &sindex);
1709*79398b25SAndroid Build Coastguard Worker 		} else
1710*79398b25SAndroid Build Coastguard Worker 			squashfs_get_cached_block(s, (char *) index,
1711*79398b25SAndroid Build Coastguard Worker 					index_start, index_offset,
1712*79398b25SAndroid Build Coastguard Worker 					sizeof(struct squashfs_dir_index),
1713*79398b25SAndroid Build Coastguard Worker 					&index_start, &index_offset);
1714*79398b25SAndroid Build Coastguard Worker 
1715*79398b25SAndroid Build Coastguard Worker 		squashfs_get_cached_block(s, index->name, index_start,
1716*79398b25SAndroid Build Coastguard Worker 					index_offset, index->size + 1,
1717*79398b25SAndroid Build Coastguard Worker 					&index_start, &index_offset);
1718*79398b25SAndroid Build Coastguard Worker 
1719*79398b25SAndroid Build Coastguard Worker 		index->name[index->size + 1] = '\0';
1720*79398b25SAndroid Build Coastguard Worker 
1721*79398b25SAndroid Build Coastguard Worker 		if (strcmp(index->name, str) > 0)
1722*79398b25SAndroid Build Coastguard Worker 			break;
1723*79398b25SAndroid Build Coastguard Worker 
1724*79398b25SAndroid Build Coastguard Worker 		length = index->index;
1725*79398b25SAndroid Build Coastguard Worker 		*next_block = index->start_block + sblk->directory_table_start;
1726*79398b25SAndroid Build Coastguard Worker 	}
1727*79398b25SAndroid Build Coastguard Worker 
1728*79398b25SAndroid Build Coastguard Worker 	*next_offset = (length + *next_offset) % SQUASHFS_METADATA_SIZE;
1729*79398b25SAndroid Build Coastguard Worker 	return length + 3;
1730*79398b25SAndroid Build Coastguard Worker }
1731*79398b25SAndroid Build Coastguard Worker 
1732*79398b25SAndroid Build Coastguard Worker 
squashfs_readdir(struct file * file,void * dirent,filldir_t filldir)1733*79398b25SAndroid Build Coastguard Worker static int squashfs_readdir(struct file *file, void *dirent, filldir_t filldir)
1734*79398b25SAndroid Build Coastguard Worker {
1735*79398b25SAndroid Build Coastguard Worker 	struct inode *i = file->f_dentry->d_inode;
1736*79398b25SAndroid Build Coastguard Worker 	struct squashfs_sb_info *msblk = &i->i_sb->u.squashfs_sb;
1737*79398b25SAndroid Build Coastguard Worker 	struct squashfs_super_block *sblk = &msblk->sblk;
1738*79398b25SAndroid Build Coastguard Worker 	long long next_block = SQUASHFS_I(i)->start_block +
1739*79398b25SAndroid Build Coastguard Worker 		sblk->directory_table_start;
1740*79398b25SAndroid Build Coastguard Worker 	int next_offset = SQUASHFS_I(i)->offset, length = 0,
1741*79398b25SAndroid Build Coastguard Worker 		dir_count;
1742*79398b25SAndroid Build Coastguard Worker 	struct squashfs_dir_header dirh;
1743*79398b25SAndroid Build Coastguard Worker 	char buffer[sizeof(struct squashfs_dir_entry) + SQUASHFS_NAME_LEN + 1];
1744*79398b25SAndroid Build Coastguard Worker 	struct squashfs_dir_entry *dire = (struct squashfs_dir_entry *) buffer;
1745*79398b25SAndroid Build Coastguard Worker 
1746*79398b25SAndroid Build Coastguard Worker 	TRACE("Entered squashfs_readdir [%llx:%x]\n", next_block, next_offset);
1747*79398b25SAndroid Build Coastguard Worker 
1748*79398b25SAndroid Build Coastguard Worker 	while(file->f_pos < 3) {
1749*79398b25SAndroid Build Coastguard Worker 		char *name;
1750*79398b25SAndroid Build Coastguard Worker 		int size, i_ino;
1751*79398b25SAndroid Build Coastguard Worker 
1752*79398b25SAndroid Build Coastguard Worker 		if(file->f_pos == 0) {
1753*79398b25SAndroid Build Coastguard Worker 			name = ".";
1754*79398b25SAndroid Build Coastguard Worker 			size = 1;
1755*79398b25SAndroid Build Coastguard Worker 			i_ino = i->i_ino;
1756*79398b25SAndroid Build Coastguard Worker 		} else {
1757*79398b25SAndroid Build Coastguard Worker 			name = "..";
1758*79398b25SAndroid Build Coastguard Worker 			size = 2;
1759*79398b25SAndroid Build Coastguard Worker 			i_ino = SQUASHFS_I(i)->u.s2.parent_inode;
1760*79398b25SAndroid Build Coastguard Worker 		}
1761*79398b25SAndroid Build Coastguard Worker 		TRACE("Calling filldir(%x, %s, %d, %d, %d, %d)\n",
1762*79398b25SAndroid Build Coastguard Worker 				(unsigned int) dirent, name, size, (int)
1763*79398b25SAndroid Build Coastguard Worker 				file->f_pos, i_ino,
1764*79398b25SAndroid Build Coastguard Worker 				squashfs_filetype_table[1]);
1765*79398b25SAndroid Build Coastguard Worker 
1766*79398b25SAndroid Build Coastguard Worker 		if (filldir(dirent, name, size,
1767*79398b25SAndroid Build Coastguard Worker 				file->f_pos, i_ino,
1768*79398b25SAndroid Build Coastguard Worker 				squashfs_filetype_table[1]) < 0) {
1769*79398b25SAndroid Build Coastguard Worker 				TRACE("Filldir returned less than 0\n");
1770*79398b25SAndroid Build Coastguard Worker 				goto finish;
1771*79398b25SAndroid Build Coastguard Worker 		}
1772*79398b25SAndroid Build Coastguard Worker 		file->f_pos += size;
1773*79398b25SAndroid Build Coastguard Worker 	}
1774*79398b25SAndroid Build Coastguard Worker 
1775*79398b25SAndroid Build Coastguard Worker 	length = get_dir_index_using_offset(i->i_sb, &next_block, &next_offset,
1776*79398b25SAndroid Build Coastguard Worker 				SQUASHFS_I(i)->u.s2.directory_index_start,
1777*79398b25SAndroid Build Coastguard Worker 				SQUASHFS_I(i)->u.s2.directory_index_offset,
1778*79398b25SAndroid Build Coastguard Worker 				SQUASHFS_I(i)->u.s2.directory_index_count,
1779*79398b25SAndroid Build Coastguard Worker 				file->f_pos);
1780*79398b25SAndroid Build Coastguard Worker 
1781*79398b25SAndroid Build Coastguard Worker 	while (length < i_size_read(i)) {
1782*79398b25SAndroid Build Coastguard Worker 		/* read directory header */
1783*79398b25SAndroid Build Coastguard Worker 		if (msblk->swap) {
1784*79398b25SAndroid Build Coastguard Worker 			struct squashfs_dir_header sdirh;
1785*79398b25SAndroid Build Coastguard Worker 
1786*79398b25SAndroid Build Coastguard Worker 			if (!squashfs_get_cached_block(i->i_sb, (char *) &sdirh,
1787*79398b25SAndroid Build Coastguard Worker 					next_block, next_offset, sizeof(sdirh),
1788*79398b25SAndroid Build Coastguard Worker 					&next_block, &next_offset))
1789*79398b25SAndroid Build Coastguard Worker 				goto failed_read;
1790*79398b25SAndroid Build Coastguard Worker 
1791*79398b25SAndroid Build Coastguard Worker 			length += sizeof(sdirh);
1792*79398b25SAndroid Build Coastguard Worker 			SQUASHFS_SWAP_DIR_HEADER(&dirh, &sdirh);
1793*79398b25SAndroid Build Coastguard Worker 		} else {
1794*79398b25SAndroid Build Coastguard Worker 			if (!squashfs_get_cached_block(i->i_sb, (char *) &dirh,
1795*79398b25SAndroid Build Coastguard Worker 					next_block, next_offset, sizeof(dirh),
1796*79398b25SAndroid Build Coastguard Worker 					&next_block, &next_offset))
1797*79398b25SAndroid Build Coastguard Worker 				goto failed_read;
1798*79398b25SAndroid Build Coastguard Worker 
1799*79398b25SAndroid Build Coastguard Worker 			length += sizeof(dirh);
1800*79398b25SAndroid Build Coastguard Worker 		}
1801*79398b25SAndroid Build Coastguard Worker 
1802*79398b25SAndroid Build Coastguard Worker 		dir_count = dirh.count + 1;
1803*79398b25SAndroid Build Coastguard Worker 		while (dir_count--) {
1804*79398b25SAndroid Build Coastguard Worker 			if (msblk->swap) {
1805*79398b25SAndroid Build Coastguard Worker 				struct squashfs_dir_entry sdire;
1806*79398b25SAndroid Build Coastguard Worker 				if (!squashfs_get_cached_block(i->i_sb, (char *)
1807*79398b25SAndroid Build Coastguard Worker 						&sdire, next_block, next_offset,
1808*79398b25SAndroid Build Coastguard Worker 						sizeof(sdire), &next_block,
1809*79398b25SAndroid Build Coastguard Worker 						&next_offset))
1810*79398b25SAndroid Build Coastguard Worker 					goto failed_read;
1811*79398b25SAndroid Build Coastguard Worker 
1812*79398b25SAndroid Build Coastguard Worker 				length += sizeof(sdire);
1813*79398b25SAndroid Build Coastguard Worker 				SQUASHFS_SWAP_DIR_ENTRY(dire, &sdire);
1814*79398b25SAndroid Build Coastguard Worker 			} else {
1815*79398b25SAndroid Build Coastguard Worker 				if (!squashfs_get_cached_block(i->i_sb, (char *)
1816*79398b25SAndroid Build Coastguard Worker 						dire, next_block, next_offset,
1817*79398b25SAndroid Build Coastguard Worker 						sizeof(*dire), &next_block,
1818*79398b25SAndroid Build Coastguard Worker 						&next_offset))
1819*79398b25SAndroid Build Coastguard Worker 					goto failed_read;
1820*79398b25SAndroid Build Coastguard Worker 
1821*79398b25SAndroid Build Coastguard Worker 				length += sizeof(*dire);
1822*79398b25SAndroid Build Coastguard Worker 			}
1823*79398b25SAndroid Build Coastguard Worker 
1824*79398b25SAndroid Build Coastguard Worker 			if (!squashfs_get_cached_block(i->i_sb, dire->name,
1825*79398b25SAndroid Build Coastguard Worker 						next_block, next_offset,
1826*79398b25SAndroid Build Coastguard Worker 						dire->size + 1, &next_block,
1827*79398b25SAndroid Build Coastguard Worker 						&next_offset))
1828*79398b25SAndroid Build Coastguard Worker 				goto failed_read;
1829*79398b25SAndroid Build Coastguard Worker 
1830*79398b25SAndroid Build Coastguard Worker 			length += dire->size + 1;
1831*79398b25SAndroid Build Coastguard Worker 
1832*79398b25SAndroid Build Coastguard Worker 			if (file->f_pos >= length)
1833*79398b25SAndroid Build Coastguard Worker 				continue;
1834*79398b25SAndroid Build Coastguard Worker 
1835*79398b25SAndroid Build Coastguard Worker 			dire->name[dire->size + 1] = '\0';
1836*79398b25SAndroid Build Coastguard Worker 
1837*79398b25SAndroid Build Coastguard Worker 			TRACE("Calling filldir(%x, %s, %d, %d, %x:%x, %d, %d)\n",
1838*79398b25SAndroid Build Coastguard Worker 					(unsigned int) dirent, dire->name,
1839*79398b25SAndroid Build Coastguard Worker 					dire->size + 1, (int) file->f_pos,
1840*79398b25SAndroid Build Coastguard Worker 					dirh.start_block, dire->offset,
1841*79398b25SAndroid Build Coastguard Worker 					dirh.inode_number + dire->inode_number,
1842*79398b25SAndroid Build Coastguard Worker 					squashfs_filetype_table[dire->type]);
1843*79398b25SAndroid Build Coastguard Worker 
1844*79398b25SAndroid Build Coastguard Worker 			if (filldir(dirent, dire->name, dire->size + 1,
1845*79398b25SAndroid Build Coastguard Worker 					file->f_pos,
1846*79398b25SAndroid Build Coastguard Worker 					dirh.inode_number + dire->inode_number,
1847*79398b25SAndroid Build Coastguard Worker 					squashfs_filetype_table[dire->type])
1848*79398b25SAndroid Build Coastguard Worker 					< 0) {
1849*79398b25SAndroid Build Coastguard Worker 				TRACE("Filldir returned less than 0\n");
1850*79398b25SAndroid Build Coastguard Worker 				goto finish;
1851*79398b25SAndroid Build Coastguard Worker 			}
1852*79398b25SAndroid Build Coastguard Worker 			file->f_pos = length;
1853*79398b25SAndroid Build Coastguard Worker 		}
1854*79398b25SAndroid Build Coastguard Worker 	}
1855*79398b25SAndroid Build Coastguard Worker 
1856*79398b25SAndroid Build Coastguard Worker finish:
1857*79398b25SAndroid Build Coastguard Worker 	return 0;
1858*79398b25SAndroid Build Coastguard Worker 
1859*79398b25SAndroid Build Coastguard Worker failed_read:
1860*79398b25SAndroid Build Coastguard Worker 	ERROR("Unable to read directory block [%llx:%x]\n", next_block,
1861*79398b25SAndroid Build Coastguard Worker 		next_offset);
1862*79398b25SAndroid Build Coastguard Worker 	return 0;
1863*79398b25SAndroid Build Coastguard Worker }
1864*79398b25SAndroid Build Coastguard Worker 
1865*79398b25SAndroid Build Coastguard Worker 
squashfs_lookup(struct inode * i,struct dentry * dentry)1866*79398b25SAndroid Build Coastguard Worker static struct dentry *squashfs_lookup(struct inode *i, struct dentry *dentry)
1867*79398b25SAndroid Build Coastguard Worker {
1868*79398b25SAndroid Build Coastguard Worker 	const unsigned char *name = dentry->d_name.name;
1869*79398b25SAndroid Build Coastguard Worker 	int len = dentry->d_name.len;
1870*79398b25SAndroid Build Coastguard Worker 	struct inode *inode = NULL;
1871*79398b25SAndroid Build Coastguard Worker 	struct squashfs_sb_info *msblk = &i->i_sb->u.squashfs_sb;
1872*79398b25SAndroid Build Coastguard Worker 	struct squashfs_super_block *sblk = &msblk->sblk;
1873*79398b25SAndroid Build Coastguard Worker 	long long next_block = SQUASHFS_I(i)->start_block +
1874*79398b25SAndroid Build Coastguard Worker 				sblk->directory_table_start;
1875*79398b25SAndroid Build Coastguard Worker 	int next_offset = SQUASHFS_I(i)->offset, length = 0,
1876*79398b25SAndroid Build Coastguard Worker 				dir_count;
1877*79398b25SAndroid Build Coastguard Worker 	struct squashfs_dir_header dirh;
1878*79398b25SAndroid Build Coastguard Worker 	char buffer[sizeof(struct squashfs_dir_entry) + SQUASHFS_NAME_LEN];
1879*79398b25SAndroid Build Coastguard Worker 	struct squashfs_dir_entry *dire = (struct squashfs_dir_entry *) buffer;
1880*79398b25SAndroid Build Coastguard Worker 
1881*79398b25SAndroid Build Coastguard Worker 	TRACE("Entered squashfs_lookup [%llx:%x]\n", next_block, next_offset);
1882*79398b25SAndroid Build Coastguard Worker 
1883*79398b25SAndroid Build Coastguard Worker 	if (len > SQUASHFS_NAME_LEN)
1884*79398b25SAndroid Build Coastguard Worker 		goto exit_loop;
1885*79398b25SAndroid Build Coastguard Worker 
1886*79398b25SAndroid Build Coastguard Worker 	length = get_dir_index_using_name(i->i_sb, &next_block, &next_offset,
1887*79398b25SAndroid Build Coastguard Worker 				SQUASHFS_I(i)->u.s2.directory_index_start,
1888*79398b25SAndroid Build Coastguard Worker 				SQUASHFS_I(i)->u.s2.directory_index_offset,
1889*79398b25SAndroid Build Coastguard Worker 				SQUASHFS_I(i)->u.s2.directory_index_count, name,
1890*79398b25SAndroid Build Coastguard Worker 				len);
1891*79398b25SAndroid Build Coastguard Worker 
1892*79398b25SAndroid Build Coastguard Worker 	while (length < i_size_read(i)) {
1893*79398b25SAndroid Build Coastguard Worker 		/* read directory header */
1894*79398b25SAndroid Build Coastguard Worker 		if (msblk->swap) {
1895*79398b25SAndroid Build Coastguard Worker 			struct squashfs_dir_header sdirh;
1896*79398b25SAndroid Build Coastguard Worker 			if (!squashfs_get_cached_block(i->i_sb, (char *) &sdirh,
1897*79398b25SAndroid Build Coastguard Worker 					next_block, next_offset, sizeof(sdirh),
1898*79398b25SAndroid Build Coastguard Worker 					&next_block, &next_offset))
1899*79398b25SAndroid Build Coastguard Worker 				goto failed_read;
1900*79398b25SAndroid Build Coastguard Worker 
1901*79398b25SAndroid Build Coastguard Worker 			length += sizeof(sdirh);
1902*79398b25SAndroid Build Coastguard Worker 			SQUASHFS_SWAP_DIR_HEADER(&dirh, &sdirh);
1903*79398b25SAndroid Build Coastguard Worker 		} else {
1904*79398b25SAndroid Build Coastguard Worker 			if (!squashfs_get_cached_block(i->i_sb, (char *) &dirh,
1905*79398b25SAndroid Build Coastguard Worker 					next_block, next_offset, sizeof(dirh),
1906*79398b25SAndroid Build Coastguard Worker 					&next_block, &next_offset))
1907*79398b25SAndroid Build Coastguard Worker 				goto failed_read;
1908*79398b25SAndroid Build Coastguard Worker 
1909*79398b25SAndroid Build Coastguard Worker 			length += sizeof(dirh);
1910*79398b25SAndroid Build Coastguard Worker 		}
1911*79398b25SAndroid Build Coastguard Worker 
1912*79398b25SAndroid Build Coastguard Worker 		dir_count = dirh.count + 1;
1913*79398b25SAndroid Build Coastguard Worker 		while (dir_count--) {
1914*79398b25SAndroid Build Coastguard Worker 			if (msblk->swap) {
1915*79398b25SAndroid Build Coastguard Worker 				struct squashfs_dir_entry sdire;
1916*79398b25SAndroid Build Coastguard Worker 				if (!squashfs_get_cached_block(i->i_sb, (char *)
1917*79398b25SAndroid Build Coastguard Worker 						&sdire, next_block,next_offset,
1918*79398b25SAndroid Build Coastguard Worker 						sizeof(sdire), &next_block,
1919*79398b25SAndroid Build Coastguard Worker 						&next_offset))
1920*79398b25SAndroid Build Coastguard Worker 					goto failed_read;
1921*79398b25SAndroid Build Coastguard Worker 
1922*79398b25SAndroid Build Coastguard Worker 				length += sizeof(sdire);
1923*79398b25SAndroid Build Coastguard Worker 				SQUASHFS_SWAP_DIR_ENTRY(dire, &sdire);
1924*79398b25SAndroid Build Coastguard Worker 			} else {
1925*79398b25SAndroid Build Coastguard Worker 				if (!squashfs_get_cached_block(i->i_sb, (char *)
1926*79398b25SAndroid Build Coastguard Worker 						dire, next_block,next_offset,
1927*79398b25SAndroid Build Coastguard Worker 						sizeof(*dire), &next_block,
1928*79398b25SAndroid Build Coastguard Worker 						&next_offset))
1929*79398b25SAndroid Build Coastguard Worker 					goto failed_read;
1930*79398b25SAndroid Build Coastguard Worker 
1931*79398b25SAndroid Build Coastguard Worker 				length += sizeof(*dire);
1932*79398b25SAndroid Build Coastguard Worker 			}
1933*79398b25SAndroid Build Coastguard Worker 
1934*79398b25SAndroid Build Coastguard Worker 			if (!squashfs_get_cached_block(i->i_sb, dire->name,
1935*79398b25SAndroid Build Coastguard Worker 					next_block, next_offset, dire->size + 1,
1936*79398b25SAndroid Build Coastguard Worker 					&next_block, &next_offset))
1937*79398b25SAndroid Build Coastguard Worker 				goto failed_read;
1938*79398b25SAndroid Build Coastguard Worker 
1939*79398b25SAndroid Build Coastguard Worker 			length += dire->size + 1;
1940*79398b25SAndroid Build Coastguard Worker 
1941*79398b25SAndroid Build Coastguard Worker 			if (name[0] < dire->name[0])
1942*79398b25SAndroid Build Coastguard Worker 				goto exit_loop;
1943*79398b25SAndroid Build Coastguard Worker 
1944*79398b25SAndroid Build Coastguard Worker 			if ((len == dire->size + 1) && !strncmp(name,
1945*79398b25SAndroid Build Coastguard Worker 						dire->name, len)) {
1946*79398b25SAndroid Build Coastguard Worker 				squashfs_inode_t ino =
1947*79398b25SAndroid Build Coastguard Worker 					SQUASHFS_MKINODE(dirh.start_block,
1948*79398b25SAndroid Build Coastguard Worker 					dire->offset);
1949*79398b25SAndroid Build Coastguard Worker 
1950*79398b25SAndroid Build Coastguard Worker 				TRACE("calling squashfs_iget for directory "
1951*79398b25SAndroid Build Coastguard Worker 					"entry %s, inode %x:%x, %d\n", name,
1952*79398b25SAndroid Build Coastguard Worker 					dirh.start_block, dire->offset,
1953*79398b25SAndroid Build Coastguard Worker 					dirh.inode_number + dire->inode_number);
1954*79398b25SAndroid Build Coastguard Worker 
1955*79398b25SAndroid Build Coastguard Worker 				inode = (msblk->iget)(i->i_sb, ino);
1956*79398b25SAndroid Build Coastguard Worker 
1957*79398b25SAndroid Build Coastguard Worker 				goto exit_loop;
1958*79398b25SAndroid Build Coastguard Worker 			}
1959*79398b25SAndroid Build Coastguard Worker 		}
1960*79398b25SAndroid Build Coastguard Worker 	}
1961*79398b25SAndroid Build Coastguard Worker 
1962*79398b25SAndroid Build Coastguard Worker exit_loop:
1963*79398b25SAndroid Build Coastguard Worker 	d_add(dentry, inode);
1964*79398b25SAndroid Build Coastguard Worker 	return ERR_PTR(0);
1965*79398b25SAndroid Build Coastguard Worker 
1966*79398b25SAndroid Build Coastguard Worker failed_read:
1967*79398b25SAndroid Build Coastguard Worker 	ERROR("Unable to read directory block [%llx:%x]\n", next_block,
1968*79398b25SAndroid Build Coastguard Worker 		next_offset);
1969*79398b25SAndroid Build Coastguard Worker 	goto exit_loop;
1970*79398b25SAndroid Build Coastguard Worker }
1971*79398b25SAndroid Build Coastguard Worker 
1972*79398b25SAndroid Build Coastguard Worker 
squashfs_put_super(struct super_block * s)1973*79398b25SAndroid Build Coastguard Worker static void squashfs_put_super(struct super_block *s)
1974*79398b25SAndroid Build Coastguard Worker {
1975*79398b25SAndroid Build Coastguard Worker 	int i;
1976*79398b25SAndroid Build Coastguard Worker 
1977*79398b25SAndroid Build Coastguard Worker 		struct squashfs_sb_info *sbi = &s->u.squashfs_sb;
1978*79398b25SAndroid Build Coastguard Worker 		if (sbi->block_cache)
1979*79398b25SAndroid Build Coastguard Worker 			for (i = 0; i < SQUASHFS_CACHED_BLKS; i++)
1980*79398b25SAndroid Build Coastguard Worker 				if (sbi->block_cache[i].block !=
1981*79398b25SAndroid Build Coastguard Worker 							SQUASHFS_INVALID_BLK)
1982*79398b25SAndroid Build Coastguard Worker 					kfree(sbi->block_cache[i].data);
1983*79398b25SAndroid Build Coastguard Worker 		if (sbi->fragment)
1984*79398b25SAndroid Build Coastguard Worker 			for (i = 0; i < SQUASHFS_CACHED_FRAGMENTS; i++)
1985*79398b25SAndroid Build Coastguard Worker 				SQUASHFS_FREE(sbi->fragment[i].data);
1986*79398b25SAndroid Build Coastguard Worker 		kfree(sbi->fragment);
1987*79398b25SAndroid Build Coastguard Worker 		kfree(sbi->block_cache);
1988*79398b25SAndroid Build Coastguard Worker 		kfree(sbi->read_data);
1989*79398b25SAndroid Build Coastguard Worker 		kfree(sbi->read_page);
1990*79398b25SAndroid Build Coastguard Worker 		kfree(sbi->uid);
1991*79398b25SAndroid Build Coastguard Worker 		kfree(sbi->fragment_index);
1992*79398b25SAndroid Build Coastguard Worker 		kfree(sbi->fragment_index_2);
1993*79398b25SAndroid Build Coastguard Worker 		kfree(sbi->meta_index);
1994*79398b25SAndroid Build Coastguard Worker 		vfree(sbi->stream.workspace);
1995*79398b25SAndroid Build Coastguard Worker 		sbi->block_cache = NULL;
1996*79398b25SAndroid Build Coastguard Worker 		sbi->uid = NULL;
1997*79398b25SAndroid Build Coastguard Worker 		sbi->read_data = NULL;
1998*79398b25SAndroid Build Coastguard Worker 		sbi->read_page = NULL;
1999*79398b25SAndroid Build Coastguard Worker 		sbi->fragment = NULL;
2000*79398b25SAndroid Build Coastguard Worker 		sbi->fragment_index = NULL;
2001*79398b25SAndroid Build Coastguard Worker 		sbi->fragment_index_2 = NULL;
2002*79398b25SAndroid Build Coastguard Worker 		sbi->meta_index = NULL;
2003*79398b25SAndroid Build Coastguard Worker 		sbi->stream.workspace = NULL;
2004*79398b25SAndroid Build Coastguard Worker }
2005*79398b25SAndroid Build Coastguard Worker 
2006*79398b25SAndroid Build Coastguard Worker 
init_squashfs_fs(void)2007*79398b25SAndroid Build Coastguard Worker static int __init init_squashfs_fs(void)
2008*79398b25SAndroid Build Coastguard Worker {
2009*79398b25SAndroid Build Coastguard Worker 
2010*79398b25SAndroid Build Coastguard Worker 	printk(KERN_INFO "squashfs: version 3.1 (2006/08/15) "
2011*79398b25SAndroid Build Coastguard Worker 		"Phillip Lougher\n");
2012*79398b25SAndroid Build Coastguard Worker 
2013*79398b25SAndroid Build Coastguard Worker 	return register_filesystem(&squashfs_fs_type);
2014*79398b25SAndroid Build Coastguard Worker }
2015*79398b25SAndroid Build Coastguard Worker 
2016*79398b25SAndroid Build Coastguard Worker 
exit_squashfs_fs(void)2017*79398b25SAndroid Build Coastguard Worker static void __exit exit_squashfs_fs(void)
2018*79398b25SAndroid Build Coastguard Worker {
2019*79398b25SAndroid Build Coastguard Worker 	unregister_filesystem(&squashfs_fs_type);
2020*79398b25SAndroid Build Coastguard Worker }
2021*79398b25SAndroid Build Coastguard Worker 
2022*79398b25SAndroid Build Coastguard Worker 
2023*79398b25SAndroid Build Coastguard Worker EXPORT_NO_SYMBOLS;
2024*79398b25SAndroid Build Coastguard Worker 
2025*79398b25SAndroid Build Coastguard Worker module_init(init_squashfs_fs);
2026*79398b25SAndroid Build Coastguard Worker module_exit(exit_squashfs_fs);
2027*79398b25SAndroid Build Coastguard Worker MODULE_DESCRIPTION("squashfs 3.1, a compressed read-only filesystem");
2028*79398b25SAndroid Build Coastguard Worker MODULE_AUTHOR("Phillip Lougher <[email protected]>");
2029*79398b25SAndroid Build Coastguard Worker MODULE_LICENSE("GPL");
2030