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