Root/target/linux/generic-2.4/patches/001-squashfs.patch

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

Archive Download this file



interactive