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