diff options
Diffstat (limited to 'fs/squashfs')
-rw-r--r-- | fs/squashfs/Kconfig | 32 | ||||
-rw-r--r-- | fs/squashfs/Makefile | 1 | ||||
-rw-r--r-- | fs/squashfs/block.c | 11 | ||||
-rw-r--r-- | fs/squashfs/cache.c | 38 | ||||
-rw-r--r-- | fs/squashfs/decompressor.c | 52 | ||||
-rw-r--r-- | fs/squashfs/decompressor.h | 18 | ||||
-rw-r--r-- | fs/squashfs/dir.c | 14 | ||||
-rw-r--r-- | fs/squashfs/export.c | 42 | ||||
-rw-r--r-- | fs/squashfs/file.c | 2 | ||||
-rw-r--r-- | fs/squashfs/fragment.c | 38 | ||||
-rw-r--r-- | fs/squashfs/id.c | 43 | ||||
-rw-r--r-- | fs/squashfs/inode.c | 2 | ||||
-rw-r--r-- | fs/squashfs/lzo_wrapper.c | 5 | ||||
-rw-r--r-- | fs/squashfs/namei.c | 14 | ||||
-rw-r--r-- | fs/squashfs/squashfs.h | 19 | ||||
-rw-r--r-- | fs/squashfs/squashfs_fs.h | 7 | ||||
-rw-r--r-- | fs/squashfs/squashfs_fs_i.h | 8 | ||||
-rw-r--r-- | fs/squashfs/squashfs_fs_sb.h | 2 | ||||
-rw-r--r-- | fs/squashfs/super.c | 147 | ||||
-rw-r--r-- | fs/squashfs/symlink.c | 2 | ||||
-rw-r--r-- | fs/squashfs/xattr.c | 11 | ||||
-rw-r--r-- | fs/squashfs/xattr.h | 7 | ||||
-rw-r--r-- | fs/squashfs/xattr_id.c | 49 | ||||
-rw-r--r-- | fs/squashfs/xz_wrapper.c | 180 | ||||
-rw-r--r-- | fs/squashfs/zlib_wrapper.c | 33 |
25 files changed, 546 insertions, 231 deletions
diff --git a/fs/squashfs/Kconfig b/fs/squashfs/Kconfig index e5f63da64d04..7797218d0b30 100644 --- a/fs/squashfs/Kconfig +++ b/fs/squashfs/Kconfig | |||
@@ -5,12 +5,12 @@ config SQUASHFS | |||
5 | help | 5 | help |
6 | Saying Y here includes support for SquashFS 4.0 (a Compressed | 6 | Saying Y here includes support for SquashFS 4.0 (a Compressed |
7 | Read-Only File System). Squashfs is a highly compressed read-only | 7 | Read-Only File System). Squashfs is a highly compressed read-only |
8 | filesystem for Linux. It uses zlib/lzo compression to compress both | 8 | filesystem for Linux. It uses zlib, lzo or xz compression to |
9 | files, inodes and directories. Inodes in the system are very small | 9 | compress both files, inodes and directories. Inodes in the system |
10 | and all blocks are packed to minimise data overhead. Block sizes | 10 | are very small and all blocks are packed to minimise data overhead. |
11 | greater than 4K are supported up to a maximum of 1 Mbytes (default | 11 | Block sizes greater than 4K are supported up to a maximum of 1 Mbytes |
12 | block size 128K). SquashFS 4.0 supports 64 bit filesystems and files | 12 | (default block size 128K). SquashFS 4.0 supports 64 bit filesystems |
13 | (larger than 4GB), full uid/gid information, hard links and | 13 | and files (larger than 4GB), full uid/gid information, hard links and |
14 | timestamps. | 14 | timestamps. |
15 | 15 | ||
16 | Squashfs is intended for general read-only filesystem use, for | 16 | Squashfs is intended for general read-only filesystem use, for |
@@ -29,7 +29,6 @@ config SQUASHFS | |||
29 | config SQUASHFS_XATTR | 29 | config SQUASHFS_XATTR |
30 | bool "Squashfs XATTR support" | 30 | bool "Squashfs XATTR support" |
31 | depends on SQUASHFS | 31 | depends on SQUASHFS |
32 | default n | ||
33 | help | 32 | help |
34 | Saying Y here includes support for extended attributes (xattrs). | 33 | Saying Y here includes support for extended attributes (xattrs). |
35 | Xattrs are name:value pairs associated with inodes by | 34 | Xattrs are name:value pairs associated with inodes by |
@@ -40,11 +39,10 @@ config SQUASHFS_XATTR | |||
40 | config SQUASHFS_LZO | 39 | config SQUASHFS_LZO |
41 | bool "Include support for LZO compressed file systems" | 40 | bool "Include support for LZO compressed file systems" |
42 | depends on SQUASHFS | 41 | depends on SQUASHFS |
43 | default n | ||
44 | select LZO_DECOMPRESS | 42 | select LZO_DECOMPRESS |
45 | help | 43 | help |
46 | Saying Y here includes support for reading Squashfs file systems | 44 | Saying Y here includes support for reading Squashfs file systems |
47 | compressed with LZO compresssion. LZO compression is mainly | 45 | compressed with LZO compression. LZO compression is mainly |
48 | aimed at embedded systems with slower CPUs where the overheads | 46 | aimed at embedded systems with slower CPUs where the overheads |
49 | of zlib are too high. | 47 | of zlib are too high. |
50 | 48 | ||
@@ -53,10 +51,24 @@ config SQUASHFS_LZO | |||
53 | 51 | ||
54 | If unsure, say N. | 52 | If unsure, say N. |
55 | 53 | ||
54 | config SQUASHFS_XZ | ||
55 | bool "Include support for XZ compressed file systems" | ||
56 | depends on SQUASHFS | ||
57 | select XZ_DEC | ||
58 | help | ||
59 | Saying Y here includes support for reading Squashfs file systems | ||
60 | compressed with XZ compression. XZ gives better compression than | ||
61 | the default zlib compression, at the expense of greater CPU and | ||
62 | memory overhead. | ||
63 | |||
64 | XZ is not the standard compression used in Squashfs and so most | ||
65 | file systems will be readable without selecting this option. | ||
66 | |||
67 | If unsure, say N. | ||
68 | |||
56 | config SQUASHFS_EMBEDDED | 69 | config SQUASHFS_EMBEDDED |
57 | bool "Additional option for memory-constrained systems" | 70 | bool "Additional option for memory-constrained systems" |
58 | depends on SQUASHFS | 71 | depends on SQUASHFS |
59 | default n | ||
60 | help | 72 | help |
61 | Saying Y here allows you to specify cache size. | 73 | Saying Y here allows you to specify cache size. |
62 | 74 | ||
diff --git a/fs/squashfs/Makefile b/fs/squashfs/Makefile index 7672bac8d328..cecf2bea07af 100644 --- a/fs/squashfs/Makefile +++ b/fs/squashfs/Makefile | |||
@@ -7,3 +7,4 @@ squashfs-y += block.o cache.o dir.o export.o file.o fragment.o id.o inode.o | |||
7 | squashfs-y += namei.o super.o symlink.o zlib_wrapper.o decompressor.o | 7 | squashfs-y += namei.o super.o symlink.o zlib_wrapper.o decompressor.o |
8 | squashfs-$(CONFIG_SQUASHFS_XATTR) += xattr.o xattr_id.o | 8 | squashfs-$(CONFIG_SQUASHFS_XATTR) += xattr.o xattr_id.o |
9 | squashfs-$(CONFIG_SQUASHFS_LZO) += lzo_wrapper.o | 9 | squashfs-$(CONFIG_SQUASHFS_LZO) += lzo_wrapper.o |
10 | squashfs-$(CONFIG_SQUASHFS_XZ) += xz_wrapper.o | ||
diff --git a/fs/squashfs/block.c b/fs/squashfs/block.c index 653c030eb840..ed0eb2a921f4 100644 --- a/fs/squashfs/block.c +++ b/fs/squashfs/block.c | |||
@@ -2,7 +2,7 @@ | |||
2 | * Squashfs - a compressed read only filesystem for Linux | 2 | * Squashfs - a compressed read only filesystem for Linux |
3 | * | 3 | * |
4 | * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008 | 4 | * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008 |
5 | * Phillip Lougher <phillip@lougher.demon.co.uk> | 5 | * Phillip Lougher <phillip@squashfs.org.uk> |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or | 7 | * This program is free software; you can redistribute it and/or |
8 | * modify it under the terms of the GNU General Public License | 8 | * modify it under the terms of the GNU General Public License |
@@ -34,7 +34,6 @@ | |||
34 | 34 | ||
35 | #include "squashfs_fs.h" | 35 | #include "squashfs_fs.h" |
36 | #include "squashfs_fs_sb.h" | 36 | #include "squashfs_fs_sb.h" |
37 | #include "squashfs_fs_i.h" | ||
38 | #include "squashfs.h" | 37 | #include "squashfs.h" |
39 | #include "decompressor.h" | 38 | #include "decompressor.h" |
40 | 39 | ||
@@ -64,6 +63,14 @@ static struct buffer_head *get_block_length(struct super_block *sb, | |||
64 | *length = (unsigned char) bh->b_data[*offset] | | 63 | *length = (unsigned char) bh->b_data[*offset] | |
65 | (unsigned char) bh->b_data[*offset + 1] << 8; | 64 | (unsigned char) bh->b_data[*offset + 1] << 8; |
66 | *offset += 2; | 65 | *offset += 2; |
66 | |||
67 | if (*offset == msblk->devblksize) { | ||
68 | put_bh(bh); | ||
69 | bh = sb_bread(sb, ++(*cur_index)); | ||
70 | if (bh == NULL) | ||
71 | return NULL; | ||
72 | *offset = 0; | ||
73 | } | ||
67 | } | 74 | } |
68 | 75 | ||
69 | return bh; | 76 | return bh; |
diff --git a/fs/squashfs/cache.c b/fs/squashfs/cache.c index 57314bee9059..f744be98cd5a 100644 --- a/fs/squashfs/cache.c +++ b/fs/squashfs/cache.c | |||
@@ -2,7 +2,7 @@ | |||
2 | * Squashfs - a compressed read only filesystem for Linux | 2 | * Squashfs - a compressed read only filesystem for Linux |
3 | * | 3 | * |
4 | * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008 | 4 | * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008 |
5 | * Phillip Lougher <phillip@lougher.demon.co.uk> | 5 | * Phillip Lougher <phillip@squashfs.org.uk> |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or | 7 | * This program is free software; you can redistribute it and/or |
8 | * modify it under the terms of the GNU General Public License | 8 | * modify it under the terms of the GNU General Public License |
@@ -29,7 +29,7 @@ | |||
29 | * plus functions layered ontop of the generic cache implementation to | 29 | * plus functions layered ontop of the generic cache implementation to |
30 | * access the metadata and fragment caches. | 30 | * access the metadata and fragment caches. |
31 | * | 31 | * |
32 | * To avoid out of memory and fragmentation isssues with vmalloc the cache | 32 | * To avoid out of memory and fragmentation issues with vmalloc the cache |
33 | * uses sequences of kmalloced PAGE_CACHE_SIZE buffers. | 33 | * uses sequences of kmalloced PAGE_CACHE_SIZE buffers. |
34 | * | 34 | * |
35 | * It should be noted that the cache is not used for file datablocks, these | 35 | * It should be noted that the cache is not used for file datablocks, these |
@@ -55,7 +55,6 @@ | |||
55 | 55 | ||
56 | #include "squashfs_fs.h" | 56 | #include "squashfs_fs.h" |
57 | #include "squashfs_fs_sb.h" | 57 | #include "squashfs_fs_sb.h" |
58 | #include "squashfs_fs_i.h" | ||
59 | #include "squashfs.h" | 58 | #include "squashfs.h" |
60 | 59 | ||
61 | /* | 60 | /* |
@@ -105,7 +104,7 @@ struct squashfs_cache_entry *squashfs_cache_get(struct super_block *sb, | |||
105 | entry = &cache->entry[i]; | 104 | entry = &cache->entry[i]; |
106 | 105 | ||
107 | /* | 106 | /* |
108 | * Initialise choosen cache entry, and fill it in from | 107 | * Initialise chosen cache entry, and fill it in from |
109 | * disk. | 108 | * disk. |
110 | */ | 109 | */ |
111 | cache->unused--; | 110 | cache->unused--; |
@@ -287,7 +286,7 @@ cleanup: | |||
287 | 286 | ||
288 | 287 | ||
289 | /* | 288 | /* |
290 | * Copy upto length bytes from cache entry to buffer starting at offset bytes | 289 | * Copy up to length bytes from cache entry to buffer starting at offset bytes |
291 | * into the cache entry. If there's not length bytes then copy the number of | 290 | * into the cache entry. If there's not length bytes then copy the number of |
292 | * bytes available. In all cases return the number of bytes copied. | 291 | * bytes available. In all cases return the number of bytes copied. |
293 | */ | 292 | */ |
@@ -394,19 +393,36 @@ struct squashfs_cache_entry *squashfs_get_datablock(struct super_block *sb, | |||
394 | /* | 393 | /* |
395 | * Read a filesystem table (uncompressed sequence of bytes) from disk | 394 | * Read a filesystem table (uncompressed sequence of bytes) from disk |
396 | */ | 395 | */ |
397 | int squashfs_read_table(struct super_block *sb, void *buffer, u64 block, | 396 | void *squashfs_read_table(struct super_block *sb, u64 block, int length) |
398 | int length) | ||
399 | { | 397 | { |
400 | int pages = (length + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; | 398 | int pages = (length + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; |
401 | int i, res; | 399 | int i, res; |
402 | void **data = kcalloc(pages, sizeof(void *), GFP_KERNEL); | 400 | void *table, *buffer, **data; |
403 | if (data == NULL) | 401 | |
404 | return -ENOMEM; | 402 | table = buffer = kmalloc(length, GFP_KERNEL); |
403 | if (table == NULL) | ||
404 | return ERR_PTR(-ENOMEM); | ||
405 | |||
406 | data = kcalloc(pages, sizeof(void *), GFP_KERNEL); | ||
407 | if (data == NULL) { | ||
408 | res = -ENOMEM; | ||
409 | goto failed; | ||
410 | } | ||
405 | 411 | ||
406 | for (i = 0; i < pages; i++, buffer += PAGE_CACHE_SIZE) | 412 | for (i = 0; i < pages; i++, buffer += PAGE_CACHE_SIZE) |
407 | data[i] = buffer; | 413 | data[i] = buffer; |
414 | |||
408 | res = squashfs_read_data(sb, data, block, length | | 415 | res = squashfs_read_data(sb, data, block, length | |
409 | SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, length, pages); | 416 | SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, length, pages); |
417 | |||
410 | kfree(data); | 418 | kfree(data); |
411 | return res; | 419 | |
420 | if (res < 0) | ||
421 | goto failed; | ||
422 | |||
423 | return table; | ||
424 | |||
425 | failed: | ||
426 | kfree(table); | ||
427 | return ERR_PTR(res); | ||
412 | } | 428 | } |
diff --git a/fs/squashfs/decompressor.c b/fs/squashfs/decompressor.c index 24af9ce9722f..9f1b0bb96f13 100644 --- a/fs/squashfs/decompressor.c +++ b/fs/squashfs/decompressor.c | |||
@@ -2,7 +2,7 @@ | |||
2 | * Squashfs - a compressed read only filesystem for Linux | 2 | * Squashfs - a compressed read only filesystem for Linux |
3 | * | 3 | * |
4 | * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 | 4 | * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 |
5 | * Phillip Lougher <phillip@lougher.demon.co.uk> | 5 | * Phillip Lougher <phillip@squashfs.org.uk> |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or | 7 | * This program is free software; you can redistribute it and/or |
8 | * modify it under the terms of the GNU General Public License | 8 | * modify it under the terms of the GNU General Public License |
@@ -23,11 +23,11 @@ | |||
23 | 23 | ||
24 | #include <linux/types.h> | 24 | #include <linux/types.h> |
25 | #include <linux/mutex.h> | 25 | #include <linux/mutex.h> |
26 | #include <linux/slab.h> | ||
26 | #include <linux/buffer_head.h> | 27 | #include <linux/buffer_head.h> |
27 | 28 | ||
28 | #include "squashfs_fs.h" | 29 | #include "squashfs_fs.h" |
29 | #include "squashfs_fs_sb.h" | 30 | #include "squashfs_fs_sb.h" |
30 | #include "squashfs_fs_i.h" | ||
31 | #include "decompressor.h" | 31 | #include "decompressor.h" |
32 | #include "squashfs.h" | 32 | #include "squashfs.h" |
33 | 33 | ||
@@ -41,23 +41,26 @@ static const struct squashfs_decompressor squashfs_lzma_unsupported_comp_ops = { | |||
41 | }; | 41 | }; |
42 | 42 | ||
43 | #ifndef CONFIG_SQUASHFS_LZO | 43 | #ifndef CONFIG_SQUASHFS_LZO |
44 | static const struct squashfs_decompressor squashfs_lzo_unsupported_comp_ops = { | 44 | static const struct squashfs_decompressor squashfs_lzo_comp_ops = { |
45 | NULL, NULL, NULL, LZO_COMPRESSION, "lzo", 0 | 45 | NULL, NULL, NULL, LZO_COMPRESSION, "lzo", 0 |
46 | }; | 46 | }; |
47 | #endif | 47 | #endif |
48 | 48 | ||
49 | #ifndef CONFIG_SQUASHFS_XZ | ||
50 | static const struct squashfs_decompressor squashfs_xz_comp_ops = { | ||
51 | NULL, NULL, NULL, XZ_COMPRESSION, "xz", 0 | ||
52 | }; | ||
53 | #endif | ||
54 | |||
49 | static const struct squashfs_decompressor squashfs_unknown_comp_ops = { | 55 | static const struct squashfs_decompressor squashfs_unknown_comp_ops = { |
50 | NULL, NULL, NULL, 0, "unknown", 0 | 56 | NULL, NULL, NULL, 0, "unknown", 0 |
51 | }; | 57 | }; |
52 | 58 | ||
53 | static const struct squashfs_decompressor *decompressor[] = { | 59 | static const struct squashfs_decompressor *decompressor[] = { |
54 | &squashfs_zlib_comp_ops, | 60 | &squashfs_zlib_comp_ops, |
55 | &squashfs_lzma_unsupported_comp_ops, | ||
56 | #ifdef CONFIG_SQUASHFS_LZO | ||
57 | &squashfs_lzo_comp_ops, | 61 | &squashfs_lzo_comp_ops, |
58 | #else | 62 | &squashfs_xz_comp_ops, |
59 | &squashfs_lzo_unsupported_comp_ops, | 63 | &squashfs_lzma_unsupported_comp_ops, |
60 | #endif | ||
61 | &squashfs_unknown_comp_ops | 64 | &squashfs_unknown_comp_ops |
62 | }; | 65 | }; |
63 | 66 | ||
@@ -72,3 +75,36 @@ const struct squashfs_decompressor *squashfs_lookup_decompressor(int id) | |||
72 | 75 | ||
73 | return decompressor[i]; | 76 | return decompressor[i]; |
74 | } | 77 | } |
78 | |||
79 | |||
80 | void *squashfs_decompressor_init(struct super_block *sb, unsigned short flags) | ||
81 | { | ||
82 | struct squashfs_sb_info *msblk = sb->s_fs_info; | ||
83 | void *strm, *buffer = NULL; | ||
84 | int length = 0; | ||
85 | |||
86 | /* | ||
87 | * Read decompressor specific options from file system if present | ||
88 | */ | ||
89 | if (SQUASHFS_COMP_OPTS(flags)) { | ||
90 | buffer = kmalloc(PAGE_CACHE_SIZE, GFP_KERNEL); | ||
91 | if (buffer == NULL) | ||
92 | return ERR_PTR(-ENOMEM); | ||
93 | |||
94 | length = squashfs_read_data(sb, &buffer, | ||
95 | sizeof(struct squashfs_super_block), 0, NULL, | ||
96 | PAGE_CACHE_SIZE, 1); | ||
97 | |||
98 | if (length < 0) { | ||
99 | strm = ERR_PTR(length); | ||
100 | goto finished; | ||
101 | } | ||
102 | } | ||
103 | |||
104 | strm = msblk->decompressor->init(msblk, buffer, length); | ||
105 | |||
106 | finished: | ||
107 | kfree(buffer); | ||
108 | |||
109 | return strm; | ||
110 | } | ||
diff --git a/fs/squashfs/decompressor.h b/fs/squashfs/decompressor.h index 7425f80783f6..8ba70cff09a6 100644 --- a/fs/squashfs/decompressor.h +++ b/fs/squashfs/decompressor.h | |||
@@ -4,7 +4,7 @@ | |||
4 | * Squashfs - a compressed read only filesystem for Linux | 4 | * Squashfs - a compressed read only filesystem for Linux |
5 | * | 5 | * |
6 | * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 | 6 | * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 |
7 | * Phillip Lougher <phillip@lougher.demon.co.uk> | 7 | * Phillip Lougher <phillip@squashfs.org.uk> |
8 | * | 8 | * |
9 | * This program is free software; you can redistribute it and/or | 9 | * This program is free software; you can redistribute it and/or |
10 | * modify it under the terms of the GNU General Public License | 10 | * modify it under the terms of the GNU General Public License |
@@ -24,7 +24,7 @@ | |||
24 | */ | 24 | */ |
25 | 25 | ||
26 | struct squashfs_decompressor { | 26 | struct squashfs_decompressor { |
27 | void *(*init)(struct squashfs_sb_info *); | 27 | void *(*init)(struct squashfs_sb_info *, void *, int); |
28 | void (*free)(void *); | 28 | void (*free)(void *); |
29 | int (*decompress)(struct squashfs_sb_info *, void **, | 29 | int (*decompress)(struct squashfs_sb_info *, void **, |
30 | struct buffer_head **, int, int, int, int, int); | 30 | struct buffer_head **, int, int, int, int, int); |
@@ -33,11 +33,6 @@ struct squashfs_decompressor { | |||
33 | int supported; | 33 | int supported; |
34 | }; | 34 | }; |
35 | 35 | ||
36 | static inline void *squashfs_decompressor_init(struct squashfs_sb_info *msblk) | ||
37 | { | ||
38 | return msblk->decompressor->init(msblk); | ||
39 | } | ||
40 | |||
41 | static inline void squashfs_decompressor_free(struct squashfs_sb_info *msblk, | 36 | static inline void squashfs_decompressor_free(struct squashfs_sb_info *msblk, |
42 | void *s) | 37 | void *s) |
43 | { | 38 | { |
@@ -52,4 +47,13 @@ static inline int squashfs_decompress(struct squashfs_sb_info *msblk, | |||
52 | return msblk->decompressor->decompress(msblk, buffer, bh, b, offset, | 47 | return msblk->decompressor->decompress(msblk, buffer, bh, b, offset, |
53 | length, srclength, pages); | 48 | length, srclength, pages); |
54 | } | 49 | } |
50 | |||
51 | #ifdef CONFIG_SQUASHFS_XZ | ||
52 | extern const struct squashfs_decompressor squashfs_xz_comp_ops; | ||
53 | #endif | ||
54 | |||
55 | #ifdef CONFIG_SQUASHFS_LZO | ||
56 | extern const struct squashfs_decompressor squashfs_lzo_comp_ops; | ||
57 | #endif | ||
58 | |||
55 | #endif | 59 | #endif |
diff --git a/fs/squashfs/dir.c b/fs/squashfs/dir.c index 12b933ac6585..9dfe2ce0fb70 100644 --- a/fs/squashfs/dir.c +++ b/fs/squashfs/dir.c | |||
@@ -2,7 +2,7 @@ | |||
2 | * Squashfs - a compressed read only filesystem for Linux | 2 | * Squashfs - a compressed read only filesystem for Linux |
3 | * | 3 | * |
4 | * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008 | 4 | * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008 |
5 | * Phillip Lougher <phillip@lougher.demon.co.uk> | 5 | * Phillip Lougher <phillip@squashfs.org.uk> |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or | 7 | * This program is free software; you can redistribute it and/or |
8 | * modify it under the terms of the GNU General Public License | 8 | * modify it under the terms of the GNU General Public License |
@@ -172,6 +172,11 @@ static int squashfs_readdir(struct file *file, void *dirent, filldir_t filldir) | |||
172 | length += sizeof(dirh); | 172 | length += sizeof(dirh); |
173 | 173 | ||
174 | dir_count = le32_to_cpu(dirh.count) + 1; | 174 | dir_count = le32_to_cpu(dirh.count) + 1; |
175 | |||
176 | /* dir_count should never be larger than 256 */ | ||
177 | if (dir_count > 256) | ||
178 | goto failed_read; | ||
179 | |||
175 | while (dir_count--) { | 180 | while (dir_count--) { |
176 | /* | 181 | /* |
177 | * Read directory entry. | 182 | * Read directory entry. |
@@ -183,6 +188,10 @@ static int squashfs_readdir(struct file *file, void *dirent, filldir_t filldir) | |||
183 | 188 | ||
184 | size = le16_to_cpu(dire->size) + 1; | 189 | size = le16_to_cpu(dire->size) + 1; |
185 | 190 | ||
191 | /* size should never be larger than SQUASHFS_NAME_LEN */ | ||
192 | if (size > SQUASHFS_NAME_LEN) | ||
193 | goto failed_read; | ||
194 | |||
186 | err = squashfs_read_metadata(inode->i_sb, dire->name, | 195 | err = squashfs_read_metadata(inode->i_sb, dire->name, |
187 | &block, &offset, size); | 196 | &block, &offset, size); |
188 | if (err < 0) | 197 | if (err < 0) |
@@ -230,5 +239,6 @@ failed_read: | |||
230 | 239 | ||
231 | const struct file_operations squashfs_dir_ops = { | 240 | const struct file_operations squashfs_dir_ops = { |
232 | .read = generic_read_dir, | 241 | .read = generic_read_dir, |
233 | .readdir = squashfs_readdir | 242 | .readdir = squashfs_readdir, |
243 | .llseek = default_llseek, | ||
234 | }; | 244 | }; |
diff --git a/fs/squashfs/export.c b/fs/squashfs/export.c index 7f93d5a9ee05..5e1101ff276f 100644 --- a/fs/squashfs/export.c +++ b/fs/squashfs/export.c | |||
@@ -2,7 +2,7 @@ | |||
2 | * Squashfs - a compressed read only filesystem for Linux | 2 | * Squashfs - a compressed read only filesystem for Linux |
3 | * | 3 | * |
4 | * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008 | 4 | * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008 |
5 | * Phillip Lougher <phillip@lougher.demon.co.uk> | 5 | * Phillip Lougher <phillip@squashfs.org.uk> |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or | 7 | * This program is free software; you can redistribute it and/or |
8 | * modify it under the terms of the GNU General Public License | 8 | * modify it under the terms of the GNU General Public License |
@@ -121,30 +121,38 @@ static struct dentry *squashfs_get_parent(struct dentry *child) | |||
121 | * Read uncompressed inode lookup table indexes off disk into memory | 121 | * Read uncompressed inode lookup table indexes off disk into memory |
122 | */ | 122 | */ |
123 | __le64 *squashfs_read_inode_lookup_table(struct super_block *sb, | 123 | __le64 *squashfs_read_inode_lookup_table(struct super_block *sb, |
124 | u64 lookup_table_start, unsigned int inodes) | 124 | u64 lookup_table_start, u64 next_table, unsigned int inodes) |
125 | { | 125 | { |
126 | unsigned int length = SQUASHFS_LOOKUP_BLOCK_BYTES(inodes); | 126 | unsigned int length = SQUASHFS_LOOKUP_BLOCK_BYTES(inodes); |
127 | __le64 *inode_lookup_table; | 127 | __le64 *table; |
128 | int err; | ||
129 | 128 | ||
130 | TRACE("In read_inode_lookup_table, length %d\n", length); | 129 | TRACE("In read_inode_lookup_table, length %d\n", length); |
131 | 130 | ||
132 | /* Allocate inode lookup table indexes */ | 131 | /* Sanity check values */ |
133 | inode_lookup_table = kmalloc(length, GFP_KERNEL); | 132 | |
134 | if (inode_lookup_table == NULL) { | 133 | /* there should always be at least one inode */ |
135 | ERROR("Failed to allocate inode lookup table\n"); | 134 | if (inodes == 0) |
136 | return ERR_PTR(-ENOMEM); | 135 | return ERR_PTR(-EINVAL); |
137 | } | 136 | |
137 | /* length bytes should not extend into the next table - this check | ||
138 | * also traps instances where lookup_table_start is incorrectly larger | ||
139 | * than the next table start | ||
140 | */ | ||
141 | if (lookup_table_start + length > next_table) | ||
142 | return ERR_PTR(-EINVAL); | ||
143 | |||
144 | table = squashfs_read_table(sb, lookup_table_start, length); | ||
138 | 145 | ||
139 | err = squashfs_read_table(sb, inode_lookup_table, lookup_table_start, | 146 | /* |
140 | length); | 147 | * table[0] points to the first inode lookup table metadata block, |
141 | if (err < 0) { | 148 | * this should be less than lookup_table_start |
142 | ERROR("unable to read inode lookup table\n"); | 149 | */ |
143 | kfree(inode_lookup_table); | 150 | if (!IS_ERR(table) && le64_to_cpu(table[0]) >= lookup_table_start) { |
144 | return ERR_PTR(err); | 151 | kfree(table); |
152 | return ERR_PTR(-EINVAL); | ||
145 | } | 153 | } |
146 | 154 | ||
147 | return inode_lookup_table; | 155 | return table; |
148 | } | 156 | } |
149 | 157 | ||
150 | 158 | ||
diff --git a/fs/squashfs/file.c b/fs/squashfs/file.c index a25c5060bdcb..38bb1c640559 100644 --- a/fs/squashfs/file.c +++ b/fs/squashfs/file.c | |||
@@ -2,7 +2,7 @@ | |||
2 | * Squashfs - a compressed read only filesystem for Linux | 2 | * Squashfs - a compressed read only filesystem for Linux |
3 | * | 3 | * |
4 | * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008 | 4 | * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008 |
5 | * Phillip Lougher <phillip@lougher.demon.co.uk> | 5 | * Phillip Lougher <phillip@squashfs.org.uk> |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or | 7 | * This program is free software; you can redistribute it and/or |
8 | * modify it under the terms of the GNU General Public License | 8 | * modify it under the terms of the GNU General Public License |
diff --git a/fs/squashfs/fragment.c b/fs/squashfs/fragment.c index 7c90bbd6879d..0ed6edbc5c71 100644 --- a/fs/squashfs/fragment.c +++ b/fs/squashfs/fragment.c | |||
@@ -2,7 +2,7 @@ | |||
2 | * Squashfs - a compressed read only filesystem for Linux | 2 | * Squashfs - a compressed read only filesystem for Linux |
3 | * | 3 | * |
4 | * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008 | 4 | * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008 |
5 | * Phillip Lougher <phillip@lougher.demon.co.uk> | 5 | * Phillip Lougher <phillip@squashfs.org.uk> |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or | 7 | * This program is free software; you can redistribute it and/or |
8 | * modify it under the terms of the GNU General Public License | 8 | * modify it under the terms of the GNU General Public License |
@@ -39,7 +39,6 @@ | |||
39 | 39 | ||
40 | #include "squashfs_fs.h" | 40 | #include "squashfs_fs.h" |
41 | #include "squashfs_fs_sb.h" | 41 | #include "squashfs_fs_sb.h" |
42 | #include "squashfs_fs_i.h" | ||
43 | #include "squashfs.h" | 42 | #include "squashfs.h" |
44 | 43 | ||
45 | /* | 44 | /* |
@@ -72,26 +71,29 @@ int squashfs_frag_lookup(struct super_block *sb, unsigned int fragment, | |||
72 | * Read the uncompressed fragment lookup table indexes off disk into memory | 71 | * Read the uncompressed fragment lookup table indexes off disk into memory |
73 | */ | 72 | */ |
74 | __le64 *squashfs_read_fragment_index_table(struct super_block *sb, | 73 | __le64 *squashfs_read_fragment_index_table(struct super_block *sb, |
75 | u64 fragment_table_start, unsigned int fragments) | 74 | u64 fragment_table_start, u64 next_table, unsigned int fragments) |
76 | { | 75 | { |
77 | unsigned int length = SQUASHFS_FRAGMENT_INDEX_BYTES(fragments); | 76 | unsigned int length = SQUASHFS_FRAGMENT_INDEX_BYTES(fragments); |
78 | __le64 *fragment_index; | 77 | __le64 *table; |
79 | int err; | ||
80 | 78 | ||
81 | /* Allocate fragment lookup table indexes */ | 79 | /* |
82 | fragment_index = kmalloc(length, GFP_KERNEL); | 80 | * Sanity check, length bytes should not extend into the next table - |
83 | if (fragment_index == NULL) { | 81 | * this check also traps instances where fragment_table_start is |
84 | ERROR("Failed to allocate fragment index table\n"); | 82 | * incorrectly larger than the next table start |
85 | return ERR_PTR(-ENOMEM); | 83 | */ |
86 | } | 84 | if (fragment_table_start + length > next_table) |
85 | return ERR_PTR(-EINVAL); | ||
86 | |||
87 | table = squashfs_read_table(sb, fragment_table_start, length); | ||
87 | 88 | ||
88 | err = squashfs_read_table(sb, fragment_index, fragment_table_start, | 89 | /* |
89 | length); | 90 | * table[0] points to the first fragment table metadata block, this |
90 | if (err < 0) { | 91 | * should be less than fragment_table_start |
91 | ERROR("unable to read fragment index table\n"); | 92 | */ |
92 | kfree(fragment_index); | 93 | if (!IS_ERR(table) && le64_to_cpu(table[0]) >= fragment_table_start) { |
93 | return ERR_PTR(err); | 94 | kfree(table); |
95 | return ERR_PTR(-EINVAL); | ||
94 | } | 96 | } |
95 | 97 | ||
96 | return fragment_index; | 98 | return table; |
97 | } | 99 | } |
diff --git a/fs/squashfs/id.c b/fs/squashfs/id.c index b7f64bcd2b70..d38ea3dab951 100644 --- a/fs/squashfs/id.c +++ b/fs/squashfs/id.c | |||
@@ -2,7 +2,7 @@ | |||
2 | * Squashfs - a compressed read only filesystem for Linux | 2 | * Squashfs - a compressed read only filesystem for Linux |
3 | * | 3 | * |
4 | * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008 | 4 | * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008 |
5 | * Phillip Lougher <phillip@lougher.demon.co.uk> | 5 | * Phillip Lougher <phillip@squashfs.org.uk> |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or | 7 | * This program is free software; you can redistribute it and/or |
8 | * modify it under the terms of the GNU General Public License | 8 | * modify it under the terms of the GNU General Public License |
@@ -37,7 +37,6 @@ | |||
37 | 37 | ||
38 | #include "squashfs_fs.h" | 38 | #include "squashfs_fs.h" |
39 | #include "squashfs_fs_sb.h" | 39 | #include "squashfs_fs_sb.h" |
40 | #include "squashfs_fs_i.h" | ||
41 | #include "squashfs.h" | 40 | #include "squashfs.h" |
42 | 41 | ||
43 | /* | 42 | /* |
@@ -67,27 +66,37 @@ int squashfs_get_id(struct super_block *sb, unsigned int index, | |||
67 | * Read uncompressed id lookup table indexes from disk into memory | 66 | * Read uncompressed id lookup table indexes from disk into memory |
68 | */ | 67 | */ |
69 | __le64 *squashfs_read_id_index_table(struct super_block *sb, | 68 | __le64 *squashfs_read_id_index_table(struct super_block *sb, |
70 | u64 id_table_start, unsigned short no_ids) | 69 | u64 id_table_start, u64 next_table, unsigned short no_ids) |
71 | { | 70 | { |
72 | unsigned int length = SQUASHFS_ID_BLOCK_BYTES(no_ids); | 71 | unsigned int length = SQUASHFS_ID_BLOCK_BYTES(no_ids); |
73 | __le64 *id_table; | 72 | __le64 *table; |
74 | int err; | ||
75 | 73 | ||
76 | TRACE("In read_id_index_table, length %d\n", length); | 74 | TRACE("In read_id_index_table, length %d\n", length); |
77 | 75 | ||
78 | /* Allocate id lookup table indexes */ | 76 | /* Sanity check values */ |
79 | id_table = kmalloc(length, GFP_KERNEL); | 77 | |
80 | if (id_table == NULL) { | 78 | /* there should always be at least one id */ |
81 | ERROR("Failed to allocate id index table\n"); | 79 | if (no_ids == 0) |
82 | return ERR_PTR(-ENOMEM); | 80 | return ERR_PTR(-EINVAL); |
83 | } | 81 | |
82 | /* | ||
83 | * length bytes should not extend into the next table - this check | ||
84 | * also traps instances where id_table_start is incorrectly larger | ||
85 | * than the next table start | ||
86 | */ | ||
87 | if (id_table_start + length > next_table) | ||
88 | return ERR_PTR(-EINVAL); | ||
89 | |||
90 | table = squashfs_read_table(sb, id_table_start, length); | ||
84 | 91 | ||
85 | err = squashfs_read_table(sb, id_table, id_table_start, length); | 92 | /* |
86 | if (err < 0) { | 93 | * table[0] points to the first id lookup table metadata block, this |
87 | ERROR("unable to read id index table\n"); | 94 | * should be less than id_table_start |
88 | kfree(id_table); | 95 | */ |
89 | return ERR_PTR(err); | 96 | if (!IS_ERR(table) && le64_to_cpu(table[0]) >= id_table_start) { |
97 | kfree(table); | ||
98 | return ERR_PTR(-EINVAL); | ||
90 | } | 99 | } |
91 | 100 | ||
92 | return id_table; | 101 | return table; |
93 | } | 102 | } |
diff --git a/fs/squashfs/inode.c b/fs/squashfs/inode.c index 62e63ad25075..04bebcaa2373 100644 --- a/fs/squashfs/inode.c +++ b/fs/squashfs/inode.c | |||
@@ -2,7 +2,7 @@ | |||
2 | * Squashfs - a compressed read only filesystem for Linux | 2 | * Squashfs - a compressed read only filesystem for Linux |
3 | * | 3 | * |
4 | * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008 | 4 | * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008 |
5 | * Phillip Lougher <phillip@lougher.demon.co.uk> | 5 | * Phillip Lougher <phillip@squashfs.org.uk> |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or | 7 | * This program is free software; you can redistribute it and/or |
8 | * modify it under the terms of the GNU General Public License | 8 | * modify it under the terms of the GNU General Public License |
diff --git a/fs/squashfs/lzo_wrapper.c b/fs/squashfs/lzo_wrapper.c index 5d87789bf1c1..00f4dfc5f088 100644 --- a/fs/squashfs/lzo_wrapper.c +++ b/fs/squashfs/lzo_wrapper.c | |||
@@ -29,7 +29,6 @@ | |||
29 | 29 | ||
30 | #include "squashfs_fs.h" | 30 | #include "squashfs_fs.h" |
31 | #include "squashfs_fs_sb.h" | 31 | #include "squashfs_fs_sb.h" |
32 | #include "squashfs_fs_i.h" | ||
33 | #include "squashfs.h" | 32 | #include "squashfs.h" |
34 | #include "decompressor.h" | 33 | #include "decompressor.h" |
35 | 34 | ||
@@ -38,7 +37,7 @@ struct squashfs_lzo { | |||
38 | void *output; | 37 | void *output; |
39 | }; | 38 | }; |
40 | 39 | ||
41 | static void *lzo_init(struct squashfs_sb_info *msblk) | 40 | static void *lzo_init(struct squashfs_sb_info *msblk, void *buff, int len) |
42 | { | 41 | { |
43 | int block_size = max_t(int, msblk->block_size, SQUASHFS_METADATA_SIZE); | 42 | int block_size = max_t(int, msblk->block_size, SQUASHFS_METADATA_SIZE); |
44 | 43 | ||
@@ -59,7 +58,7 @@ failed2: | |||
59 | failed: | 58 | failed: |
60 | ERROR("Failed to allocate lzo workspace\n"); | 59 | ERROR("Failed to allocate lzo workspace\n"); |
61 | kfree(stream); | 60 | kfree(stream); |
62 | return NULL; | 61 | return ERR_PTR(-ENOMEM); |
63 | } | 62 | } |
64 | 63 | ||
65 | 64 | ||
diff --git a/fs/squashfs/namei.c b/fs/squashfs/namei.c index 7a9464d08cf6..4bc63ac64bc0 100644 --- a/fs/squashfs/namei.c +++ b/fs/squashfs/namei.c | |||
@@ -2,7 +2,7 @@ | |||
2 | * Squashfs - a compressed read only filesystem for Linux | 2 | * Squashfs - a compressed read only filesystem for Linux |
3 | * | 3 | * |
4 | * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008 | 4 | * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008 |
5 | * Phillip Lougher <phillip@lougher.demon.co.uk> | 5 | * Phillip Lougher <phillip@squashfs.org.uk> |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or | 7 | * This program is free software; you can redistribute it and/or |
8 | * modify it under the terms of the GNU General Public License | 8 | * modify it under the terms of the GNU General Public License |
@@ -176,6 +176,11 @@ static struct dentry *squashfs_lookup(struct inode *dir, struct dentry *dentry, | |||
176 | length += sizeof(dirh); | 176 | length += sizeof(dirh); |
177 | 177 | ||
178 | dir_count = le32_to_cpu(dirh.count) + 1; | 178 | dir_count = le32_to_cpu(dirh.count) + 1; |
179 | |||
180 | /* dir_count should never be larger than 256 */ | ||
181 | if (dir_count > 256) | ||
182 | goto data_error; | ||
183 | |||
179 | while (dir_count--) { | 184 | while (dir_count--) { |
180 | /* | 185 | /* |
181 | * Read directory entry. | 186 | * Read directory entry. |
@@ -187,6 +192,10 @@ static struct dentry *squashfs_lookup(struct inode *dir, struct dentry *dentry, | |||
187 | 192 | ||
188 | size = le16_to_cpu(dire->size) + 1; | 193 | size = le16_to_cpu(dire->size) + 1; |
189 | 194 | ||
195 | /* size should never be larger than SQUASHFS_NAME_LEN */ | ||
196 | if (size > SQUASHFS_NAME_LEN) | ||
197 | goto data_error; | ||
198 | |||
190 | err = squashfs_read_metadata(dir->i_sb, dire->name, | 199 | err = squashfs_read_metadata(dir->i_sb, dire->name, |
191 | &block, &offset, size); | 200 | &block, &offset, size); |
192 | if (err < 0) | 201 | if (err < 0) |
@@ -228,6 +237,9 @@ exit_lookup: | |||
228 | d_add(dentry, inode); | 237 | d_add(dentry, inode); |
229 | return ERR_PTR(0); | 238 | return ERR_PTR(0); |
230 | 239 | ||
240 | data_error: | ||
241 | err = -EIO; | ||
242 | |||
231 | read_failure: | 243 | read_failure: |
232 | ERROR("Unable to read directory block [%llx:%x]\n", | 244 | ERROR("Unable to read directory block [%llx:%x]\n", |
233 | squashfs_i(dir)->start + msblk->directory_table, | 245 | squashfs_i(dir)->start + msblk->directory_table, |
diff --git a/fs/squashfs/squashfs.h b/fs/squashfs/squashfs.h index 5d45569d5f72..e3be6a71cfa7 100644 --- a/fs/squashfs/squashfs.h +++ b/fs/squashfs/squashfs.h | |||
@@ -2,7 +2,7 @@ | |||
2 | * Squashfs - a compressed read only filesystem for Linux | 2 | * Squashfs - a compressed read only filesystem for Linux |
3 | * | 3 | * |
4 | * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008 | 4 | * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008 |
5 | * Phillip Lougher <phillip@lougher.demon.co.uk> | 5 | * Phillip Lougher <phillip@squashfs.org.uk> |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or | 7 | * This program is free software; you can redistribute it and/or |
8 | * modify it under the terms of the GNU General Public License | 8 | * modify it under the terms of the GNU General Public License |
@@ -27,11 +27,6 @@ | |||
27 | 27 | ||
28 | #define WARNING(s, args...) pr_warning("SQUASHFS: "s, ## args) | 28 | #define WARNING(s, args...) pr_warning("SQUASHFS: "s, ## args) |
29 | 29 | ||
30 | static inline struct squashfs_inode_info *squashfs_i(struct inode *inode) | ||
31 | { | ||
32 | return list_entry(inode, struct squashfs_inode_info, vfs_inode); | ||
33 | } | ||
34 | |||
35 | /* block.c */ | 30 | /* block.c */ |
36 | extern int squashfs_read_data(struct super_block *, void **, u64, int, u64 *, | 31 | extern int squashfs_read_data(struct super_block *, void **, u64, int, u64 *, |
37 | int, int); | 32 | int, int); |
@@ -49,23 +44,24 @@ extern struct squashfs_cache_entry *squashfs_get_fragment(struct super_block *, | |||
49 | u64, int); | 44 | u64, int); |
50 | extern struct squashfs_cache_entry *squashfs_get_datablock(struct super_block *, | 45 | extern struct squashfs_cache_entry *squashfs_get_datablock(struct super_block *, |
51 | u64, int); | 46 | u64, int); |
52 | extern int squashfs_read_table(struct super_block *, void *, u64, int); | 47 | extern void *squashfs_read_table(struct super_block *, u64, int); |
53 | 48 | ||
54 | /* decompressor.c */ | 49 | /* decompressor.c */ |
55 | extern const struct squashfs_decompressor *squashfs_lookup_decompressor(int); | 50 | extern const struct squashfs_decompressor *squashfs_lookup_decompressor(int); |
51 | extern void *squashfs_decompressor_init(struct super_block *, unsigned short); | ||
56 | 52 | ||
57 | /* export.c */ | 53 | /* export.c */ |
58 | extern __le64 *squashfs_read_inode_lookup_table(struct super_block *, u64, | 54 | extern __le64 *squashfs_read_inode_lookup_table(struct super_block *, u64, u64, |
59 | unsigned int); | 55 | unsigned int); |
60 | 56 | ||
61 | /* fragment.c */ | 57 | /* fragment.c */ |
62 | extern int squashfs_frag_lookup(struct super_block *, unsigned int, u64 *); | 58 | extern int squashfs_frag_lookup(struct super_block *, unsigned int, u64 *); |
63 | extern __le64 *squashfs_read_fragment_index_table(struct super_block *, | 59 | extern __le64 *squashfs_read_fragment_index_table(struct super_block *, |
64 | u64, unsigned int); | 60 | u64, u64, unsigned int); |
65 | 61 | ||
66 | /* id.c */ | 62 | /* id.c */ |
67 | extern int squashfs_get_id(struct super_block *, unsigned int, unsigned int *); | 63 | extern int squashfs_get_id(struct super_block *, unsigned int, unsigned int *); |
68 | extern __le64 *squashfs_read_id_index_table(struct super_block *, u64, | 64 | extern __le64 *squashfs_read_id_index_table(struct super_block *, u64, u64, |
69 | unsigned short); | 65 | unsigned short); |
70 | 66 | ||
71 | /* inode.c */ | 67 | /* inode.c */ |
@@ -104,6 +100,3 @@ extern const struct xattr_handler *squashfs_xattr_handlers[]; | |||
104 | 100 | ||
105 | /* zlib_wrapper.c */ | 101 | /* zlib_wrapper.c */ |
106 | extern const struct squashfs_decompressor squashfs_zlib_comp_ops; | 102 | extern const struct squashfs_decompressor squashfs_zlib_comp_ops; |
107 | |||
108 | /* lzo_wrapper.c */ | ||
109 | extern const struct squashfs_decompressor squashfs_lzo_comp_ops; | ||
diff --git a/fs/squashfs/squashfs_fs.h b/fs/squashfs/squashfs_fs.h index c5137fc9ab11..b4a4e539a08c 100644 --- a/fs/squashfs/squashfs_fs.h +++ b/fs/squashfs/squashfs_fs.h | |||
@@ -4,7 +4,7 @@ | |||
4 | * Squashfs | 4 | * Squashfs |
5 | * | 5 | * |
6 | * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008 | 6 | * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008 |
7 | * Phillip Lougher <phillip@lougher.demon.co.uk> | 7 | * Phillip Lougher <phillip@squashfs.org.uk> |
8 | * | 8 | * |
9 | * This program is free software; you can redistribute it and/or | 9 | * This program is free software; you can redistribute it and/or |
10 | * modify it under the terms of the GNU General Public License | 10 | * modify it under the terms of the GNU General Public License |
@@ -57,6 +57,7 @@ | |||
57 | #define SQUASHFS_ALWAYS_FRAG 5 | 57 | #define SQUASHFS_ALWAYS_FRAG 5 |
58 | #define SQUASHFS_DUPLICATE 6 | 58 | #define SQUASHFS_DUPLICATE 6 |
59 | #define SQUASHFS_EXPORT 7 | 59 | #define SQUASHFS_EXPORT 7 |
60 | #define SQUASHFS_COMP_OPT 10 | ||
60 | 61 | ||
61 | #define SQUASHFS_BIT(flag, bit) ((flag >> bit) & 1) | 62 | #define SQUASHFS_BIT(flag, bit) ((flag >> bit) & 1) |
62 | 63 | ||
@@ -81,6 +82,9 @@ | |||
81 | #define SQUASHFS_EXPORTABLE(flags) SQUASHFS_BIT(flags, \ | 82 | #define SQUASHFS_EXPORTABLE(flags) SQUASHFS_BIT(flags, \ |
82 | SQUASHFS_EXPORT) | 83 | SQUASHFS_EXPORT) |
83 | 84 | ||
85 | #define SQUASHFS_COMP_OPTS(flags) SQUASHFS_BIT(flags, \ | ||
86 | SQUASHFS_COMP_OPT) | ||
87 | |||
84 | /* Max number of types and file types */ | 88 | /* Max number of types and file types */ |
85 | #define SQUASHFS_DIR_TYPE 1 | 89 | #define SQUASHFS_DIR_TYPE 1 |
86 | #define SQUASHFS_REG_TYPE 2 | 90 | #define SQUASHFS_REG_TYPE 2 |
@@ -238,6 +242,7 @@ struct meta_index { | |||
238 | #define ZLIB_COMPRESSION 1 | 242 | #define ZLIB_COMPRESSION 1 |
239 | #define LZMA_COMPRESSION 2 | 243 | #define LZMA_COMPRESSION 2 |
240 | #define LZO_COMPRESSION 3 | 244 | #define LZO_COMPRESSION 3 |
245 | #define XZ_COMPRESSION 4 | ||
241 | 246 | ||
242 | struct squashfs_super_block { | 247 | struct squashfs_super_block { |
243 | __le32 s_magic; | 248 | __le32 s_magic; |
diff --git a/fs/squashfs/squashfs_fs_i.h b/fs/squashfs/squashfs_fs_i.h index d3e3a37f28a1..73588e7700ed 100644 --- a/fs/squashfs/squashfs_fs_i.h +++ b/fs/squashfs/squashfs_fs_i.h | |||
@@ -4,7 +4,7 @@ | |||
4 | * Squashfs | 4 | * Squashfs |
5 | * | 5 | * |
6 | * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008 | 6 | * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008 |
7 | * Phillip Lougher <phillip@lougher.demon.co.uk> | 7 | * Phillip Lougher <phillip@squashfs.org.uk> |
8 | * | 8 | * |
9 | * This program is free software; you can redistribute it and/or | 9 | * This program is free software; you can redistribute it and/or |
10 | * modify it under the terms of the GNU General Public License | 10 | * modify it under the terms of the GNU General Public License |
@@ -45,4 +45,10 @@ struct squashfs_inode_info { | |||
45 | }; | 45 | }; |
46 | struct inode vfs_inode; | 46 | struct inode vfs_inode; |
47 | }; | 47 | }; |
48 | |||
49 | |||
50 | static inline struct squashfs_inode_info *squashfs_i(struct inode *inode) | ||
51 | { | ||
52 | return list_entry(inode, struct squashfs_inode_info, vfs_inode); | ||
53 | } | ||
48 | #endif | 54 | #endif |
diff --git a/fs/squashfs/squashfs_fs_sb.h b/fs/squashfs/squashfs_fs_sb.h index d9037a5215f0..651f0b31d296 100644 --- a/fs/squashfs/squashfs_fs_sb.h +++ b/fs/squashfs/squashfs_fs_sb.h | |||
@@ -4,7 +4,7 @@ | |||
4 | * Squashfs | 4 | * Squashfs |
5 | * | 5 | * |
6 | * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008 | 6 | * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008 |
7 | * Phillip Lougher <phillip@lougher.demon.co.uk> | 7 | * Phillip Lougher <phillip@squashfs.org.uk> |
8 | * | 8 | * |
9 | * This program is free software; you can redistribute it and/or | 9 | * This program is free software; you can redistribute it and/or |
10 | * modify it under the terms of the GNU General Public License | 10 | * modify it under the terms of the GNU General Public License |
diff --git a/fs/squashfs/super.c b/fs/squashfs/super.c index 88b4f8606652..7438850c62d0 100644 --- a/fs/squashfs/super.c +++ b/fs/squashfs/super.c | |||
@@ -2,7 +2,7 @@ | |||
2 | * Squashfs - a compressed read only filesystem for Linux | 2 | * Squashfs - a compressed read only filesystem for Linux |
3 | * | 3 | * |
4 | * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008 | 4 | * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008 |
5 | * Phillip Lougher <phillip@lougher.demon.co.uk> | 5 | * Phillip Lougher <phillip@squashfs.org.uk> |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or | 7 | * This program is free software; you can redistribute it and/or |
8 | * modify it under the terms of the GNU General Public License | 8 | * modify it under the terms of the GNU General Public License |
@@ -30,7 +30,6 @@ | |||
30 | #include <linux/fs.h> | 30 | #include <linux/fs.h> |
31 | #include <linux/vfs.h> | 31 | #include <linux/vfs.h> |
32 | #include <linux/slab.h> | 32 | #include <linux/slab.h> |
33 | #include <linux/smp_lock.h> | ||
34 | #include <linux/mutex.h> | 33 | #include <linux/mutex.h> |
35 | #include <linux/pagemap.h> | 34 | #include <linux/pagemap.h> |
36 | #include <linux/init.h> | 35 | #include <linux/init.h> |
@@ -84,7 +83,7 @@ static int squashfs_fill_super(struct super_block *sb, void *data, int silent) | |||
84 | long long root_inode; | 83 | long long root_inode; |
85 | unsigned short flags; | 84 | unsigned short flags; |
86 | unsigned int fragments; | 85 | unsigned int fragments; |
87 | u64 lookup_table_start, xattr_id_table_start; | 86 | u64 lookup_table_start, xattr_id_table_start, next_table; |
88 | int err; | 87 | int err; |
89 | 88 | ||
90 | TRACE("Entered squashfs_fill_superblock\n"); | 89 | TRACE("Entered squashfs_fill_superblock\n"); |
@@ -96,12 +95,6 @@ static int squashfs_fill_super(struct super_block *sb, void *data, int silent) | |||
96 | } | 95 | } |
97 | msblk = sb->s_fs_info; | 96 | msblk = sb->s_fs_info; |
98 | 97 | ||
99 | sblk = kzalloc(sizeof(*sblk), GFP_KERNEL); | ||
100 | if (sblk == NULL) { | ||
101 | ERROR("Failed to allocate squashfs_super_block\n"); | ||
102 | goto failure; | ||
103 | } | ||
104 | |||
105 | msblk->devblksize = sb_min_blocksize(sb, BLOCK_SIZE); | 98 | msblk->devblksize = sb_min_blocksize(sb, BLOCK_SIZE); |
106 | msblk->devblksize_log2 = ffz(~msblk->devblksize); | 99 | msblk->devblksize_log2 = ffz(~msblk->devblksize); |
107 | 100 | ||
@@ -115,10 +108,12 @@ static int squashfs_fill_super(struct super_block *sb, void *data, int silent) | |||
115 | * of bytes_used) we need to set it to an initial sensible dummy value | 108 | * of bytes_used) we need to set it to an initial sensible dummy value |
116 | */ | 109 | */ |
117 | msblk->bytes_used = sizeof(*sblk); | 110 | msblk->bytes_used = sizeof(*sblk); |
118 | err = squashfs_read_table(sb, sblk, SQUASHFS_START, sizeof(*sblk)); | 111 | sblk = squashfs_read_table(sb, SQUASHFS_START, sizeof(*sblk)); |
119 | 112 | ||
120 | if (err < 0) { | 113 | if (IS_ERR(sblk)) { |
121 | ERROR("unable to read squashfs_super_block\n"); | 114 | ERROR("unable to read squashfs_super_block\n"); |
115 | err = PTR_ERR(sblk); | ||
116 | sblk = NULL; | ||
122 | goto failed_mount; | 117 | goto failed_mount; |
123 | } | 118 | } |
124 | 119 | ||
@@ -200,10 +195,6 @@ static int squashfs_fill_super(struct super_block *sb, void *data, int silent) | |||
200 | 195 | ||
201 | err = -ENOMEM; | 196 | err = -ENOMEM; |
202 | 197 | ||
203 | msblk->stream = squashfs_decompressor_init(msblk); | ||
204 | if (msblk->stream == NULL) | ||
205 | goto failed_mount; | ||
206 | |||
207 | msblk->block_cache = squashfs_cache_init("metadata", | 198 | msblk->block_cache = squashfs_cache_init("metadata", |
208 | SQUASHFS_CACHED_BLKS, SQUASHFS_METADATA_SIZE); | 199 | SQUASHFS_CACHED_BLKS, SQUASHFS_METADATA_SIZE); |
209 | if (msblk->block_cache == NULL) | 200 | if (msblk->block_cache == NULL) |
@@ -216,18 +207,68 @@ static int squashfs_fill_super(struct super_block *sb, void *data, int silent) | |||
216 | goto failed_mount; | 207 | goto failed_mount; |
217 | } | 208 | } |
218 | 209 | ||
210 | msblk->stream = squashfs_decompressor_init(sb, flags); | ||
211 | if (IS_ERR(msblk->stream)) { | ||
212 | err = PTR_ERR(msblk->stream); | ||
213 | msblk->stream = NULL; | ||
214 | goto failed_mount; | ||
215 | } | ||
216 | |||
217 | /* Handle xattrs */ | ||
218 | sb->s_xattr = squashfs_xattr_handlers; | ||
219 | xattr_id_table_start = le64_to_cpu(sblk->xattr_id_table_start); | ||
220 | if (xattr_id_table_start == SQUASHFS_INVALID_BLK) { | ||
221 | next_table = msblk->bytes_used; | ||
222 | goto allocate_id_index_table; | ||
223 | } | ||
224 | |||
225 | /* Allocate and read xattr id lookup table */ | ||
226 | msblk->xattr_id_table = squashfs_read_xattr_id_table(sb, | ||
227 | xattr_id_table_start, &msblk->xattr_table, &msblk->xattr_ids); | ||
228 | if (IS_ERR(msblk->xattr_id_table)) { | ||
229 | ERROR("unable to read xattr id index table\n"); | ||
230 | err = PTR_ERR(msblk->xattr_id_table); | ||
231 | msblk->xattr_id_table = NULL; | ||
232 | if (err != -ENOTSUPP) | ||
233 | goto failed_mount; | ||
234 | } | ||
235 | next_table = msblk->xattr_table; | ||
236 | |||
237 | allocate_id_index_table: | ||
219 | /* Allocate and read id index table */ | 238 | /* Allocate and read id index table */ |
220 | msblk->id_table = squashfs_read_id_index_table(sb, | 239 | msblk->id_table = squashfs_read_id_index_table(sb, |
221 | le64_to_cpu(sblk->id_table_start), le16_to_cpu(sblk->no_ids)); | 240 | le64_to_cpu(sblk->id_table_start), next_table, |
241 | le16_to_cpu(sblk->no_ids)); | ||
222 | if (IS_ERR(msblk->id_table)) { | 242 | if (IS_ERR(msblk->id_table)) { |
243 | ERROR("unable to read id index table\n"); | ||
223 | err = PTR_ERR(msblk->id_table); | 244 | err = PTR_ERR(msblk->id_table); |
224 | msblk->id_table = NULL; | 245 | msblk->id_table = NULL; |
225 | goto failed_mount; | 246 | goto failed_mount; |
226 | } | 247 | } |
248 | next_table = le64_to_cpu(msblk->id_table[0]); | ||
249 | |||
250 | /* Handle inode lookup table */ | ||
251 | lookup_table_start = le64_to_cpu(sblk->lookup_table_start); | ||
252 | if (lookup_table_start == SQUASHFS_INVALID_BLK) | ||
253 | goto handle_fragments; | ||
254 | |||
255 | /* Allocate and read inode lookup table */ | ||
256 | msblk->inode_lookup_table = squashfs_read_inode_lookup_table(sb, | ||
257 | lookup_table_start, next_table, msblk->inodes); | ||
258 | if (IS_ERR(msblk->inode_lookup_table)) { | ||
259 | ERROR("unable to read inode lookup table\n"); | ||
260 | err = PTR_ERR(msblk->inode_lookup_table); | ||
261 | msblk->inode_lookup_table = NULL; | ||
262 | goto failed_mount; | ||
263 | } | ||
264 | next_table = le64_to_cpu(msblk->inode_lookup_table[0]); | ||
265 | |||
266 | sb->s_export_op = &squashfs_export_ops; | ||
227 | 267 | ||
268 | handle_fragments: | ||
228 | fragments = le32_to_cpu(sblk->fragments); | 269 | fragments = le32_to_cpu(sblk->fragments); |
229 | if (fragments == 0) | 270 | if (fragments == 0) |
230 | goto allocate_lookup_table; | 271 | goto check_directory_table; |
231 | 272 | ||
232 | msblk->fragment_cache = squashfs_cache_init("fragment", | 273 | msblk->fragment_cache = squashfs_cache_init("fragment", |
233 | SQUASHFS_CACHED_FRAGMENTS, msblk->block_size); | 274 | SQUASHFS_CACHED_FRAGMENTS, msblk->block_size); |
@@ -238,45 +279,29 @@ static int squashfs_fill_super(struct super_block *sb, void *data, int silent) | |||
238 | 279 | ||
239 | /* Allocate and read fragment index table */ | 280 | /* Allocate and read fragment index table */ |
240 | msblk->fragment_index = squashfs_read_fragment_index_table(sb, | 281 | msblk->fragment_index = squashfs_read_fragment_index_table(sb, |
241 | le64_to_cpu(sblk->fragment_table_start), fragments); | 282 | le64_to_cpu(sblk->fragment_table_start), next_table, fragments); |
242 | if (IS_ERR(msblk->fragment_index)) { | 283 | if (IS_ERR(msblk->fragment_index)) { |
284 | ERROR("unable to read fragment index table\n"); | ||
243 | err = PTR_ERR(msblk->fragment_index); | 285 | err = PTR_ERR(msblk->fragment_index); |
244 | msblk->fragment_index = NULL; | 286 | msblk->fragment_index = NULL; |
245 | goto failed_mount; | 287 | goto failed_mount; |
246 | } | 288 | } |
289 | next_table = le64_to_cpu(msblk->fragment_index[0]); | ||
247 | 290 | ||
248 | allocate_lookup_table: | 291 | check_directory_table: |
249 | lookup_table_start = le64_to_cpu(sblk->lookup_table_start); | 292 | /* Sanity check directory_table */ |
250 | if (lookup_table_start == SQUASHFS_INVALID_BLK) | 293 | if (msblk->directory_table >= next_table) { |
251 | goto allocate_xattr_table; | 294 | err = -EINVAL; |
252 | |||
253 | /* Allocate and read inode lookup table */ | ||
254 | msblk->inode_lookup_table = squashfs_read_inode_lookup_table(sb, | ||
255 | lookup_table_start, msblk->inodes); | ||
256 | if (IS_ERR(msblk->inode_lookup_table)) { | ||
257 | err = PTR_ERR(msblk->inode_lookup_table); | ||
258 | msblk->inode_lookup_table = NULL; | ||
259 | goto failed_mount; | 295 | goto failed_mount; |
260 | } | 296 | } |
261 | 297 | ||
262 | sb->s_export_op = &squashfs_export_ops; | 298 | /* Sanity check inode_table */ |
263 | 299 | if (msblk->inode_table >= msblk->directory_table) { | |
264 | allocate_xattr_table: | 300 | err = -EINVAL; |
265 | sb->s_xattr = squashfs_xattr_handlers; | 301 | goto failed_mount; |
266 | xattr_id_table_start = le64_to_cpu(sblk->xattr_id_table_start); | ||
267 | if (xattr_id_table_start == SQUASHFS_INVALID_BLK) | ||
268 | goto allocate_root; | ||
269 | |||
270 | /* Allocate and read xattr id lookup table */ | ||
271 | msblk->xattr_id_table = squashfs_read_xattr_id_table(sb, | ||
272 | xattr_id_table_start, &msblk->xattr_table, &msblk->xattr_ids); | ||
273 | if (IS_ERR(msblk->xattr_id_table)) { | ||
274 | err = PTR_ERR(msblk->xattr_id_table); | ||
275 | msblk->xattr_id_table = NULL; | ||
276 | if (err != -ENOTSUPP) | ||
277 | goto failed_mount; | ||
278 | } | 302 | } |
279 | allocate_root: | 303 | |
304 | /* allocate root */ | ||
280 | root = new_inode(sb); | 305 | root = new_inode(sb); |
281 | if (!root) { | 306 | if (!root) { |
282 | err = -ENOMEM; | 307 | err = -ENOMEM; |
@@ -316,11 +341,6 @@ failed_mount: | |||
316 | sb->s_fs_info = NULL; | 341 | sb->s_fs_info = NULL; |
317 | kfree(sblk); | 342 | kfree(sblk); |
318 | return err; | 343 | return err; |
319 | |||
320 | failure: | ||
321 | kfree(sb->s_fs_info); | ||
322 | sb->s_fs_info = NULL; | ||
323 | return -ENOMEM; | ||
324 | } | 344 | } |
325 | 345 | ||
326 | 346 | ||
@@ -354,8 +374,6 @@ static int squashfs_remount(struct super_block *sb, int *flags, char *data) | |||
354 | 374 | ||
355 | static void squashfs_put_super(struct super_block *sb) | 375 | static void squashfs_put_super(struct super_block *sb) |
356 | { | 376 | { |
357 | lock_kernel(); | ||
358 | |||
359 | if (sb->s_fs_info) { | 377 | if (sb->s_fs_info) { |
360 | struct squashfs_sb_info *sbi = sb->s_fs_info; | 378 | struct squashfs_sb_info *sbi = sb->s_fs_info; |
361 | squashfs_cache_delete(sbi->block_cache); | 379 | squashfs_cache_delete(sbi->block_cache); |
@@ -370,17 +388,13 @@ static void squashfs_put_super(struct super_block *sb) | |||
370 | kfree(sb->s_fs_info); | 388 | kfree(sb->s_fs_info); |
371 | sb->s_fs_info = NULL; | 389 | sb->s_fs_info = NULL; |
372 | } | 390 | } |
373 | |||
374 | unlock_kernel(); | ||
375 | } | 391 | } |
376 | 392 | ||
377 | 393 | ||
378 | static int squashfs_get_sb(struct file_system_type *fs_type, int flags, | 394 | static struct dentry *squashfs_mount(struct file_system_type *fs_type, |
379 | const char *dev_name, void *data, | 395 | int flags, const char *dev_name, void *data) |
380 | struct vfsmount *mnt) | ||
381 | { | 396 | { |
382 | return get_sb_bdev(fs_type, flags, dev_name, data, squashfs_fill_super, | 397 | return mount_bdev(fs_type, flags, dev_name, data, squashfs_fill_super); |
383 | mnt); | ||
384 | } | 398 | } |
385 | 399 | ||
386 | 400 | ||
@@ -447,16 +461,23 @@ static struct inode *squashfs_alloc_inode(struct super_block *sb) | |||
447 | } | 461 | } |
448 | 462 | ||
449 | 463 | ||
450 | static void squashfs_destroy_inode(struct inode *inode) | 464 | static void squashfs_i_callback(struct rcu_head *head) |
451 | { | 465 | { |
466 | struct inode *inode = container_of(head, struct inode, i_rcu); | ||
467 | INIT_LIST_HEAD(&inode->i_dentry); | ||
452 | kmem_cache_free(squashfs_inode_cachep, squashfs_i(inode)); | 468 | kmem_cache_free(squashfs_inode_cachep, squashfs_i(inode)); |
453 | } | 469 | } |
454 | 470 | ||
471 | static void squashfs_destroy_inode(struct inode *inode) | ||
472 | { | ||
473 | call_rcu(&inode->i_rcu, squashfs_i_callback); | ||
474 | } | ||
475 | |||
455 | 476 | ||
456 | static struct file_system_type squashfs_fs_type = { | 477 | static struct file_system_type squashfs_fs_type = { |
457 | .owner = THIS_MODULE, | 478 | .owner = THIS_MODULE, |
458 | .name = "squashfs", | 479 | .name = "squashfs", |
459 | .get_sb = squashfs_get_sb, | 480 | .mount = squashfs_mount, |
460 | .kill_sb = kill_block_super, | 481 | .kill_sb = kill_block_super, |
461 | .fs_flags = FS_REQUIRES_DEV | 482 | .fs_flags = FS_REQUIRES_DEV |
462 | }; | 483 | }; |
@@ -472,5 +493,5 @@ static const struct super_operations squashfs_super_ops = { | |||
472 | module_init(init_squashfs_fs); | 493 | module_init(init_squashfs_fs); |
473 | module_exit(exit_squashfs_fs); | 494 | module_exit(exit_squashfs_fs); |
474 | MODULE_DESCRIPTION("squashfs 4.0, a compressed read-only filesystem"); | 495 | MODULE_DESCRIPTION("squashfs 4.0, a compressed read-only filesystem"); |
475 | MODULE_AUTHOR("Phillip Lougher <phillip@lougher.demon.co.uk>"); | 496 | MODULE_AUTHOR("Phillip Lougher <phillip@squashfs.org.uk>"); |
476 | MODULE_LICENSE("GPL"); | 497 | MODULE_LICENSE("GPL"); |
diff --git a/fs/squashfs/symlink.c b/fs/squashfs/symlink.c index ec86434921e1..1191817264cc 100644 --- a/fs/squashfs/symlink.c +++ b/fs/squashfs/symlink.c | |||
@@ -2,7 +2,7 @@ | |||
2 | * Squashfs - a compressed read only filesystem for Linux | 2 | * Squashfs - a compressed read only filesystem for Linux |
3 | * | 3 | * |
4 | * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008 | 4 | * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008 |
5 | * Phillip Lougher <phillip@lougher.demon.co.uk> | 5 | * Phillip Lougher <phillip@squashfs.org.uk> |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or | 7 | * This program is free software; you can redistribute it and/or |
8 | * modify it under the terms of the GNU General Public License | 8 | * modify it under the terms of the GNU General Public License |
diff --git a/fs/squashfs/xattr.c b/fs/squashfs/xattr.c index 652b8541f9c6..92fcde7b4d61 100644 --- a/fs/squashfs/xattr.c +++ b/fs/squashfs/xattr.c | |||
@@ -2,7 +2,7 @@ | |||
2 | * Squashfs - a compressed read only filesystem for Linux | 2 | * Squashfs - a compressed read only filesystem for Linux |
3 | * | 3 | * |
4 | * Copyright (c) 2010 | 4 | * Copyright (c) 2010 |
5 | * Phillip Lougher <phillip@lougher.demon.co.uk> | 5 | * Phillip Lougher <phillip@squashfs.org.uk> |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or | 7 | * This program is free software; you can redistribute it and/or |
8 | * modify it under the terms of the GNU General Public License | 8 | * modify it under the terms of the GNU General Public License |
@@ -158,17 +158,18 @@ static int squashfs_xattr_get(struct inode *inode, int name_index, | |||
158 | strncmp(target, name, name_size) == 0) { | 158 | strncmp(target, name, name_size) == 0) { |
159 | /* found xattr */ | 159 | /* found xattr */ |
160 | if (type & SQUASHFS_XATTR_VALUE_OOL) { | 160 | if (type & SQUASHFS_XATTR_VALUE_OOL) { |
161 | __le64 xattr; | 161 | __le64 xattr_val; |
162 | u64 xattr; | ||
162 | /* val is a reference to the real location */ | 163 | /* val is a reference to the real location */ |
163 | err = squashfs_read_metadata(sb, &val, &start, | 164 | err = squashfs_read_metadata(sb, &val, &start, |
164 | &offset, sizeof(val)); | 165 | &offset, sizeof(val)); |
165 | if (err < 0) | 166 | if (err < 0) |
166 | goto failed; | 167 | goto failed; |
167 | err = squashfs_read_metadata(sb, &xattr, &start, | 168 | err = squashfs_read_metadata(sb, &xattr_val, |
168 | &offset, sizeof(xattr)); | 169 | &start, &offset, sizeof(xattr_val)); |
169 | if (err < 0) | 170 | if (err < 0) |
170 | goto failed; | 171 | goto failed; |
171 | xattr = le64_to_cpu(xattr); | 172 | xattr = le64_to_cpu(xattr_val); |
172 | start = SQUASHFS_XATTR_BLK(xattr) + | 173 | start = SQUASHFS_XATTR_BLK(xattr) + |
173 | msblk->xattr_table; | 174 | msblk->xattr_table; |
174 | offset = SQUASHFS_XATTR_OFFSET(xattr); | 175 | offset = SQUASHFS_XATTR_OFFSET(xattr); |
diff --git a/fs/squashfs/xattr.h b/fs/squashfs/xattr.h index 49fe0d719fbf..c83f5d9ec125 100644 --- a/fs/squashfs/xattr.h +++ b/fs/squashfs/xattr.h | |||
@@ -2,7 +2,7 @@ | |||
2 | * Squashfs - a compressed read only filesystem for Linux | 2 | * Squashfs - a compressed read only filesystem for Linux |
3 | * | 3 | * |
4 | * Copyright (c) 2010 | 4 | * Copyright (c) 2010 |
5 | * Phillip Lougher <phillip@lougher.demon.co.uk> | 5 | * Phillip Lougher <phillip@squashfs.org.uk> |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or | 7 | * This program is free software; you can redistribute it and/or |
8 | * modify it under the terms of the GNU General Public License | 8 | * modify it under the terms of the GNU General Public License |
@@ -25,17 +25,18 @@ | |||
25 | extern __le64 *squashfs_read_xattr_id_table(struct super_block *, u64, | 25 | extern __le64 *squashfs_read_xattr_id_table(struct super_block *, u64, |
26 | u64 *, int *); | 26 | u64 *, int *); |
27 | extern int squashfs_xattr_lookup(struct super_block *, unsigned int, int *, | 27 | extern int squashfs_xattr_lookup(struct super_block *, unsigned int, int *, |
28 | int *, unsigned long long *); | 28 | unsigned int *, unsigned long long *); |
29 | #else | 29 | #else |
30 | static inline __le64 *squashfs_read_xattr_id_table(struct super_block *sb, | 30 | static inline __le64 *squashfs_read_xattr_id_table(struct super_block *sb, |
31 | u64 start, u64 *xattr_table_start, int *xattr_ids) | 31 | u64 start, u64 *xattr_table_start, int *xattr_ids) |
32 | { | 32 | { |
33 | ERROR("Xattrs in filesystem, these will be ignored\n"); | 33 | ERROR("Xattrs in filesystem, these will be ignored\n"); |
34 | *xattr_table_start = start; | ||
34 | return ERR_PTR(-ENOTSUPP); | 35 | return ERR_PTR(-ENOTSUPP); |
35 | } | 36 | } |
36 | 37 | ||
37 | static inline int squashfs_xattr_lookup(struct super_block *sb, | 38 | static inline int squashfs_xattr_lookup(struct super_block *sb, |
38 | unsigned int index, int *count, int *size, | 39 | unsigned int index, int *count, unsigned int *size, |
39 | unsigned long long *xattr) | 40 | unsigned long long *xattr) |
40 | { | 41 | { |
41 | return 0; | 42 | return 0; |
diff --git a/fs/squashfs/xattr_id.c b/fs/squashfs/xattr_id.c index cfb41106098f..c89607d690c4 100644 --- a/fs/squashfs/xattr_id.c +++ b/fs/squashfs/xattr_id.c | |||
@@ -2,7 +2,7 @@ | |||
2 | * Squashfs - a compressed read only filesystem for Linux | 2 | * Squashfs - a compressed read only filesystem for Linux |
3 | * | 3 | * |
4 | * Copyright (c) 2010 | 4 | * Copyright (c) 2010 |
5 | * Phillip Lougher <phillip@lougher.demon.co.uk> | 5 | * Phillip Lougher <phillip@squashfs.org.uk> |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or | 7 | * This program is free software; you can redistribute it and/or |
8 | * modify it under the terms of the GNU General Public License | 8 | * modify it under the terms of the GNU General Public License |
@@ -32,8 +32,8 @@ | |||
32 | 32 | ||
33 | #include "squashfs_fs.h" | 33 | #include "squashfs_fs.h" |
34 | #include "squashfs_fs_sb.h" | 34 | #include "squashfs_fs_sb.h" |
35 | #include "squashfs_fs_i.h" | ||
36 | #include "squashfs.h" | 35 | #include "squashfs.h" |
36 | #include "xattr.h" | ||
37 | 37 | ||
38 | /* | 38 | /* |
39 | * Map xattr id using the xattr id look up table | 39 | * Map xattr id using the xattr id look up table |
@@ -67,34 +67,29 @@ __le64 *squashfs_read_xattr_id_table(struct super_block *sb, u64 start, | |||
67 | u64 *xattr_table_start, int *xattr_ids) | 67 | u64 *xattr_table_start, int *xattr_ids) |
68 | { | 68 | { |
69 | unsigned int len; | 69 | unsigned int len; |
70 | __le64 *xid_table; | 70 | struct squashfs_xattr_id_table *id_table; |
71 | struct squashfs_xattr_id_table id_table; | 71 | |
72 | int err; | 72 | id_table = squashfs_read_table(sb, start, sizeof(*id_table)); |
73 | if (IS_ERR(id_table)) | ||
74 | return (__le64 *) id_table; | ||
75 | |||
76 | *xattr_table_start = le64_to_cpu(id_table->xattr_table_start); | ||
77 | *xattr_ids = le32_to_cpu(id_table->xattr_ids); | ||
78 | kfree(id_table); | ||
79 | |||
80 | /* Sanity check values */ | ||
81 | |||
82 | /* there is always at least one xattr id */ | ||
83 | if (*xattr_ids == 0) | ||
84 | return ERR_PTR(-EINVAL); | ||
85 | |||
86 | /* xattr_table should be less than start */ | ||
87 | if (*xattr_table_start >= start) | ||
88 | return ERR_PTR(-EINVAL); | ||
73 | 89 | ||
74 | err = squashfs_read_table(sb, &id_table, start, sizeof(id_table)); | ||
75 | if (err < 0) { | ||
76 | ERROR("unable to read xattr id table\n"); | ||
77 | return ERR_PTR(err); | ||
78 | } | ||
79 | *xattr_table_start = le64_to_cpu(id_table.xattr_table_start); | ||
80 | *xattr_ids = le32_to_cpu(id_table.xattr_ids); | ||
81 | len = SQUASHFS_XATTR_BLOCK_BYTES(*xattr_ids); | 90 | len = SQUASHFS_XATTR_BLOCK_BYTES(*xattr_ids); |
82 | 91 | ||
83 | TRACE("In read_xattr_index_table, length %d\n", len); | 92 | TRACE("In read_xattr_index_table, length %d\n", len); |
84 | 93 | ||
85 | /* Allocate xattr id lookup table indexes */ | 94 | return squashfs_read_table(sb, start + sizeof(*id_table), len); |
86 | xid_table = kmalloc(len, GFP_KERNEL); | ||
87 | if (xid_table == NULL) { | ||
88 | ERROR("Failed to allocate xattr id index table\n"); | ||
89 | return ERR_PTR(-ENOMEM); | ||
90 | } | ||
91 | |||
92 | err = squashfs_read_table(sb, xid_table, start + sizeof(id_table), len); | ||
93 | if (err < 0) { | ||
94 | ERROR("unable to read xattr id index table\n"); | ||
95 | kfree(xid_table); | ||
96 | return ERR_PTR(err); | ||
97 | } | ||
98 | |||
99 | return xid_table; | ||
100 | } | 95 | } |
diff --git a/fs/squashfs/xz_wrapper.c b/fs/squashfs/xz_wrapper.c new file mode 100644 index 000000000000..1760b7d108f6 --- /dev/null +++ b/fs/squashfs/xz_wrapper.c | |||
@@ -0,0 +1,180 @@ | |||
1 | /* | ||
2 | * Squashfs - a compressed read only filesystem for Linux | ||
3 | * | ||
4 | * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 | ||
5 | * Phillip Lougher <phillip@squashfs.org.uk> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License | ||
9 | * as published by the Free Software Foundation; either version 2, | ||
10 | * or (at your option) any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
20 | * | ||
21 | * xz_wrapper.c | ||
22 | */ | ||
23 | |||
24 | |||
25 | #include <linux/mutex.h> | ||
26 | #include <linux/buffer_head.h> | ||
27 | #include <linux/slab.h> | ||
28 | #include <linux/xz.h> | ||
29 | #include <linux/bitops.h> | ||
30 | |||
31 | #include "squashfs_fs.h" | ||
32 | #include "squashfs_fs_sb.h" | ||
33 | #include "squashfs.h" | ||
34 | #include "decompressor.h" | ||
35 | |||
36 | struct squashfs_xz { | ||
37 | struct xz_dec *state; | ||
38 | struct xz_buf buf; | ||
39 | }; | ||
40 | |||
41 | struct comp_opts { | ||
42 | __le32 dictionary_size; | ||
43 | __le32 flags; | ||
44 | }; | ||
45 | |||
46 | static void *squashfs_xz_init(struct squashfs_sb_info *msblk, void *buff, | ||
47 | int len) | ||
48 | { | ||
49 | struct comp_opts *comp_opts = buff; | ||
50 | struct squashfs_xz *stream; | ||
51 | int dict_size = msblk->block_size; | ||
52 | int err, n; | ||
53 | |||
54 | if (comp_opts) { | ||
55 | /* check compressor options are the expected length */ | ||
56 | if (len < sizeof(*comp_opts)) { | ||
57 | err = -EIO; | ||
58 | goto failed; | ||
59 | } | ||
60 | |||
61 | dict_size = le32_to_cpu(comp_opts->dictionary_size); | ||
62 | |||
63 | /* the dictionary size should be 2^n or 2^n+2^(n+1) */ | ||
64 | n = ffs(dict_size) - 1; | ||
65 | if (dict_size != (1 << n) && dict_size != (1 << n) + | ||
66 | (1 << (n + 1))) { | ||
67 | err = -EIO; | ||
68 | goto failed; | ||
69 | } | ||
70 | } | ||
71 | |||
72 | dict_size = max_t(int, dict_size, SQUASHFS_METADATA_SIZE); | ||
73 | |||
74 | stream = kmalloc(sizeof(*stream), GFP_KERNEL); | ||
75 | if (stream == NULL) { | ||
76 | err = -ENOMEM; | ||
77 | goto failed; | ||
78 | } | ||
79 | |||
80 | stream->state = xz_dec_init(XZ_PREALLOC, dict_size); | ||
81 | if (stream->state == NULL) { | ||
82 | kfree(stream); | ||
83 | err = -ENOMEM; | ||
84 | goto failed; | ||
85 | } | ||
86 | |||
87 | return stream; | ||
88 | |||
89 | failed: | ||
90 | ERROR("Failed to initialise xz decompressor\n"); | ||
91 | return ERR_PTR(err); | ||
92 | } | ||
93 | |||
94 | |||
95 | static void squashfs_xz_free(void *strm) | ||
96 | { | ||
97 | struct squashfs_xz *stream = strm; | ||
98 | |||
99 | if (stream) { | ||
100 | xz_dec_end(stream->state); | ||
101 | kfree(stream); | ||
102 | } | ||
103 | } | ||
104 | |||
105 | |||
106 | static int squashfs_xz_uncompress(struct squashfs_sb_info *msblk, void **buffer, | ||
107 | struct buffer_head **bh, int b, int offset, int length, int srclength, | ||
108 | int pages) | ||
109 | { | ||
110 | enum xz_ret xz_err; | ||
111 | int avail, total = 0, k = 0, page = 0; | ||
112 | struct squashfs_xz *stream = msblk->stream; | ||
113 | |||
114 | mutex_lock(&msblk->read_data_mutex); | ||
115 | |||
116 | xz_dec_reset(stream->state); | ||
117 | stream->buf.in_pos = 0; | ||
118 | stream->buf.in_size = 0; | ||
119 | stream->buf.out_pos = 0; | ||
120 | stream->buf.out_size = PAGE_CACHE_SIZE; | ||
121 | stream->buf.out = buffer[page++]; | ||
122 | |||
123 | do { | ||
124 | if (stream->buf.in_pos == stream->buf.in_size && k < b) { | ||
125 | avail = min(length, msblk->devblksize - offset); | ||
126 | length -= avail; | ||
127 | wait_on_buffer(bh[k]); | ||
128 | if (!buffer_uptodate(bh[k])) | ||
129 | goto release_mutex; | ||
130 | |||
131 | stream->buf.in = bh[k]->b_data + offset; | ||
132 | stream->buf.in_size = avail; | ||
133 | stream->buf.in_pos = 0; | ||
134 | offset = 0; | ||
135 | } | ||
136 | |||
137 | if (stream->buf.out_pos == stream->buf.out_size | ||
138 | && page < pages) { | ||
139 | stream->buf.out = buffer[page++]; | ||
140 | stream->buf.out_pos = 0; | ||
141 | total += PAGE_CACHE_SIZE; | ||
142 | } | ||
143 | |||
144 | xz_err = xz_dec_run(stream->state, &stream->buf); | ||
145 | |||
146 | if (stream->buf.in_pos == stream->buf.in_size && k < b) | ||
147 | put_bh(bh[k++]); | ||
148 | } while (xz_err == XZ_OK); | ||
149 | |||
150 | if (xz_err != XZ_STREAM_END) { | ||
151 | ERROR("xz_dec_run error, data probably corrupt\n"); | ||
152 | goto release_mutex; | ||
153 | } | ||
154 | |||
155 | if (k < b) { | ||
156 | ERROR("xz_uncompress error, input remaining\n"); | ||
157 | goto release_mutex; | ||
158 | } | ||
159 | |||
160 | total += stream->buf.out_pos; | ||
161 | mutex_unlock(&msblk->read_data_mutex); | ||
162 | return total; | ||
163 | |||
164 | release_mutex: | ||
165 | mutex_unlock(&msblk->read_data_mutex); | ||
166 | |||
167 | for (; k < b; k++) | ||
168 | put_bh(bh[k]); | ||
169 | |||
170 | return -EIO; | ||
171 | } | ||
172 | |||
173 | const struct squashfs_decompressor squashfs_xz_comp_ops = { | ||
174 | .init = squashfs_xz_init, | ||
175 | .free = squashfs_xz_free, | ||
176 | .decompress = squashfs_xz_uncompress, | ||
177 | .id = XZ_COMPRESSION, | ||
178 | .name = "xz", | ||
179 | .supported = 1 | ||
180 | }; | ||
diff --git a/fs/squashfs/zlib_wrapper.c b/fs/squashfs/zlib_wrapper.c index 7a603874e483..55d918fd2d86 100644 --- a/fs/squashfs/zlib_wrapper.c +++ b/fs/squashfs/zlib_wrapper.c | |||
@@ -2,7 +2,7 @@ | |||
2 | * Squashfs - a compressed read only filesystem for Linux | 2 | * Squashfs - a compressed read only filesystem for Linux |
3 | * | 3 | * |
4 | * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 | 4 | * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 |
5 | * Phillip Lougher <phillip@lougher.demon.co.uk> | 5 | * Phillip Lougher <phillip@squashfs.org.uk> |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or | 7 | * This program is free software; you can redistribute it and/or |
8 | * modify it under the terms of the GNU General Public License | 8 | * modify it under the terms of the GNU General Public License |
@@ -26,20 +26,19 @@ | |||
26 | #include <linux/buffer_head.h> | 26 | #include <linux/buffer_head.h> |
27 | #include <linux/slab.h> | 27 | #include <linux/slab.h> |
28 | #include <linux/zlib.h> | 28 | #include <linux/zlib.h> |
29 | #include <linux/vmalloc.h> | ||
29 | 30 | ||
30 | #include "squashfs_fs.h" | 31 | #include "squashfs_fs.h" |
31 | #include "squashfs_fs_sb.h" | 32 | #include "squashfs_fs_sb.h" |
32 | #include "squashfs_fs_i.h" | ||
33 | #include "squashfs.h" | 33 | #include "squashfs.h" |
34 | #include "decompressor.h" | 34 | #include "decompressor.h" |
35 | 35 | ||
36 | static void *zlib_init(struct squashfs_sb_info *dummy) | 36 | static void *zlib_init(struct squashfs_sb_info *dummy, void *buff, int len) |
37 | { | 37 | { |
38 | z_stream *stream = kmalloc(sizeof(z_stream), GFP_KERNEL); | 38 | z_stream *stream = kmalloc(sizeof(z_stream), GFP_KERNEL); |
39 | if (stream == NULL) | 39 | if (stream == NULL) |
40 | goto failed; | 40 | goto failed; |
41 | stream->workspace = kmalloc(zlib_inflate_workspacesize(), | 41 | stream->workspace = vmalloc(zlib_inflate_workspacesize()); |
42 | GFP_KERNEL); | ||
43 | if (stream->workspace == NULL) | 42 | if (stream->workspace == NULL) |
44 | goto failed; | 43 | goto failed; |
45 | 44 | ||
@@ -48,7 +47,7 @@ static void *zlib_init(struct squashfs_sb_info *dummy) | |||
48 | failed: | 47 | failed: |
49 | ERROR("Failed to allocate zlib workspace\n"); | 48 | ERROR("Failed to allocate zlib workspace\n"); |
50 | kfree(stream); | 49 | kfree(stream); |
51 | return NULL; | 50 | return ERR_PTR(-ENOMEM); |
52 | } | 51 | } |
53 | 52 | ||
54 | 53 | ||
@@ -57,7 +56,7 @@ static void zlib_free(void *strm) | |||
57 | z_stream *stream = strm; | 56 | z_stream *stream = strm; |
58 | 57 | ||
59 | if (stream) | 58 | if (stream) |
60 | kfree(stream->workspace); | 59 | vfree(stream->workspace); |
61 | kfree(stream); | 60 | kfree(stream); |
62 | } | 61 | } |
63 | 62 | ||
@@ -66,8 +65,8 @@ static int zlib_uncompress(struct squashfs_sb_info *msblk, void **buffer, | |||
66 | struct buffer_head **bh, int b, int offset, int length, int srclength, | 65 | struct buffer_head **bh, int b, int offset, int length, int srclength, |
67 | int pages) | 66 | int pages) |
68 | { | 67 | { |
69 | int zlib_err = 0, zlib_init = 0; | 68 | int zlib_err, zlib_init = 0; |
70 | int avail, bytes, k = 0, page = 0; | 69 | int k = 0, page = 0; |
71 | z_stream *stream = msblk->stream; | 70 | z_stream *stream = msblk->stream; |
72 | 71 | ||
73 | mutex_lock(&msblk->read_data_mutex); | 72 | mutex_lock(&msblk->read_data_mutex); |
@@ -75,21 +74,14 @@ static int zlib_uncompress(struct squashfs_sb_info *msblk, void **buffer, | |||
75 | stream->avail_out = 0; | 74 | stream->avail_out = 0; |
76 | stream->avail_in = 0; | 75 | stream->avail_in = 0; |
77 | 76 | ||
78 | bytes = length; | ||
79 | do { | 77 | do { |
80 | if (stream->avail_in == 0 && k < b) { | 78 | if (stream->avail_in == 0 && k < b) { |
81 | avail = min(bytes, msblk->devblksize - offset); | 79 | int avail = min(length, msblk->devblksize - offset); |
82 | bytes -= avail; | 80 | length -= avail; |
83 | wait_on_buffer(bh[k]); | 81 | wait_on_buffer(bh[k]); |
84 | if (!buffer_uptodate(bh[k])) | 82 | if (!buffer_uptodate(bh[k])) |
85 | goto release_mutex; | 83 | goto release_mutex; |
86 | 84 | ||
87 | if (avail == 0) { | ||
88 | offset = 0; | ||
89 | put_bh(bh[k++]); | ||
90 | continue; | ||
91 | } | ||
92 | |||
93 | stream->next_in = bh[k]->b_data + offset; | 85 | stream->next_in = bh[k]->b_data + offset; |
94 | stream->avail_in = avail; | 86 | stream->avail_in = avail; |
95 | offset = 0; | 87 | offset = 0; |
@@ -128,6 +120,11 @@ static int zlib_uncompress(struct squashfs_sb_info *msblk, void **buffer, | |||
128 | goto release_mutex; | 120 | goto release_mutex; |
129 | } | 121 | } |
130 | 122 | ||
123 | if (k < b) { | ||
124 | ERROR("zlib_uncompress error, data remaining\n"); | ||
125 | goto release_mutex; | ||
126 | } | ||
127 | |||
131 | length = stream->total_out; | 128 | length = stream->total_out; |
132 | mutex_unlock(&msblk->read_data_mutex); | 129 | mutex_unlock(&msblk->read_data_mutex); |
133 | return length; | 130 | return length; |