Magellan Linux

Annotation of /trunk/kernel26-alx/patches-2.6.21-r14/0152-2.6.21-squashfs-3.2-r2.patch

Parent Directory Parent Directory | Revision Log Revision Log


Revision 447 - (hide annotations) (download)
Tue Jan 22 17:55:52 2008 UTC (16 years, 3 months ago) by niro
File size: 132210 byte(s)
-2.6.21-alx-r14 - fixed some natsemi errors on wys terminals

1 niro 447 diff -x .gitignore -Nurp linux-2.6.20/fs/Kconfig linux-2.6.20-squashfs3.2-r2/fs/Kconfig
2     --- linux-2.6.20/fs/Kconfig 2006-12-25 01:13:12.000000000 +0000
3     +++ linux-2.6.20-squashfs3.2-r2/fs/Kconfig 2007-01-16 02:06:03.000000000 +0000
4     @@ -1404,6 +1404,71 @@ config CRAMFS
5    
6     If unsure, say N.
7    
8     +config SQUASHFS
9     + tristate "SquashFS 3.2 - Squashed file system support"
10     + select ZLIB_INFLATE
11     + help
12     + Saying Y here includes support for SquashFS 3.2 (a Compressed Read-Only File
13     + System). Squashfs is a highly compressed read-only filesystem for Linux.
14     + It uses zlib compression to compress both files, inodes and directories.
15     + Inodes in the system are very small and all blocks are packed to minimise
16     + data overhead. Block sizes greater than 4K are supported up to a maximum of 64K.
17     + SquashFS 3.1 supports 64 bit filesystems and files (larger than 4GB), full
18     + uid/gid information, hard links and timestamps.
19     +
20     + Squashfs is intended for general read-only filesystem use, for archival
21     + use (i.e. in cases where a .tar.gz file may be used), and in embedded
22     + systems where low overhead is needed. Further information and filesystem tools
23     + are available from http://squashfs.sourceforge.net.
24     +
25     + If you want to compile this as a module ( = code which can be
26     + inserted in and removed from the running kernel whenever you want),
27     + say M here and read <file:Documentation/modules.txt>. The module
28     + will be called squashfs. Note that the root file system (the one
29     + containing the directory /) cannot be compiled as a module.
30     +
31     + If unsure, say N.
32     +
33     +config SQUASHFS_EMBEDDED
34     +
35     + bool "Additional options for memory-constrained systems"
36     + depends on SQUASHFS
37     + default n
38     + help
39     + Saying Y here allows you to specify cache sizes and how Squashfs
40     + allocates memory. This is only intended for memory constrained
41     + systems.
42     +
43     + If unsure, say N.
44     +
45     +config SQUASHFS_FRAGMENT_CACHE_SIZE
46     + int "Number of fragments cached" if SQUASHFS_EMBEDDED
47     + depends on SQUASHFS
48     + default "3"
49     + help
50     + By default SquashFS caches the last 3 fragments read from
51     + the filesystem. Increasing this amount may mean SquashFS
52     + has to re-read fragments less often from disk, at the expense
53     + of extra system memory. Decreasing this amount will mean
54     + SquashFS uses less memory at the expense of extra reads from disk.
55     +
56     + Note there must be at least one cached fragment. Anything
57     + much more than three will probably not make much difference.
58     +
59     +config SQUASHFS_VMALLOC
60     + bool "Use Vmalloc rather than Kmalloc" if SQUASHFS_EMBEDDED
61     + depends on SQUASHFS
62     + default n
63     + help
64     + By default SquashFS uses kmalloc to obtain fragment cache memory.
65     + Kmalloc memory is the standard kernel allocator, but it can fail
66     + on memory constrained systems. Because of the way Vmalloc works,
67     + Vmalloc can succeed when kmalloc fails. Specifying this option
68     + will make SquashFS always use Vmalloc to allocate the
69     + fragment cache memory.
70     +
71     + If unsure, say N.
72     +
73     config VXFS_FS
74     tristate "FreeVxFS file system support (VERITAS VxFS(TM) compatible)"
75     depends on BLOCK
76     diff -x .gitignore -Nurp linux-2.6.20/fs/Makefile linux-2.6.20-squashfs3.2-r2/fs/Makefile
77     --- linux-2.6.20/fs/Makefile 2006-12-25 01:13:12.000000000 +0000
78     +++ linux-2.6.20-squashfs3.2-r2/fs/Makefile 2007-01-16 02:06:03.000000000 +0000
79     @@ -68,6 +68,7 @@ obj-$(CONFIG_JBD) += jbd/
80     obj-$(CONFIG_JBD2) += jbd2/
81     obj-$(CONFIG_EXT2_FS) += ext2/
82     obj-$(CONFIG_CRAMFS) += cramfs/
83     +obj-$(CONFIG_SQUASHFS) += squashfs/
84     obj-$(CONFIG_RAMFS) += ramfs/
85     obj-$(CONFIG_HUGETLBFS) += hugetlbfs/
86     obj-$(CONFIG_CODA_FS) += coda/
87     diff -x .gitignore -Nurp linux-2.6.20/fs/squashfs/inode.c linux-2.6.20-squashfs3.2-r2/fs/squashfs/inode.c
88     --- linux-2.6.20/fs/squashfs/inode.c 1970-01-01 01:00:00.000000000 +0100
89     +++ linux-2.6.20-squashfs3.2-r2/fs/squashfs/inode.c 2007-01-16 02:28:36.000000000 +0000
90     @@ -0,0 +1,2329 @@
91     +/*
92     + * Squashfs - a compressed read only filesystem for Linux
93     + *
94     + * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007
95     + * Phillip Lougher <phillip@lougher.org.uk>
96     + *
97     + * This program is free software; you can redistribute it and/or
98     + * modify it under the terms of the GNU General Public License
99     + * as published by the Free Software Foundation; either version 2,
100     + * or (at your option) any later version.
101     + *
102     + * This program is distributed in the hope that it will be useful,
103     + * but WITHOUT ANY WARRANTY; without even the implied warranty of
104     + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
105     + * GNU General Public License for more details.
106     + *
107     + * You should have received a copy of the GNU General Public License
108     + * along with this program; if not, write to the Free Software
109     + * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
110     + *
111     + * inode.c
112     + */
113     +
114     +#include <linux/squashfs_fs.h>
115     +#include <linux/module.h>
116     +#include <linux/zlib.h>
117     +#include <linux/fs.h>
118     +#include <linux/squashfs_fs_sb.h>
119     +#include <linux/squashfs_fs_i.h>
120     +#include <linux/buffer_head.h>
121     +#include <linux/vfs.h>
122     +#include <linux/vmalloc.h>
123     +#include <linux/smp_lock.h>
124     +
125     +#include "squashfs.h"
126     +
127     +static void vfs_read_inode(struct inode *i);
128     +static struct dentry *squashfs_get_parent(struct dentry *child);
129     +static int squashfs_read_inode(struct inode *i, squashfs_inode_t inode);
130     +static int squashfs_statfs(struct dentry *, struct kstatfs *);
131     +static int squashfs_symlink_readpage(struct file *file, struct page *page);
132     +static long long read_blocklist(struct inode *inode, int index,
133     + int readahead_blks, char *block_list,
134     + unsigned short **block_p, unsigned int *bsize);
135     +static int squashfs_readpage(struct file *file, struct page *page);
136     +static int squashfs_readpage4K(struct file *file, struct page *page);
137     +static int squashfs_readdir(struct file *, void *, filldir_t);
138     +static struct dentry *squashfs_lookup(struct inode *, struct dentry *,
139     + struct nameidata *);
140     +static int squashfs_remount(struct super_block *s, int *flags, char *data);
141     +static void squashfs_put_super(struct super_block *);
142     +static int squashfs_get_sb(struct file_system_type *,int, const char *, void *,
143     + struct vfsmount *);
144     +static struct inode *squashfs_alloc_inode(struct super_block *sb);
145     +static void squashfs_destroy_inode(struct inode *inode);
146     +static int init_inodecache(void);
147     +static void destroy_inodecache(void);
148     +
149     +static struct file_system_type squashfs_fs_type = {
150     + .owner = THIS_MODULE,
151     + .name = "squashfs",
152     + .get_sb = squashfs_get_sb,
153     + .kill_sb = kill_block_super,
154     + .fs_flags = FS_REQUIRES_DEV
155     +};
156     +
157     +static const unsigned char squashfs_filetype_table[] = {
158     + DT_UNKNOWN, DT_DIR, DT_REG, DT_LNK, DT_BLK, DT_CHR, DT_FIFO, DT_SOCK
159     +};
160     +
161     +static struct super_operations squashfs_super_ops = {
162     + .alloc_inode = squashfs_alloc_inode,
163     + .destroy_inode = squashfs_destroy_inode,
164     + .statfs = squashfs_statfs,
165     + .put_super = squashfs_put_super,
166     + .remount_fs = squashfs_remount
167     +};
168     +
169     +static struct super_operations squashfs_export_super_ops = {
170     + .alloc_inode = squashfs_alloc_inode,
171     + .destroy_inode = squashfs_destroy_inode,
172     + .statfs = squashfs_statfs,
173     + .put_super = squashfs_put_super,
174     + .read_inode = vfs_read_inode
175     +};
176     +
177     +static struct export_operations squashfs_export_ops = {
178     + .get_parent = squashfs_get_parent
179     +};
180     +
181     +SQSH_EXTERN const struct address_space_operations squashfs_symlink_aops = {
182     + .readpage = squashfs_symlink_readpage
183     +};
184     +
185     +SQSH_EXTERN const struct address_space_operations squashfs_aops = {
186     + .readpage = squashfs_readpage
187     +};
188     +
189     +SQSH_EXTERN const struct address_space_operations squashfs_aops_4K = {
190     + .readpage = squashfs_readpage4K
191     +};
192     +
193     +static const struct file_operations squashfs_dir_ops = {
194     + .read = generic_read_dir,
195     + .readdir = squashfs_readdir
196     +};
197     +
198     +SQSH_EXTERN struct inode_operations squashfs_dir_inode_ops = {
199     + .lookup = squashfs_lookup
200     +};
201     +
202     +
203     +static struct buffer_head *get_block_length(struct super_block *s,
204     + int *cur_index, int *offset, int *c_byte)
205     +{
206     + struct squashfs_sb_info *msblk = s->s_fs_info;
207     + unsigned short temp;
208     + struct buffer_head *bh;
209     +
210     + if (!(bh = sb_bread(s, *cur_index)))
211     + goto out;
212     +
213     + if (msblk->devblksize - *offset == 1) {
214     + if (msblk->swap)
215     + ((unsigned char *) &temp)[1] = *((unsigned char *)
216     + (bh->b_data + *offset));
217     + else
218     + ((unsigned char *) &temp)[0] = *((unsigned char *)
219     + (bh->b_data + *offset));
220     + brelse(bh);
221     + if (!(bh = sb_bread(s, ++(*cur_index))))
222     + goto out;
223     + if (msblk->swap)
224     + ((unsigned char *) &temp)[0] = *((unsigned char *)
225     + bh->b_data);
226     + else
227     + ((unsigned char *) &temp)[1] = *((unsigned char *)
228     + bh->b_data);
229     + *c_byte = temp;
230     + *offset = 1;
231     + } else {
232     + if (msblk->swap) {
233     + ((unsigned char *) &temp)[1] = *((unsigned char *)
234     + (bh->b_data + *offset));
235     + ((unsigned char *) &temp)[0] = *((unsigned char *)
236     + (bh->b_data + *offset + 1));
237     + } else {
238     + ((unsigned char *) &temp)[0] = *((unsigned char *)
239     + (bh->b_data + *offset));
240     + ((unsigned char *) &temp)[1] = *((unsigned char *)
241     + (bh->b_data + *offset + 1));
242     + }
243     + *c_byte = temp;
244     + *offset += 2;
245     + }
246     +
247     + if (SQUASHFS_CHECK_DATA(msblk->sblk.flags)) {
248     + if (*offset == msblk->devblksize) {
249     + brelse(bh);
250     + if (!(bh = sb_bread(s, ++(*cur_index))))
251     + goto out;
252     + *offset = 0;
253     + }
254     + if (*((unsigned char *) (bh->b_data + *offset)) !=
255     + SQUASHFS_MARKER_BYTE) {
256     + ERROR("Metadata block marker corrupt @ %x\n",
257     + *cur_index);
258     + brelse(bh);
259     + goto out;
260     + }
261     + (*offset)++;
262     + }
263     + return bh;
264     +
265     +out:
266     + return NULL;
267     +}
268     +
269     +
270     +SQSH_EXTERN unsigned int squashfs_read_data(struct super_block *s, char *buffer,
271     + long long index, unsigned int length,
272     + long long *next_index, int srclength)
273     +{
274     + struct squashfs_sb_info *msblk = s->s_fs_info;
275     + struct squashfs_super_block *sblk = &msblk->sblk;
276     + struct buffer_head *bh[((SQUASHFS_FILE_MAX_SIZE - 1) >>
277     + msblk->devblksize_log2) + 2];
278     + unsigned int offset = index & ((1 << msblk->devblksize_log2) - 1);
279     + unsigned int cur_index = index >> msblk->devblksize_log2;
280     + int bytes, avail_bytes, b = 0, k = 0;
281     + unsigned int compressed;
282     + unsigned int c_byte = length;
283     +
284     + if (c_byte) {
285     + bytes = msblk->devblksize - offset;
286     + compressed = SQUASHFS_COMPRESSED_BLOCK(c_byte);
287     + c_byte = SQUASHFS_COMPRESSED_SIZE_BLOCK(c_byte);
288     +
289     + TRACE("Block @ 0x%llx, %scompressed size %d, src size %d\n", index, compressed
290     + ? "" : "un", (unsigned int) c_byte, srclength);
291     +
292     + if (c_byte > srclength || index < 0 || (index + c_byte) > sblk->bytes_used)
293     + goto read_failure;
294     +
295     + if (!(bh[0] = sb_getblk(s, cur_index)))
296     + goto block_release;
297     +
298     + for (b = 1; bytes < c_byte; b++) {
299     + if (!(bh[b] = sb_getblk(s, ++cur_index)))
300     + goto block_release;
301     + bytes += msblk->devblksize;
302     + }
303     + ll_rw_block(READ, b, bh);
304     + } else {
305     + if (index < 0 || (index + 2) > sblk->bytes_used)
306     + goto read_failure;
307     +
308     + if (!(bh[0] = get_block_length(s, &cur_index, &offset,
309     + &c_byte)))
310     + goto read_failure;
311     +
312     + bytes = msblk->devblksize - offset;
313     + compressed = SQUASHFS_COMPRESSED(c_byte);
314     + c_byte = SQUASHFS_COMPRESSED_SIZE(c_byte);
315     +
316     + TRACE("Block @ 0x%llx, %scompressed size %d\n", index, compressed
317     + ? "" : "un", (unsigned int) c_byte);
318     +
319     + if (c_byte > srclength || (index + c_byte) > sblk->bytes_used)
320     + goto read_failure;
321     +
322     + for (b = 1; bytes < c_byte; b++) {
323     + if (!(bh[b] = sb_getblk(s, ++cur_index)))
324     + goto block_release;
325     + bytes += msblk->devblksize;
326     + }
327     + ll_rw_block(READ, b - 1, bh + 1);
328     + }
329     +
330     + if (compressed) {
331     + int zlib_err = 0;
332     +
333     + /*
334     + * uncompress block
335     + */
336     +
337     + mutex_lock(&msblk->read_data_mutex);
338     +
339     + msblk->stream.next_out = buffer;
340     + msblk->stream.avail_out = srclength;
341     +
342     + for (bytes = 0; k < b; k++) {
343     + avail_bytes = (c_byte - bytes) > (msblk->devblksize - offset) ?
344     + msblk->devblksize - offset :
345     + c_byte - bytes;
346     + wait_on_buffer(bh[k]);
347     + if (!buffer_uptodate(bh[k]))
348     + goto release_mutex;
349     +
350     + msblk->stream.next_in = bh[k]->b_data + offset;
351     + msblk->stream.avail_in = avail_bytes;
352     +
353     + if (k == 0) {
354     + zlib_err = zlib_inflateInit(&msblk->stream);
355     + if (zlib_err != Z_OK) {
356     + ERROR("zlib_inflateInit returned unexpected result 0x%x, srclength %d\n",
357     + zlib_err, srclength);
358     + goto release_mutex;
359     + }
360     +
361     + if (avail_bytes == 0) {
362     + offset = 0;
363     + brelse(bh[k]);
364     + continue;
365     + }
366     + }
367     +
368     + zlib_err = zlib_inflate(&msblk->stream, Z_NO_FLUSH);
369     + if (zlib_err != Z_OK && zlib_err != Z_STREAM_END) {
370     + ERROR("zlib_inflate returned unexpected result 0x%x, srclength %d, avail_in %d, avail_out %d\n",
371     + zlib_err, srclength, msblk->stream.avail_in, msblk->stream.avail_out);
372     + goto release_mutex;
373     + }
374     +
375     + bytes += avail_bytes;
376     + offset = 0;
377     + brelse(bh[k]);
378     + }
379     +
380     + if (zlib_err != Z_STREAM_END)
381     + goto release_mutex;
382     +
383     + zlib_err = zlib_inflateEnd(&msblk->stream);
384     + if (zlib_err != Z_OK) {
385     + ERROR("zlib_inflateEnd returned unexpected result 0x%x, srclength %d\n",
386     + zlib_err, srclength);
387     + goto release_mutex;
388     + }
389     + bytes = msblk->stream.total_out;
390     + mutex_unlock(&msblk->read_data_mutex);
391     + } else {
392     + int i;
393     +
394     + for(i = 0; i < b; i++) {
395     + wait_on_buffer(bh[i]);
396     + if(!buffer_uptodate(bh[i]))
397     + goto block_release;
398     + }
399     +
400     + for (bytes = 0; k < b; k++) {
401     + avail_bytes = (c_byte - bytes) > (msblk->devblksize - offset) ?
402     + msblk->devblksize - offset :
403     + c_byte - bytes;
404     + memcpy(buffer + bytes, bh[k]->b_data + offset, avail_bytes);
405     + bytes += avail_bytes;
406     + offset = 0;
407     + brelse(bh[k]);
408     + }
409     + }
410     +
411     + if (next_index)
412     + *next_index = index + c_byte + (length ? 0 :
413     + (SQUASHFS_CHECK_DATA(msblk->sblk.flags)
414     + ? 3 : 2));
415     + return bytes;
416     +
417     +release_mutex:
418     + mutex_unlock(&msblk->read_data_mutex);
419     +
420     +block_release:
421     + for (; k < b; k++)
422     + brelse(bh[k]);
423     +
424     +read_failure:
425     + ERROR("sb_bread failed reading block 0x%x\n", cur_index);
426     + return 0;
427     +}
428     +
429     +
430     +SQSH_EXTERN int squashfs_get_cached_block(struct super_block *s, char *buffer,
431     + long long block, unsigned int offset,
432     + int length, long long *next_block,
433     + unsigned int *next_offset)
434     +{
435     + struct squashfs_sb_info *msblk = s->s_fs_info;
436     + int n, i, bytes, return_length = length;
437     + long long next_index;
438     +
439     + TRACE("Entered squashfs_get_cached_block [%llx:%x]\n", block, offset);
440     +
441     + while ( 1 ) {
442     + for (i = 0; i < SQUASHFS_CACHED_BLKS; i++)
443     + if (msblk->block_cache[i].block == block)
444     + break;
445     +
446     + mutex_lock(&msblk->block_cache_mutex);
447     +
448     + if (i == SQUASHFS_CACHED_BLKS) {
449     + /* read inode header block */
450     + for (i = msblk->next_cache, n = SQUASHFS_CACHED_BLKS;
451     + n ; n --, i = (i + 1) %
452     + SQUASHFS_CACHED_BLKS)
453     + if (msblk->block_cache[i].block !=
454     + SQUASHFS_USED_BLK)
455     + break;
456     +
457     + if (n == 0) {
458     + wait_queue_t wait;
459     +
460     + init_waitqueue_entry(&wait, current);
461     + add_wait_queue(&msblk->waitq, &wait);
462     + set_current_state(TASK_UNINTERRUPTIBLE);
463     + mutex_unlock(&msblk->block_cache_mutex);
464     + schedule();
465     + set_current_state(TASK_RUNNING);
466     + remove_wait_queue(&msblk->waitq, &wait);
467     + continue;
468     + }
469     + msblk->next_cache = (i + 1) % SQUASHFS_CACHED_BLKS;
470     +
471     + if (msblk->block_cache[i].block ==
472     + SQUASHFS_INVALID_BLK) {
473     + if (!(msblk->block_cache[i].data =
474     + kmalloc(SQUASHFS_METADATA_SIZE,
475     + GFP_KERNEL))) {
476     + ERROR("Failed to allocate cache"
477     + "block\n");
478     + mutex_unlock(&msblk->block_cache_mutex);
479     + goto out;
480     + }
481     + }
482     +
483     + msblk->block_cache[i].block = SQUASHFS_USED_BLK;
484     + mutex_unlock(&msblk->block_cache_mutex);
485     +
486     + msblk->block_cache[i].length = squashfs_read_data(s,
487     + msblk->block_cache[i].data, block, 0, &next_index, SQUASHFS_METADATA_SIZE);
488     + if (msblk->block_cache[i].length == 0) {
489     + ERROR("Unable to read cache block [%llx:%x]\n",
490     + block, offset);
491     + mutex_lock(&msblk->block_cache_mutex);
492     + msblk->block_cache[i].block = SQUASHFS_INVALID_BLK;
493     + kfree(msblk->block_cache[i].data);
494     + wake_up(&msblk->waitq);
495     + mutex_unlock(&msblk->block_cache_mutex);
496     + goto out;
497     + }
498     +
499     + mutex_lock(&msblk->block_cache_mutex);
500     + wake_up(&msblk->waitq);
501     + msblk->block_cache[i].block = block;
502     + msblk->block_cache[i].next_index = next_index;
503     + TRACE("Read cache block [%llx:%x]\n", block, offset);
504     + }
505     +
506     + if (msblk->block_cache[i].block != block) {
507     + mutex_unlock(&msblk->block_cache_mutex);
508     + continue;
509     + }
510     +
511     + bytes = msblk->block_cache[i].length - offset;
512     +
513     + if (bytes < 1) {
514     + mutex_unlock(&msblk->block_cache_mutex);
515     + goto out;
516     + } else if (bytes >= length) {
517     + if (buffer)
518     + memcpy(buffer, msblk->block_cache[i].data +
519     + offset, length);
520     + if (msblk->block_cache[i].length - offset == length) {
521     + *next_block = msblk->block_cache[i].next_index;
522     + *next_offset = 0;
523     + } else {
524     + *next_block = block;
525     + *next_offset = offset + length;
526     + }
527     + mutex_unlock(&msblk->block_cache_mutex);
528     + goto finish;
529     + } else {
530     + if (buffer) {
531     + memcpy(buffer, msblk->block_cache[i].data +
532     + offset, bytes);
533     + buffer += bytes;
534     + }
535     + block = msblk->block_cache[i].next_index;
536     + mutex_unlock(&msblk->block_cache_mutex);
537     + length -= bytes;
538     + offset = 0;
539     + }
540     + }
541     +
542     +finish:
543     + return return_length;
544     +out:
545     + return 0;
546     +}
547     +
548     +
549     +static int get_fragment_location(struct super_block *s, unsigned int fragment,
550     + long long *fragment_start_block,
551     + unsigned int *fragment_size)
552     +{
553     + struct squashfs_sb_info *msblk = s->s_fs_info;
554     + long long start_block =
555     + msblk->fragment_index[SQUASHFS_FRAGMENT_INDEX(fragment)];
556     + int offset = SQUASHFS_FRAGMENT_INDEX_OFFSET(fragment);
557     + struct squashfs_fragment_entry fragment_entry;
558     +
559     + if (msblk->swap) {
560     + struct squashfs_fragment_entry sfragment_entry;
561     +
562     + if (!squashfs_get_cached_block(s, (char *) &sfragment_entry,
563     + start_block, offset,
564     + sizeof(sfragment_entry), &start_block,
565     + &offset))
566     + goto out;
567     + SQUASHFS_SWAP_FRAGMENT_ENTRY(&fragment_entry, &sfragment_entry);
568     + } else
569     + if (!squashfs_get_cached_block(s, (char *) &fragment_entry,
570     + start_block, offset,
571     + sizeof(fragment_entry), &start_block,
572     + &offset))
573     + goto out;
574     +
575     + *fragment_start_block = fragment_entry.start_block;
576     + *fragment_size = fragment_entry.size;
577     +
578     + return 1;
579     +
580     +out:
581     + return 0;
582     +}
583     +
584     +
585     +SQSH_EXTERN void release_cached_fragment(struct squashfs_sb_info *msblk, struct
586     + squashfs_fragment_cache *fragment)
587     +{
588     + mutex_lock(&msblk->fragment_mutex);
589     + fragment->locked --;
590     + wake_up(&msblk->fragment_wait_queue);
591     + mutex_unlock(&msblk->fragment_mutex);
592     +}
593     +
594     +
595     +SQSH_EXTERN struct squashfs_fragment_cache *get_cached_fragment(struct super_block
596     + *s, long long start_block,
597     + int length)
598     +{
599     + int i, n;
600     + struct squashfs_sb_info *msblk = s->s_fs_info;
601     + struct squashfs_super_block *sblk = &msblk->sblk;
602     +
603     + while ( 1 ) {
604     + mutex_lock(&msblk->fragment_mutex);
605     +
606     + for (i = 0; i < SQUASHFS_CACHED_FRAGMENTS &&
607     + msblk->fragment[i].block != start_block; i++);
608     +
609     + if (i == SQUASHFS_CACHED_FRAGMENTS) {
610     + for (i = msblk->next_fragment, n =
611     + SQUASHFS_CACHED_FRAGMENTS; n &&
612     + msblk->fragment[i].locked; n--, i = (i + 1) %
613     + SQUASHFS_CACHED_FRAGMENTS);
614     +
615     + if (n == 0) {
616     + wait_queue_t wait;
617     +
618     + init_waitqueue_entry(&wait, current);
619     + add_wait_queue(&msblk->fragment_wait_queue,
620     + &wait);
621     + set_current_state(TASK_UNINTERRUPTIBLE);
622     + mutex_unlock(&msblk->fragment_mutex);
623     + schedule();
624     + set_current_state(TASK_RUNNING);
625     + remove_wait_queue(&msblk->fragment_wait_queue,
626     + &wait);
627     + continue;
628     + }
629     + msblk->next_fragment = (msblk->next_fragment + 1) %
630     + SQUASHFS_CACHED_FRAGMENTS;
631     +
632     + if (msblk->fragment[i].data == NULL)
633     + if (!(msblk->fragment[i].data = SQUASHFS_ALLOC
634     + (SQUASHFS_FILE_MAX_SIZE))) {
635     + ERROR("Failed to allocate fragment "
636     + "cache block\n");
637     + mutex_unlock(&msblk->fragment_mutex);
638     + goto out;
639     + }
640     +
641     + msblk->fragment[i].block = SQUASHFS_INVALID_BLK;
642     + msblk->fragment[i].locked = 1;
643     + mutex_unlock(&msblk->fragment_mutex);
644     +
645     + if (!(msblk->fragment[i].length = squashfs_read_data(s,
646     + msblk->fragment[i].data,
647     + start_block, length, NULL, sblk->block_size))) {
648     + ERROR("Unable to read fragment cache block "
649     + "[%llx]\n", start_block);
650     + msblk->fragment[i].locked = 0;
651     + smp_mb();
652     + goto out;
653     + }
654     +
655     + mutex_lock(&msblk->fragment_mutex);
656     + msblk->fragment[i].block = start_block;
657     + TRACE("New fragment %d, start block %lld, locked %d\n",
658     + i, msblk->fragment[i].block,
659     + msblk->fragment[i].locked);
660     + mutex_unlock(&msblk->fragment_mutex);
661     + break;
662     + }
663     +
664     + msblk->fragment[i].locked++;
665     + mutex_unlock(&msblk->fragment_mutex);
666     + TRACE("Got fragment %d, start block %lld, locked %d\n", i,
667     + msblk->fragment[i].block,
668     + msblk->fragment[i].locked);
669     + break;
670     + }
671     +
672     + return &msblk->fragment[i];
673     +
674     +out:
675     + return NULL;
676     +}
677     +
678     +
679     +static void squashfs_new_inode(struct squashfs_sb_info *msblk, struct inode *i,
680     + struct squashfs_base_inode_header *inodeb)
681     +{
682     + i->i_ino = inodeb->inode_number;
683     + i->i_mtime.tv_sec = inodeb->mtime;
684     + i->i_atime.tv_sec = inodeb->mtime;
685     + i->i_ctime.tv_sec = inodeb->mtime;
686     + i->i_uid = msblk->uid[inodeb->uid];
687     + i->i_mode = inodeb->mode;
688     + i->i_size = 0;
689     + if (inodeb->guid == SQUASHFS_GUIDS)
690     + i->i_gid = i->i_uid;
691     + else
692     + i->i_gid = msblk->guid[inodeb->guid];
693     +}
694     +
695     +
696     +static squashfs_inode_t squashfs_inode_lookup(struct super_block *s, int ino)
697     +{
698     + struct squashfs_sb_info *msblk = s->s_fs_info;
699     + long long start = msblk->inode_lookup_table[SQUASHFS_LOOKUP_BLOCK(ino - 1)];
700     + int offset = SQUASHFS_LOOKUP_BLOCK_OFFSET(ino - 1);
701     + squashfs_inode_t inode;
702     +
703     + TRACE("Entered squashfs_inode_lookup, inode_number = %d\n", ino);
704     +
705     + if (msblk->swap) {
706     + squashfs_inode_t sinode;
707     +
708     + if (!squashfs_get_cached_block(s, (char *) &sinode, start, offset,
709     + sizeof(sinode), &start, &offset))
710     + goto out;
711     + SQUASHFS_SWAP_INODE_T((&inode), &sinode);
712     + } else if (!squashfs_get_cached_block(s, (char *) &inode, start, offset,
713     + sizeof(inode), &start, &offset))
714     + goto out;
715     +
716     + TRACE("squashfs_inode_lookup, inode = 0x%llx\n", inode);
717     +
718     + return inode;
719     +
720     +out:
721     + return SQUASHFS_INVALID_BLK;
722     +}
723     +
724     +
725     +static void vfs_read_inode(struct inode *i)
726     +{
727     + struct squashfs_sb_info *msblk = i->i_sb->s_fs_info;
728     + squashfs_inode_t inode = squashfs_inode_lookup(i->i_sb, i->i_ino);
729     +
730     + TRACE("Entered vfs_read_inode\n");
731     +
732     + if(inode != SQUASHFS_INVALID_BLK)
733     + (msblk->read_inode)(i, inode);
734     +}
735     +
736     +
737     +static struct dentry *squashfs_get_parent(struct dentry *child)
738     +{
739     + struct inode *i = child->d_inode;
740     + struct inode *parent = iget(i->i_sb, SQUASHFS_I(i)->u.s2.parent_inode);
741     + struct dentry *rv;
742     +
743     + TRACE("Entered squashfs_get_parent\n");
744     +
745     + if(parent == NULL) {
746     + rv = ERR_PTR(-EACCES);
747     + goto out;
748     + }
749     +
750     + rv = d_alloc_anon(parent);
751     + if(rv == NULL)
752     + rv = ERR_PTR(-ENOMEM);
753     +
754     +out:
755     + return rv;
756     +}
757     +
758     +
759     +SQSH_EXTERN struct inode *squashfs_iget(struct super_block *s, squashfs_inode_t inode, unsigned int inode_number)
760     +{
761     + struct squashfs_sb_info *msblk = s->s_fs_info;
762     + struct inode *i = iget_locked(s, inode_number);
763     +
764     + TRACE("Entered squashfs_iget\n");
765     +
766     + if(i && (i->i_state & I_NEW)) {
767     + (msblk->read_inode)(i, inode);
768     + unlock_new_inode(i);
769     + }
770     +
771     + return i;
772     +}
773     +
774     +
775     +static int squashfs_read_inode(struct inode *i, squashfs_inode_t inode)
776     +{
777     + struct super_block *s = i->i_sb;
778     + struct squashfs_sb_info *msblk = s->s_fs_info;
779     + struct squashfs_super_block *sblk = &msblk->sblk;
780     + long long block = SQUASHFS_INODE_BLK(inode) +
781     + sblk->inode_table_start;
782     + unsigned int offset = SQUASHFS_INODE_OFFSET(inode);
783     + long long next_block;
784     + unsigned int next_offset;
785     + union squashfs_inode_header id, sid;
786     + struct squashfs_base_inode_header *inodeb = &id.base,
787     + *sinodeb = &sid.base;
788     +
789     + TRACE("Entered squashfs_read_inode\n");
790     +
791     + if (msblk->swap) {
792     + if (!squashfs_get_cached_block(s, (char *) sinodeb, block,
793     + offset, sizeof(*sinodeb), &next_block,
794     + &next_offset))
795     + goto failed_read;
796     + SQUASHFS_SWAP_BASE_INODE_HEADER(inodeb, sinodeb,
797     + sizeof(*sinodeb));
798     + } else
799     + if (!squashfs_get_cached_block(s, (char *) inodeb, block,
800     + offset, sizeof(*inodeb), &next_block,
801     + &next_offset))
802     + goto failed_read;
803     +
804     + squashfs_new_inode(msblk, i, inodeb);
805     +
806     + switch(inodeb->inode_type) {
807     + case SQUASHFS_FILE_TYPE: {
808     + unsigned int frag_size;
809     + long long frag_blk;
810     + struct squashfs_reg_inode_header *inodep = &id.reg;
811     + struct squashfs_reg_inode_header *sinodep = &sid.reg;
812     +
813     + if (msblk->swap) {
814     + if (!squashfs_get_cached_block(s, (char *)
815     + sinodep, block, offset,
816     + sizeof(*sinodep), &next_block,
817     + &next_offset))
818     + goto failed_read;
819     + SQUASHFS_SWAP_REG_INODE_HEADER(inodep, sinodep);
820     + } else
821     + if (!squashfs_get_cached_block(s, (char *)
822     + inodep, block, offset,
823     + sizeof(*inodep), &next_block,
824     + &next_offset))
825     + goto failed_read;
826     +
827     + frag_blk = SQUASHFS_INVALID_BLK;
828     + if (inodep->fragment != SQUASHFS_INVALID_FRAG &&
829     + !get_fragment_location(s,
830     + inodep->fragment, &frag_blk, &frag_size))
831     + goto failed_read;
832     +
833     + i->i_nlink = 1;
834     + i->i_size = inodep->file_size;
835     + i->i_fop = &generic_ro_fops;
836     + i->i_mode |= S_IFREG;
837     + i->i_blocks = ((i->i_size - 1) >> 9) + 1;
838     + SQUASHFS_I(i)->u.s1.fragment_start_block = frag_blk;
839     + SQUASHFS_I(i)->u.s1.fragment_size = frag_size;
840     + SQUASHFS_I(i)->u.s1.fragment_offset = inodep->offset;
841     + SQUASHFS_I(i)->start_block = inodep->start_block;
842     + SQUASHFS_I(i)->u.s1.block_list_start = next_block;
843     + SQUASHFS_I(i)->offset = next_offset;
844     + if (sblk->block_size > 4096)
845     + i->i_data.a_ops = &squashfs_aops;
846     + else
847     + i->i_data.a_ops = &squashfs_aops_4K;
848     +
849     + TRACE("File inode %x:%x, start_block %llx, "
850     + "block_list_start %llx, offset %x\n",
851     + SQUASHFS_INODE_BLK(inode), offset,
852     + inodep->start_block, next_block,
853     + next_offset);
854     + break;
855     + }
856     + case SQUASHFS_LREG_TYPE: {
857     + unsigned int frag_size;
858     + long long frag_blk;
859     + struct squashfs_lreg_inode_header *inodep = &id.lreg;
860     + struct squashfs_lreg_inode_header *sinodep = &sid.lreg;
861     +
862     + if (msblk->swap) {
863     + if (!squashfs_get_cached_block(s, (char *)
864     + sinodep, block, offset,
865     + sizeof(*sinodep), &next_block,
866     + &next_offset))
867     + goto failed_read;
868     + SQUASHFS_SWAP_LREG_INODE_HEADER(inodep, sinodep);
869     + } else
870     + if (!squashfs_get_cached_block(s, (char *)
871     + inodep, block, offset,
872     + sizeof(*inodep), &next_block,
873     + &next_offset))
874     + goto failed_read;
875     +
876     + frag_blk = SQUASHFS_INVALID_BLK;
877     + if (inodep->fragment != SQUASHFS_INVALID_FRAG &&
878     + !get_fragment_location(s,
879     + inodep->fragment, &frag_blk, &frag_size))
880     + goto failed_read;
881     +
882     + i->i_nlink = inodep->nlink;
883     + i->i_size = inodep->file_size;
884     + i->i_fop = &generic_ro_fops;
885     + i->i_mode |= S_IFREG;
886     + i->i_blocks = ((i->i_size - 1) >> 9) + 1;
887     + SQUASHFS_I(i)->u.s1.fragment_start_block = frag_blk;
888     + SQUASHFS_I(i)->u.s1.fragment_size = frag_size;
889     + SQUASHFS_I(i)->u.s1.fragment_offset = inodep->offset;
890     + SQUASHFS_I(i)->start_block = inodep->start_block;
891     + SQUASHFS_I(i)->u.s1.block_list_start = next_block;
892     + SQUASHFS_I(i)->offset = next_offset;
893     + if (sblk->block_size > 4096)
894     + i->i_data.a_ops = &squashfs_aops;
895     + else
896     + i->i_data.a_ops = &squashfs_aops_4K;
897     +
898     + TRACE("File inode %x:%x, start_block %llx, "
899     + "block_list_start %llx, offset %x\n",
900     + SQUASHFS_INODE_BLK(inode), offset,
901     + inodep->start_block, next_block,
902     + next_offset);
903     + break;
904     + }
905     + case SQUASHFS_DIR_TYPE: {
906     + struct squashfs_dir_inode_header *inodep = &id.dir;
907     + struct squashfs_dir_inode_header *sinodep = &sid.dir;
908     +
909     + if (msblk->swap) {
910     + if (!squashfs_get_cached_block(s, (char *)
911     + sinodep, block, offset,
912     + sizeof(*sinodep), &next_block,
913     + &next_offset))
914     + goto failed_read;
915     + SQUASHFS_SWAP_DIR_INODE_HEADER(inodep, sinodep);
916     + } else
917     + if (!squashfs_get_cached_block(s, (char *)
918     + inodep, block, offset,
919     + sizeof(*inodep), &next_block,
920     + &next_offset))
921     + goto failed_read;
922     +
923     + i->i_nlink = inodep->nlink;
924     + i->i_size = inodep->file_size;
925     + i->i_op = &squashfs_dir_inode_ops;
926     + i->i_fop = &squashfs_dir_ops;
927     + i->i_mode |= S_IFDIR;
928     + SQUASHFS_I(i)->start_block = inodep->start_block;
929     + SQUASHFS_I(i)->offset = inodep->offset;
930     + SQUASHFS_I(i)->u.s2.directory_index_count = 0;
931     + SQUASHFS_I(i)->u.s2.parent_inode = inodep->parent_inode;
932     +
933     + TRACE("Directory inode %x:%x, start_block %x, offset "
934     + "%x\n", SQUASHFS_INODE_BLK(inode),
935     + offset, inodep->start_block,
936     + inodep->offset);
937     + break;
938     + }
939     + case SQUASHFS_LDIR_TYPE: {
940     + struct squashfs_ldir_inode_header *inodep = &id.ldir;
941     + struct squashfs_ldir_inode_header *sinodep = &sid.ldir;
942     +
943     + if (msblk->swap) {
944     + if (!squashfs_get_cached_block(s, (char *)
945     + sinodep, block, offset,
946     + sizeof(*sinodep), &next_block,
947     + &next_offset))
948     + goto failed_read;
949     + SQUASHFS_SWAP_LDIR_INODE_HEADER(inodep,
950     + sinodep);
951     + } else
952     + if (!squashfs_get_cached_block(s, (char *)
953     + inodep, block, offset,
954     + sizeof(*inodep), &next_block,
955     + &next_offset))
956     + goto failed_read;
957     +
958     + i->i_nlink = inodep->nlink;
959     + i->i_size = inodep->file_size;
960     + i->i_op = &squashfs_dir_inode_ops;
961     + i->i_fop = &squashfs_dir_ops;
962     + i->i_mode |= S_IFDIR;
963     + SQUASHFS_I(i)->start_block = inodep->start_block;
964     + SQUASHFS_I(i)->offset = inodep->offset;
965     + SQUASHFS_I(i)->u.s2.directory_index_start = next_block;
966     + SQUASHFS_I(i)->u.s2.directory_index_offset =
967     + next_offset;
968     + SQUASHFS_I(i)->u.s2.directory_index_count =
969     + inodep->i_count;
970     + SQUASHFS_I(i)->u.s2.parent_inode = inodep->parent_inode;
971     +
972     + TRACE("Long directory inode %x:%x, start_block %x, "
973     + "offset %x\n",
974     + SQUASHFS_INODE_BLK(inode), offset,
975     + inodep->start_block, inodep->offset);
976     + break;
977     + }
978     + case SQUASHFS_SYMLINK_TYPE: {
979     + struct squashfs_symlink_inode_header *inodep =
980     + &id.symlink;
981     + struct squashfs_symlink_inode_header *sinodep =
982     + &sid.symlink;
983     +
984     + if (msblk->swap) {
985     + if (!squashfs_get_cached_block(s, (char *)
986     + sinodep, block, offset,
987     + sizeof(*sinodep), &next_block,
988     + &next_offset))
989     + goto failed_read;
990     + SQUASHFS_SWAP_SYMLINK_INODE_HEADER(inodep,
991     + sinodep);
992     + } else
993     + if (!squashfs_get_cached_block(s, (char *)
994     + inodep, block, offset,
995     + sizeof(*inodep), &next_block,
996     + &next_offset))
997     + goto failed_read;
998     +
999     + i->i_nlink = inodep->nlink;
1000     + i->i_size = inodep->symlink_size;
1001     + i->i_op = &page_symlink_inode_operations;
1002     + i->i_data.a_ops = &squashfs_symlink_aops;
1003     + i->i_mode |= S_IFLNK;
1004     + SQUASHFS_I(i)->start_block = next_block;
1005     + SQUASHFS_I(i)->offset = next_offset;
1006     +
1007     + TRACE("Symbolic link inode %x:%x, start_block %llx, "
1008     + "offset %x\n",
1009     + SQUASHFS_INODE_BLK(inode), offset,
1010     + next_block, next_offset);
1011     + break;
1012     + }
1013     + case SQUASHFS_BLKDEV_TYPE:
1014     + case SQUASHFS_CHRDEV_TYPE: {
1015     + struct squashfs_dev_inode_header *inodep = &id.dev;
1016     + struct squashfs_dev_inode_header *sinodep = &sid.dev;
1017     +
1018     + if (msblk->swap) {
1019     + if (!squashfs_get_cached_block(s, (char *)
1020     + sinodep, block, offset,
1021     + sizeof(*sinodep), &next_block,
1022     + &next_offset))
1023     + goto failed_read;
1024     + SQUASHFS_SWAP_DEV_INODE_HEADER(inodep, sinodep);
1025     + } else
1026     + if (!squashfs_get_cached_block(s, (char *)
1027     + inodep, block, offset,
1028     + sizeof(*inodep), &next_block,
1029     + &next_offset))
1030     + goto failed_read;
1031     +
1032     + i->i_nlink = inodep->nlink;
1033     + i->i_mode |= (inodeb->inode_type ==
1034     + SQUASHFS_CHRDEV_TYPE) ? S_IFCHR :
1035     + S_IFBLK;
1036     + init_special_inode(i, i->i_mode,
1037     + old_decode_dev(inodep->rdev));
1038     +
1039     + TRACE("Device inode %x:%x, rdev %x\n",
1040     + SQUASHFS_INODE_BLK(inode), offset,
1041     + inodep->rdev);
1042     + break;
1043     + }
1044     + case SQUASHFS_FIFO_TYPE:
1045     + case SQUASHFS_SOCKET_TYPE: {
1046     + struct squashfs_ipc_inode_header *inodep = &id.ipc;
1047     + struct squashfs_ipc_inode_header *sinodep = &sid.ipc;
1048     +
1049     + if (msblk->swap) {
1050     + if (!squashfs_get_cached_block(s, (char *)
1051     + sinodep, block, offset,
1052     + sizeof(*sinodep), &next_block,
1053     + &next_offset))
1054     + goto failed_read;
1055     + SQUASHFS_SWAP_IPC_INODE_HEADER(inodep, sinodep);
1056     + } else
1057     + if (!squashfs_get_cached_block(s, (char *)
1058     + inodep, block, offset,
1059     + sizeof(*inodep), &next_block,
1060     + &next_offset))
1061     + goto failed_read;
1062     +
1063     + i->i_nlink = inodep->nlink;
1064     + i->i_mode |= (inodeb->inode_type == SQUASHFS_FIFO_TYPE)
1065     + ? S_IFIFO : S_IFSOCK;
1066     + init_special_inode(i, i->i_mode, 0);
1067     + break;
1068     + }
1069     + default:
1070     + ERROR("Unknown inode type %d in squashfs_iget!\n",
1071     + inodeb->inode_type);
1072     + goto failed_read1;
1073     + }
1074     +
1075     + return 1;
1076     +
1077     +failed_read:
1078     + ERROR("Unable to read inode [%llx:%x]\n", block, offset);
1079     +
1080     +failed_read1:
1081     + make_bad_inode(i);
1082     + return 0;
1083     +}
1084     +
1085     +
1086     +static int read_inode_lookup_table(struct super_block *s)
1087     +{
1088     + struct squashfs_sb_info *msblk = s->s_fs_info;
1089     + struct squashfs_super_block *sblk = &msblk->sblk;
1090     + unsigned int length = SQUASHFS_LOOKUP_BLOCK_BYTES(sblk->inodes);
1091     +
1092     + TRACE("In read_inode_lookup_table, length %d\n", length);
1093     +
1094     + /* Allocate inode lookup table */
1095     + if (!(msblk->inode_lookup_table = kmalloc(length, GFP_KERNEL))) {
1096     + ERROR("Failed to allocate inode lookup table\n");
1097     + return 0;
1098     + }
1099     +
1100     + if (!squashfs_read_data(s, (char *) msblk->inode_lookup_table,
1101     + sblk->lookup_table_start, length |
1102     + SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, length)) {
1103     + ERROR("unable to read inode lookup table\n");
1104     + return 0;
1105     + }
1106     +
1107     + if (msblk->swap) {
1108     + int i;
1109     + long long block;
1110     +
1111     + for (i = 0; i < SQUASHFS_LOOKUP_BLOCKS(sblk->inodes); i++) {
1112     + SQUASHFS_SWAP_LOOKUP_BLOCKS((&block),
1113     + &msblk->inode_lookup_table[i], 1);
1114     + msblk->inode_lookup_table[i] = block;
1115     + }
1116     + }
1117     +
1118     + return 1;
1119     +}
1120     +
1121     +
1122     +static int read_fragment_index_table(struct super_block *s)
1123     +{
1124     + struct squashfs_sb_info *msblk = s->s_fs_info;
1125     + struct squashfs_super_block *sblk = &msblk->sblk;
1126     + unsigned int length = SQUASHFS_FRAGMENT_INDEX_BYTES(sblk->fragments);
1127     +
1128     + if(length == 0)
1129     + return 1;
1130     +
1131     + /* Allocate fragment index table */
1132     + if (!(msblk->fragment_index = kmalloc(length, GFP_KERNEL))) {
1133     + ERROR("Failed to allocate fragment index table\n");
1134     + return 0;
1135     + }
1136     +
1137     + if (!squashfs_read_data(s, (char *) msblk->fragment_index,
1138     + sblk->fragment_table_start, length |
1139     + SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, length)) {
1140     + ERROR("unable to read fragment index table\n");
1141     + return 0;
1142     + }
1143     +
1144     + if (msblk->swap) {
1145     + int i;
1146     + long long fragment;
1147     +
1148     + for (i = 0; i < SQUASHFS_FRAGMENT_INDEXES(sblk->fragments); i++) {
1149     + SQUASHFS_SWAP_FRAGMENT_INDEXES((&fragment),
1150     + &msblk->fragment_index[i], 1);
1151     + msblk->fragment_index[i] = fragment;
1152     + }
1153     + }
1154     +
1155     + return 1;
1156     +}
1157     +
1158     +
1159     +static int supported_squashfs_filesystem(struct squashfs_sb_info *msblk, int silent)
1160     +{
1161     + struct squashfs_super_block *sblk = &msblk->sblk;
1162     +
1163     + msblk->read_inode = squashfs_read_inode;
1164     + msblk->read_blocklist = read_blocklist;
1165     + msblk->read_fragment_index_table = read_fragment_index_table;
1166     +
1167     + if (sblk->s_major == 1) {
1168     + if (!squashfs_1_0_supported(msblk)) {
1169     + SERROR("Major/Minor mismatch, Squashfs 1.0 filesystems "
1170     + "are unsupported\n");
1171     + SERROR("Please recompile with "
1172     + "Squashfs 1.0 support enabled\n");
1173     + return 0;
1174     + }
1175     + } else if (sblk->s_major == 2) {
1176     + if (!squashfs_2_0_supported(msblk)) {
1177     + SERROR("Major/Minor mismatch, Squashfs 2.0 filesystems "
1178     + "are unsupported\n");
1179     + SERROR("Please recompile with "
1180     + "Squashfs 2.0 support enabled\n");
1181     + return 0;
1182     + }
1183     + } else if(sblk->s_major != SQUASHFS_MAJOR || sblk->s_minor >
1184     + SQUASHFS_MINOR) {
1185     + SERROR("Major/Minor mismatch, trying to mount newer %d.%d "
1186     + "filesystem\n", sblk->s_major, sblk->s_minor);
1187     + SERROR("Please update your kernel\n");
1188     + return 0;
1189     + }
1190     +
1191     + return 1;
1192     +}
1193     +
1194     +
1195     +static int squashfs_fill_super(struct super_block *s, void *data, int silent)
1196     +{
1197     + struct squashfs_sb_info *msblk;
1198     + struct squashfs_super_block *sblk;
1199     + int i;
1200     + char b[BDEVNAME_SIZE];
1201     + struct inode *root;
1202     +
1203     + TRACE("Entered squashfs_read_superblock\n");
1204     +
1205     + if (!(s->s_fs_info = kmalloc(sizeof(struct squashfs_sb_info),
1206     + GFP_KERNEL))) {
1207     + ERROR("Failed to allocate superblock\n");
1208     + goto failure;
1209     + }
1210     + memset(s->s_fs_info, 0, sizeof(struct squashfs_sb_info));
1211     + msblk = s->s_fs_info;
1212     + if (!(msblk->stream.workspace = vmalloc(zlib_inflate_workspacesize()))) {
1213     + ERROR("Failed to allocate zlib workspace\n");
1214     + goto failure;
1215     + }
1216     + sblk = &msblk->sblk;
1217     +
1218     + msblk->devblksize = sb_min_blocksize(s, BLOCK_SIZE);
1219     + msblk->devblksize_log2 = ffz(~msblk->devblksize);
1220     +
1221     + mutex_init(&msblk->read_data_mutex);
1222     + mutex_init(&msblk->read_page_mutex);
1223     + mutex_init(&msblk->block_cache_mutex);
1224     + mutex_init(&msblk->fragment_mutex);
1225     + mutex_init(&msblk->meta_index_mutex);
1226     +
1227     + init_waitqueue_head(&msblk->waitq);
1228     + init_waitqueue_head(&msblk->fragment_wait_queue);
1229     +
1230     + sblk->bytes_used = sizeof(struct squashfs_super_block);
1231     + if (!squashfs_read_data(s, (char *) sblk, SQUASHFS_START,
1232     + sizeof(struct squashfs_super_block) |
1233     + SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, sizeof(struct squashfs_super_block))) {
1234     + SERROR("unable to read superblock\n");
1235     + goto failed_mount;
1236     + }
1237     +
1238     + /* Check it is a SQUASHFS superblock */
1239     + msblk->swap = 0;
1240     + if ((s->s_magic = sblk->s_magic) != SQUASHFS_MAGIC) {
1241     + if (sblk->s_magic == SQUASHFS_MAGIC_SWAP) {
1242     + struct squashfs_super_block ssblk;
1243     +
1244     + WARNING("Mounting a different endian SQUASHFS "
1245     + "filesystem on %s\n", bdevname(s->s_bdev, b));
1246     +
1247     + SQUASHFS_SWAP_SUPER_BLOCK(&ssblk, sblk);
1248     + memcpy(sblk, &ssblk, sizeof(struct squashfs_super_block));
1249     + msblk->swap = 1;
1250     + } else {
1251     + SERROR("Can't find a SQUASHFS superblock on %s\n",
1252     + bdevname(s->s_bdev, b));
1253     + goto failed_mount;
1254     + }
1255     + }
1256     +
1257     + /* Check the MAJOR & MINOR versions */
1258     + if(!supported_squashfs_filesystem(msblk, silent))
1259     + goto failed_mount;
1260     +
1261     + /* Check the filesystem does not extend beyond the end of the
1262     + block device */
1263     + if(sblk->bytes_used < 0 || sblk->bytes_used > i_size_read(s->s_bdev->bd_inode))
1264     + goto failed_mount;
1265     +
1266     + /* Check the root inode for sanity */
1267     + if (SQUASHFS_INODE_OFFSET(sblk->root_inode) > SQUASHFS_METADATA_SIZE)
1268     + goto failed_mount;
1269     +
1270     + TRACE("Found valid superblock on %s\n", bdevname(s->s_bdev, b));
1271     + TRACE("Inodes are %scompressed\n",
1272     + SQUASHFS_UNCOMPRESSED_INODES
1273     + (sblk->flags) ? "un" : "");
1274     + TRACE("Data is %scompressed\n",
1275     + SQUASHFS_UNCOMPRESSED_DATA(sblk->flags)
1276     + ? "un" : "");
1277     + TRACE("Check data is %s present in the filesystem\n",
1278     + SQUASHFS_CHECK_DATA(sblk->flags) ?
1279     + "" : "not");
1280     + TRACE("Filesystem size %lld bytes\n", sblk->bytes_used);
1281     + TRACE("Block size %d\n", sblk->block_size);
1282     + TRACE("Number of inodes %d\n", sblk->inodes);
1283     + if (sblk->s_major > 1)
1284     + TRACE("Number of fragments %d\n", sblk->fragments);
1285     + TRACE("Number of uids %d\n", sblk->no_uids);
1286     + TRACE("Number of gids %d\n", sblk->no_guids);
1287     + TRACE("sblk->inode_table_start %llx\n", sblk->inode_table_start);
1288     + TRACE("sblk->directory_table_start %llx\n", sblk->directory_table_start);
1289     + if (sblk->s_major > 1)
1290     + TRACE("sblk->fragment_table_start %llx\n",
1291     + sblk->fragment_table_start);
1292     + TRACE("sblk->uid_start %llx\n", sblk->uid_start);
1293     +
1294     + s->s_flags |= MS_RDONLY;
1295     + s->s_op = &squashfs_super_ops;
1296     +
1297     + /* Init inode_table block pointer array */
1298     + if (!(msblk->block_cache = kmalloc(sizeof(struct squashfs_cache) *
1299     + SQUASHFS_CACHED_BLKS, GFP_KERNEL))) {
1300     + ERROR("Failed to allocate block cache\n");
1301     + goto failed_mount;
1302     + }
1303     +
1304     + for (i = 0; i < SQUASHFS_CACHED_BLKS; i++)
1305     + msblk->block_cache[i].block = SQUASHFS_INVALID_BLK;
1306     +
1307     + msblk->next_cache = 0;
1308     +
1309     + /* Allocate read_page block */
1310     + if (!(msblk->read_page = kmalloc(sblk->block_size, GFP_KERNEL))) {
1311     + ERROR("Failed to allocate read_page block\n");
1312     + goto failed_mount;
1313     + }
1314     +
1315     + /* Allocate uid and gid tables */
1316     + if (!(msblk->uid = kmalloc((sblk->no_uids + sblk->no_guids) *
1317     + sizeof(unsigned int), GFP_KERNEL))) {
1318     + ERROR("Failed to allocate uid/gid table\n");
1319     + goto failed_mount;
1320     + }
1321     + msblk->guid = msblk->uid + sblk->no_uids;
1322     +
1323     + if (msblk->swap) {
1324     + unsigned int suid[sblk->no_uids + sblk->no_guids];
1325     +
1326     + if (!squashfs_read_data(s, (char *) &suid, sblk->uid_start,
1327     + ((sblk->no_uids + sblk->no_guids) *
1328     + sizeof(unsigned int)) |
1329     + SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, (sblk->no_uids + sblk->no_guids) * sizeof(unsigned int))) {
1330     + ERROR("unable to read uid/gid table\n");
1331     + goto failed_mount;
1332     + }
1333     +
1334     + SQUASHFS_SWAP_DATA(msblk->uid, suid, (sblk->no_uids +
1335     + sblk->no_guids), (sizeof(unsigned int) * 8));
1336     + } else
1337     + if (!squashfs_read_data(s, (char *) msblk->uid, sblk->uid_start,
1338     + ((sblk->no_uids + sblk->no_guids) *
1339     + sizeof(unsigned int)) |
1340     + SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, (sblk->no_uids + sblk->no_guids) * sizeof(unsigned int))) {
1341     + ERROR("unable to read uid/gid table\n");
1342     + goto failed_mount;
1343     + }
1344     +
1345     +
1346     + if (sblk->s_major == 1 && squashfs_1_0_supported(msblk))
1347     + goto allocate_root;
1348     +
1349     + if (!(msblk->fragment = kmalloc(sizeof(struct squashfs_fragment_cache) *
1350     + SQUASHFS_CACHED_FRAGMENTS, GFP_KERNEL))) {
1351     + ERROR("Failed to allocate fragment block cache\n");
1352     + goto failed_mount;
1353     + }
1354     +
1355     + for (i = 0; i < SQUASHFS_CACHED_FRAGMENTS; i++) {
1356     + msblk->fragment[i].locked = 0;
1357     + msblk->fragment[i].block = SQUASHFS_INVALID_BLK;
1358     + msblk->fragment[i].data = NULL;
1359     + }
1360     +
1361     + msblk->next_fragment = 0;
1362     +
1363     + /* Allocate and read fragment index table */
1364     + if (msblk->read_fragment_index_table(s) == 0)
1365     + goto failed_mount;
1366     +
1367     + if(sblk->s_major < 3 || sblk->lookup_table_start == SQUASHFS_INVALID_BLK)
1368     + goto allocate_root;
1369     +
1370     + /* Allocate and read inode lookup table */
1371     + if (read_inode_lookup_table(s) == 0)
1372     + goto failed_mount;
1373     +
1374     + s->s_op = &squashfs_export_super_ops;
1375     + s->s_export_op = &squashfs_export_ops;
1376     +
1377     +allocate_root:
1378     + root = new_inode(s);
1379     + if ((msblk->read_inode)(root, sblk->root_inode) == 0)
1380     + goto failed_mount;
1381     + insert_inode_hash(root);
1382     +
1383     + if ((s->s_root = d_alloc_root(root)) == NULL) {
1384     + ERROR("Root inode create failed\n");
1385     + iput(root);
1386     + goto failed_mount;
1387     + }
1388     +
1389     + TRACE("Leaving squashfs_read_super\n");
1390     + return 0;
1391     +
1392     +failed_mount:
1393     + kfree(msblk->inode_lookup_table);
1394     + kfree(msblk->fragment_index);
1395     + kfree(msblk->fragment);
1396     + kfree(msblk->uid);
1397     + kfree(msblk->read_page);
1398     + kfree(msblk->block_cache);
1399     + kfree(msblk->fragment_index_2);
1400     + vfree(msblk->stream.workspace);
1401     + kfree(s->s_fs_info);
1402     + s->s_fs_info = NULL;
1403     + return -EINVAL;
1404     +
1405     +failure:
1406     + return -ENOMEM;
1407     +}
1408     +
1409     +
1410     +static int squashfs_statfs(struct dentry *dentry, struct kstatfs *buf)
1411     +{
1412     + struct squashfs_sb_info *msblk = dentry->d_sb->s_fs_info;
1413     + struct squashfs_super_block *sblk = &msblk->sblk;
1414     +
1415     + TRACE("Entered squashfs_statfs\n");
1416     +
1417     + buf->f_type = SQUASHFS_MAGIC;
1418     + buf->f_bsize = sblk->block_size;
1419     + buf->f_blocks = ((sblk->bytes_used - 1) >> sblk->block_log) + 1;
1420     + buf->f_bfree = buf->f_bavail = 0;
1421     + buf->f_files = sblk->inodes;
1422     + buf->f_ffree = 0;
1423     + buf->f_namelen = SQUASHFS_NAME_LEN;
1424     +
1425     + return 0;
1426     +}
1427     +
1428     +
1429     +static int squashfs_symlink_readpage(struct file *file, struct page *page)
1430     +{
1431     + struct inode *inode = page->mapping->host;
1432     + int index = page->index << PAGE_CACHE_SHIFT, length, bytes;
1433     + long long block = SQUASHFS_I(inode)->start_block;
1434     + int offset = SQUASHFS_I(inode)->offset;
1435     + void *pageaddr = kmap(page);
1436     +
1437     + TRACE("Entered squashfs_symlink_readpage, page index %ld, start block "
1438     + "%llx, offset %x\n", page->index,
1439     + SQUASHFS_I(inode)->start_block,
1440     + SQUASHFS_I(inode)->offset);
1441     +
1442     + for (length = 0; length < index; length += bytes) {
1443     + if (!(bytes = squashfs_get_cached_block(inode->i_sb, NULL,
1444     + block, offset, PAGE_CACHE_SIZE, &block,
1445     + &offset))) {
1446     + ERROR("Unable to read symbolic link [%llx:%x]\n", block,
1447     + offset);
1448     + goto skip_read;
1449     + }
1450     + }
1451     +
1452     + if (length != index) {
1453     + ERROR("(squashfs_symlink_readpage) length != index\n");
1454     + bytes = 0;
1455     + goto skip_read;
1456     + }
1457     +
1458     + bytes = (i_size_read(inode) - length) > PAGE_CACHE_SIZE ? PAGE_CACHE_SIZE :
1459     + i_size_read(inode) - length;
1460     +
1461     + if (!(bytes = squashfs_get_cached_block(inode->i_sb, pageaddr, block,
1462     + offset, bytes, &block, &offset)))
1463     + ERROR("Unable to read symbolic link [%llx:%x]\n", block, offset);
1464     +
1465     +skip_read:
1466     + memset(pageaddr + bytes, 0, PAGE_CACHE_SIZE - bytes);
1467     + kunmap(page);
1468     + flush_dcache_page(page);
1469     + SetPageUptodate(page);
1470     + unlock_page(page);
1471     +
1472     + return 0;
1473     +}
1474     +
1475     +
1476     +struct meta_index *locate_meta_index(struct inode *inode, int index, int offset)
1477     +{
1478     + struct meta_index *meta = NULL;
1479     + struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info;
1480     + int i;
1481     +
1482     + mutex_lock(&msblk->meta_index_mutex);
1483     +
1484     + TRACE("locate_meta_index: index %d, offset %d\n", index, offset);
1485     +
1486     + if(msblk->meta_index == NULL)
1487     + goto not_allocated;
1488     +
1489     + for (i = 0; i < SQUASHFS_META_NUMBER; i ++)
1490     + if (msblk->meta_index[i].inode_number == inode->i_ino &&
1491     + msblk->meta_index[i].offset >= offset &&
1492     + msblk->meta_index[i].offset <= index &&
1493     + msblk->meta_index[i].locked == 0) {
1494     + TRACE("locate_meta_index: entry %d, offset %d\n", i,
1495     + msblk->meta_index[i].offset);
1496     + meta = &msblk->meta_index[i];
1497     + offset = meta->offset;
1498     + }
1499     +
1500     + if (meta)
1501     + meta->locked = 1;
1502     +
1503     +not_allocated:
1504     + mutex_unlock(&msblk->meta_index_mutex);
1505     +
1506     + return meta;
1507     +}
1508     +
1509     +
1510     +struct meta_index *empty_meta_index(struct inode *inode, int offset, int skip)
1511     +{
1512     + struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info;
1513     + struct meta_index *meta = NULL;
1514     + int i;
1515     +
1516     + mutex_lock(&msblk->meta_index_mutex);
1517     +
1518     + TRACE("empty_meta_index: offset %d, skip %d\n", offset, skip);
1519     +
1520     + if(msblk->meta_index == NULL) {
1521     + if (!(msblk->meta_index = kmalloc(sizeof(struct meta_index) *
1522     + SQUASHFS_META_NUMBER, GFP_KERNEL))) {
1523     + ERROR("Failed to allocate meta_index\n");
1524     + goto failed;
1525     + }
1526     + for(i = 0; i < SQUASHFS_META_NUMBER; i++) {
1527     + msblk->meta_index[i].inode_number = 0;
1528     + msblk->meta_index[i].locked = 0;
1529     + }
1530     + msblk->next_meta_index = 0;
1531     + }
1532     +
1533     + for(i = SQUASHFS_META_NUMBER; i &&
1534     + msblk->meta_index[msblk->next_meta_index].locked; i --)
1535     + msblk->next_meta_index = (msblk->next_meta_index + 1) %
1536     + SQUASHFS_META_NUMBER;
1537     +
1538     + if(i == 0) {
1539     + TRACE("empty_meta_index: failed!\n");
1540     + goto failed;
1541     + }
1542     +
1543     + TRACE("empty_meta_index: returned meta entry %d, %p\n",
1544     + msblk->next_meta_index,
1545     + &msblk->meta_index[msblk->next_meta_index]);
1546     +
1547     + meta = &msblk->meta_index[msblk->next_meta_index];
1548     + msblk->next_meta_index = (msblk->next_meta_index + 1) %
1549     + SQUASHFS_META_NUMBER;
1550     +
1551     + meta->inode_number = inode->i_ino;
1552     + meta->offset = offset;
1553     + meta->skip = skip;
1554     + meta->entries = 0;
1555     + meta->locked = 1;
1556     +
1557     +failed:
1558     + mutex_unlock(&msblk->meta_index_mutex);
1559     + return meta;
1560     +}
1561     +
1562     +
1563     +void release_meta_index(struct inode *inode, struct meta_index *meta)
1564     +{
1565     + meta->locked = 0;
1566     + smp_mb();
1567     +}
1568     +
1569     +
1570     +static int read_block_index(struct super_block *s, int blocks, char *block_list,
1571     + long long *start_block, int *offset)
1572     +{
1573     + struct squashfs_sb_info *msblk = s->s_fs_info;
1574     + unsigned int *block_listp;
1575     + int block = 0;
1576     +
1577     + if (msblk->swap) {
1578     + char sblock_list[blocks << 2];
1579     +
1580     + if (!squashfs_get_cached_block(s, sblock_list, *start_block,
1581     + *offset, blocks << 2, start_block, offset)) {
1582     + ERROR("Unable to read block list [%llx:%x]\n",
1583     + *start_block, *offset);
1584     + goto failure;
1585     + }
1586     + SQUASHFS_SWAP_INTS(((unsigned int *)block_list),
1587     + ((unsigned int *)sblock_list), blocks);
1588     + } else
1589     + if (!squashfs_get_cached_block(s, block_list, *start_block,
1590     + *offset, blocks << 2, start_block, offset)) {
1591     + ERROR("Unable to read block list [%llx:%x]\n",
1592     + *start_block, *offset);
1593     + goto failure;
1594     + }
1595     +
1596     + for (block_listp = (unsigned int *) block_list; blocks;
1597     + block_listp++, blocks --)
1598     + block += SQUASHFS_COMPRESSED_SIZE_BLOCK(*block_listp);
1599     +
1600     + return block;
1601     +
1602     +failure:
1603     + return -1;
1604     +}
1605     +
1606     +
1607     +#define SIZE 256
1608     +
1609     +static inline int calculate_skip(int blocks) {
1610     + int skip = (blocks - 1) / ((SQUASHFS_SLOTS * SQUASHFS_META_ENTRIES + 1) * SQUASHFS_META_INDEXES);
1611     + return skip >= 7 ? 7 : skip + 1;
1612     +}
1613     +
1614     +
1615     +static int get_meta_index(struct inode *inode, int index,
1616     + long long *index_block, int *index_offset,
1617     + long long *data_block, char *block_list)
1618     +{
1619     + struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info;
1620     + struct squashfs_super_block *sblk = &msblk->sblk;
1621     + int skip = calculate_skip(i_size_read(inode) >> sblk->block_log);
1622     + int offset = 0;
1623     + struct meta_index *meta;
1624     + struct meta_entry *meta_entry;
1625     + long long cur_index_block = SQUASHFS_I(inode)->u.s1.block_list_start;
1626     + int cur_offset = SQUASHFS_I(inode)->offset;
1627     + long long cur_data_block = SQUASHFS_I(inode)->start_block;
1628     + int i;
1629     +
1630     + index /= SQUASHFS_META_INDEXES * skip;
1631     +
1632     + while ( offset < index ) {
1633     + meta = locate_meta_index(inode, index, offset + 1);
1634     +
1635     + if (meta == NULL) {
1636     + if ((meta = empty_meta_index(inode, offset + 1,
1637     + skip)) == NULL)
1638     + goto all_done;
1639     + } else {
1640     + if(meta->entries == 0)
1641     + goto failed;
1642     + offset = index < meta->offset + meta->entries ? index :
1643     + meta->offset + meta->entries - 1;
1644     + meta_entry = &meta->meta_entry[offset - meta->offset];
1645     + cur_index_block = meta_entry->index_block + sblk->inode_table_start;
1646     + cur_offset = meta_entry->offset;
1647     + cur_data_block = meta_entry->data_block;
1648     + TRACE("get_meta_index: offset %d, meta->offset %d, "
1649     + "meta->entries %d\n", offset, meta->offset,
1650     + meta->entries);
1651     + TRACE("get_meta_index: index_block 0x%llx, offset 0x%x"
1652     + " data_block 0x%llx\n", cur_index_block,
1653     + cur_offset, cur_data_block);
1654     + }
1655     +
1656     + for (i = meta->offset + meta->entries; i <= index &&
1657     + i < meta->offset + SQUASHFS_META_ENTRIES; i++) {
1658     + int blocks = skip * SQUASHFS_META_INDEXES;
1659     +
1660     + while (blocks) {
1661     + int block = blocks > (SIZE >> 2) ? (SIZE >> 2) :
1662     + blocks;
1663     + int res = read_block_index(inode->i_sb, block,
1664     + block_list, &cur_index_block,
1665     + &cur_offset);
1666     +
1667     + if (res == -1)
1668     + goto failed;
1669     +
1670     + cur_data_block += res;
1671     + blocks -= block;
1672     + }
1673     +
1674     + meta_entry = &meta->meta_entry[i - meta->offset];
1675     + meta_entry->index_block = cur_index_block - sblk->inode_table_start;
1676     + meta_entry->offset = cur_offset;
1677     + meta_entry->data_block = cur_data_block;
1678     + meta->entries ++;
1679     + offset ++;
1680     + }
1681     +
1682     + TRACE("get_meta_index: meta->offset %d, meta->entries %d\n",
1683     + meta->offset, meta->entries);
1684     +
1685     + release_meta_index(inode, meta);
1686     + }
1687     +
1688     +all_done:
1689     + *index_block = cur_index_block;
1690     + *index_offset = cur_offset;
1691     + *data_block = cur_data_block;
1692     +
1693     + return offset * SQUASHFS_META_INDEXES * skip;
1694     +
1695     +failed:
1696     + release_meta_index(inode, meta);
1697     + return -1;
1698     +}
1699     +
1700     +
1701     +static long long read_blocklist(struct inode *inode, int index,
1702     + int readahead_blks, char *block_list,
1703     + unsigned short **block_p, unsigned int *bsize)
1704     +{
1705     + long long block_ptr;
1706     + int offset;
1707     + long long block;
1708     + int res = get_meta_index(inode, index, &block_ptr, &offset, &block,
1709     + block_list);
1710     +
1711     + TRACE("read_blocklist: res %d, index %d, block_ptr 0x%llx, offset"
1712     + " 0x%x, block 0x%llx\n", res, index, block_ptr, offset,
1713     + block);
1714     +
1715     + if(res == -1)
1716     + goto failure;
1717     +
1718     + index -= res;
1719     +
1720     + while ( index ) {
1721     + int blocks = index > (SIZE >> 2) ? (SIZE >> 2) : index;
1722     + int res = read_block_index(inode->i_sb, blocks, block_list,
1723     + &block_ptr, &offset);
1724     + if (res == -1)
1725     + goto failure;
1726     + block += res;
1727     + index -= blocks;
1728     + }
1729     +
1730     + if (read_block_index(inode->i_sb, 1, block_list,
1731     + &block_ptr, &offset) == -1)
1732     + goto failure;
1733     + *bsize = *((unsigned int *) block_list);
1734     +
1735     + return block;
1736     +
1737     +failure:
1738     + return 0;
1739     +}
1740     +
1741     +
1742     +static int squashfs_readpage(struct file *file, struct page *page)
1743     +{
1744     + struct inode *inode = page->mapping->host;
1745     + struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info;
1746     + struct squashfs_super_block *sblk = &msblk->sblk;
1747     + unsigned char *block_list;
1748     + long long block;
1749     + unsigned int bsize, i = 0, bytes = 0, byte_offset = 0;
1750     + int index = page->index >> (sblk->block_log - PAGE_CACHE_SHIFT);
1751     + void *pageaddr;
1752     + struct squashfs_fragment_cache *fragment = NULL;
1753     + char *data_ptr = msblk->read_page;
1754     +
1755     + int mask = (1 << (sblk->block_log - PAGE_CACHE_SHIFT)) - 1;
1756     + int start_index = page->index & ~mask;
1757     + int end_index = start_index | mask;
1758     +
1759     + TRACE("Entered squashfs_readpage, page index %lx, start block %llx\n",
1760     + page->index,
1761     + SQUASHFS_I(inode)->start_block);
1762     +
1763     + if (!(block_list = kmalloc(SIZE, GFP_KERNEL))) {
1764     + ERROR("Failed to allocate block_list\n");
1765     + goto skip_read;
1766     + }
1767     +
1768     + if (page->index >= ((i_size_read(inode) + PAGE_CACHE_SIZE - 1) >>
1769     + PAGE_CACHE_SHIFT))
1770     + goto skip_read;
1771     +
1772     + if (SQUASHFS_I(inode)->u.s1.fragment_start_block == SQUASHFS_INVALID_BLK
1773     + || index < (i_size_read(inode) >>
1774     + sblk->block_log)) {
1775     + if ((block = (msblk->read_blocklist)(inode, index, 1,
1776     + block_list, NULL, &bsize)) == 0)
1777     + goto skip_read;
1778     +
1779     + mutex_lock(&msblk->read_page_mutex);
1780     +
1781     + if (!(bytes = squashfs_read_data(inode->i_sb, msblk->read_page,
1782     + block, bsize, NULL, sblk->block_size))) {
1783     + ERROR("Unable to read page, block %llx, size %x\n", block,
1784     + bsize);
1785     + mutex_unlock(&msblk->read_page_mutex);
1786     + goto skip_read;
1787     + }
1788     + } else {
1789     + if ((fragment = get_cached_fragment(inode->i_sb,
1790     + SQUASHFS_I(inode)->
1791     + u.s1.fragment_start_block,
1792     + SQUASHFS_I(inode)->u.s1.fragment_size))
1793     + == NULL) {
1794     + ERROR("Unable to read page, block %llx, size %x\n",
1795     + SQUASHFS_I(inode)->
1796     + u.s1.fragment_start_block,
1797     + (int) SQUASHFS_I(inode)->
1798     + u.s1.fragment_size);
1799     + goto skip_read;
1800     + }
1801     + bytes = SQUASHFS_I(inode)->u.s1.fragment_offset +
1802     + (i_size_read(inode) & (sblk->block_size
1803     + - 1));
1804     + byte_offset = SQUASHFS_I(inode)->u.s1.fragment_offset;
1805     + data_ptr = fragment->data;
1806     + }
1807     +
1808     + for (i = start_index; i <= end_index && byte_offset < bytes;
1809     + i++, byte_offset += PAGE_CACHE_SIZE) {
1810     + struct page *push_page;
1811     + int avail = (bytes - byte_offset) > PAGE_CACHE_SIZE ?
1812     + PAGE_CACHE_SIZE : bytes - byte_offset;
1813     +
1814     + TRACE("bytes %d, i %d, byte_offset %d, available_bytes %d\n",
1815     + bytes, i, byte_offset, avail);
1816     +
1817     + push_page = (i == page->index) ? page :
1818     + grab_cache_page_nowait(page->mapping, i);
1819     +
1820     + if (!push_page)
1821     + continue;
1822     +
1823     + if (PageUptodate(push_page))
1824     + goto skip_page;
1825     +
1826     + pageaddr = kmap_atomic(push_page, KM_USER0);
1827     + memcpy(pageaddr, data_ptr + byte_offset, avail);
1828     + memset(pageaddr + avail, 0, PAGE_CACHE_SIZE - avail);
1829     + kunmap_atomic(pageaddr, KM_USER0);
1830     + flush_dcache_page(push_page);
1831     + SetPageUptodate(push_page);
1832     +skip_page:
1833     + unlock_page(push_page);
1834     + if(i != page->index)
1835     + page_cache_release(push_page);
1836     + }
1837     +
1838     + if (SQUASHFS_I(inode)->u.s1.fragment_start_block == SQUASHFS_INVALID_BLK
1839     + || index < (i_size_read(inode) >>
1840     + sblk->block_log))
1841     + mutex_unlock(&msblk->read_page_mutex);
1842     + else
1843     + release_cached_fragment(msblk, fragment);
1844     +
1845     + kfree(block_list);
1846     + return 0;
1847     +
1848     +skip_read:
1849     + pageaddr = kmap_atomic(page, KM_USER0);
1850     + memset(pageaddr + bytes, 0, PAGE_CACHE_SIZE - bytes);
1851     + kunmap_atomic(pageaddr, KM_USER0);
1852     + flush_dcache_page(page);
1853     + SetPageUptodate(page);
1854     + unlock_page(page);
1855     +
1856     + kfree(block_list);
1857     + return 0;
1858     +}
1859     +
1860     +
1861     +static int squashfs_readpage4K(struct file *file, struct page *page)
1862     +{
1863     + struct inode *inode = page->mapping->host;
1864     + struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info;
1865     + struct squashfs_super_block *sblk = &msblk->sblk;
1866     + unsigned char *block_list;
1867     + long long block;
1868     + unsigned int bsize, bytes = 0;
1869     + void *pageaddr;
1870     +
1871     + TRACE("Entered squashfs_readpage4K, page index %lx, start block %llx\n",
1872     + page->index,
1873     + SQUASHFS_I(inode)->start_block);
1874     +
1875     + if (page->index >= ((i_size_read(inode) + PAGE_CACHE_SIZE - 1) >>
1876     + PAGE_CACHE_SHIFT)) {
1877     + block_list = NULL;
1878     + goto skip_read;
1879     + }
1880     +
1881     + if (!(block_list = kmalloc(SIZE, GFP_KERNEL))) {
1882     + ERROR("Failed to allocate block_list\n");
1883     + goto skip_read;
1884     + }
1885     +
1886     + if (SQUASHFS_I(inode)->u.s1.fragment_start_block == SQUASHFS_INVALID_BLK
1887     + || page->index < (i_size_read(inode) >>
1888     + sblk->block_log)) {
1889     + block = (msblk->read_blocklist)(inode, page->index, 1,
1890     + block_list, NULL, &bsize);
1891     + if(block == 0)
1892     + goto skip_read;
1893     +
1894     + mutex_lock(&msblk->read_page_mutex);
1895     + bytes = squashfs_read_data(inode->i_sb, msblk->read_page, block,
1896     + bsize, NULL, sblk->block_size);
1897     + if (bytes) {
1898     + pageaddr = kmap_atomic(page, KM_USER0);
1899     + memcpy(pageaddr, msblk->read_page, bytes);
1900     + kunmap_atomic(pageaddr, KM_USER0);
1901     + } else
1902     + ERROR("Unable to read page, block %llx, size %x\n",
1903     + block, bsize);
1904     + mutex_unlock(&msblk->read_page_mutex);
1905     + } else {
1906     + struct squashfs_fragment_cache *fragment =
1907     + get_cached_fragment(inode->i_sb,
1908     + SQUASHFS_I(inode)->
1909     + u.s1.fragment_start_block,
1910     + SQUASHFS_I(inode)-> u.s1.fragment_size);
1911     + if (fragment) {
1912     + bytes = i_size_read(inode) & (sblk->block_size - 1);
1913     + pageaddr = kmap_atomic(page, KM_USER0);
1914     + memcpy(pageaddr, fragment->data + SQUASHFS_I(inode)->
1915     + u.s1.fragment_offset, bytes);
1916     + kunmap_atomic(pageaddr, KM_USER0);
1917     + release_cached_fragment(msblk, fragment);
1918     + } else
1919     + ERROR("Unable to read page, block %llx, size %x\n",
1920     + SQUASHFS_I(inode)->
1921     + u.s1.fragment_start_block, (int)
1922     + SQUASHFS_I(inode)-> u.s1.fragment_size);
1923     + }
1924     +
1925     +skip_read:
1926     + pageaddr = kmap_atomic(page, KM_USER0);
1927     + memset(pageaddr + bytes, 0, PAGE_CACHE_SIZE - bytes);
1928     + kunmap_atomic(pageaddr, KM_USER0);
1929     + flush_dcache_page(page);
1930     + SetPageUptodate(page);
1931     + unlock_page(page);
1932     +
1933     + kfree(block_list);
1934     + return 0;
1935     +}
1936     +
1937     +
1938     +static int get_dir_index_using_offset(struct super_block *s, long long
1939     + *next_block, unsigned int *next_offset,
1940     + long long index_start,
1941     + unsigned int index_offset, int i_count,
1942     + long long f_pos)
1943     +{
1944     + struct squashfs_sb_info *msblk = s->s_fs_info;
1945     + struct squashfs_super_block *sblk = &msblk->sblk;
1946     + int i, length = 0;
1947     + struct squashfs_dir_index index;
1948     +
1949     + TRACE("Entered get_dir_index_using_offset, i_count %d, f_pos %d\n",
1950     + i_count, (unsigned int) f_pos);
1951     +
1952     + f_pos =- 3;
1953     + if (f_pos == 0)
1954     + goto finish;
1955     +
1956     + for (i = 0; i < i_count; i++) {
1957     + if (msblk->swap) {
1958     + struct squashfs_dir_index sindex;
1959     + squashfs_get_cached_block(s, (char *) &sindex,
1960     + index_start, index_offset,
1961     + sizeof(sindex), &index_start,
1962     + &index_offset);
1963     + SQUASHFS_SWAP_DIR_INDEX(&index, &sindex);
1964     + } else
1965     + squashfs_get_cached_block(s, (char *) &index,
1966     + index_start, index_offset,
1967     + sizeof(index), &index_start,
1968     + &index_offset);
1969     +
1970     + if (index.index > f_pos)
1971     + break;
1972     +
1973     + squashfs_get_cached_block(s, NULL, index_start, index_offset,
1974     + index.size + 1, &index_start,
1975     + &index_offset);
1976     +
1977     + length = index.index;
1978     + *next_block = index.start_block + sblk->directory_table_start;
1979     + }
1980     +
1981     + *next_offset = (length + *next_offset) % SQUASHFS_METADATA_SIZE;
1982     +
1983     +finish:
1984     + return length + 3;
1985     +}
1986     +
1987     +
1988     +static int get_dir_index_using_name(struct super_block *s, long long
1989     + *next_block, unsigned int *next_offset,
1990     + long long index_start,
1991     + unsigned int index_offset, int i_count,
1992     + const char *name, int size)
1993     +{
1994     + struct squashfs_sb_info *msblk = s->s_fs_info;
1995     + struct squashfs_super_block *sblk = &msblk->sblk;
1996     + int i, length = 0;
1997     + struct squashfs_dir_index *index;
1998     + char *str;
1999     +
2000     + TRACE("Entered get_dir_index_using_name, i_count %d\n", i_count);
2001     +
2002     + if (!(str = kmalloc(sizeof(struct squashfs_dir_index) +
2003     + (SQUASHFS_NAME_LEN + 1) * 2, GFP_KERNEL))) {
2004     + ERROR("Failed to allocate squashfs_dir_index\n");
2005     + goto failure;
2006     + }
2007     +
2008     + index = (struct squashfs_dir_index *) (str + SQUASHFS_NAME_LEN + 1);
2009     + strncpy(str, name, size);
2010     + str[size] = '\0';
2011     +
2012     + for (i = 0; i < i_count; i++) {
2013     + if (msblk->swap) {
2014     + struct squashfs_dir_index sindex;
2015     + squashfs_get_cached_block(s, (char *) &sindex,
2016     + index_start, index_offset,
2017     + sizeof(sindex), &index_start,
2018     + &index_offset);
2019     + SQUASHFS_SWAP_DIR_INDEX(index, &sindex);
2020     + } else
2021     + squashfs_get_cached_block(s, (char *) index,
2022     + index_start, index_offset,
2023     + sizeof(struct squashfs_dir_index),
2024     + &index_start, &index_offset);
2025     +
2026     + squashfs_get_cached_block(s, index->name, index_start,
2027     + index_offset, index->size + 1,
2028     + &index_start, &index_offset);
2029     +
2030     + index->name[index->size + 1] = '\0';
2031     +
2032     + if (strcmp(index->name, str) > 0)
2033     + break;
2034     +
2035     + length = index->index;
2036     + *next_block = index->start_block + sblk->directory_table_start;
2037     + }
2038     +
2039     + *next_offset = (length + *next_offset) % SQUASHFS_METADATA_SIZE;
2040     + kfree(str);
2041     +failure:
2042     + return length + 3;
2043     +}
2044     +
2045     +
2046     +static int squashfs_readdir(struct file *file, void *dirent, filldir_t filldir)
2047     +{
2048     + struct inode *i = file->f_dentry->d_inode;
2049     + struct squashfs_sb_info *msblk = i->i_sb->s_fs_info;
2050     + struct squashfs_super_block *sblk = &msblk->sblk;
2051     + long long next_block = SQUASHFS_I(i)->start_block +
2052     + sblk->directory_table_start;
2053     + int next_offset = SQUASHFS_I(i)->offset, length = 0,
2054     + dir_count;
2055     + struct squashfs_dir_header dirh;
2056     + struct squashfs_dir_entry *dire;
2057     +
2058     + TRACE("Entered squashfs_readdir [%llx:%x]\n", next_block, next_offset);
2059     +
2060     + if (!(dire = kmalloc(sizeof(struct squashfs_dir_entry) +
2061     + SQUASHFS_NAME_LEN + 1, GFP_KERNEL))) {
2062     + ERROR("Failed to allocate squashfs_dir_entry\n");
2063     + goto finish;
2064     + }
2065     +
2066     + while(file->f_pos < 3) {
2067     + char *name;
2068     + int size, i_ino;
2069     +
2070     + if(file->f_pos == 0) {
2071     + name = ".";
2072     + size = 1;
2073     + i_ino = i->i_ino;
2074     + } else {
2075     + name = "..";
2076     + size = 2;
2077     + i_ino = SQUASHFS_I(i)->u.s2.parent_inode;
2078     + }
2079     + TRACE("Calling filldir(%x, %s, %d, %d, %d, %d)\n",
2080     + (unsigned int) dirent, name, size, (int)
2081     + file->f_pos, i_ino,
2082     + squashfs_filetype_table[1]);
2083     +
2084     + if (filldir(dirent, name, size,
2085     + file->f_pos, i_ino,
2086     + squashfs_filetype_table[1]) < 0) {
2087     + TRACE("Filldir returned less than 0\n");
2088     + goto finish;
2089     + }
2090     + file->f_pos += size;
2091     + }
2092     +
2093     + length = get_dir_index_using_offset(i->i_sb, &next_block, &next_offset,
2094     + SQUASHFS_I(i)->u.s2.directory_index_start,
2095     + SQUASHFS_I(i)->u.s2.directory_index_offset,
2096     + SQUASHFS_I(i)->u.s2.directory_index_count,
2097     + file->f_pos);
2098     +
2099     + while (length < i_size_read(i)) {
2100     + /* read directory header */
2101     + if (msblk->swap) {
2102     + struct squashfs_dir_header sdirh;
2103     +
2104     + if (!squashfs_get_cached_block(i->i_sb, (char *) &sdirh,
2105     + next_block, next_offset, sizeof(sdirh),
2106     + &next_block, &next_offset))
2107     + goto failed_read;
2108     +
2109     + length += sizeof(sdirh);
2110     + SQUASHFS_SWAP_DIR_HEADER(&dirh, &sdirh);
2111     + } else {
2112     + if (!squashfs_get_cached_block(i->i_sb, (char *) &dirh,
2113     + next_block, next_offset, sizeof(dirh),
2114     + &next_block, &next_offset))
2115     + goto failed_read;
2116     +
2117     + length += sizeof(dirh);
2118     + }
2119     +
2120     + dir_count = dirh.count + 1;
2121     + while (dir_count--) {
2122     + if (msblk->swap) {
2123     + struct squashfs_dir_entry sdire;
2124     + if (!squashfs_get_cached_block(i->i_sb, (char *)
2125     + &sdire, next_block, next_offset,
2126     + sizeof(sdire), &next_block,
2127     + &next_offset))
2128     + goto failed_read;
2129     +
2130     + length += sizeof(sdire);
2131     + SQUASHFS_SWAP_DIR_ENTRY(dire, &sdire);
2132     + } else {
2133     + if (!squashfs_get_cached_block(i->i_sb, (char *)
2134     + dire, next_block, next_offset,
2135     + sizeof(*dire), &next_block,
2136     + &next_offset))
2137     + goto failed_read;
2138     +
2139     + length += sizeof(*dire);
2140     + }
2141     +
2142     + if (!squashfs_get_cached_block(i->i_sb, dire->name,
2143     + next_block, next_offset,
2144     + dire->size + 1, &next_block,
2145     + &next_offset))
2146     + goto failed_read;
2147     +
2148     + length += dire->size + 1;
2149     +
2150     + if (file->f_pos >= length)
2151     + continue;
2152     +
2153     + dire->name[dire->size + 1] = '\0';
2154     +
2155     + TRACE("Calling filldir(%x, %s, %d, %d, %x:%x, %d, %d)\n",
2156     + (unsigned int) dirent, dire->name,
2157     + dire->size + 1, (int) file->f_pos,
2158     + dirh.start_block, dire->offset,
2159     + dirh.inode_number + dire->inode_number,
2160     + squashfs_filetype_table[dire->type]);
2161     +
2162     + if (filldir(dirent, dire->name, dire->size + 1,
2163     + file->f_pos,
2164     + dirh.inode_number + dire->inode_number,
2165     + squashfs_filetype_table[dire->type])
2166     + < 0) {
2167     + TRACE("Filldir returned less than 0\n");
2168     + goto finish;
2169     + }
2170     + file->f_pos = length;
2171     + }
2172     + }
2173     +
2174     +finish:
2175     + kfree(dire);
2176     + return 0;
2177     +
2178     +failed_read:
2179     + ERROR("Unable to read directory block [%llx:%x]\n", next_block,
2180     + next_offset);
2181     + kfree(dire);
2182     + return 0;
2183     +}
2184     +
2185     +
2186     +static struct dentry *squashfs_lookup(struct inode *i, struct dentry *dentry,
2187     + struct nameidata *nd)
2188     +{
2189     + const unsigned char *name = dentry->d_name.name;
2190     + int len = dentry->d_name.len;
2191     + struct inode *inode = NULL;
2192     + struct squashfs_sb_info *msblk = i->i_sb->s_fs_info;
2193     + struct squashfs_super_block *sblk = &msblk->sblk;
2194     + long long next_block = SQUASHFS_I(i)->start_block +
2195     + sblk->directory_table_start;
2196     + int next_offset = SQUASHFS_I(i)->offset, length = 0,
2197     + dir_count;
2198     + struct squashfs_dir_header dirh;
2199     + struct squashfs_dir_entry *dire;
2200     +
2201     + TRACE("Entered squashfs_lookup [%llx:%x]\n", next_block, next_offset);
2202     +
2203     + if (!(dire = kmalloc(sizeof(struct squashfs_dir_entry) +
2204     + SQUASHFS_NAME_LEN + 1, GFP_KERNEL))) {
2205     + ERROR("Failed to allocate squashfs_dir_entry\n");
2206     + goto exit_lookup;
2207     + }
2208     +
2209     + if (len > SQUASHFS_NAME_LEN)
2210     + goto exit_lookup;
2211     +
2212     + length = get_dir_index_using_name(i->i_sb, &next_block, &next_offset,
2213     + SQUASHFS_I(i)->u.s2.directory_index_start,
2214     + SQUASHFS_I(i)->u.s2.directory_index_offset,
2215     + SQUASHFS_I(i)->u.s2.directory_index_count, name,
2216     + len);
2217     +
2218     + while (length < i_size_read(i)) {
2219     + /* read directory header */
2220     + if (msblk->swap) {
2221     + struct squashfs_dir_header sdirh;
2222     + if (!squashfs_get_cached_block(i->i_sb, (char *) &sdirh,
2223     + next_block, next_offset, sizeof(sdirh),
2224     + &next_block, &next_offset))
2225     + goto failed_read;
2226     +
2227     + length += sizeof(sdirh);
2228     + SQUASHFS_SWAP_DIR_HEADER(&dirh, &sdirh);
2229     + } else {
2230     + if (!squashfs_get_cached_block(i->i_sb, (char *) &dirh,
2231     + next_block, next_offset, sizeof(dirh),
2232     + &next_block, &next_offset))
2233     + goto failed_read;
2234     +
2235     + length += sizeof(dirh);
2236     + }
2237     +
2238     + dir_count = dirh.count + 1;
2239     + while (dir_count--) {
2240     + if (msblk->swap) {
2241     + struct squashfs_dir_entry sdire;
2242     + if (!squashfs_get_cached_block(i->i_sb, (char *)
2243     + &sdire, next_block,next_offset,
2244     + sizeof(sdire), &next_block,
2245     + &next_offset))
2246     + goto failed_read;
2247     +
2248     + length += sizeof(sdire);
2249     + SQUASHFS_SWAP_DIR_ENTRY(dire, &sdire);
2250     + } else {
2251     + if (!squashfs_get_cached_block(i->i_sb, (char *)
2252     + dire, next_block,next_offset,
2253     + sizeof(*dire), &next_block,
2254     + &next_offset))
2255     + goto failed_read;
2256     +
2257     + length += sizeof(*dire);
2258     + }
2259     +
2260     + if (!squashfs_get_cached_block(i->i_sb, dire->name,
2261     + next_block, next_offset, dire->size + 1,
2262     + &next_block, &next_offset))
2263     + goto failed_read;
2264     +
2265     + length += dire->size + 1;
2266     +
2267     + if (name[0] < dire->name[0])
2268     + goto exit_lookup;
2269     +
2270     + if ((len == dire->size + 1) && !strncmp(name, dire->name, len)) {
2271     + squashfs_inode_t ino = SQUASHFS_MKINODE(dirh.start_block,
2272     + dire->offset);
2273     +
2274     + TRACE("calling squashfs_iget for directory "
2275     + "entry %s, inode %x:%x, %d\n", name,
2276     + dirh.start_block, dire->offset,
2277     + dirh.inode_number + dire->inode_number);
2278     +
2279     + inode = squashfs_iget(i->i_sb, ino, dirh.inode_number + dire->inode_number);
2280     +
2281     + goto exit_lookup;
2282     + }
2283     + }
2284     + }
2285     +
2286     +exit_lookup:
2287     + kfree(dire);
2288     + if (inode)
2289     + return d_splice_alias(inode, dentry);
2290     + d_add(dentry, inode);
2291     + return ERR_PTR(0);
2292     +
2293     +failed_read:
2294     + ERROR("Unable to read directory block [%llx:%x]\n", next_block,
2295     + next_offset);
2296     + goto exit_lookup;
2297     +}
2298     +
2299     +
2300     +static int squashfs_remount(struct super_block *s, int *flags, char *data)
2301     +{
2302     + *flags |= MS_RDONLY;
2303     + return 0;
2304     +}
2305     +
2306     +
2307     +static void squashfs_put_super(struct super_block *s)
2308     +{
2309     + int i;
2310     +
2311     + if (s->s_fs_info) {
2312     + struct squashfs_sb_info *sbi = s->s_fs_info;
2313     + if (sbi->block_cache)
2314     + for (i = 0; i < SQUASHFS_CACHED_BLKS; i++)
2315     + if (sbi->block_cache[i].block !=
2316     + SQUASHFS_INVALID_BLK)
2317     + kfree(sbi->block_cache[i].data);
2318     + if (sbi->fragment)
2319     + for (i = 0; i < SQUASHFS_CACHED_FRAGMENTS; i++)
2320     + SQUASHFS_FREE(sbi->fragment[i].data);
2321     + kfree(sbi->fragment);
2322     + kfree(sbi->block_cache);
2323     + kfree(sbi->read_page);
2324     + kfree(sbi->uid);
2325     + kfree(sbi->fragment_index);
2326     + kfree(sbi->fragment_index_2);
2327     + kfree(sbi->meta_index);
2328     + vfree(sbi->stream.workspace);
2329     + kfree(s->s_fs_info);
2330     + s->s_fs_info = NULL;
2331     + }
2332     +}
2333     +
2334     +
2335     +static int squashfs_get_sb(struct file_system_type *fs_type, int flags,
2336     + const char *dev_name, void *data,
2337     + struct vfsmount *mnt)
2338     +{
2339     + return get_sb_bdev(fs_type, flags, dev_name, data, squashfs_fill_super,
2340     + mnt);
2341     +}
2342     +
2343     +
2344     +static int __init init_squashfs_fs(void)
2345     +{
2346     + int err = init_inodecache();
2347     + if (err)
2348     + goto out;
2349     +
2350     + printk(KERN_INFO "squashfs: version 3.2-r2 (2007/01/15) "
2351     + "Phillip Lougher\n");
2352     +
2353     + if ((err = register_filesystem(&squashfs_fs_type)))
2354     + destroy_inodecache();
2355     +
2356     +out:
2357     + return err;
2358     +}
2359     +
2360     +
2361     +static void __exit exit_squashfs_fs(void)
2362     +{
2363     + unregister_filesystem(&squashfs_fs_type);
2364     + destroy_inodecache();
2365     +}
2366     +
2367     +
2368     +static struct kmem_cache * squashfs_inode_cachep;
2369     +
2370     +
2371     +static struct inode *squashfs_alloc_inode(struct super_block *sb)
2372     +{
2373     + struct squashfs_inode_info *ei;
2374     + ei = kmem_cache_alloc(squashfs_inode_cachep, GFP_KERNEL);
2375     + if (!ei)
2376     + return NULL;
2377     + return &ei->vfs_inode;
2378     +}
2379     +
2380     +
2381     +static void squashfs_destroy_inode(struct inode *inode)
2382     +{
2383     + kmem_cache_free(squashfs_inode_cachep, SQUASHFS_I(inode));
2384     +}
2385     +
2386     +
2387     +static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flags)
2388     +{
2389     + struct squashfs_inode_info *ei = foo;
2390     +
2391     + if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
2392     + SLAB_CTOR_CONSTRUCTOR)
2393     + inode_init_once(&ei->vfs_inode);
2394     +}
2395     +
2396     +
2397     +static int __init init_inodecache(void)
2398     +{
2399     + squashfs_inode_cachep = kmem_cache_create("squashfs_inode_cache",
2400     + sizeof(struct squashfs_inode_info),
2401     + 0, SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT,
2402     + init_once, NULL);
2403     + if (squashfs_inode_cachep == NULL)
2404     + return -ENOMEM;
2405     + return 0;
2406     +}
2407     +
2408     +
2409     +static void destroy_inodecache(void)
2410     +{
2411     + kmem_cache_destroy(squashfs_inode_cachep);
2412     +}
2413     +
2414     +
2415     +module_init(init_squashfs_fs);
2416     +module_exit(exit_squashfs_fs);
2417     +MODULE_DESCRIPTION("squashfs 3.2-r2, a compressed read-only filesystem");
2418     +MODULE_AUTHOR("Phillip Lougher <phillip@lougher.org.uk>");
2419     +MODULE_LICENSE("GPL");
2420     diff -x .gitignore -Nurp linux-2.6.20/fs/squashfs/Makefile linux-2.6.20-squashfs3.2-r2/fs/squashfs/Makefile
2421     --- linux-2.6.20/fs/squashfs/Makefile 1970-01-01 01:00:00.000000000 +0100
2422     +++ linux-2.6.20-squashfs3.2-r2/fs/squashfs/Makefile 2007-01-12 00:06:09.000000000 +0000
2423     @@ -0,0 +1,7 @@
2424     +#
2425     +# Makefile for the linux squashfs routines.
2426     +#
2427     +
2428     +obj-$(CONFIG_SQUASHFS) += squashfs.o
2429     +squashfs-y += inode.o
2430     +squashfs-y += squashfs2_0.o
2431     diff -x .gitignore -Nurp linux-2.6.20/fs/squashfs/squashfs2_0.c linux-2.6.20-squashfs3.2-r2/fs/squashfs/squashfs2_0.c
2432     --- linux-2.6.20/fs/squashfs/squashfs2_0.c 1970-01-01 01:00:00.000000000 +0100
2433     +++ linux-2.6.20-squashfs3.2-r2/fs/squashfs/squashfs2_0.c 2007-01-12 02:27:20.000000000 +0000
2434     @@ -0,0 +1,742 @@
2435     +/*
2436     + * Squashfs - a compressed read only filesystem for Linux
2437     + *
2438     + * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007
2439     + * Phillip Lougher <phillip@lougher.org.uk>
2440     + *
2441     + * This program is free software; you can redistribute it and/or
2442     + * modify it under the terms of the GNU General Public License
2443     + * as published by the Free Software Foundation; either version 2,
2444     + * or (at your option) any later version.
2445     + *
2446     + * This program is distributed in the hope that it will be useful,
2447     + * but WITHOUT ANY WARRANTY; without even the implied warranty of
2448     + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2449     + * GNU General Public License for more details.
2450     + *
2451     + * You should have received a copy of the GNU General Public License
2452     + * along with this program; if not, write to the Free Software
2453     + * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
2454     + *
2455     + * squashfs2_0.c
2456     + */
2457     +
2458     +#include <linux/squashfs_fs.h>
2459     +#include <linux/module.h>
2460     +#include <linux/zlib.h>
2461     +#include <linux/fs.h>
2462     +#include <linux/squashfs_fs_sb.h>
2463     +#include <linux/squashfs_fs_i.h>
2464     +
2465     +#include "squashfs.h"
2466     +static int squashfs_readdir_2(struct file *file, void *dirent, filldir_t filldir);
2467     +static struct dentry *squashfs_lookup_2(struct inode *, struct dentry *,
2468     + struct nameidata *);
2469     +
2470     +static struct file_operations squashfs_dir_ops_2 = {
2471     + .read = generic_read_dir,
2472     + .readdir = squashfs_readdir_2
2473     +};
2474     +
2475     +static struct inode_operations squashfs_dir_inode_ops_2 = {
2476     + .lookup = squashfs_lookup_2
2477     +};
2478     +
2479     +static unsigned char squashfs_filetype_table[] = {
2480     + DT_UNKNOWN, DT_DIR, DT_REG, DT_LNK, DT_BLK, DT_CHR, DT_FIFO, DT_SOCK
2481     +};
2482     +
2483     +static int read_fragment_index_table_2(struct super_block *s)
2484     +{
2485     + struct squashfs_sb_info *msblk = s->s_fs_info;
2486     + struct squashfs_super_block *sblk = &msblk->sblk;
2487     +
2488     + if (!(msblk->fragment_index_2 = kmalloc(SQUASHFS_FRAGMENT_INDEX_BYTES_2
2489     + (sblk->fragments), GFP_KERNEL))) {
2490     + ERROR("Failed to allocate uid/gid table\n");
2491     + return 0;
2492     + }
2493     +
2494     + if (SQUASHFS_FRAGMENT_INDEX_BYTES_2(sblk->fragments) &&
2495     + !squashfs_read_data(s, (char *)
2496     + msblk->fragment_index_2,
2497     + sblk->fragment_table_start,
2498     + SQUASHFS_FRAGMENT_INDEX_BYTES_2
2499     + (sblk->fragments) |
2500     + SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, SQUASHFS_FRAGMENT_INDEX_BYTES_2(sblk->fragments))) {
2501     + ERROR("unable to read fragment index table\n");
2502     + return 0;
2503     + }
2504     +
2505     + if (msblk->swap) {
2506     + int i;
2507     + unsigned int fragment;
2508     +
2509     + for (i = 0; i < SQUASHFS_FRAGMENT_INDEXES_2(sblk->fragments);
2510     + i++) {
2511     + SQUASHFS_SWAP_FRAGMENT_INDEXES_2((&fragment),
2512     + &msblk->fragment_index_2[i], 1);
2513     + msblk->fragment_index_2[i] = fragment;
2514     + }
2515     + }
2516     +
2517     + return 1;
2518     +}
2519     +
2520     +
2521     +static int get_fragment_location_2(struct super_block *s, unsigned int fragment,
2522     + long long *fragment_start_block,
2523     + unsigned int *fragment_size)
2524     +{
2525     + struct squashfs_sb_info *msblk = s->s_fs_info;
2526     + long long start_block =
2527     + msblk->fragment_index_2[SQUASHFS_FRAGMENT_INDEX_2(fragment)];
2528     + int offset = SQUASHFS_FRAGMENT_INDEX_OFFSET_2(fragment);
2529     + struct squashfs_fragment_entry_2 fragment_entry;
2530     +
2531     + if (msblk->swap) {
2532     + struct squashfs_fragment_entry_2 sfragment_entry;
2533     +
2534     + if (!squashfs_get_cached_block(s, (char *) &sfragment_entry,
2535     + start_block, offset,
2536     + sizeof(sfragment_entry), &start_block,
2537     + &offset))
2538     + goto out;
2539     + SQUASHFS_SWAP_FRAGMENT_ENTRY_2(&fragment_entry, &sfragment_entry);
2540     + } else
2541     + if (!squashfs_get_cached_block(s, (char *) &fragment_entry,
2542     + start_block, offset,
2543     + sizeof(fragment_entry), &start_block,
2544     + &offset))
2545     + goto out;
2546     +
2547     + *fragment_start_block = fragment_entry.start_block;
2548     + *fragment_size = fragment_entry.size;
2549     +
2550     + return 1;
2551     +
2552     +out:
2553     + return 0;
2554     +}
2555     +
2556     +
2557     +static void squashfs_new_inode(struct squashfs_sb_info *msblk, struct inode *i,
2558     + struct squashfs_base_inode_header_2 *inodeb, unsigned int ino)
2559     +{
2560     + struct squashfs_super_block *sblk = &msblk->sblk;
2561     +
2562     + i->i_ino = ino;
2563     + i->i_mtime.tv_sec = sblk->mkfs_time;
2564     + i->i_atime.tv_sec = sblk->mkfs_time;
2565     + i->i_ctime.tv_sec = sblk->mkfs_time;
2566     + i->i_uid = msblk->uid[inodeb->uid];
2567     + i->i_mode = inodeb->mode;
2568     + i->i_nlink = 1;
2569     + i->i_size = 0;
2570     + if (inodeb->guid == SQUASHFS_GUIDS)
2571     + i->i_gid = i->i_uid;
2572     + else
2573     + i->i_gid = msblk->guid[inodeb->guid];
2574     +}
2575     +
2576     +
2577     +static int squashfs_read_inode_2(struct inode *i, squashfs_inode_t inode)
2578     +{
2579     + struct super_block *s = i->i_sb;
2580     + struct squashfs_sb_info *msblk = s->s_fs_info;
2581     + struct squashfs_super_block *sblk = &msblk->sblk;
2582     + unsigned int block = SQUASHFS_INODE_BLK(inode) +
2583     + sblk->inode_table_start;
2584     + unsigned int offset = SQUASHFS_INODE_OFFSET(inode);
2585     + unsigned int ino = i->i_ino;
2586     + long long next_block;
2587     + unsigned int next_offset;
2588     + union squashfs_inode_header_2 id, sid;
2589     + struct squashfs_base_inode_header_2 *inodeb = &id.base,
2590     + *sinodeb = &sid.base;
2591     +
2592     + TRACE("Entered squashfs_iget\n");
2593     +
2594     + if (msblk->swap) {
2595     + if (!squashfs_get_cached_block(s, (char *) sinodeb, block,
2596     + offset, sizeof(*sinodeb), &next_block,
2597     + &next_offset))
2598     + goto failed_read;
2599     + SQUASHFS_SWAP_BASE_INODE_HEADER_2(inodeb, sinodeb,
2600     + sizeof(*sinodeb));
2601     + } else
2602     + if (!squashfs_get_cached_block(s, (char *) inodeb, block,
2603     + offset, sizeof(*inodeb), &next_block,
2604     + &next_offset))
2605     + goto failed_read;
2606     +
2607     + squashfs_new_inode(msblk, i, inodeb, ino);
2608     +
2609     + switch(inodeb->inode_type) {
2610     + case SQUASHFS_FILE_TYPE: {
2611     + struct squashfs_reg_inode_header_2 *inodep = &id.reg;
2612     + struct squashfs_reg_inode_header_2 *sinodep = &sid.reg;
2613     + long long frag_blk;
2614     + unsigned int frag_size = 0;
2615     +
2616     + if (msblk->swap) {
2617     + if (!squashfs_get_cached_block(s, (char *)
2618     + sinodep, block, offset,
2619     + sizeof(*sinodep), &next_block,
2620     + &next_offset))
2621     + goto failed_read;
2622     + SQUASHFS_SWAP_REG_INODE_HEADER_2(inodep, sinodep);
2623     + } else
2624     + if (!squashfs_get_cached_block(s, (char *)
2625     + inodep, block, offset,
2626     + sizeof(*inodep), &next_block,
2627     + &next_offset))
2628     + goto failed_read;
2629     +
2630     + frag_blk = SQUASHFS_INVALID_BLK;
2631     + if (inodep->fragment != SQUASHFS_INVALID_FRAG &&
2632     + !get_fragment_location_2(s,
2633     + inodep->fragment, &frag_blk, &frag_size))
2634     + goto failed_read;
2635     +
2636     + i->i_size = inodep->file_size;
2637     + i->i_fop = &generic_ro_fops;
2638     + i->i_mode |= S_IFREG;
2639     + i->i_mtime.tv_sec = inodep->mtime;
2640     + i->i_atime.tv_sec = inodep->mtime;
2641     + i->i_ctime.tv_sec = inodep->mtime;
2642     + i->i_blocks = ((i->i_size - 1) >> 9) + 1;
2643     + SQUASHFS_I(i)->u.s1.fragment_start_block = frag_blk;
2644     + SQUASHFS_I(i)->u.s1.fragment_size = frag_size;
2645     + SQUASHFS_I(i)->u.s1.fragment_offset = inodep->offset;
2646     + SQUASHFS_I(i)->start_block = inodep->start_block;
2647     + SQUASHFS_I(i)->u.s1.block_list_start = next_block;
2648     + SQUASHFS_I(i)->offset = next_offset;
2649     + if (sblk->block_size > 4096)
2650     + i->i_data.a_ops = &squashfs_aops;
2651     + else
2652     + i->i_data.a_ops = &squashfs_aops_4K;
2653     +
2654     + TRACE("File inode %x:%x, start_block %x, "
2655     + "block_list_start %llx, offset %x\n",
2656     + SQUASHFS_INODE_BLK(inode), offset,
2657     + inodep->start_block, next_block,
2658     + next_offset);
2659     + break;
2660     + }
2661     + case SQUASHFS_DIR_TYPE: {
2662     + struct squashfs_dir_inode_header_2 *inodep = &id.dir;
2663     + struct squashfs_dir_inode_header_2 *sinodep = &sid.dir;
2664     +
2665     + if (msblk->swap) {
2666     + if (!squashfs_get_cached_block(s, (char *)
2667     + sinodep, block, offset,
2668     + sizeof(*sinodep), &next_block,
2669     + &next_offset))
2670     + goto failed_read;
2671     + SQUASHFS_SWAP_DIR_INODE_HEADER_2(inodep, sinodep);
2672     + } else
2673     + if (!squashfs_get_cached_block(s, (char *)
2674     + inodep, block, offset,
2675     + sizeof(*inodep), &next_block,
2676     + &next_offset))
2677     + goto failed_read;
2678     +
2679     + i->i_size = inodep->file_size;
2680     + i->i_op = &squashfs_dir_inode_ops_2;
2681     + i->i_fop = &squashfs_dir_ops_2;
2682     + i->i_mode |= S_IFDIR;
2683     + i->i_mtime.tv_sec = inodep->mtime;
2684     + i->i_atime.tv_sec = inodep->mtime;
2685     + i->i_ctime.tv_sec = inodep->mtime;
2686     + SQUASHFS_I(i)->start_block = inodep->start_block;
2687     + SQUASHFS_I(i)->offset = inodep->offset;
2688     + SQUASHFS_I(i)->u.s2.directory_index_count = 0;
2689     + SQUASHFS_I(i)->u.s2.parent_inode = 0;
2690     +
2691     + TRACE("Directory inode %x:%x, start_block %x, offset "
2692     + "%x\n", SQUASHFS_INODE_BLK(inode),
2693     + offset, inodep->start_block,
2694     + inodep->offset);
2695     + break;
2696     + }
2697     + case SQUASHFS_LDIR_TYPE: {
2698     + struct squashfs_ldir_inode_header_2 *inodep = &id.ldir;
2699     + struct squashfs_ldir_inode_header_2 *sinodep = &sid.ldir;
2700     +
2701     + if (msblk->swap) {
2702     + if (!squashfs_get_cached_block(s, (char *)
2703     + sinodep, block, offset,
2704     + sizeof(*sinodep), &next_block,
2705     + &next_offset))
2706     + goto failed_read;
2707     + SQUASHFS_SWAP_LDIR_INODE_HEADER_2(inodep,
2708     + sinodep);
2709     + } else
2710     + if (!squashfs_get_cached_block(s, (char *)
2711     + inodep, block, offset,
2712     + sizeof(*inodep), &next_block,
2713     + &next_offset))
2714     + goto failed_read;
2715     +
2716     + i->i_size = inodep->file_size;
2717     + i->i_op = &squashfs_dir_inode_ops_2;
2718     + i->i_fop = &squashfs_dir_ops_2;
2719     + i->i_mode |= S_IFDIR;
2720     + i->i_mtime.tv_sec = inodep->mtime;
2721     + i->i_atime.tv_sec = inodep->mtime;
2722     + i->i_ctime.tv_sec = inodep->mtime;
2723     + SQUASHFS_I(i)->start_block = inodep->start_block;
2724     + SQUASHFS_I(i)->offset = inodep->offset;
2725     + SQUASHFS_I(i)->u.s2.directory_index_start = next_block;
2726     + SQUASHFS_I(i)->u.s2.directory_index_offset =
2727     + next_offset;
2728     + SQUASHFS_I(i)->u.s2.directory_index_count =
2729     + inodep->i_count;
2730     + SQUASHFS_I(i)->u.s2.parent_inode = 0;
2731     +
2732     + TRACE("Long directory inode %x:%x, start_block %x, "
2733     + "offset %x\n",
2734     + SQUASHFS_INODE_BLK(inode), offset,
2735     + inodep->start_block, inodep->offset);
2736     + break;
2737     + }
2738     + case SQUASHFS_SYMLINK_TYPE: {
2739     + struct squashfs_symlink_inode_header_2 *inodep =
2740     + &id.symlink;
2741     + struct squashfs_symlink_inode_header_2 *sinodep =
2742     + &sid.symlink;
2743     +
2744     + if (msblk->swap) {
2745     + if (!squashfs_get_cached_block(s, (char *)
2746     + sinodep, block, offset,
2747     + sizeof(*sinodep), &next_block,
2748     + &next_offset))
2749     + goto failed_read;
2750     + SQUASHFS_SWAP_SYMLINK_INODE_HEADER_2(inodep,
2751     + sinodep);
2752     + } else
2753     + if (!squashfs_get_cached_block(s, (char *)
2754     + inodep, block, offset,
2755     + sizeof(*inodep), &next_block,
2756     + &next_offset))
2757     + goto failed_read;
2758     +
2759     + i->i_size = inodep->symlink_size;
2760     + i->i_op = &page_symlink_inode_operations;
2761     + i->i_data.a_ops = &squashfs_symlink_aops;
2762     + i->i_mode |= S_IFLNK;
2763     + SQUASHFS_I(i)->start_block = next_block;
2764     + SQUASHFS_I(i)->offset = next_offset;
2765     +
2766     + TRACE("Symbolic link inode %x:%x, start_block %llx, "
2767     + "offset %x\n",
2768     + SQUASHFS_INODE_BLK(inode), offset,
2769     + next_block, next_offset);
2770     + break;
2771     + }
2772     + case SQUASHFS_BLKDEV_TYPE:
2773     + case SQUASHFS_CHRDEV_TYPE: {
2774     + struct squashfs_dev_inode_header_2 *inodep = &id.dev;
2775     + struct squashfs_dev_inode_header_2 *sinodep = &sid.dev;
2776     +
2777     + if (msblk->swap) {
2778     + if (!squashfs_get_cached_block(s, (char *)
2779     + sinodep, block, offset,
2780     + sizeof(*sinodep), &next_block,
2781     + &next_offset))
2782     + goto failed_read;
2783     + SQUASHFS_SWAP_DEV_INODE_HEADER_2(inodep, sinodep);
2784     + } else
2785     + if (!squashfs_get_cached_block(s, (char *)
2786     + inodep, block, offset,
2787     + sizeof(*inodep), &next_block,
2788     + &next_offset))
2789     + goto failed_read;
2790     +
2791     + i->i_mode |= (inodeb->inode_type ==
2792     + SQUASHFS_CHRDEV_TYPE) ? S_IFCHR :
2793     + S_IFBLK;
2794     + init_special_inode(i, i->i_mode,
2795     + old_decode_dev(inodep->rdev));
2796     +
2797     + TRACE("Device inode %x:%x, rdev %x\n",
2798     + SQUASHFS_INODE_BLK(inode), offset,
2799     + inodep->rdev);
2800     + break;
2801     + }
2802     + case SQUASHFS_FIFO_TYPE:
2803     + case SQUASHFS_SOCKET_TYPE: {
2804     +
2805     + i->i_mode |= (inodeb->inode_type == SQUASHFS_FIFO_TYPE)
2806     + ? S_IFIFO : S_IFSOCK;
2807     + init_special_inode(i, i->i_mode, 0);
2808     + break;
2809     + }
2810     + default:
2811     + ERROR("Unknown inode type %d in squashfs_iget!\n",
2812     + inodeb->inode_type);
2813     + goto failed_read1;
2814     + }
2815     +
2816     + return 1;
2817     +
2818     +failed_read:
2819     + ERROR("Unable to read inode [%x:%x]\n", block, offset);
2820     +
2821     +failed_read1:
2822     + return 0;
2823     +}
2824     +
2825     +
2826     +static int get_dir_index_using_offset(struct super_block *s, long long
2827     + *next_block, unsigned int *next_offset,
2828     + long long index_start,
2829     + unsigned int index_offset, int i_count,
2830     + long long f_pos)
2831     +{
2832     + struct squashfs_sb_info *msblk = s->s_fs_info;
2833     + struct squashfs_super_block *sblk = &msblk->sblk;
2834     + int i, length = 0;
2835     + struct squashfs_dir_index_2 index;
2836     +
2837     + TRACE("Entered get_dir_index_using_offset, i_count %d, f_pos %d\n",
2838     + i_count, (unsigned int) f_pos);
2839     +
2840     + if (f_pos == 0)
2841     + goto finish;
2842     +
2843     + for (i = 0; i < i_count; i++) {
2844     + if (msblk->swap) {
2845     + struct squashfs_dir_index_2 sindex;
2846     + squashfs_get_cached_block(s, (char *) &sindex,
2847     + index_start, index_offset,
2848     + sizeof(sindex), &index_start,
2849     + &index_offset);
2850     + SQUASHFS_SWAP_DIR_INDEX_2(&index, &sindex);
2851     + } else
2852     + squashfs_get_cached_block(s, (char *) &index,
2853     + index_start, index_offset,
2854     + sizeof(index), &index_start,
2855     + &index_offset);
2856     +
2857     + if (index.index > f_pos)
2858     + break;
2859     +
2860     + squashfs_get_cached_block(s, NULL, index_start, index_offset,
2861     + index.size + 1, &index_start,
2862     + &index_offset);
2863     +
2864     + length = index.index;
2865     + *next_block = index.start_block + sblk->directory_table_start;
2866     + }
2867     +
2868     + *next_offset = (length + *next_offset) % SQUASHFS_METADATA_SIZE;
2869     +
2870     +finish:
2871     + return length;
2872     +}
2873     +
2874     +
2875     +static int get_dir_index_using_name(struct super_block *s, long long
2876     + *next_block, unsigned int *next_offset,
2877     + long long index_start,
2878     + unsigned int index_offset, int i_count,
2879     + const char *name, int size)
2880     +{
2881     + struct squashfs_sb_info *msblk = s->s_fs_info;
2882     + struct squashfs_super_block *sblk = &msblk->sblk;
2883     + int i, length = 0;
2884     + struct squashfs_dir_index_2 *index;
2885     + char *str;
2886     +
2887     + TRACE("Entered get_dir_index_using_name, i_count %d\n", i_count);
2888     +
2889     + if (!(str = kmalloc(sizeof(struct squashfs_dir_index) +
2890     + (SQUASHFS_NAME_LEN + 1) * 2, GFP_KERNEL))) {
2891     + ERROR("Failed to allocate squashfs_dir_index\n");
2892     + goto failure;
2893     + }
2894     +
2895     + index = (struct squashfs_dir_index_2 *) (str + SQUASHFS_NAME_LEN + 1);
2896     + strncpy(str, name, size);
2897     + str[size] = '\0';
2898     +
2899     + for (i = 0; i < i_count; i++) {
2900     + if (msblk->swap) {
2901     + struct squashfs_dir_index_2 sindex;
2902     + squashfs_get_cached_block(s, (char *) &sindex,
2903     + index_start, index_offset,
2904     + sizeof(sindex), &index_start,
2905     + &index_offset);
2906     + SQUASHFS_SWAP_DIR_INDEX_2(index, &sindex);
2907     + } else
2908     + squashfs_get_cached_block(s, (char *) index,
2909     + index_start, index_offset,
2910     + sizeof(struct squashfs_dir_index_2),
2911     + &index_start, &index_offset);
2912     +
2913     + squashfs_get_cached_block(s, index->name, index_start,
2914     + index_offset, index->size + 1,
2915     + &index_start, &index_offset);
2916     +
2917     + index->name[index->size + 1] = '\0';
2918     +
2919     + if (strcmp(index->name, str) > 0)
2920     + break;
2921     +
2922     + length = index->index;
2923     + *next_block = index->start_block + sblk->directory_table_start;
2924     + }
2925     +
2926     + *next_offset = (length + *next_offset) % SQUASHFS_METADATA_SIZE;
2927     + kfree(str);
2928     +failure:
2929     + return length;
2930     +}
2931     +
2932     +
2933     +static int squashfs_readdir_2(struct file *file, void *dirent, filldir_t filldir)
2934     +{
2935     + struct inode *i = file->f_dentry->d_inode;
2936     + struct squashfs_sb_info *msblk = i->i_sb->s_fs_info;
2937     + struct squashfs_super_block *sblk = &msblk->sblk;
2938     + long long next_block = SQUASHFS_I(i)->start_block +
2939     + sblk->directory_table_start;
2940     + int next_offset = SQUASHFS_I(i)->offset, length = 0,
2941     + dir_count;
2942     + struct squashfs_dir_header_2 dirh;
2943     + struct squashfs_dir_entry_2 *dire;
2944     +
2945     + TRACE("Entered squashfs_readdir_2 [%llx:%x]\n", next_block, next_offset);
2946     +
2947     + if (!(dire = kmalloc(sizeof(struct squashfs_dir_entry) +
2948     + SQUASHFS_NAME_LEN + 1, GFP_KERNEL))) {
2949     + ERROR("Failed to allocate squashfs_dir_entry\n");
2950     + goto finish;
2951     + }
2952     +
2953     + length = get_dir_index_using_offset(i->i_sb, &next_block, &next_offset,
2954     + SQUASHFS_I(i)->u.s2.directory_index_start,
2955     + SQUASHFS_I(i)->u.s2.directory_index_offset,
2956     + SQUASHFS_I(i)->u.s2.directory_index_count,
2957     + file->f_pos);
2958     +
2959     + while (length < i_size_read(i)) {
2960     + /* read directory header */
2961     + if (msblk->swap) {
2962     + struct squashfs_dir_header_2 sdirh;
2963     +
2964     + if (!squashfs_get_cached_block(i->i_sb, (char *) &sdirh,
2965     + next_block, next_offset, sizeof(sdirh),
2966     + &next_block, &next_offset))
2967     + goto failed_read;
2968     +
2969     + length += sizeof(sdirh);
2970     + SQUASHFS_SWAP_DIR_HEADER_2(&dirh, &sdirh);
2971     + } else {
2972     + if (!squashfs_get_cached_block(i->i_sb, (char *) &dirh,
2973     + next_block, next_offset, sizeof(dirh),
2974     + &next_block, &next_offset))
2975     + goto failed_read;
2976     +
2977     + length += sizeof(dirh);
2978     + }
2979     +
2980     + dir_count = dirh.count + 1;
2981     + while (dir_count--) {
2982     + if (msblk->swap) {
2983     + struct squashfs_dir_entry_2 sdire;
2984     + if (!squashfs_get_cached_block(i->i_sb, (char *)
2985     + &sdire, next_block, next_offset,
2986     + sizeof(sdire), &next_block,
2987     + &next_offset))
2988     + goto failed_read;
2989     +
2990     + length += sizeof(sdire);
2991     + SQUASHFS_SWAP_DIR_ENTRY_2(dire, &sdire);
2992     + } else {
2993     + if (!squashfs_get_cached_block(i->i_sb, (char *)
2994     + dire, next_block, next_offset,
2995     + sizeof(*dire), &next_block,
2996     + &next_offset))
2997     + goto failed_read;
2998     +
2999     + length += sizeof(*dire);
3000     + }
3001     +
3002     + if (!squashfs_get_cached_block(i->i_sb, dire->name,
3003     + next_block, next_offset,
3004     + dire->size + 1, &next_block,
3005     + &next_offset))
3006     + goto failed_read;
3007     +
3008     + length += dire->size + 1;
3009     +
3010     + if (file->f_pos >= length)
3011     + continue;
3012     +
3013     + dire->name[dire->size + 1] = '\0';
3014     +
3015     + TRACE("Calling filldir(%x, %s, %d, %d, %x:%x, %d)\n",
3016     + (unsigned int) dirent, dire->name,
3017     + dire->size + 1, (int) file->f_pos,
3018     + dirh.start_block, dire->offset,
3019     + squashfs_filetype_table[dire->type]);
3020     +
3021     + if (filldir(dirent, dire->name, dire->size + 1,
3022     + file->f_pos, SQUASHFS_MK_VFS_INODE(
3023     + dirh.start_block, dire->offset),
3024     + squashfs_filetype_table[dire->type])
3025     + < 0) {
3026     + TRACE("Filldir returned less than 0\n");
3027     + goto finish;
3028     + }
3029     + file->f_pos = length;
3030     + }
3031     + }
3032     +
3033     +finish:
3034     + kfree(dire);
3035     + return 0;
3036     +
3037     +failed_read:
3038     + ERROR("Unable to read directory block [%llx:%x]\n", next_block,
3039     + next_offset);
3040     + kfree(dire);
3041     + return 0;
3042     +}
3043     +
3044     +
3045     +static struct dentry *squashfs_lookup_2(struct inode *i, struct dentry *dentry,
3046     + struct nameidata *nd)
3047     +{
3048     + const unsigned char *name = dentry->d_name.name;
3049     + int len = dentry->d_name.len;
3050     + struct inode *inode = NULL;
3051     + struct squashfs_sb_info *msblk = i->i_sb->s_fs_info;
3052     + struct squashfs_super_block *sblk = &msblk->sblk;
3053     + long long next_block = SQUASHFS_I(i)->start_block +
3054     + sblk->directory_table_start;
3055     + int next_offset = SQUASHFS_I(i)->offset, length = 0,
3056     + dir_count;
3057     + struct squashfs_dir_header_2 dirh;
3058     + struct squashfs_dir_entry_2 *dire;
3059     + int sorted = sblk->s_major == 2 && sblk->s_minor >= 1;
3060     +
3061     + TRACE("Entered squashfs_lookup_2 [%llx:%x]\n", next_block, next_offset);
3062     +
3063     + if (!(dire = kmalloc(sizeof(struct squashfs_dir_entry) +
3064     + SQUASHFS_NAME_LEN + 1, GFP_KERNEL))) {
3065     + ERROR("Failed to allocate squashfs_dir_entry\n");
3066     + goto exit_loop;
3067     + }
3068     +
3069     + if (len > SQUASHFS_NAME_LEN)
3070     + goto exit_loop;
3071     +
3072     + length = get_dir_index_using_name(i->i_sb, &next_block, &next_offset,
3073     + SQUASHFS_I(i)->u.s2.directory_index_start,
3074     + SQUASHFS_I(i)->u.s2.directory_index_offset,
3075     + SQUASHFS_I(i)->u.s2.directory_index_count, name,
3076     + len);
3077     +
3078     + while (length < i_size_read(i)) {
3079     + /* read directory header */
3080     + if (msblk->swap) {
3081     + struct squashfs_dir_header_2 sdirh;
3082     + if (!squashfs_get_cached_block(i->i_sb, (char *) &sdirh,
3083     + next_block, next_offset, sizeof(sdirh),
3084     + &next_block, &next_offset))
3085     + goto failed_read;
3086     +
3087     + length += sizeof(sdirh);
3088     + SQUASHFS_SWAP_DIR_HEADER_2(&dirh, &sdirh);
3089     + } else {
3090     + if (!squashfs_get_cached_block(i->i_sb, (char *) &dirh,
3091     + next_block, next_offset, sizeof(dirh),
3092     + &next_block, &next_offset))
3093     + goto failed_read;
3094     +
3095     + length += sizeof(dirh);
3096     + }
3097     +
3098     + dir_count = dirh.count + 1;
3099     + while (dir_count--) {
3100     + if (msblk->swap) {
3101     + struct squashfs_dir_entry_2 sdire;
3102     + if (!squashfs_get_cached_block(i->i_sb, (char *)
3103     + &sdire, next_block,next_offset,
3104     + sizeof(sdire), &next_block,
3105     + &next_offset))
3106     + goto failed_read;
3107     +
3108     + length += sizeof(sdire);
3109     + SQUASHFS_SWAP_DIR_ENTRY_2(dire, &sdire);
3110     + } else {
3111     + if (!squashfs_get_cached_block(i->i_sb, (char *)
3112     + dire, next_block,next_offset,
3113     + sizeof(*dire), &next_block,
3114     + &next_offset))
3115     + goto failed_read;
3116     +
3117     + length += sizeof(*dire);
3118     + }
3119     +
3120     + if (!squashfs_get_cached_block(i->i_sb, dire->name,
3121     + next_block, next_offset, dire->size + 1,
3122     + &next_block, &next_offset))
3123     + goto failed_read;
3124     +
3125     + length += dire->size + 1;
3126     +
3127     + if (sorted && name[0] < dire->name[0])
3128     + goto exit_loop;
3129     +
3130     + if ((len == dire->size + 1) && !strncmp(name,
3131     + dire->name, len)) {
3132     + squashfs_inode_t ino =
3133     + SQUASHFS_MKINODE(dirh.start_block,
3134     + dire->offset);
3135     + unsigned int inode_number = SQUASHFS_MK_VFS_INODE(dirh.start_block,
3136     + dire->offset);
3137     +
3138     + TRACE("calling squashfs_iget for directory "
3139     + "entry %s, inode %x:%x, %lld\n", name,
3140     + dirh.start_block, dire->offset, ino);
3141     +
3142     + inode = squashfs_iget(i->i_sb, ino, inode_number);
3143     +
3144     + goto exit_loop;
3145     + }
3146     + }
3147     + }
3148     +
3149     +exit_loop:
3150     + kfree(dire);
3151     + d_add(dentry, inode);
3152     + return ERR_PTR(0);
3153     +
3154     +failed_read:
3155     + ERROR("Unable to read directory block [%llx:%x]\n", next_block,
3156     + next_offset);
3157     + goto exit_loop;
3158     +}
3159     +
3160     +
3161     +int squashfs_2_0_supported(struct squashfs_sb_info *msblk)
3162     +{
3163     + struct squashfs_super_block *sblk = &msblk->sblk;
3164     +
3165     + msblk->read_inode = squashfs_read_inode_2;
3166     + msblk->read_fragment_index_table = read_fragment_index_table_2;
3167     +
3168     + sblk->bytes_used = sblk->bytes_used_2;
3169     + sblk->uid_start = sblk->uid_start_2;
3170     + sblk->guid_start = sblk->guid_start_2;
3171     + sblk->inode_table_start = sblk->inode_table_start_2;
3172     + sblk->directory_table_start = sblk->directory_table_start_2;
3173     + sblk->fragment_table_start = sblk->fragment_table_start_2;
3174     +
3175     + return 1;
3176     +}
3177     diff -x .gitignore -Nurp linux-2.6.20/fs/squashfs/squashfs.h linux-2.6.20-squashfs3.2-r2/fs/squashfs/squashfs.h
3178     --- linux-2.6.20/fs/squashfs/squashfs.h 1970-01-01 01:00:00.000000000 +0100
3179     +++ linux-2.6.20-squashfs3.2-r2/fs/squashfs/squashfs.h 2007-01-12 01:42:11.000000000 +0000
3180     @@ -0,0 +1,87 @@
3181     +/*
3182     + * Squashfs - a compressed read only filesystem for Linux
3183     + *
3184     + * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007
3185     + * Phillip Lougher <phillip@lougher.org.uk>
3186     + *
3187     + * This program is free software; you can redistribute it and/or
3188     + * modify it under the terms of the GNU General Public License
3189     + * as published by the Free Software Foundation; either version 2,
3190     + * or (at your option) any later version.
3191     + *
3192     + * This program is distributed in the hope that it will be useful,
3193     + * but WITHOUT ANY WARRANTY; without even the implied warranty of
3194     + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3195     + * GNU General Public License for more details.
3196     + *
3197     + * You should have received a copy of the GNU General Public License
3198     + * along with this program; if not, write to the Free Software
3199     + * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
3200     + *
3201     + * squashfs.h
3202     + */
3203     +
3204     +#ifdef CONFIG_SQUASHFS_1_0_COMPATIBILITY
3205     +#undef CONFIG_SQUASHFS_1_0_COMPATIBILITY
3206     +#endif
3207     +
3208     +#ifdef SQUASHFS_TRACE
3209     +#define TRACE(s, args...) printk(KERN_NOTICE "SQUASHFS: "s, ## args)
3210     +#else
3211     +#define TRACE(s, args...) {}
3212     +#endif
3213     +
3214     +#define ERROR(s, args...) printk(KERN_ERR "SQUASHFS error: "s, ## args)
3215     +
3216     +#define SERROR(s, args...) do { \
3217     + if (!silent) \
3218     + printk(KERN_ERR "SQUASHFS error: "s, ## args);\
3219     + } while(0)
3220     +
3221     +#define WARNING(s, args...) printk(KERN_WARNING "SQUASHFS: "s, ## args)
3222     +
3223     +static inline struct squashfs_inode_info *SQUASHFS_I(struct inode *inode)
3224     +{
3225     + return list_entry(inode, struct squashfs_inode_info, vfs_inode);
3226     +}
3227     +
3228     +#if defined(CONFIG_SQUASHFS_1_0_COMPATIBILITY ) || defined(CONFIG_SQUASHFS_2_0_COMPATIBILITY)
3229     +#define SQSH_EXTERN
3230     +extern unsigned int squashfs_read_data(struct super_block *s, char *buffer,
3231     + long long index, unsigned int length,
3232     + long long *next_index, int srclength);
3233     +extern int squashfs_get_cached_block(struct super_block *s, char *buffer,
3234     + long long block, unsigned int offset,
3235     + int length, long long *next_block,
3236     + unsigned int *next_offset);
3237     +extern void release_cached_fragment(struct squashfs_sb_info *msblk, struct
3238     + squashfs_fragment_cache *fragment);
3239     +extern struct squashfs_fragment_cache *get_cached_fragment(struct super_block
3240     + *s, long long start_block,
3241     + int length);
3242     +extern struct inode *squashfs_iget(struct super_block *s, squashfs_inode_t inode, unsigned int inode_number);
3243     +extern const struct address_space_operations squashfs_symlink_aops;
3244     +extern const struct address_space_operations squashfs_aops;
3245     +extern const struct address_space_operations squashfs_aops_4K;
3246     +extern struct inode_operations squashfs_dir_inode_ops;
3247     +#else
3248     +#define SQSH_EXTERN static
3249     +#endif
3250     +
3251     +#ifdef CONFIG_SQUASHFS_1_0_COMPATIBILITY
3252     +extern int squashfs_1_0_supported(struct squashfs_sb_info *msblk);
3253     +#else
3254     +static inline int squashfs_1_0_supported(struct squashfs_sb_info *msblk)
3255     +{
3256     + return 0;
3257     +}
3258     +#endif
3259     +
3260     +#ifdef CONFIG_SQUASHFS_2_0_COMPATIBILITY
3261     +extern int squashfs_2_0_supported(struct squashfs_sb_info *msblk);
3262     +#else
3263     +static inline int squashfs_2_0_supported(struct squashfs_sb_info *msblk)
3264     +{
3265     + return 0;
3266     +}
3267     +#endif
3268     diff -x .gitignore -Nurp linux-2.6.20/include/linux/squashfs_fs.h linux-2.6.20-squashfs3.2-r2/include/linux/squashfs_fs.h
3269     --- linux-2.6.20/include/linux/squashfs_fs.h 1970-01-01 01:00:00.000000000 +0100
3270     +++ linux-2.6.20-squashfs3.2-r2/include/linux/squashfs_fs.h 2007-01-12 00:06:09.000000000 +0000
3271     @@ -0,0 +1,934 @@
3272     +#ifndef SQUASHFS_FS
3273     +#define SQUASHFS_FS
3274     +
3275     +/*
3276     + * Squashfs
3277     + *
3278     + * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007
3279     + * Phillip Lougher <phillip@lougher.org.uk>
3280     + *
3281     + * This program is free software; you can redistribute it and/or
3282     + * modify it under the terms of the GNU General Public License
3283     + * as published by the Free Software Foundation; either version 2,
3284     + * or (at your option) any later version.
3285     + *
3286     + * This program is distributed in the hope that it will be useful,
3287     + * but WITHOUT ANY WARRANTY; without even the implied warranty of
3288     + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3289     + * GNU General Public License for more details.
3290     + *
3291     + * You should have received a copy of the GNU General Public License
3292     + * along with this program; if not, write to the Free Software
3293     + * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
3294     + *
3295     + * squashfs_fs.h
3296     + */
3297     +
3298     +#ifndef CONFIG_SQUASHFS_2_0_COMPATIBILITY
3299     +#define CONFIG_SQUASHFS_2_0_COMPATIBILITY
3300     +#endif
3301     +
3302     +#ifdef CONFIG_SQUASHFS_VMALLOC
3303     +#define SQUASHFS_ALLOC(a) vmalloc(a)
3304     +#define SQUASHFS_FREE(a) vfree(a)
3305     +#else
3306     +#define SQUASHFS_ALLOC(a) kmalloc(a, GFP_KERNEL)
3307     +#define SQUASHFS_FREE(a) kfree(a)
3308     +#endif
3309     +#define SQUASHFS_CACHED_FRAGMENTS CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE
3310     +#define SQUASHFS_MAJOR 3
3311     +#define SQUASHFS_MINOR 0
3312     +#define SQUASHFS_MAGIC 0x73717368
3313     +#define SQUASHFS_MAGIC_SWAP 0x68737173
3314     +#define SQUASHFS_START 0
3315     +
3316     +/* size of metadata (inode and directory) blocks */
3317     +#define SQUASHFS_METADATA_SIZE 8192
3318     +#define SQUASHFS_METADATA_LOG 13
3319     +
3320     +/* default size of data blocks */
3321     +#define SQUASHFS_FILE_SIZE 65536
3322     +#define SQUASHFS_FILE_LOG 16
3323     +
3324     +#define SQUASHFS_FILE_MAX_SIZE 65536
3325     +
3326     +/* Max number of uids and gids */
3327     +#define SQUASHFS_UIDS 256
3328     +#define SQUASHFS_GUIDS 255
3329     +
3330     +/* Max length of filename (not 255) */
3331     +#define SQUASHFS_NAME_LEN 256
3332     +
3333     +#define SQUASHFS_INVALID ((long long) 0xffffffffffff)
3334     +#define SQUASHFS_INVALID_FRAG ((unsigned int) 0xffffffff)
3335     +#define SQUASHFS_INVALID_BLK ((long long) -1)
3336     +#define SQUASHFS_USED_BLK ((long long) -2)
3337     +
3338     +/* Filesystem flags */
3339     +#define SQUASHFS_NOI 0
3340     +#define SQUASHFS_NOD 1
3341     +#define SQUASHFS_CHECK 2
3342     +#define SQUASHFS_NOF 3
3343     +#define SQUASHFS_NO_FRAG 4
3344     +#define SQUASHFS_ALWAYS_FRAG 5
3345     +#define SQUASHFS_DUPLICATE 6
3346     +#define SQUASHFS_EXPORT 7
3347     +
3348     +#define SQUASHFS_BIT(flag, bit) ((flag >> bit) & 1)
3349     +
3350     +#define SQUASHFS_UNCOMPRESSED_INODES(flags) SQUASHFS_BIT(flags, \
3351     + SQUASHFS_NOI)
3352     +
3353     +#define SQUASHFS_UNCOMPRESSED_DATA(flags) SQUASHFS_BIT(flags, \
3354     + SQUASHFS_NOD)
3355     +
3356     +#define SQUASHFS_UNCOMPRESSED_FRAGMENTS(flags) SQUASHFS_BIT(flags, \
3357     + SQUASHFS_NOF)
3358     +
3359     +#define SQUASHFS_NO_FRAGMENTS(flags) SQUASHFS_BIT(flags, \
3360     + SQUASHFS_NO_FRAG)
3361     +
3362     +#define SQUASHFS_ALWAYS_FRAGMENTS(flags) SQUASHFS_BIT(flags, \
3363     + SQUASHFS_ALWAYS_FRAG)
3364     +
3365     +#define SQUASHFS_DUPLICATES(flags) SQUASHFS_BIT(flags, \
3366     + SQUASHFS_DUPLICATE)
3367     +
3368     +#define SQUASHFS_EXPORTABLE(flags) SQUASHFS_BIT(flags, \
3369     + SQUASHFS_EXPORT)
3370     +
3371     +#define SQUASHFS_CHECK_DATA(flags) SQUASHFS_BIT(flags, \
3372     + SQUASHFS_CHECK)
3373     +
3374     +#define SQUASHFS_MKFLAGS(noi, nod, check_data, nof, no_frag, always_frag, \
3375     + duplicate_checking, exortable) (noi | (nod << 1) | (check_data << 2) \
3376     + | (nof << 3) | (no_frag << 4) | (always_frag << 5) | \
3377     + (duplicate_checking << 6) | (exportable << 7))
3378     +
3379     +/* Max number of types and file types */
3380     +#define SQUASHFS_DIR_TYPE 1
3381     +#define SQUASHFS_FILE_TYPE 2
3382     +#define SQUASHFS_SYMLINK_TYPE 3
3383     +#define SQUASHFS_BLKDEV_TYPE 4
3384     +#define SQUASHFS_CHRDEV_TYPE 5
3385     +#define SQUASHFS_FIFO_TYPE 6
3386     +#define SQUASHFS_SOCKET_TYPE 7
3387     +#define SQUASHFS_LDIR_TYPE 8
3388     +#define SQUASHFS_LREG_TYPE 9
3389     +
3390     +/* 1.0 filesystem type definitions */
3391     +#define SQUASHFS_TYPES 5
3392     +#define SQUASHFS_IPC_TYPE 0
3393     +
3394     +/* Flag whether block is compressed or uncompressed, bit is set if block is
3395     + * uncompressed */
3396     +#define SQUASHFS_COMPRESSED_BIT (1 << 15)
3397     +
3398     +#define SQUASHFS_COMPRESSED_SIZE(B) (((B) & ~SQUASHFS_COMPRESSED_BIT) ? \
3399     + (B) & ~SQUASHFS_COMPRESSED_BIT : SQUASHFS_COMPRESSED_BIT)
3400     +
3401     +#define SQUASHFS_COMPRESSED(B) (!((B) & SQUASHFS_COMPRESSED_BIT))
3402     +
3403     +#define SQUASHFS_COMPRESSED_BIT_BLOCK (1 << 24)
3404     +
3405     +#define SQUASHFS_COMPRESSED_SIZE_BLOCK(B) (((B) & \
3406     + ~SQUASHFS_COMPRESSED_BIT_BLOCK) ? (B) & \
3407     + ~SQUASHFS_COMPRESSED_BIT_BLOCK : SQUASHFS_COMPRESSED_BIT_BLOCK)
3408     +
3409     +#define SQUASHFS_COMPRESSED_BLOCK(B) (!((B) & SQUASHFS_COMPRESSED_BIT_BLOCK))
3410     +
3411     +/*
3412     + * Inode number ops. Inodes consist of a compressed block number, and an
3413     + * uncompressed offset within that block
3414     + */
3415     +#define SQUASHFS_INODE_BLK(a) ((unsigned int) ((a) >> 16))
3416     +
3417     +#define SQUASHFS_INODE_OFFSET(a) ((unsigned int) ((a) & 0xffff))
3418     +
3419     +#define SQUASHFS_MKINODE(A, B) ((squashfs_inode_t)(((squashfs_inode_t) (A)\
3420     + << 16) + (B)))
3421     +
3422     +/* Compute 32 bit VFS inode number from squashfs inode number */
3423     +#define SQUASHFS_MK_VFS_INODE(a, b) ((unsigned int) (((a) << 8) + \
3424     + ((b) >> 2) + 1))
3425     +/* XXX */
3426     +
3427     +/* Translate between VFS mode and squashfs mode */
3428     +#define SQUASHFS_MODE(a) ((a) & 0xfff)
3429     +
3430     +/* fragment and fragment table defines */
3431     +#define SQUASHFS_FRAGMENT_BYTES(A) ((A) * sizeof(struct squashfs_fragment_entry))
3432     +
3433     +#define SQUASHFS_FRAGMENT_INDEX(A) (SQUASHFS_FRAGMENT_BYTES(A) / \
3434     + SQUASHFS_METADATA_SIZE)
3435     +
3436     +#define SQUASHFS_FRAGMENT_INDEX_OFFSET(A) (SQUASHFS_FRAGMENT_BYTES(A) % \
3437     + SQUASHFS_METADATA_SIZE)
3438     +
3439     +#define SQUASHFS_FRAGMENT_INDEXES(A) ((SQUASHFS_FRAGMENT_BYTES(A) + \
3440     + SQUASHFS_METADATA_SIZE - 1) / \
3441     + SQUASHFS_METADATA_SIZE)
3442     +
3443     +#define SQUASHFS_FRAGMENT_INDEX_BYTES(A) (SQUASHFS_FRAGMENT_INDEXES(A) *\
3444     + sizeof(long long))
3445     +
3446     +/* inode lookup table defines */
3447     +#define SQUASHFS_LOOKUP_BYTES(A) ((A) * sizeof(squashfs_inode_t))
3448     +
3449     +#define SQUASHFS_LOOKUP_BLOCK(A) (SQUASHFS_LOOKUP_BYTES(A) / \
3450     + SQUASHFS_METADATA_SIZE)
3451     +
3452     +#define SQUASHFS_LOOKUP_BLOCK_OFFSET(A) (SQUASHFS_LOOKUP_BYTES(A) % \
3453     + SQUASHFS_METADATA_SIZE)
3454     +
3455     +#define SQUASHFS_LOOKUP_BLOCKS(A) ((SQUASHFS_LOOKUP_BYTES(A) + \
3456     + SQUASHFS_METADATA_SIZE - 1) / \
3457     + SQUASHFS_METADATA_SIZE)
3458     +
3459     +#define SQUASHFS_LOOKUP_BLOCK_BYTES(A) (SQUASHFS_LOOKUP_BLOCKS(A) *\
3460     + sizeof(long long))
3461     +
3462     +/* cached data constants for filesystem */
3463     +#define SQUASHFS_CACHED_BLKS 8
3464     +
3465     +#define SQUASHFS_MAX_FILE_SIZE_LOG 64
3466     +
3467     +#define SQUASHFS_MAX_FILE_SIZE ((long long) 1 << \
3468     + (SQUASHFS_MAX_FILE_SIZE_LOG - 2))
3469     +
3470     +#define SQUASHFS_MARKER_BYTE 0xff
3471     +
3472     +/* meta index cache */
3473     +#define SQUASHFS_META_INDEXES (SQUASHFS_METADATA_SIZE / sizeof(unsigned int))
3474     +#define SQUASHFS_META_ENTRIES 31
3475     +#define SQUASHFS_META_NUMBER 8
3476     +#define SQUASHFS_SLOTS 4
3477     +
3478     +struct meta_entry {
3479     + long long data_block;
3480     + unsigned int index_block;
3481     + unsigned short offset;
3482     + unsigned short pad;
3483     +};
3484     +
3485     +struct meta_index {
3486     + unsigned int inode_number;
3487     + unsigned int offset;
3488     + unsigned short entries;
3489     + unsigned short skip;
3490     + unsigned short locked;
3491     + unsigned short pad;
3492     + struct meta_entry meta_entry[SQUASHFS_META_ENTRIES];
3493     +};
3494     +
3495     +
3496     +/*
3497     + * definitions for structures on disk
3498     + */
3499     +
3500     +typedef long long squashfs_block_t;
3501     +typedef long long squashfs_inode_t;
3502     +
3503     +struct squashfs_super_block {
3504     + unsigned int s_magic;
3505     + unsigned int inodes;
3506     + unsigned int bytes_used_2;
3507     + unsigned int uid_start_2;
3508     + unsigned int guid_start_2;
3509     + unsigned int inode_table_start_2;
3510     + unsigned int directory_table_start_2;
3511     + unsigned int s_major:16;
3512     + unsigned int s_minor:16;
3513     + unsigned int block_size_1:16;
3514     + unsigned int block_log:16;
3515     + unsigned int flags:8;
3516     + unsigned int no_uids:8;
3517     + unsigned int no_guids:8;
3518     + unsigned int mkfs_time /* time of filesystem creation */;
3519     + squashfs_inode_t root_inode;
3520     + unsigned int block_size;
3521     + unsigned int fragments;
3522     + unsigned int fragment_table_start_2;
3523     + long long bytes_used;
3524     + long long uid_start;
3525     + long long guid_start;
3526     + long long inode_table_start;
3527     + long long directory_table_start;
3528     + long long fragment_table_start;
3529     + long long lookup_table_start;
3530     +} __attribute__ ((packed));
3531     +
3532     +struct squashfs_dir_index {
3533     + unsigned int index;
3534     + unsigned int start_block;
3535     + unsigned char size;
3536     + unsigned char name[0];
3537     +} __attribute__ ((packed));
3538     +
3539     +#define SQUASHFS_BASE_INODE_HEADER \
3540     + unsigned int inode_type:4; \
3541     + unsigned int mode:12; \
3542     + unsigned int uid:8; \
3543     + unsigned int guid:8; \
3544     + unsigned int mtime; \
3545     + unsigned int inode_number;
3546     +
3547     +struct squashfs_base_inode_header {
3548     + SQUASHFS_BASE_INODE_HEADER;
3549     +} __attribute__ ((packed));
3550     +
3551     +struct squashfs_ipc_inode_header {
3552     + SQUASHFS_BASE_INODE_HEADER;
3553     + unsigned int nlink;
3554     +} __attribute__ ((packed));
3555     +
3556     +struct squashfs_dev_inode_header {
3557     + SQUASHFS_BASE_INODE_HEADER;
3558     + unsigned int nlink;
3559     + unsigned short rdev;
3560     +} __attribute__ ((packed));
3561     +
3562     +struct squashfs_symlink_inode_header {
3563     + SQUASHFS_BASE_INODE_HEADER;
3564     + unsigned int nlink;
3565     + unsigned short symlink_size;
3566     + char symlink[0];
3567     +} __attribute__ ((packed));
3568     +
3569     +struct squashfs_reg_inode_header {
3570     + SQUASHFS_BASE_INODE_HEADER;
3571     + squashfs_block_t start_block;
3572     + unsigned int fragment;
3573     + unsigned int offset;
3574     + unsigned int file_size;
3575     + unsigned short block_list[0];
3576     +} __attribute__ ((packed));
3577     +
3578     +struct squashfs_lreg_inode_header {
3579     + SQUASHFS_BASE_INODE_HEADER;
3580     + unsigned int nlink;
3581     + squashfs_block_t start_block;
3582     + unsigned int fragment;
3583     + unsigned int offset;
3584     + long long file_size;
3585     + unsigned short block_list[0];
3586     +} __attribute__ ((packed));
3587     +
3588     +struct squashfs_dir_inode_header {
3589     + SQUASHFS_BASE_INODE_HEADER;
3590     + unsigned int nlink;
3591     + unsigned int file_size:19;
3592     + unsigned int offset:13;
3593     + unsigned int start_block;
3594     + unsigned int parent_inode;
3595     +} __attribute__ ((packed));
3596     +
3597     +struct squashfs_ldir_inode_header {
3598     + SQUASHFS_BASE_INODE_HEADER;
3599     + unsigned int nlink;
3600     + unsigned int file_size:27;
3601     + unsigned int offset:13;
3602     + unsigned int start_block;
3603     + unsigned int i_count:16;
3604     + unsigned int parent_inode;
3605     + struct squashfs_dir_index index[0];
3606     +} __attribute__ ((packed));
3607     +
3608     +union squashfs_inode_header {
3609     + struct squashfs_base_inode_header base;
3610     + struct squashfs_dev_inode_header dev;
3611     + struct squashfs_symlink_inode_header symlink;
3612     + struct squashfs_reg_inode_header reg;
3613     + struct squashfs_lreg_inode_header lreg;
3614     + struct squashfs_dir_inode_header dir;
3615     + struct squashfs_ldir_inode_header ldir;
3616     + struct squashfs_ipc_inode_header ipc;
3617     +};
3618     +
3619     +struct squashfs_dir_entry {
3620     + unsigned int offset:13;
3621     + unsigned int type:3;
3622     + unsigned int size:8;
3623     + int inode_number:16;
3624     + char name[0];
3625     +} __attribute__ ((packed));
3626     +
3627     +struct squashfs_dir_header {
3628     + unsigned int count:8;
3629     + unsigned int start_block;
3630     + unsigned int inode_number;
3631     +} __attribute__ ((packed));
3632     +
3633     +struct squashfs_fragment_entry {
3634     + long long start_block;
3635     + unsigned int size;
3636     + unsigned int pending;
3637     +} __attribute__ ((packed));
3638     +
3639     +extern int squashfs_uncompress_block(void *d, int dstlen, void *s, int srclen);
3640     +extern int squashfs_uncompress_init(void);
3641     +extern int squashfs_uncompress_exit(void);
3642     +
3643     +/*
3644     + * macros to convert each packed bitfield structure from little endian to big
3645     + * endian and vice versa. These are needed when creating or using a filesystem
3646     + * on a machine with different byte ordering to the target architecture.
3647     + *
3648     + */
3649     +
3650     +#define SQUASHFS_SWAP_START \
3651     + int bits;\
3652     + int b_pos;\
3653     + unsigned long long val;\
3654     + unsigned char *s;\
3655     + unsigned char *d;
3656     +
3657     +#define SQUASHFS_SWAP_SUPER_BLOCK(s, d) {\
3658     + SQUASHFS_SWAP_START\
3659     + SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_super_block));\
3660     + SQUASHFS_SWAP((s)->s_magic, d, 0, 32);\
3661     + SQUASHFS_SWAP((s)->inodes, d, 32, 32);\
3662     + SQUASHFS_SWAP((s)->bytes_used_2, d, 64, 32);\
3663     + SQUASHFS_SWAP((s)->uid_start_2, d, 96, 32);\
3664     + SQUASHFS_SWAP((s)->guid_start_2, d, 128, 32);\
3665     + SQUASHFS_SWAP((s)->inode_table_start_2, d, 160, 32);\
3666     + SQUASHFS_SWAP((s)->directory_table_start_2, d, 192, 32);\
3667     + SQUASHFS_SWAP((s)->s_major, d, 224, 16);\
3668     + SQUASHFS_SWAP((s)->s_minor, d, 240, 16);\
3669     + SQUASHFS_SWAP((s)->block_size_1, d, 256, 16);\
3670     + SQUASHFS_SWAP((s)->block_log, d, 272, 16);\
3671     + SQUASHFS_SWAP((s)->flags, d, 288, 8);\
3672     + SQUASHFS_SWAP((s)->no_uids, d, 296, 8);\
3673     + SQUASHFS_SWAP((s)->no_guids, d, 304, 8);\
3674     + SQUASHFS_SWAP((s)->mkfs_time, d, 312, 32);\
3675     + SQUASHFS_SWAP((s)->root_inode, d, 344, 64);\
3676     + SQUASHFS_SWAP((s)->block_size, d, 408, 32);\
3677     + SQUASHFS_SWAP((s)->fragments, d, 440, 32);\
3678     + SQUASHFS_SWAP((s)->fragment_table_start_2, d, 472, 32);\
3679     + SQUASHFS_SWAP((s)->bytes_used, d, 504, 64);\
3680     + SQUASHFS_SWAP((s)->uid_start, d, 568, 64);\
3681     + SQUASHFS_SWAP((s)->guid_start, d, 632, 64);\
3682     + SQUASHFS_SWAP((s)->inode_table_start, d, 696, 64);\
3683     + SQUASHFS_SWAP((s)->directory_table_start, d, 760, 64);\
3684     + SQUASHFS_SWAP((s)->fragment_table_start, d, 824, 64);\
3685     + SQUASHFS_SWAP((s)->lookup_table_start, d, 888, 64);\
3686     +}
3687     +
3688     +#define SQUASHFS_SWAP_BASE_INODE_CORE(s, d, n)\
3689     + SQUASHFS_MEMSET(s, d, n);\
3690     + SQUASHFS_SWAP((s)->inode_type, d, 0, 4);\
3691     + SQUASHFS_SWAP((s)->mode, d, 4, 12);\
3692     + SQUASHFS_SWAP((s)->uid, d, 16, 8);\
3693     + SQUASHFS_SWAP((s)->guid, d, 24, 8);\
3694     + SQUASHFS_SWAP((s)->mtime, d, 32, 32);\
3695     + SQUASHFS_SWAP((s)->inode_number, d, 64, 32);
3696     +
3697     +#define SQUASHFS_SWAP_BASE_INODE_HEADER(s, d, n) {\
3698     + SQUASHFS_SWAP_START\
3699     + SQUASHFS_SWAP_BASE_INODE_CORE(s, d, n)\
3700     +}
3701     +
3702     +#define SQUASHFS_SWAP_IPC_INODE_HEADER(s, d) {\
3703     + SQUASHFS_SWAP_START\
3704     + SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \
3705     + sizeof(struct squashfs_ipc_inode_header))\
3706     + SQUASHFS_SWAP((s)->nlink, d, 96, 32);\
3707     +}
3708     +
3709     +#define SQUASHFS_SWAP_DEV_INODE_HEADER(s, d) {\
3710     + SQUASHFS_SWAP_START\
3711     + SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \
3712     + sizeof(struct squashfs_dev_inode_header)); \
3713     + SQUASHFS_SWAP((s)->nlink, d, 96, 32);\
3714     + SQUASHFS_SWAP((s)->rdev, d, 128, 16);\
3715     +}
3716     +
3717     +#define SQUASHFS_SWAP_SYMLINK_INODE_HEADER(s, d) {\
3718     + SQUASHFS_SWAP_START\
3719     + SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \
3720     + sizeof(struct squashfs_symlink_inode_header));\
3721     + SQUASHFS_SWAP((s)->nlink, d, 96, 32);\
3722     + SQUASHFS_SWAP((s)->symlink_size, d, 128, 16);\
3723     +}
3724     +
3725     +#define SQUASHFS_SWAP_REG_INODE_HEADER(s, d) {\
3726     + SQUASHFS_SWAP_START\
3727     + SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \
3728     + sizeof(struct squashfs_reg_inode_header));\
3729     + SQUASHFS_SWAP((s)->start_block, d, 96, 64);\
3730     + SQUASHFS_SWAP((s)->fragment, d, 160, 32);\
3731     + SQUASHFS_SWAP((s)->offset, d, 192, 32);\
3732     + SQUASHFS_SWAP((s)->file_size, d, 224, 32);\
3733     +}
3734     +
3735     +#define SQUASHFS_SWAP_LREG_INODE_HEADER(s, d) {\
3736     + SQUASHFS_SWAP_START\
3737     + SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \
3738     + sizeof(struct squashfs_lreg_inode_header));\
3739     + SQUASHFS_SWAP((s)->nlink, d, 96, 32);\
3740     + SQUASHFS_SWAP((s)->start_block, d, 128, 64);\
3741     + SQUASHFS_SWAP((s)->fragment, d, 192, 32);\
3742     + SQUASHFS_SWAP((s)->offset, d, 224, 32);\
3743     + SQUASHFS_SWAP((s)->file_size, d, 256, 64);\
3744     +}
3745     +
3746     +#define SQUASHFS_SWAP_DIR_INODE_HEADER(s, d) {\
3747     + SQUASHFS_SWAP_START\
3748     + SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \
3749     + sizeof(struct squashfs_dir_inode_header));\
3750     + SQUASHFS_SWAP((s)->nlink, d, 96, 32);\
3751     + SQUASHFS_SWAP((s)->file_size, d, 128, 19);\
3752     + SQUASHFS_SWAP((s)->offset, d, 147, 13);\
3753     + SQUASHFS_SWAP((s)->start_block, d, 160, 32);\
3754     + SQUASHFS_SWAP((s)->parent_inode, d, 192, 32);\
3755     +}
3756     +
3757     +#define SQUASHFS_SWAP_LDIR_INODE_HEADER(s, d) {\
3758     + SQUASHFS_SWAP_START\
3759     + SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \
3760     + sizeof(struct squashfs_ldir_inode_header));\
3761     + SQUASHFS_SWAP((s)->nlink, d, 96, 32);\
3762     + SQUASHFS_SWAP((s)->file_size, d, 128, 27);\
3763     + SQUASHFS_SWAP((s)->offset, d, 155, 13);\
3764     + SQUASHFS_SWAP((s)->start_block, d, 168, 32);\
3765     + SQUASHFS_SWAP((s)->i_count, d, 200, 16);\
3766     + SQUASHFS_SWAP((s)->parent_inode, d, 216, 32);\
3767     +}
3768     +
3769     +#define SQUASHFS_SWAP_DIR_INDEX(s, d) {\
3770     + SQUASHFS_SWAP_START\
3771     + SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_index));\
3772     + SQUASHFS_SWAP((s)->index, d, 0, 32);\
3773     + SQUASHFS_SWAP((s)->start_block, d, 32, 32);\
3774     + SQUASHFS_SWAP((s)->size, d, 64, 8);\
3775     +}
3776     +
3777     +#define SQUASHFS_SWAP_DIR_HEADER(s, d) {\
3778     + SQUASHFS_SWAP_START\
3779     + SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_header));\
3780     + SQUASHFS_SWAP((s)->count, d, 0, 8);\
3781     + SQUASHFS_SWAP((s)->start_block, d, 8, 32);\
3782     + SQUASHFS_SWAP((s)->inode_number, d, 40, 32);\
3783     +}
3784     +
3785     +#define SQUASHFS_SWAP_DIR_ENTRY(s, d) {\
3786     + SQUASHFS_SWAP_START\
3787     + SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_entry));\
3788     + SQUASHFS_SWAP((s)->offset, d, 0, 13);\
3789     + SQUASHFS_SWAP((s)->type, d, 13, 3);\
3790     + SQUASHFS_SWAP((s)->size, d, 16, 8);\
3791     + SQUASHFS_SWAP((s)->inode_number, d, 24, 16);\
3792     +}
3793     +
3794     +#define SQUASHFS_SWAP_FRAGMENT_ENTRY(s, d) {\
3795     + SQUASHFS_SWAP_START\
3796     + SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_fragment_entry));\
3797     + SQUASHFS_SWAP((s)->start_block, d, 0, 64);\
3798     + SQUASHFS_SWAP((s)->size, d, 64, 32);\
3799     +}
3800     +
3801     +#define SQUASHFS_SWAP_INODE_T(s, d) SQUASHFS_SWAP_LONG_LONGS(s, d, 1)
3802     +
3803     +#define SQUASHFS_SWAP_SHORTS(s, d, n) {\
3804     + int entry;\
3805     + int bit_position;\
3806     + SQUASHFS_SWAP_START\
3807     + SQUASHFS_MEMSET(s, d, n * 2);\
3808     + for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += \
3809     + 16)\
3810     + SQUASHFS_SWAP(s[entry], d, bit_position, 16);\
3811     +}
3812     +
3813     +#define SQUASHFS_SWAP_INTS(s, d, n) {\
3814     + int entry;\
3815     + int bit_position;\
3816     + SQUASHFS_SWAP_START\
3817     + SQUASHFS_MEMSET(s, d, n * 4);\
3818     + for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += \
3819     + 32)\
3820     + SQUASHFS_SWAP(s[entry], d, bit_position, 32);\
3821     +}
3822     +
3823     +#define SQUASHFS_SWAP_LONG_LONGS(s, d, n) {\
3824     + int entry;\
3825     + int bit_position;\
3826     + SQUASHFS_SWAP_START\
3827     + SQUASHFS_MEMSET(s, d, n * 8);\
3828     + for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += \
3829     + 64)\
3830     + SQUASHFS_SWAP(s[entry], d, bit_position, 64);\
3831     +}
3832     +
3833     +#define SQUASHFS_SWAP_DATA(s, d, n, bits) {\
3834     + int entry;\
3835     + int bit_position;\
3836     + SQUASHFS_SWAP_START\
3837     + SQUASHFS_MEMSET(s, d, n * bits / 8);\
3838     + for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += \
3839     + bits)\
3840     + SQUASHFS_SWAP(s[entry], d, bit_position, bits);\
3841     +}
3842     +
3843     +#define SQUASHFS_SWAP_FRAGMENT_INDEXES(s, d, n) SQUASHFS_SWAP_LONG_LONGS(s, d, n)
3844     +#define SQUASHFS_SWAP_LOOKUP_BLOCKS(s, d, n) SQUASHFS_SWAP_LONG_LONGS(s, d, n)
3845     +
3846     +#ifdef CONFIG_SQUASHFS_1_0_COMPATIBILITY
3847     +
3848     +struct squashfs_base_inode_header_1 {
3849     + unsigned int inode_type:4;
3850     + unsigned int mode:12; /* protection */
3851     + unsigned int uid:4; /* index into uid table */
3852     + unsigned int guid:4; /* index into guid table */
3853     +} __attribute__ ((packed));
3854     +
3855     +struct squashfs_ipc_inode_header_1 {
3856     + unsigned int inode_type:4;
3857     + unsigned int mode:12; /* protection */
3858     + unsigned int uid:4; /* index into uid table */
3859     + unsigned int guid:4; /* index into guid table */
3860     + unsigned int type:4;
3861     + unsigned int offset:4;
3862     +} __attribute__ ((packed));
3863     +
3864     +struct squashfs_dev_inode_header_1 {
3865     + unsigned int inode_type:4;
3866     + unsigned int mode:12; /* protection */
3867     + unsigned int uid:4; /* index into uid table */
3868     + unsigned int guid:4; /* index into guid table */
3869     + unsigned short rdev;
3870     +} __attribute__ ((packed));
3871     +
3872     +struct squashfs_symlink_inode_header_1 {
3873     + unsigned int inode_type:4;
3874     + unsigned int mode:12; /* protection */
3875     + unsigned int uid:4; /* index into uid table */
3876     + unsigned int guid:4; /* index into guid table */
3877     + unsigned short symlink_size;
3878     + char symlink[0];
3879     +} __attribute__ ((packed));
3880     +
3881     +struct squashfs_reg_inode_header_1 {
3882     + unsigned int inode_type:4;
3883     + unsigned int mode:12; /* protection */
3884     + unsigned int uid:4; /* index into uid table */
3885     + unsigned int guid:4; /* index into guid table */
3886     + unsigned int mtime;
3887     + unsigned int start_block;
3888     + unsigned int file_size:32;
3889     + unsigned short block_list[0];
3890     +} __attribute__ ((packed));
3891     +
3892     +struct squashfs_dir_inode_header_1 {
3893     + unsigned int inode_type:4;
3894     + unsigned int mode:12; /* protection */
3895     + unsigned int uid:4; /* index into uid table */
3896     + unsigned int guid:4; /* index into guid table */
3897     + unsigned int file_size:19;
3898     + unsigned int offset:13;
3899     + unsigned int mtime;
3900     + unsigned int start_block:24;
3901     +} __attribute__ ((packed));
3902     +
3903     +#define SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, n) \
3904     + SQUASHFS_MEMSET(s, d, n);\
3905     + SQUASHFS_SWAP((s)->inode_type, d, 0, 4);\
3906     + SQUASHFS_SWAP((s)->mode, d, 4, 12);\
3907     + SQUASHFS_SWAP((s)->uid, d, 16, 4);\
3908     + SQUASHFS_SWAP((s)->guid, d, 20, 4);
3909     +
3910     +#define SQUASHFS_SWAP_BASE_INODE_HEADER_1(s, d, n) {\
3911     + SQUASHFS_SWAP_START\
3912     + SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, n)\
3913     +}
3914     +
3915     +#define SQUASHFS_SWAP_IPC_INODE_HEADER_1(s, d) {\
3916     + SQUASHFS_SWAP_START\
3917     + SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \
3918     + sizeof(struct squashfs_ipc_inode_header_1));\
3919     + SQUASHFS_SWAP((s)->type, d, 24, 4);\
3920     + SQUASHFS_SWAP((s)->offset, d, 28, 4);\
3921     +}
3922     +
3923     +#define SQUASHFS_SWAP_DEV_INODE_HEADER_1(s, d) {\
3924     + SQUASHFS_SWAP_START\
3925     + SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \
3926     + sizeof(struct squashfs_dev_inode_header_1));\
3927     + SQUASHFS_SWAP((s)->rdev, d, 24, 16);\
3928     +}
3929     +
3930     +#define SQUASHFS_SWAP_SYMLINK_INODE_HEADER_1(s, d) {\
3931     + SQUASHFS_SWAP_START\
3932     + SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \
3933     + sizeof(struct squashfs_symlink_inode_header_1));\
3934     + SQUASHFS_SWAP((s)->symlink_size, d, 24, 16);\
3935     +}
3936     +
3937     +#define SQUASHFS_SWAP_REG_INODE_HEADER_1(s, d) {\
3938     + SQUASHFS_SWAP_START\
3939     + SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \
3940     + sizeof(struct squashfs_reg_inode_header_1));\
3941     + SQUASHFS_SWAP((s)->mtime, d, 24, 32);\
3942     + SQUASHFS_SWAP((s)->start_block, d, 56, 32);\
3943     + SQUASHFS_SWAP((s)->file_size, d, 88, 32);\
3944     +}
3945     +
3946     +#define SQUASHFS_SWAP_DIR_INODE_HEADER_1(s, d) {\
3947     + SQUASHFS_SWAP_START\
3948     + SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \
3949     + sizeof(struct squashfs_dir_inode_header_1));\
3950     + SQUASHFS_SWAP((s)->file_size, d, 24, 19);\
3951     + SQUASHFS_SWAP((s)->offset, d, 43, 13);\
3952     + SQUASHFS_SWAP((s)->mtime, d, 56, 32);\
3953     + SQUASHFS_SWAP((s)->start_block, d, 88, 24);\
3954     +}
3955     +
3956     +#endif
3957     +
3958     +#ifdef CONFIG_SQUASHFS_2_0_COMPATIBILITY
3959     +
3960     +struct squashfs_dir_index_2 {
3961     + unsigned int index:27;
3962     + unsigned int start_block:29;
3963     + unsigned char size;
3964     + unsigned char name[0];
3965     +} __attribute__ ((packed));
3966     +
3967     +struct squashfs_base_inode_header_2 {
3968     + unsigned int inode_type:4;
3969     + unsigned int mode:12; /* protection */
3970     + unsigned int uid:8; /* index into uid table */
3971     + unsigned int guid:8; /* index into guid table */
3972     +} __attribute__ ((packed));
3973     +
3974     +struct squashfs_ipc_inode_header_2 {
3975     + unsigned int inode_type:4;
3976     + unsigned int mode:12; /* protection */
3977     + unsigned int uid:8; /* index into uid table */
3978     + unsigned int guid:8; /* index into guid table */
3979     +} __attribute__ ((packed));
3980     +
3981     +struct squashfs_dev_inode_header_2 {
3982     + unsigned int inode_type:4;
3983     + unsigned int mode:12; /* protection */
3984     + unsigned int uid:8; /* index into uid table */
3985     + unsigned int guid:8; /* index into guid table */
3986     + unsigned short rdev;
3987     +} __attribute__ ((packed));
3988     +
3989     +struct squashfs_symlink_inode_header_2 {
3990     + unsigned int inode_type:4;
3991     + unsigned int mode:12; /* protection */
3992     + unsigned int uid:8; /* index into uid table */
3993     + unsigned int guid:8; /* index into guid table */
3994     + unsigned short symlink_size;
3995     + char symlink[0];
3996     +} __attribute__ ((packed));
3997     +
3998     +struct squashfs_reg_inode_header_2 {
3999     + unsigned int inode_type:4;
4000     + unsigned int mode:12; /* protection */
4001     + unsigned int uid:8; /* index into uid table */
4002     + unsigned int guid:8; /* index into guid table */
4003     + unsigned int mtime;
4004     + unsigned int start_block;
4005     + unsigned int fragment;
4006     + unsigned int offset;
4007     + unsigned int file_size:32;
4008     + unsigned short block_list[0];
4009     +} __attribute__ ((packed));
4010     +
4011     +struct squashfs_dir_inode_header_2 {
4012     + unsigned int inode_type:4;
4013     + unsigned int mode:12; /* protection */
4014     + unsigned int uid:8; /* index into uid table */
4015     + unsigned int guid:8; /* index into guid table */
4016     + unsigned int file_size:19;
4017     + unsigned int offset:13;
4018     + unsigned int mtime;
4019     + unsigned int start_block:24;
4020     +} __attribute__ ((packed));
4021     +
4022     +struct squashfs_ldir_inode_header_2 {
4023     + unsigned int inode_type:4;
4024     + unsigned int mode:12; /* protection */
4025     + unsigned int uid:8; /* index into uid table */
4026     + unsigned int guid:8; /* index into guid table */
4027     + unsigned int file_size:27;
4028     + unsigned int offset:13;
4029     + unsigned int mtime;
4030     + unsigned int start_block:24;
4031     + unsigned int i_count:16;
4032     + struct squashfs_dir_index_2 index[0];
4033     +} __attribute__ ((packed));
4034     +
4035     +union squashfs_inode_header_2 {
4036     + struct squashfs_base_inode_header_2 base;
4037     + struct squashfs_dev_inode_header_2 dev;
4038     + struct squashfs_symlink_inode_header_2 symlink;
4039     + struct squashfs_reg_inode_header_2 reg;
4040     + struct squashfs_dir_inode_header_2 dir;
4041     + struct squashfs_ldir_inode_header_2 ldir;
4042     + struct squashfs_ipc_inode_header_2 ipc;
4043     +};
4044     +
4045     +struct squashfs_dir_header_2 {
4046     + unsigned int count:8;
4047     + unsigned int start_block:24;
4048     +} __attribute__ ((packed));
4049     +
4050     +struct squashfs_dir_entry_2 {
4051     + unsigned int offset:13;
4052     + unsigned int type:3;
4053     + unsigned int size:8;
4054     + char name[0];
4055     +} __attribute__ ((packed));
4056     +
4057     +struct squashfs_fragment_entry_2 {
4058     + unsigned int start_block;
4059     + unsigned int size;
4060     +} __attribute__ ((packed));
4061     +
4062     +#define SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, n)\
4063     + SQUASHFS_MEMSET(s, d, n);\
4064     + SQUASHFS_SWAP((s)->inode_type, d, 0, 4);\
4065     + SQUASHFS_SWAP((s)->mode, d, 4, 12);\
4066     + SQUASHFS_SWAP((s)->uid, d, 16, 8);\
4067     + SQUASHFS_SWAP((s)->guid, d, 24, 8);\
4068     +
4069     +#define SQUASHFS_SWAP_BASE_INODE_HEADER_2(s, d, n) {\
4070     + SQUASHFS_SWAP_START\
4071     + SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, n)\
4072     +}
4073     +
4074     +#define SQUASHFS_SWAP_IPC_INODE_HEADER_2(s, d) \
4075     + SQUASHFS_SWAP_BASE_INODE_HEADER_2(s, d, sizeof(struct squashfs_ipc_inode_header_2))
4076     +
4077     +#define SQUASHFS_SWAP_DEV_INODE_HEADER_2(s, d) {\
4078     + SQUASHFS_SWAP_START\
4079     + SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \
4080     + sizeof(struct squashfs_dev_inode_header_2)); \
4081     + SQUASHFS_SWAP((s)->rdev, d, 32, 16);\
4082     +}
4083     +
4084     +#define SQUASHFS_SWAP_SYMLINK_INODE_HEADER_2(s, d) {\
4085     + SQUASHFS_SWAP_START\
4086     + SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \
4087     + sizeof(struct squashfs_symlink_inode_header_2));\
4088     + SQUASHFS_SWAP((s)->symlink_size, d, 32, 16);\
4089     +}
4090     +
4091     +#define SQUASHFS_SWAP_REG_INODE_HEADER_2(s, d) {\
4092     + SQUASHFS_SWAP_START\
4093     + SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \
4094     + sizeof(struct squashfs_reg_inode_header_2));\
4095     + SQUASHFS_SWAP((s)->mtime, d, 32, 32);\
4096     + SQUASHFS_SWAP((s)->start_block, d, 64, 32);\
4097     + SQUASHFS_SWAP((s)->fragment, d, 96, 32);\
4098     + SQUASHFS_SWAP((s)->offset, d, 128, 32);\
4099     + SQUASHFS_SWAP((s)->file_size, d, 160, 32);\
4100     +}
4101     +
4102     +#define SQUASHFS_SWAP_DIR_INODE_HEADER_2(s, d) {\
4103     + SQUASHFS_SWAP_START\
4104     + SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \
4105     + sizeof(struct squashfs_dir_inode_header_2));\
4106     + SQUASHFS_SWAP((s)->file_size, d, 32, 19);\
4107     + SQUASHFS_SWAP((s)->offset, d, 51, 13);\
4108     + SQUASHFS_SWAP((s)->mtime, d, 64, 32);\
4109     + SQUASHFS_SWAP((s)->start_block, d, 96, 24);\
4110     +}
4111     +
4112     +#define SQUASHFS_SWAP_LDIR_INODE_HEADER_2(s, d) {\
4113     + SQUASHFS_SWAP_START\
4114     + SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \
4115     + sizeof(struct squashfs_ldir_inode_header_2));\
4116     + SQUASHFS_SWAP((s)->file_size, d, 32, 27);\
4117     + SQUASHFS_SWAP((s)->offset, d, 59, 13);\
4118     + SQUASHFS_SWAP((s)->mtime, d, 72, 32);\
4119     + SQUASHFS_SWAP((s)->start_block, d, 104, 24);\
4120     + SQUASHFS_SWAP((s)->i_count, d, 128, 16);\
4121     +}
4122     +
4123     +#define SQUASHFS_SWAP_DIR_INDEX_2(s, d) {\
4124     + SQUASHFS_SWAP_START\
4125     + SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_index_2));\
4126     + SQUASHFS_SWAP((s)->index, d, 0, 27);\
4127     + SQUASHFS_SWAP((s)->start_block, d, 27, 29);\
4128     + SQUASHFS_SWAP((s)->size, d, 56, 8);\
4129     +}
4130     +#define SQUASHFS_SWAP_DIR_HEADER_2(s, d) {\
4131     + SQUASHFS_SWAP_START\
4132     + SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_header_2));\
4133     + SQUASHFS_SWAP((s)->count, d, 0, 8);\
4134     + SQUASHFS_SWAP((s)->start_block, d, 8, 24);\
4135     +}
4136     +
4137     +#define SQUASHFS_SWAP_DIR_ENTRY_2(s, d) {\
4138     + SQUASHFS_SWAP_START\
4139     + SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_entry_2));\
4140     + SQUASHFS_SWAP((s)->offset, d, 0, 13);\
4141     + SQUASHFS_SWAP((s)->type, d, 13, 3);\
4142     + SQUASHFS_SWAP((s)->size, d, 16, 8);\
4143     +}
4144     +
4145     +#define SQUASHFS_SWAP_FRAGMENT_ENTRY_2(s, d) {\
4146     + SQUASHFS_SWAP_START\
4147     + SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_fragment_entry_2));\
4148     + SQUASHFS_SWAP((s)->start_block, d, 0, 32);\
4149     + SQUASHFS_SWAP((s)->size, d, 32, 32);\
4150     +}
4151     +
4152     +#define SQUASHFS_SWAP_FRAGMENT_INDEXES_2(s, d, n) SQUASHFS_SWAP_INTS(s, d, n)
4153     +
4154     +/* fragment and fragment table defines */
4155     +#define SQUASHFS_FRAGMENT_BYTES_2(A) (A * sizeof(struct squashfs_fragment_entry_2))
4156     +
4157     +#define SQUASHFS_FRAGMENT_INDEX_2(A) (SQUASHFS_FRAGMENT_BYTES_2(A) / \
4158     + SQUASHFS_METADATA_SIZE)
4159     +
4160     +#define SQUASHFS_FRAGMENT_INDEX_OFFSET_2(A) (SQUASHFS_FRAGMENT_BYTES_2(A) % \
4161     + SQUASHFS_METADATA_SIZE)
4162     +
4163     +#define SQUASHFS_FRAGMENT_INDEXES_2(A) ((SQUASHFS_FRAGMENT_BYTES_2(A) + \
4164     + SQUASHFS_METADATA_SIZE - 1) / \
4165     + SQUASHFS_METADATA_SIZE)
4166     +
4167     +#define SQUASHFS_FRAGMENT_INDEX_BYTES_2(A) (SQUASHFS_FRAGMENT_INDEXES_2(A) *\
4168     + sizeof(int))
4169     +
4170     +#endif
4171     +
4172     +#ifdef __KERNEL__
4173     +
4174     +/*
4175     + * macros used to swap each structure entry, taking into account
4176     + * bitfields and different bitfield placing conventions on differing
4177     + * architectures
4178     + */
4179     +
4180     +#include <asm/byteorder.h>
4181     +
4182     +#ifdef __BIG_ENDIAN
4183     + /* convert from little endian to big endian */
4184     +#define SQUASHFS_SWAP(value, p, pos, tbits) _SQUASHFS_SWAP(value, p, pos, \
4185     + tbits, b_pos)
4186     +#else
4187     + /* convert from big endian to little endian */
4188     +#define SQUASHFS_SWAP(value, p, pos, tbits) _SQUASHFS_SWAP(value, p, pos, \
4189     + tbits, 64 - tbits - b_pos)
4190     +#endif
4191     +
4192     +#define _SQUASHFS_SWAP(value, p, pos, tbits, SHIFT) {\
4193     + b_pos = pos % 8;\
4194     + val = 0;\
4195     + s = (unsigned char *)p + (pos / 8);\
4196     + d = ((unsigned char *) &val) + 7;\
4197     + for(bits = 0; bits < (tbits + b_pos); bits += 8) \
4198     + *d-- = *s++;\
4199     + value = (val >> (SHIFT))/* & ((1 << tbits) - 1)*/;\
4200     +}
4201     +
4202     +#define SQUASHFS_MEMSET(s, d, n) memset(s, 0, n);
4203     +
4204     +#endif
4205     +#endif
4206     diff -x .gitignore -Nurp linux-2.6.20/include/linux/squashfs_fs_i.h linux-2.6.20-squashfs3.2-r2/include/linux/squashfs_fs_i.h
4207     --- linux-2.6.20/include/linux/squashfs_fs_i.h 1970-01-01 01:00:00.000000000 +0100
4208     +++ linux-2.6.20-squashfs3.2-r2/include/linux/squashfs_fs_i.h 2007-01-12 00:06:09.000000000 +0000
4209     @@ -0,0 +1,45 @@
4210     +#ifndef SQUASHFS_FS_I
4211     +#define SQUASHFS_FS_I
4212     +/*
4213     + * Squashfs
4214     + *
4215     + * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007
4216     + * Phillip Lougher <phillip@lougher.org.uk>
4217     + *
4218     + * This program is free software; you can redistribute it and/or
4219     + * modify it under the terms of the GNU General Public License
4220     + * as published by the Free Software Foundation; either version 2,
4221     + * or (at your option) any later version.
4222     + *
4223     + * This program is distributed in the hope that it will be useful,
4224     + * but WITHOUT ANY WARRANTY; without even the implied warranty of
4225     + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4226     + * GNU General Public License for more details.
4227     + *
4228     + * You should have received a copy of the GNU General Public License
4229     + * along with this program; if not, write to the Free Software
4230     + * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
4231     + *
4232     + * squashfs_fs_i.h
4233     + */
4234     +
4235     +struct squashfs_inode_info {
4236     + long long start_block;
4237     + unsigned int offset;
4238     + union {
4239     + struct {
4240     + long long fragment_start_block;
4241     + unsigned int fragment_size;
4242     + unsigned int fragment_offset;
4243     + long long block_list_start;
4244     + } s1;
4245     + struct {
4246     + long long directory_index_start;
4247     + unsigned int directory_index_offset;
4248     + unsigned int directory_index_count;
4249     + unsigned int parent_inode;
4250     + } s2;
4251     + } u;
4252     + struct inode vfs_inode;
4253     +};
4254     +#endif
4255     diff -x .gitignore -Nurp linux-2.6.20/include/linux/squashfs_fs_sb.h linux-2.6.20-squashfs3.2-r2/include/linux/squashfs_fs_sb.h
4256     --- linux-2.6.20/include/linux/squashfs_fs_sb.h 1970-01-01 01:00:00.000000000 +0100
4257     +++ linux-2.6.20-squashfs3.2-r2/include/linux/squashfs_fs_sb.h 2007-01-12 01:23:47.000000000 +0000
4258     @@ -0,0 +1,74 @@
4259     +#ifndef SQUASHFS_FS_SB
4260     +#define SQUASHFS_FS_SB
4261     +/*
4262     + * Squashfs
4263     + *
4264     + * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007
4265     + * Phillip Lougher <phillip@lougher.org.uk>
4266     + *
4267     + * This program is free software; you can redistribute it and/or
4268     + * modify it under the terms of the GNU General Public License
4269     + * as published by the Free Software Foundation; either version 2,
4270     + * or (at your option) any later version.
4271     + *
4272     + * This program is distributed in the hope that it will be useful,
4273     + * but WITHOUT ANY WARRANTY; without even the implied warranty of
4274     + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4275     + * GNU General Public License for more details.
4276     + *
4277     + * You should have received a copy of the GNU General Public License
4278     + * along with this program; if not, write to the Free Software
4279     + * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
4280     + *
4281     + * squashfs_fs_sb.h
4282     + */
4283     +
4284     +#include <linux/squashfs_fs.h>
4285     +
4286     +struct squashfs_cache {
4287     + long long block;
4288     + int length;
4289     + long long next_index;
4290     + char *data;
4291     +};
4292     +
4293     +struct squashfs_fragment_cache {
4294     + long long block;
4295     + int length;
4296     + unsigned int locked;
4297     + char *data;
4298     +};
4299     +
4300     +struct squashfs_sb_info {
4301     + struct squashfs_super_block sblk;
4302     + int devblksize;
4303     + int devblksize_log2;
4304     + int swap;
4305     + struct squashfs_cache *block_cache;
4306     + struct squashfs_fragment_cache *fragment;
4307     + int next_cache;
4308     + int next_fragment;
4309     + int next_meta_index;
4310     + unsigned int *uid;
4311     + unsigned int *guid;
4312     + long long *fragment_index;
4313     + unsigned int *fragment_index_2;
4314     + char *read_page;
4315     + struct mutex read_data_mutex;
4316     + struct mutex read_page_mutex;
4317     + struct mutex block_cache_mutex;
4318     + struct mutex fragment_mutex;
4319     + struct mutex meta_index_mutex;
4320     + wait_queue_head_t waitq;
4321     + wait_queue_head_t fragment_wait_queue;
4322     + struct meta_index *meta_index;
4323     + z_stream stream;
4324     + long long *inode_lookup_table;
4325     + int (*read_inode)(struct inode *i, squashfs_inode_t \
4326     + inode);
4327     + long long (*read_blocklist)(struct inode *inode, int \
4328     + index, int readahead_blks, char *block_list, \
4329     + unsigned short **block_p, unsigned int *bsize);
4330     + int (*read_fragment_index_table)(struct super_block *s);
4331     +};
4332     +#endif
4333     diff -x .gitignore -Nurp linux-2.6.20/init/do_mounts_rd.c linux-2.6.20-squashfs3.2-r2/init/do_mounts_rd.c
4334     --- linux-2.6.20/init/do_mounts_rd.c 2006-11-29 21:57:37.000000000 +0000
4335     +++ linux-2.6.20-squashfs3.2-r2/init/do_mounts_rd.c 2007-01-16 02:06:03.000000000 +0000
4336     @@ -5,6 +5,7 @@
4337     #include <linux/ext2_fs.h>
4338     #include <linux/romfs_fs.h>
4339     #include <linux/cramfs_fs.h>
4340     +#include <linux/squashfs_fs.h>
4341     #include <linux/initrd.h>
4342     #include <linux/string.h>
4343    
4344     @@ -39,6 +40,7 @@ static int __init crd_load(int in_fd, in
4345     * numbers could not be found.
4346     *
4347     * We currently check for the following magic numbers:
4348     + * squashfs
4349     * minix
4350     * ext2
4351     * romfs
4352     @@ -53,6 +55,7 @@ identify_ramdisk_image(int fd, int start
4353     struct ext2_super_block *ext2sb;
4354     struct romfs_super_block *romfsb;
4355     struct cramfs_super *cramfsb;
4356     + struct squashfs_super_block *squashfsb;
4357     int nblocks = -1;
4358     unsigned char *buf;
4359    
4360     @@ -64,6 +67,7 @@ identify_ramdisk_image(int fd, int start
4361     ext2sb = (struct ext2_super_block *) buf;
4362     romfsb = (struct romfs_super_block *) buf;
4363     cramfsb = (struct cramfs_super *) buf;
4364     + squashfsb = (struct squashfs_super_block *) buf;
4365     memset(buf, 0xe5, size);
4366    
4367     /*
4368     @@ -101,6 +105,18 @@ identify_ramdisk_image(int fd, int start
4369     goto done;
4370     }
4371    
4372     + /* squashfs is at block zero too */
4373     + if (squashfsb->s_magic == SQUASHFS_MAGIC) {
4374     + printk(KERN_NOTICE
4375     + "RAMDISK: squashfs filesystem found at block %d\n",
4376     + start_block);
4377     + if (squashfsb->s_major < 3)
4378     + nblocks = (squashfsb->bytes_used_2+BLOCK_SIZE-1)>>BLOCK_SIZE_BITS;
4379     + else
4380     + nblocks = (squashfsb->bytes_used+BLOCK_SIZE-1)>>BLOCK_SIZE_BITS;
4381     + goto done;
4382     + }
4383     +
4384     /*
4385     * Read block 1 to test for minix and ext2 superblock
4386     */