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