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