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