]>
Commit | Line | Data |
---|---|---|
9cdc8a28 | 1 | diff --new-file -ur linux-2.6.6/fs/Kconfig linux-2.6.6-squashfs2.0/fs/Kconfig |
2 | --- linux-2.6.6/fs/Kconfig 2004-05-10 03:32:38.000000000 +0100 | |
3 | +++ linux-2.6.6-squashfs2.0/fs/Kconfig 2004-05-20 21:28:29.000000000 +0100 | |
4 | @@ -1145,6 +1145,29 @@ | |
5 | ||
6 | If unsure, say N. | |
7 | ||
8 | +config SQUASHFS | |
9 | + tristate "SquashFS 2.0 - Squashed file system support" | |
10 | + select ZLIB_INFLATE | |
11 | + help | |
12 | + Saying Y here includes support for SquashFs 2.0 (Compressed Read-Only File | |
13 | + System). Squashfs is a highly compressed read-only filesystem for Linux. | |
14 | + It uses zlib compression to compress both files, inodes and directories. | |
15 | + Inodes in the system are very small and all blocks are packed to minimise | |
16 | + data overhead. Block sizes greater than 4K are supported up to a maximum of 64K. | |
17 | + | |
18 | + Squashfs is intended for general read-only filesystem use, for archival | |
19 | + use (i.e. in cases where a .tar.gz file may be used), and in embedded | |
20 | + systems where low overhead is needed. Further information and filesystem tools | |
21 | + are available from http://squashfs.sourceforge.net. | |
22 | + | |
23 | + If you want to compile this as a module ( = code which can be | |
24 | + inserted in and removed from the running kernel whenever you want), | |
25 | + say M here and read <file:Documentation/modules.txt>. The module | |
26 | + will be called squashfs. Note that the root file system (the one | |
27 | + containing the directory /) cannot be compiled as a module. | |
28 | + | |
29 | + If unsure, say N. | |
30 | + | |
31 | config VXFS_FS | |
32 | tristate "FreeVxFS file system support (VERITAS VxFS(TM) compatible)" | |
33 | help | |
34 | diff --new-file -ur linux-2.6.6/fs/Makefile linux-2.6.6-squashfs2.0/fs/Makefile | |
35 | --- linux-2.6.6/fs/Makefile 2004-05-10 03:32:38.000000000 +0100 | |
36 | +++ linux-2.6.6-squashfs2.0/fs/Makefile 2004-05-20 21:26:38.000000000 +0100 | |
37 | @@ -50,6 +50,7 @@ | |
38 | obj-$(CONFIG_JBD) += jbd/ | |
39 | obj-$(CONFIG_EXT2_FS) += ext2/ | |
40 | obj-$(CONFIG_CRAMFS) += cramfs/ | |
41 | +obj-$(CONFIG_SQUASHFS) += squashfs/ | |
42 | obj-$(CONFIG_RAMFS) += ramfs/ | |
43 | obj-$(CONFIG_HUGETLBFS) += hugetlbfs/ | |
44 | obj-$(CONFIG_CODA_FS) += coda/ | |
45 | diff --new-file -ur linux-2.6.6/fs/squashfs/inode.c linux-2.6.6-squashfs2.0/fs/squashfs/inode.c | |
46 | --- linux-2.6.6/fs/squashfs/inode.c 1970-01-01 01:00:00.000000000 +0100 | |
47 | +++ linux-2.6.6-squashfs2.0/fs/squashfs/inode.c 2004-05-20 21:41:50.000000000 +0100 | |
48 | @@ -0,0 +1,1626 @@ | |
49 | +/* | |
50 | + * Squashfs - a compressed read only filesystem for Linux | |
51 | + * | |
52 | + * Copyright (c) 2002, 2003, 2004 Phillip Lougher <plougher@users.sourceforge.net> | |
53 | + * | |
54 | + * This program is free software; you can redistribute it and/or | |
55 | + * modify it under the terms of the GNU General Public License | |
56 | + * as published by the Free Software Foundation; either version 2, | |
57 | + * or (at your option) any later version. | |
58 | + * | |
59 | + * This program is distributed in the hope that it will be useful, | |
60 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
61 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
62 | + * GNU General Public License for more details. | |
63 | + * | |
64 | + * You should have received a copy of the GNU General Public License | |
65 | + * along with this program; if not, write to the Free Software | |
66 | + * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |
67 | + * | |
68 | + * inode.c | |
69 | + */ | |
70 | + | |
71 | +#define SQUASHFS_1_0_COMPATIBILITY | |
72 | + | |
73 | +#include <linux/types.h> | |
74 | +#include <linux/squashfs_fs.h> | |
75 | +#include <linux/module.h> | |
76 | +#include <linux/errno.h> | |
77 | +#include <linux/slab.h> | |
78 | +#include <linux/fs.h> | |
79 | +#include <linux/smp_lock.h> | |
80 | +#include <linux/slab.h> | |
81 | +#include <linux/squashfs_fs_sb.h> | |
82 | +#include <linux/squashfs_fs_i.h> | |
83 | +#include <linux/buffer_head.h> | |
84 | +#include <linux/vfs.h> | |
85 | +#include <linux/init.h> | |
86 | +#include <linux/dcache.h> | |
87 | +#include <asm/uaccess.h> | |
88 | +#include <linux/wait.h> | |
89 | +#include <asm/semaphore.h> | |
90 | +#include <linux/zlib.h> | |
91 | +#include <linux/blkdev.h> | |
92 | +#include <linux/vmalloc.h> | |
93 | + | |
94 | +#ifdef SQUASHFS_TRACE | |
95 | +#define TRACE(s, args...) printk(KERN_NOTICE "SQUASHFS: "s, ## args) | |
96 | +#else | |
97 | +#define TRACE(s, args...) {} | |
98 | +#endif | |
99 | + | |
100 | +#define ERROR(s, args...) printk(KERN_ERR "SQUASHFS error: "s, ## args) | |
101 | + | |
102 | +#define SERROR(s, args...) if(!silent) printk(KERN_ERR "SQUASHFS error: "s, ## args) | |
103 | +#define WARNING(s, args...) printk(KERN_WARNING "SQUASHFS: "s, ## args) | |
104 | + | |
105 | +static void squashfs_put_super(struct super_block *); | |
106 | +static int squashfs_statfs(struct super_block *, struct kstatfs *); | |
107 | +static int squashfs_symlink_readpage(struct file *file, struct page *page); | |
108 | +static int squashfs_readpage(struct file *file, struct page *page); | |
109 | +static int squashfs_readpage4K(struct file *file, struct page *page); | |
110 | +static int squashfs_readdir(struct file *, void *, filldir_t); | |
111 | +static struct dentry *squashfs_lookup(struct inode *, struct dentry *, struct nameidata *); | |
112 | +static unsigned int read_data(struct super_block *s, char *buffer, | |
113 | + unsigned int index, unsigned int length, int, unsigned int *next_index); | |
114 | +static int squashfs_get_cached_block(struct super_block *s, char *buffer, | |
115 | + unsigned int block, unsigned int offset, int length, | |
116 | + unsigned int *next_block, unsigned int *next_offset); | |
117 | +static struct inode *squashfs_iget(struct super_block *s, squashfs_inode inode); | |
118 | +static unsigned int read_blocklist(struct inode *inode, int index, int readahead_blks, | |
119 | + char *block_list, char **block_p, unsigned int *bsize); | |
120 | +static void squashfs_put_super(struct super_block *s); | |
121 | +static struct super_block *squashfs_get_sb(struct file_system_type *, int, const char *, void *); | |
122 | +static struct inode *squashfs_alloc_inode(struct super_block *sb); | |
123 | +static void squashfs_destroy_inode(struct inode *inode); | |
124 | +static int init_inodecache(void); | |
125 | +static void destroy_inodecache(void); | |
126 | + | |
127 | +#ifdef SQUASHFS_1_0_COMPATIBILITY | |
128 | +static int squashfs_readpage_lessthan4K(struct file *file, struct page *page); | |
129 | +static struct inode *squashfs_iget_1(struct super_block *s, squashfs_inode inode); | |
130 | +static unsigned int read_blocklist_1(struct inode *inode, int index, int readahead_blks, | |
131 | + char *block_list, char **block_p, unsigned int *bsize); | |
132 | +#endif | |
133 | + | |
134 | +DECLARE_MUTEX(read_data_mutex); | |
135 | + | |
136 | +static z_stream stream; | |
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 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_ops = { | |
151 | + .alloc_inode = squashfs_alloc_inode, | |
152 | + .destroy_inode = squashfs_destroy_inode, | |
153 | + .statfs = squashfs_statfs, | |
154 | + .put_super = squashfs_put_super, | |
155 | +}; | |
156 | + | |
157 | +static struct address_space_operations squashfs_symlink_aops = { | |
158 | + .readpage = squashfs_symlink_readpage | |
159 | +}; | |
160 | + | |
161 | +static struct address_space_operations squashfs_aops = { | |
162 | + .readpage = squashfs_readpage | |
163 | +}; | |
164 | + | |
165 | +static struct address_space_operations squashfs_aops_4K = { | |
166 | + .readpage = squashfs_readpage4K | |
167 | +}; | |
168 | + | |
169 | +#ifdef SQUASHFS_1_0_COMPATIBILITY | |
170 | +static struct address_space_operations squashfs_aops_lessthan4K = { | |
171 | + .readpage = squashfs_readpage_lessthan4K | |
172 | +}; | |
173 | +#endif | |
174 | + | |
175 | +static struct file_operations squashfs_dir_ops = { | |
176 | + .read = generic_read_dir, | |
177 | + .readdir = squashfs_readdir | |
178 | +}; | |
179 | + | |
180 | +static struct inode_operations squashfs_dir_inode_ops = { | |
181 | + .lookup = squashfs_lookup | |
182 | +}; | |
183 | + | |
184 | + | |
185 | +static inline struct squashfs_inode_info *SQUASHFS_I(struct inode *inode) | |
186 | +{ | |
187 | + return list_entry(inode, struct squashfs_inode_info, vfs_inode); | |
188 | +} | |
189 | + | |
190 | + | |
191 | +static unsigned int read_data(struct super_block *s, char *buffer, | |
192 | + unsigned int index, unsigned int length, int datablock, unsigned int *next_index) | |
193 | +{ | |
194 | + squashfs_sb_info *msBlk = (squashfs_sb_info *)s->s_fs_info; | |
195 | + struct buffer_head *bh[((SQUASHFS_FILE_MAX_SIZE - 1) >> msBlk->devblksize_log2) + 2]; | |
196 | + unsigned int offset = index & ((1 << msBlk->devblksize_log2) - 1); | |
197 | + unsigned int cur_index = index >> msBlk->devblksize_log2; | |
198 | + int bytes, avail_bytes, b, k; | |
199 | + char *c_buffer; | |
200 | + unsigned int compressed; | |
201 | + unsigned int c_byte = length; | |
202 | + | |
203 | + if(c_byte) { | |
204 | + bytes = msBlk->devblksize - offset; | |
205 | + if(datablock) { | |
206 | + c_buffer = (compressed = SQUASHFS_COMPRESSED_BLOCK(c_byte)) ? msBlk->read_data : buffer; | |
207 | + c_byte = SQUASHFS_COMPRESSED_SIZE_BLOCK(c_byte); | |
208 | + } else { | |
209 | + c_buffer = (compressed = SQUASHFS_COMPRESSED(c_byte)) ? msBlk->read_data : buffer; | |
210 | + c_byte = SQUASHFS_COMPRESSED_SIZE(c_byte); | |
211 | + } | |
212 | + | |
213 | + TRACE("Block @ 0x%x, %scompressed size %d\n", index, compressed ? "" : "un", (unsigned int) c_byte); | |
214 | + | |
215 | + if(!(bh[0] = sb_getblk(s, cur_index))) | |
216 | + goto block_release; | |
217 | + for(b = 1; bytes < c_byte; b++) { | |
218 | + if(!(bh[b] = sb_getblk(s, ++cur_index))) | |
219 | + goto block_release; | |
220 | + bytes += msBlk->devblksize; | |
221 | + } | |
222 | + ll_rw_block(READ, b, bh); | |
223 | + } else { | |
224 | + unsigned short temp; | |
225 | + if(!(bh[0] = sb_bread(s, cur_index))) | |
226 | + goto read_failure; | |
227 | + | |
228 | + if(msBlk->devblksize - offset == 1) { | |
229 | + if(msBlk->swap) | |
230 | + ((unsigned char *) &temp)[1] = *((unsigned char *) (bh[0]->b_data + offset)); | |
231 | + else | |
232 | + ((unsigned char *) &temp)[0] = *((unsigned char *) (bh[0]->b_data + offset)); | |
233 | + brelse(bh[0]); | |
234 | + if(!(bh[0] = sb_bread(s, ++cur_index))) | |
235 | + goto read_failure; | |
236 | + if(msBlk->swap) | |
237 | + ((unsigned char *) &temp)[0] = *((unsigned char *) bh[0]->b_data); | |
238 | + else | |
239 | + ((unsigned char *) &temp)[1] = *((unsigned char *) bh[0]->b_data); | |
240 | + c_byte = temp; | |
241 | + offset = 1; | |
242 | + } | |
243 | + else { | |
244 | + if(msBlk->swap) { | |
245 | + unsigned short temp; | |
246 | + ((unsigned char *) &temp)[1] = *((unsigned char *) (bh[0]->b_data + offset)); | |
247 | + ((unsigned char *) &temp)[0] = *((unsigned char *) (bh[0]->b_data + offset + 1)); | |
248 | + c_byte = temp; | |
249 | + } else | |
250 | + c_byte = *((unsigned short *) (bh[0]->b_data + offset)); | |
251 | + offset += 2; | |
252 | + } | |
253 | + if(SQUASHFS_CHECK_DATA(msBlk->sBlk.flags)) { | |
254 | + if(offset == msBlk->devblksize) { | |
255 | + brelse(bh[0]); | |
256 | + if(!(bh[0] = sb_bread(s, ++cur_index))) | |
257 | + goto read_failure; | |
258 | + offset = 0; | |
259 | + } | |
260 | + if(*((unsigned char *) (bh[0]->b_data + offset)) != SQUASHFS_MARKER_BYTE) { | |
261 | + ERROR("Metadata block marker corrupt @ %x\n", index); | |
262 | + brelse(bh[0]); | |
263 | + return 0; | |
264 | + } | |
265 | + offset ++; | |
266 | + } | |
267 | + | |
268 | + bytes = msBlk->devblksize - offset; | |
269 | + if(datablock) { | |
270 | + c_buffer = (compressed = SQUASHFS_COMPRESSED_BLOCK(c_byte)) ? msBlk->read_data : buffer; | |
271 | + c_byte = SQUASHFS_COMPRESSED_SIZE_BLOCK(c_byte); | |
272 | + } else { | |
273 | + c_buffer = (compressed = SQUASHFS_COMPRESSED(c_byte)) ? msBlk->read_data : buffer; | |
274 | + c_byte = SQUASHFS_COMPRESSED_SIZE(c_byte); | |
275 | + } | |
276 | + | |
277 | + TRACE("Block @ 0x%x, %scompressed size %d\n", index, compressed ? "" : "un", (unsigned int) c_byte); | |
278 | + | |
279 | + for(b = 1; bytes < c_byte; b++) { | |
280 | + if(!(bh[b] = sb_getblk(s, ++cur_index))) | |
281 | + goto block_release; | |
282 | + bytes += msBlk->devblksize; | |
283 | + } | |
284 | + ll_rw_block(READ, b - 1, bh + 1); | |
285 | + } | |
286 | + | |
287 | + if(compressed) | |
288 | + down(&read_data_mutex); | |
289 | + | |
290 | + for(bytes = 0, k = 0; k < b; k++) { | |
291 | + avail_bytes = (c_byte - bytes) > (msBlk->devblksize - offset) ? msBlk->devblksize - offset : c_byte - bytes; | |
292 | + wait_on_buffer(bh[k]); | |
293 | + memcpy(c_buffer + bytes, bh[k]->b_data + offset, avail_bytes); | |
294 | + bytes += avail_bytes; | |
295 | + offset = 0; | |
296 | + brelse(bh[k]); | |
297 | + } | |
298 | + | |
299 | + /* | |
300 | + * uncompress block | |
301 | + */ | |
302 | + if(compressed) { | |
303 | + int zlib_err; | |
304 | + | |
305 | + stream.next_in = c_buffer; | |
306 | + stream.avail_in = c_byte; | |
307 | + stream.next_out = buffer; | |
308 | + stream.avail_out = msBlk->read_size; | |
309 | + if(((zlib_err = zlib_inflateInit(&stream)) != Z_OK) || | |
310 | + ((zlib_err = zlib_inflate(&stream, Z_FINISH)) != Z_STREAM_END) || | |
311 | + ((zlib_err = zlib_inflateEnd(&stream)) != Z_OK)) { | |
312 | + ERROR("zlib_fs returned unexpected result 0x%x\n", zlib_err); | |
313 | + bytes = 0; | |
314 | + } else | |
315 | + bytes = stream.total_out; | |
316 | + up(&read_data_mutex); | |
317 | + } | |
318 | + | |
319 | + if(next_index) | |
320 | + *next_index = index + c_byte + (length ? 0 : (SQUASHFS_CHECK_DATA(msBlk->sBlk.flags) ? 3 : 2)); | |
321 | + | |
322 | + return bytes; | |
323 | + | |
324 | +block_release: | |
325 | + while(--b >= 0) brelse(bh[b]); | |
326 | + | |
327 | +read_failure: | |
328 | + ERROR("sb_bread failed reading block 0x%x\n", cur_index); | |
329 | + return 0; | |
330 | +} | |
331 | + | |
332 | + | |
333 | +static int squashfs_get_cached_block(struct super_block *s, char *buffer, | |
334 | + unsigned int block, unsigned int offset, int length, | |
335 | + unsigned int *next_block, unsigned int *next_offset) | |
336 | +{ | |
337 | + squashfs_sb_info *msBlk = (squashfs_sb_info *)s->s_fs_info; | |
338 | + int n, i, bytes, return_length = length; | |
339 | + unsigned int next_index; | |
340 | + | |
341 | + TRACE("Entered squashfs_get_cached_block [%x:%x]\n", block, offset); | |
342 | + | |
343 | + for(;;) { | |
344 | + for(i = 0; i < SQUASHFS_CACHED_BLKS; i++) | |
345 | + if(msBlk->block_cache[i].block == block) | |
346 | + break; | |
347 | + | |
348 | + down(&msBlk->block_cache_mutex); | |
349 | + if(i == SQUASHFS_CACHED_BLKS) { | |
350 | + /* read inode header block */ | |
351 | + for(i = msBlk->next_cache, n = SQUASHFS_CACHED_BLKS; n ; n --, i = (i + 1) % SQUASHFS_CACHED_BLKS) | |
352 | + if(msBlk->block_cache[i].block != SQUASHFS_USED_BLK) | |
353 | + break; | |
354 | + if(n == 0) { | |
355 | + wait_queue_t wait; | |
356 | + | |
357 | + init_waitqueue_entry(&wait, current); | |
358 | + add_wait_queue(&msBlk->waitq, &wait); | |
359 | + up(&msBlk->block_cache_mutex); | |
360 | + set_current_state(TASK_UNINTERRUPTIBLE); | |
361 | + schedule(); | |
362 | + set_current_state(TASK_RUNNING); | |
363 | + remove_wait_queue(&msBlk->waitq, &wait); | |
364 | + continue; | |
365 | + } | |
366 | + msBlk->next_cache = (i + 1) % SQUASHFS_CACHED_BLKS; | |
367 | + | |
368 | + if(msBlk->block_cache[i].block == SQUASHFS_INVALID_BLK) { | |
369 | + if(!(msBlk->block_cache[i].data = (unsigned char *) | |
370 | + kmalloc(SQUASHFS_METADATA_SIZE, GFP_KERNEL))) { | |
371 | + ERROR("Failed to allocate cache block\n"); | |
372 | + up(&msBlk->block_cache_mutex); | |
373 | + return 0; | |
374 | + } | |
375 | + } | |
376 | + | |
377 | + msBlk->block_cache[i].block = SQUASHFS_USED_BLK; | |
378 | + up(&msBlk->block_cache_mutex); | |
379 | + if(!(msBlk->block_cache[i].length = read_data(s, msBlk->block_cache[i].data, block, 0, 0, | |
380 | + &next_index))) { | |
381 | + ERROR("Unable to read cache block [%x:%x]\n", block, offset); | |
382 | + return 0; | |
383 | + } | |
384 | + down(&msBlk->block_cache_mutex); | |
385 | + wake_up(&msBlk->waitq); | |
386 | + msBlk->block_cache[i].block = block; | |
387 | + msBlk->block_cache[i].next_index = next_index; | |
388 | + TRACE("Read cache block [%x:%x]\n", block, offset); | |
389 | + } | |
390 | + | |
391 | + if(msBlk->block_cache[i].block != block) { | |
392 | + up(&msBlk->block_cache_mutex); | |
393 | + continue; | |
394 | + } | |
395 | + | |
396 | + if((bytes = msBlk->block_cache[i].length - offset) >= length) { | |
397 | + if(buffer) | |
398 | + memcpy(buffer, msBlk->block_cache[i].data + offset, length); | |
399 | + if(msBlk->block_cache[i].length - offset == length) { | |
400 | + *next_block = msBlk->block_cache[i].next_index; | |
401 | + *next_offset = 0; | |
402 | + } else { | |
403 | + *next_block = block; | |
404 | + *next_offset = offset + length; | |
405 | + } | |
406 | + | |
407 | + up(&msBlk->block_cache_mutex); | |
408 | + return return_length; | |
409 | + } else { | |
410 | + if(buffer) { | |
411 | + memcpy(buffer, msBlk->block_cache[i].data + offset, bytes); | |
412 | + buffer += bytes; | |
413 | + } | |
414 | + block = msBlk->block_cache[i].next_index; | |
415 | + up(&msBlk->block_cache_mutex); | |
416 | + length -= bytes; | |
417 | + offset = 0; | |
418 | + } | |
419 | + } | |
420 | +} | |
421 | + | |
422 | + | |
423 | +static int get_fragment_location(struct super_block *s, unsigned int fragment, unsigned int *fragment_start_block, unsigned int *fragment_size) | |
424 | +{ | |
425 | + squashfs_sb_info *msBlk = (squashfs_sb_info *)s->s_fs_info; | |
426 | + unsigned int start_block = msBlk->fragment_index[SQUASHFS_FRAGMENT_INDEX(fragment)]; | |
427 | + int offset = SQUASHFS_FRAGMENT_INDEX_OFFSET(fragment); | |
428 | + squashfs_fragment_entry fragment_entry; | |
429 | + | |
430 | + if(msBlk->swap) { | |
431 | + squashfs_fragment_entry sfragment_entry; | |
432 | + | |
433 | + if(!squashfs_get_cached_block(s, (char *) &sfragment_entry, start_block, offset, | |
434 | + sizeof(sfragment_entry), &start_block, &offset)) | |
435 | + return 0; | |
436 | + SQUASHFS_SWAP_FRAGMENT_ENTRY(&fragment_entry, &sfragment_entry); | |
437 | + } else | |
438 | + if(!squashfs_get_cached_block(s, (char *) &fragment_entry, start_block, offset, | |
439 | + sizeof(fragment_entry), &start_block, &offset)) | |
440 | + return 0; | |
441 | + | |
442 | + *fragment_start_block = fragment_entry.start_block; | |
443 | + *fragment_size = fragment_entry.size; | |
444 | + | |
445 | + return 1; | |
446 | +} | |
447 | + | |
448 | + | |
449 | +void release_cached_fragment(squashfs_sb_info *msBlk, struct squashfs_fragment_cache *fragment) | |
450 | +{ | |
451 | + down(&msBlk->fragment_mutex); | |
452 | + fragment->locked --; | |
453 | + wake_up(&msBlk->fragment_wait_queue); | |
454 | + up(&msBlk->fragment_mutex); | |
455 | +} | |
456 | + | |
457 | + | |
458 | +struct squashfs_fragment_cache *get_cached_fragment(struct super_block *s, unsigned int start_block, int length) | |
459 | +{ | |
460 | + int i, n; | |
461 | + squashfs_sb_info *msBlk = (squashfs_sb_info *)s->s_fs_info; | |
462 | + | |
463 | + for(;;) { | |
464 | + down(&msBlk->fragment_mutex); | |
465 | + for(i = 0; i < SQUASHFS_CACHED_FRAGMENTS && msBlk->fragment[i].block != start_block; i++); | |
466 | + if(i == SQUASHFS_CACHED_FRAGMENTS) { | |
467 | + for(i = msBlk->next_fragment, n = SQUASHFS_CACHED_FRAGMENTS; | |
468 | + n && msBlk->fragment[i].locked; n--, i = (i + 1) % SQUASHFS_CACHED_FRAGMENTS); | |
469 | + | |
470 | + if(n == 0) { | |
471 | + wait_queue_t wait; | |
472 | + | |
473 | + init_waitqueue_entry(&wait, current); | |
474 | + add_wait_queue(&msBlk->fragment_wait_queue, &wait); | |
475 | + up(&msBlk->fragment_mutex); | |
476 | + set_current_state(TASK_UNINTERRUPTIBLE); | |
477 | + schedule(); | |
478 | + set_current_state(TASK_RUNNING); | |
479 | + remove_wait_queue(&msBlk->fragment_wait_queue, &wait); | |
480 | + continue; | |
481 | + } | |
482 | + msBlk->next_fragment = (msBlk->next_fragment + 1) % SQUASHFS_CACHED_FRAGMENTS; | |
483 | + | |
484 | + if(msBlk->fragment[i].data == NULL) | |
485 | + if(!(msBlk->fragment[i].data = (unsigned char *) | |
486 | + kmalloc(SQUASHFS_FILE_MAX_SIZE, GFP_KERNEL))) { | |
487 | + ERROR("Failed to allocate fragment cache block\n"); | |
488 | + up(&msBlk->fragment_mutex); | |
489 | + return NULL; | |
490 | + } | |
491 | + | |
492 | + msBlk->fragment[i].block = SQUASHFS_INVALID_BLK; | |
493 | + msBlk->fragment[i].locked = 1; | |
494 | + up(&msBlk->fragment_mutex); | |
495 | + if(!(msBlk->fragment[i].length = read_data(s, msBlk->fragment[i].data, start_block, length, | |
496 | + 1, NULL))) { | |
497 | + ERROR("Unable to read fragment cache block [%x]\n", start_block); | |
498 | + msBlk->fragment[i].locked = 0; | |
499 | + return NULL; | |
500 | + } | |
501 | + msBlk->fragment[i].block = start_block; | |
502 | + TRACE("New fragment %d, start block %d, locked %d\n", i, msBlk->fragment[i].block, msBlk->fragment[i].locked); | |
503 | + return &msBlk->fragment[i]; | |
504 | + } | |
505 | + | |
506 | + msBlk->fragment[i].locked ++; | |
507 | + up(&msBlk->fragment_mutex); | |
508 | + | |
509 | + TRACE("Got fragment %d, start block %d, locked %d\n", i, msBlk->fragment[i].block, msBlk->fragment[i].locked); | |
510 | + return &msBlk->fragment[i]; | |
511 | + } | |
512 | +} | |
513 | + | |
514 | + | |
515 | +#ifdef SQUASHFS_1_0_COMPATIBILITY | |
516 | +static struct inode *squashfs_iget_1(struct super_block *s, squashfs_inode inode) | |
517 | +{ | |
518 | + struct inode *i = new_inode(s); | |
519 | + squashfs_sb_info *msBlk = (squashfs_sb_info *)s->s_fs_info; | |
520 | + squashfs_super_block *sBlk = &msBlk->sBlk; | |
521 | + unsigned int block = SQUASHFS_INODE_BLK(inode) + sBlk->inode_table_start; | |
522 | + unsigned int offset = SQUASHFS_INODE_OFFSET(inode); | |
523 | + unsigned int next_block, next_offset; | |
524 | + squashfs_base_inode_header_1 inodeb; | |
525 | + | |
526 | + TRACE("Entered squashfs_iget_1\n"); | |
527 | + | |
528 | + if(msBlk->swap) { | |
529 | + squashfs_base_inode_header_1 sinodeb; | |
530 | + | |
531 | + if(!squashfs_get_cached_block(s, (char *) &sinodeb, block, offset, | |
532 | + sizeof(sinodeb), &next_block, &next_offset)) | |
533 | + goto failed_read; | |
534 | + SQUASHFS_SWAP_BASE_INODE_HEADER_1(&inodeb, &sinodeb, sizeof(sinodeb)); | |
535 | + } else | |
536 | + if(!squashfs_get_cached_block(s, (char *) &inodeb, block, offset, | |
537 | + sizeof(inodeb), &next_block, &next_offset)) | |
538 | + goto failed_read; | |
539 | + | |
540 | + i->i_nlink = 1; | |
541 | + | |
542 | + i->i_mtime.tv_sec = sBlk->mkfs_time; | |
543 | + i->i_atime.tv_sec = sBlk->mkfs_time; | |
544 | + i->i_ctime.tv_sec = sBlk->mkfs_time; | |
545 | + | |
546 | + if(inodeb.inode_type != SQUASHFS_IPC_TYPE) | |
547 | + i->i_uid = msBlk->uid[((inodeb.inode_type - 1) / SQUASHFS_TYPES) * 16 + inodeb.uid]; | |
548 | + i->i_ino = SQUASHFS_MK_VFS_INODE(block - sBlk->inode_table_start, offset); | |
549 | + | |
550 | + i->i_mode = inodeb.mode; | |
551 | + | |
552 | + switch(inodeb.inode_type == SQUASHFS_IPC_TYPE ? SQUASHFS_IPC_TYPE : (inodeb.inode_type - 1) % SQUASHFS_TYPES + 1) { | |
553 | + case SQUASHFS_FILE_TYPE: { | |
554 | + squashfs_reg_inode_header_1 inodep; | |
555 | + | |
556 | + if(msBlk->swap) { | |
557 | + squashfs_reg_inode_header_1 sinodep; | |
558 | + | |
559 | + if(!squashfs_get_cached_block(s, (char *) &sinodep, block, offset, sizeof(sinodep), | |
560 | + &next_block, &next_offset)) | |
561 | + goto failed_read; | |
562 | + SQUASHFS_SWAP_REG_INODE_HEADER_1(&inodep, &sinodep); | |
563 | + } else | |
564 | + if(!squashfs_get_cached_block(s, (char *) &inodep, block, offset, sizeof(inodep), | |
565 | + &next_block, &next_offset)) | |
566 | + goto failed_read; | |
567 | + | |
568 | + i->i_size = inodep.file_size; | |
569 | + i->i_fop = &generic_ro_fops; | |
570 | + if(sBlk->block_size > 4096) | |
571 | + i->i_data.a_ops = &squashfs_aops; | |
572 | + else if(sBlk->block_size == 4096) | |
573 | + i->i_data.a_ops = &squashfs_aops_4K; | |
574 | + else | |
575 | + i->i_data.a_ops = &squashfs_aops_lessthan4K; | |
576 | + i->i_mode |= S_IFREG; | |
577 | + i->i_mtime.tv_sec = inodep.mtime; | |
578 | + i->i_atime.tv_sec = inodep.mtime; | |
579 | + i->i_ctime.tv_sec = inodep.mtime; | |
580 | + i->i_blocks = ((i->i_size - 1) >> 9) + 1; | |
581 | + i->i_blksize = PAGE_CACHE_SIZE; | |
582 | + SQUASHFS_I(i)->fragment_start_block = SQUASHFS_INVALID_BLK; | |
583 | + SQUASHFS_I(i)->fragment_offset = 0; | |
584 | + SQUASHFS_I(i)->start_block = inodep.start_block; | |
585 | + SQUASHFS_I(i)->block_list_start = next_block; | |
586 | + SQUASHFS_I(i)->offset = next_offset; | |
587 | + TRACE("File inode %x:%x, start_block %x, block_list_start %x, offset %x\n", | |
588 | + SQUASHFS_INODE_BLK(inode), offset, inodep.start_block, next_block, next_offset); | |
589 | + break; | |
590 | + } | |
591 | + case SQUASHFS_DIR_TYPE: { | |
592 | + squashfs_dir_inode_header_1 inodep; | |
593 | + | |
594 | + if(msBlk->swap) { | |
595 | + squashfs_dir_inode_header_1 sinodep; | |
596 | + | |
597 | + if(!squashfs_get_cached_block(s, (char *) &sinodep, block, offset, sizeof(sinodep), | |
598 | + &next_block, &next_offset)) | |
599 | + goto failed_read; | |
600 | + SQUASHFS_SWAP_DIR_INODE_HEADER_1(&inodep, &sinodep); | |
601 | + } else | |
602 | + if(!squashfs_get_cached_block(s, (char *) &inodep, block, offset, sizeof(inodep), | |
603 | + &next_block, &next_offset)) | |
604 | + goto failed_read; | |
605 | + | |
606 | + i->i_size = inodep.file_size; | |
607 | + i->i_op = &squashfs_dir_inode_ops; | |
608 | + i->i_fop = &squashfs_dir_ops; | |
609 | + i->i_mode |= S_IFDIR; | |
610 | + i->i_mtime.tv_sec = inodep.mtime; | |
611 | + i->i_atime.tv_sec = inodep.mtime; | |
612 | + i->i_ctime.tv_sec = inodep.mtime; | |
613 | + SQUASHFS_I(i)->start_block = inodep.start_block; | |
614 | + SQUASHFS_I(i)->offset = inodep.offset; | |
615 | + TRACE("Directory inode %x:%x, start_block %x, offset %x\n", SQUASHFS_INODE_BLK(inode), offset, | |
616 | + inodep.start_block, inodep.offset); | |
617 | + break; | |
618 | + } | |
619 | + case SQUASHFS_SYMLINK_TYPE: { | |
620 | + squashfs_symlink_inode_header_1 inodep; | |
621 | + | |
622 | + if(msBlk->swap) { | |
623 | + squashfs_symlink_inode_header_1 sinodep; | |
624 | + | |
625 | + if(!squashfs_get_cached_block(s, (char *) &sinodep, block, offset, sizeof(sinodep), | |
626 | + &next_block, &next_offset)) | |
627 | + goto failed_read; | |
628 | + SQUASHFS_SWAP_SYMLINK_INODE_HEADER_1(&inodep, &sinodep); | |
629 | + } else | |
630 | + if(!squashfs_get_cached_block(s, (char *) &inodep, block, offset, sizeof(inodep), | |
631 | + &next_block, &next_offset)) | |
632 | + goto failed_read; | |
633 | + | |
634 | + i->i_size = inodep.symlink_size; | |
635 | + i->i_op = &page_symlink_inode_operations; | |
636 | + i->i_data.a_ops = &squashfs_symlink_aops; | |
637 | + i->i_mode |= S_IFLNK; | |
638 | + SQUASHFS_I(i)->start_block = next_block; | |
639 | + SQUASHFS_I(i)->offset = next_offset; | |
640 | + TRACE("Symbolic link inode %x:%x, start_block %x, offset %x\n", | |
641 | + SQUASHFS_INODE_BLK(inode), offset, next_block, next_offset); | |
642 | + break; | |
643 | + } | |
644 | + case SQUASHFS_BLKDEV_TYPE: | |
645 | + case SQUASHFS_CHRDEV_TYPE: { | |
646 | + squashfs_dev_inode_header_1 inodep; | |
647 | + | |
648 | + if(msBlk->swap) { | |
649 | + squashfs_dev_inode_header_1 sinodep; | |
650 | + | |
651 | + if(!squashfs_get_cached_block(s, (char *) &sinodep, block, offset, sizeof(sinodep), | |
652 | + &next_block, &next_offset)) | |
653 | + goto failed_read; | |
654 | + SQUASHFS_SWAP_DEV_INODE_HEADER_1(&inodep, &sinodep); | |
655 | + } else | |
656 | + if(!squashfs_get_cached_block(s, (char *) &inodep, block, offset, sizeof(inodep), | |
657 | + &next_block, &next_offset)) | |
658 | + goto failed_read; | |
659 | + | |
660 | + i->i_size = 0; | |
661 | + i->i_mode |= (inodeb.inode_type == SQUASHFS_CHRDEV_TYPE) ? S_IFCHR : S_IFBLK; | |
662 | + init_special_inode(i, i->i_mode, old_decode_dev(inodep.rdev)); | |
663 | + TRACE("Device inode %x:%x, rdev %x\n", SQUASHFS_INODE_BLK(inode), offset, inodep.rdev); | |
664 | + break; | |
665 | + } | |
666 | + case SQUASHFS_IPC_TYPE: { | |
667 | + squashfs_ipc_inode_header_1 inodep; | |
668 | + | |
669 | + if(msBlk->swap) { | |
670 | + squashfs_ipc_inode_header_1 sinodep; | |
671 | + | |
672 | + if(!squashfs_get_cached_block(s, (char *) &sinodep, block, offset, sizeof(sinodep), | |
673 | + &next_block, &next_offset)) | |
674 | + goto failed_read; | |
675 | + SQUASHFS_SWAP_IPC_INODE_HEADER_1(&inodep, &sinodep); | |
676 | + } else | |
677 | + if(!squashfs_get_cached_block(s, (char *) &inodep, block, offset, sizeof(inodep), | |
678 | + &next_block, &next_offset)) | |
679 | + goto failed_read; | |
680 | + | |
681 | + i->i_size = 0; | |
682 | + i->i_mode |= (inodep.type == SQUASHFS_FIFO_TYPE) ? S_IFIFO : S_IFSOCK; | |
683 | + i->i_uid = msBlk->uid[inodep.offset * 16 + inodeb.uid]; | |
684 | + init_special_inode(i, i->i_mode, 0); | |
685 | + break; | |
686 | + } | |
687 | + default: | |
688 | + ERROR("Unknown inode type %d in squashfs_iget!\n", inodeb.inode_type); | |
689 | + goto failed_read1; | |
690 | + } | |
691 | + | |
692 | + if(inodeb.guid == SQUASHFS_GUIDS) | |
693 | + i->i_gid = i->i_uid; | |
694 | + else | |
695 | + i->i_gid = msBlk->guid[inodeb.guid]; | |
696 | + | |
697 | + return i; | |
698 | + | |
699 | +failed_read: | |
700 | + ERROR("Unable to read inode [%x:%x]\n", block, offset); | |
701 | + | |
702 | +failed_read1: | |
703 | + return NULL; | |
704 | +} | |
705 | +#endif | |
706 | + | |
707 | + | |
708 | +static struct inode *squashfs_iget(struct super_block *s, squashfs_inode inode) | |
709 | +{ | |
710 | + struct inode *i = new_inode(s); | |
711 | + squashfs_sb_info *msBlk = (squashfs_sb_info *)s->s_fs_info; | |
712 | + squashfs_super_block *sBlk = &msBlk->sBlk; | |
713 | + unsigned int block = SQUASHFS_INODE_BLK(inode) + sBlk->inode_table_start; | |
714 | + unsigned int offset = SQUASHFS_INODE_OFFSET(inode); | |
715 | + unsigned int next_block, next_offset; | |
716 | + squashfs_base_inode_header inodeb; | |
717 | + | |
718 | + TRACE("Entered squashfs_iget\n"); | |
719 | + | |
720 | + if(msBlk->swap) { | |
721 | + squashfs_base_inode_header sinodeb; | |
722 | + | |
723 | + if(!squashfs_get_cached_block(s, (char *) &sinodeb, block, offset, | |
724 | + sizeof(sinodeb), &next_block, &next_offset)) | |
725 | + goto failed_read; | |
726 | + SQUASHFS_SWAP_BASE_INODE_HEADER(&inodeb, &sinodeb, sizeof(sinodeb)); | |
727 | + } else | |
728 | + if(!squashfs_get_cached_block(s, (char *) &inodeb, block, offset, | |
729 | + sizeof(inodeb), &next_block, &next_offset)) | |
730 | + goto failed_read; | |
731 | + | |
732 | + i->i_nlink = 1; | |
733 | + | |
734 | + i->i_mtime.tv_sec = sBlk->mkfs_time; | |
735 | + i->i_atime.tv_sec = sBlk->mkfs_time; | |
736 | + i->i_ctime.tv_sec = sBlk->mkfs_time; | |
737 | + | |
738 | + i->i_uid = msBlk->uid[inodeb.uid]; | |
739 | + i->i_ino = SQUASHFS_MK_VFS_INODE(block - sBlk->inode_table_start, offset); | |
740 | + | |
741 | + i->i_mode = inodeb.mode; | |
742 | + | |
743 | + switch(inodeb.inode_type) { | |
744 | + case SQUASHFS_FILE_TYPE: { | |
745 | + squashfs_reg_inode_header inodep; | |
746 | + | |
747 | + if(msBlk->swap) { | |
748 | + squashfs_reg_inode_header sinodep; | |
749 | + | |
750 | + if(!squashfs_get_cached_block(s, (char *) &sinodep, block, offset, sizeof(sinodep), | |
751 | + &next_block, &next_offset)) | |
752 | + goto failed_read; | |
753 | + SQUASHFS_SWAP_REG_INODE_HEADER(&inodep, &sinodep); | |
754 | + } else | |
755 | + if(!squashfs_get_cached_block(s, (char *) &inodep, block, offset, sizeof(inodep), | |
756 | + &next_block, &next_offset)) | |
757 | + goto failed_read; | |
758 | + | |
759 | + SQUASHFS_I(i)->fragment_start_block = SQUASHFS_INVALID_BLK; | |
760 | + if(inodep.fragment != SQUASHFS_INVALID_BLK && !get_fragment_location(s, inodep.fragment, | |
761 | + &SQUASHFS_I(i)->fragment_start_block, &SQUASHFS_I(i)->fragment_size)) | |
762 | + goto failed_read; | |
763 | + | |
764 | + SQUASHFS_I(i)->fragment_offset = inodep.offset; | |
765 | + i->i_size = inodep.file_size; | |
766 | + i->i_fop = &generic_ro_fops; | |
767 | + if(sBlk->block_size > 4096) | |
768 | + i->i_data.a_ops = &squashfs_aops; | |
769 | + else | |
770 | + i->i_data.a_ops = &squashfs_aops_4K; | |
771 | + i->i_mode |= S_IFREG; | |
772 | + i->i_mtime.tv_sec = inodep.mtime; | |
773 | + i->i_atime.tv_sec = inodep.mtime; | |
774 | + i->i_ctime.tv_sec = inodep.mtime; | |
775 | + i->i_blocks = ((i->i_size - 1) >> 9) + 1; | |
776 | + i->i_blksize = PAGE_CACHE_SIZE; | |
777 | + SQUASHFS_I(i)->start_block = inodep.start_block; | |
778 | + SQUASHFS_I(i)->block_list_start = next_block; | |
779 | + SQUASHFS_I(i)->offset = next_offset; | |
780 | + TRACE("File inode %x:%x, start_block %x, block_list_start %x, offset %x\n", | |
781 | + SQUASHFS_INODE_BLK(inode), offset, inodep.start_block, next_block, next_offset); | |
782 | + break; | |
783 | + } | |
784 | + case SQUASHFS_DIR_TYPE: { | |
785 | + squashfs_dir_inode_header inodep; | |
786 | + | |
787 | + if(msBlk->swap) { | |
788 | + squashfs_dir_inode_header sinodep; | |
789 | + | |
790 | + if(!squashfs_get_cached_block(s, (char *) &sinodep, block, offset, sizeof(sinodep), | |
791 | + &next_block, &next_offset)) | |
792 | + goto failed_read; | |
793 | + SQUASHFS_SWAP_DIR_INODE_HEADER(&inodep, &sinodep); | |
794 | + } else | |
795 | + if(!squashfs_get_cached_block(s, (char *) &inodep, block, offset, sizeof(inodep), | |
796 | + &next_block, &next_offset)) | |
797 | + goto failed_read; | |
798 | + | |
799 | + i->i_size = inodep.file_size; | |
800 | + i->i_op = &squashfs_dir_inode_ops; | |
801 | + i->i_fop = &squashfs_dir_ops; | |
802 | + i->i_mode |= S_IFDIR; | |
803 | + i->i_mtime.tv_sec = inodep.mtime; | |
804 | + i->i_atime.tv_sec = inodep.mtime; | |
805 | + i->i_ctime.tv_sec = inodep.mtime; | |
806 | + SQUASHFS_I(i)->start_block = inodep.start_block; | |
807 | + SQUASHFS_I(i)->offset = inodep.offset; | |
808 | + TRACE("Directory inode %x:%x, start_block %x, offset %x\n", SQUASHFS_INODE_BLK(inode), offset, | |
809 | + inodep.start_block, inodep.offset); | |
810 | + break; | |
811 | + } | |
812 | + case SQUASHFS_SYMLINK_TYPE: { | |
813 | + squashfs_symlink_inode_header inodep; | |
814 | + | |
815 | + if(msBlk->swap) { | |
816 | + squashfs_symlink_inode_header sinodep; | |
817 | + | |
818 | + if(!squashfs_get_cached_block(s, (char *) &sinodep, block, offset, sizeof(sinodep), | |
819 | + &next_block, &next_offset)) | |
820 | + goto failed_read; | |
821 | + SQUASHFS_SWAP_SYMLINK_INODE_HEADER(&inodep, &sinodep); | |
822 | + } else | |
823 | + if(!squashfs_get_cached_block(s, (char *) &inodep, block, offset, sizeof(inodep), | |
824 | + &next_block, &next_offset)) | |
825 | + goto failed_read; | |
826 | + | |
827 | + i->i_size = inodep.symlink_size; | |
828 | + i->i_op = &page_symlink_inode_operations; | |
829 | + i->i_data.a_ops = &squashfs_symlink_aops; | |
830 | + i->i_mode |= S_IFLNK; | |
831 | + SQUASHFS_I(i)->start_block = next_block; | |
832 | + SQUASHFS_I(i)->offset = next_offset; | |
833 | + TRACE("Symbolic link inode %x:%x, start_block %x, offset %x\n", | |
834 | + SQUASHFS_INODE_BLK(inode), offset, next_block, next_offset); | |
835 | + break; | |
836 | + } | |
837 | + case SQUASHFS_BLKDEV_TYPE: | |
838 | + case SQUASHFS_CHRDEV_TYPE: { | |
839 | + squashfs_dev_inode_header inodep; | |
840 | + | |
841 | + if(msBlk->swap) { | |
842 | + squashfs_dev_inode_header sinodep; | |
843 | + | |
844 | + if(!squashfs_get_cached_block(s, (char *) &sinodep, block, offset, sizeof(sinodep), | |
845 | + &next_block, &next_offset)) | |
846 | + goto failed_read; | |
847 | + SQUASHFS_SWAP_DEV_INODE_HEADER(&inodep, &sinodep); | |
848 | + } else | |
849 | + if(!squashfs_get_cached_block(s, (char *) &inodep, block, offset, sizeof(inodep), | |
850 | + &next_block, &next_offset)) | |
851 | + goto failed_read; | |
852 | + | |
853 | + i->i_size = 0; | |
854 | + i->i_mode |= (inodeb.inode_type == SQUASHFS_CHRDEV_TYPE) ? S_IFCHR : S_IFBLK; | |
855 | + init_special_inode(i, i->i_mode, old_decode_dev(inodep.rdev)); | |
856 | + TRACE("Device inode %x:%x, rdev %x\n", SQUASHFS_INODE_BLK(inode), offset, inodep.rdev); | |
857 | + break; | |
858 | + } | |
859 | + case SQUASHFS_FIFO_TYPE: | |
860 | + case SQUASHFS_SOCKET_TYPE: { | |
861 | + i->i_size = 0; | |
862 | + i->i_mode |= (inodeb.inode_type == SQUASHFS_FIFO_TYPE) ? S_IFIFO : S_IFSOCK; | |
863 | + init_special_inode(i, i->i_mode, 0); | |
864 | + break; | |
865 | + } | |
866 | + default: | |
867 | + ERROR("Unknown inode type %d in squashfs_iget!\n", inodeb.inode_type); | |
868 | + goto failed_read1; | |
869 | + } | |
870 | + | |
871 | + if(inodeb.guid == SQUASHFS_GUIDS) | |
872 | + i->i_gid = i->i_uid; | |
873 | + else | |
874 | + i->i_gid = msBlk->guid[inodeb.guid]; | |
875 | + | |
876 | + return i; | |
877 | + | |
878 | +failed_read: | |
879 | + ERROR("Unable to read inode [%x:%x]\n", block, offset); | |
880 | + | |
881 | +failed_read1: | |
882 | + return NULL; | |
883 | +} | |
884 | + | |
885 | + | |
886 | +static int squashfs_fill_super(struct super_block *s, | |
887 | + void *data, int silent) | |
888 | +{ | |
889 | + squashfs_sb_info *msBlk; | |
890 | + squashfs_super_block *sBlk; | |
891 | + int i; | |
892 | + char b[BDEVNAME_SIZE]; | |
893 | + | |
894 | + TRACE("Entered squashfs_read_superblock\n"); | |
895 | + | |
896 | + if(!(msBlk = (squashfs_sb_info *) s->s_fs_info = (void *) kmalloc(sizeof(squashfs_sb_info), GFP_KERNEL))) { | |
897 | + ERROR("Failed to allocate superblock\n"); | |
898 | + return -ENOMEM; | |
899 | + } | |
900 | + sBlk = &msBlk->sBlk; | |
901 | + | |
902 | + msBlk->devblksize = sb_min_blocksize(s, BLOCK_SIZE); | |
903 | + msBlk->devblksize_log2 = ffz(~msBlk->devblksize); | |
904 | + | |
905 | + init_MUTEX(&msBlk->read_page_mutex); | |
906 | + init_MUTEX(&msBlk->block_cache_mutex); | |
907 | + init_MUTEX(&msBlk->fragment_mutex); | |
908 | + | |
909 | + init_waitqueue_head(&msBlk->waitq); | |
910 | + init_waitqueue_head(&msBlk->fragment_wait_queue); | |
911 | + | |
912 | + if(!read_data(s, (char *) sBlk, SQUASHFS_START, sizeof(squashfs_super_block) | SQUASHFS_COMPRESSED_BIT, 0, NULL)) { | |
913 | + SERROR("unable to read superblock\n"); | |
914 | + goto failed_mount; | |
915 | + } | |
916 | + | |
917 | + /* Check it is a SQUASHFS superblock */ | |
918 | + msBlk->swap = 0; | |
919 | + if((s->s_magic = sBlk->s_magic) != SQUASHFS_MAGIC) { | |
920 | + if(sBlk->s_magic == SQUASHFS_MAGIC_SWAP) { | |
921 | + squashfs_super_block sblk; | |
922 | + WARNING("Mounting a different endian SQUASHFS filesystem on %s\n", bdevname(s->s_bdev, b)); | |
923 | + SQUASHFS_SWAP_SUPER_BLOCK(&sblk, sBlk); | |
924 | + memcpy(sBlk, &sblk, sizeof(squashfs_super_block)); | |
925 | + msBlk->swap = 1; | |
926 | + } else { | |
927 | + SERROR("Can't find a SQUASHFS superblock on %s\n", bdevname(s->s_bdev, b)); | |
928 | + goto failed_mount; | |
929 | + } | |
930 | + } | |
931 | + | |
932 | + /* Check the MAJOR & MINOR versions */ | |
933 | +#ifdef SQUASHFS_1_0_COMPATIBILITY | |
934 | + if((sBlk->s_major != 1) && (sBlk->s_major != 2 || sBlk->s_minor > SQUASHFS_MINOR)) { | |
935 | + SERROR("Major/Minor mismatch, filesystem is (%d:%d), I support (1 : x) or (2 : <= %d)\n", | |
936 | + sBlk->s_major, sBlk->s_minor, SQUASHFS_MINOR); | |
937 | + goto failed_mount; | |
938 | + } | |
939 | + if(sBlk->s_major == 1) | |
940 | + sBlk->block_size = sBlk->block_size_1; | |
941 | +#else | |
942 | + if(sBlk->s_major != SQUASHFS_MAJOR || sBlk->s_minor > SQUASHFS_MINOR) { | |
943 | + SERROR("Major/Minor mismatch, filesystem is (%d:%d), I support (%d: <= %d)\n", | |
944 | + sBlk->s_major, sBlk->s_minor, SQUASHFS_MAJOR, SQUASHFS_MINOR); | |
945 | + goto failed_mount; | |
946 | + } | |
947 | +#endif | |
948 | + | |
949 | + TRACE("Found valid superblock on %s\n", bdevname(s->s_bdev, b)); | |
950 | + TRACE("Inodes are %scompressed\n", SQUASHFS_UNCOMPRESSED_INODES(sBlk->flags) ? "un" : ""); | |
951 | + TRACE("Data is %scompressed\n", SQUASHFS_UNCOMPRESSED_DATA(sBlk->flags) ? "un" : ""); | |
952 | + TRACE("Check data is %s present in the filesystem\n", SQUASHFS_CHECK_DATA(sBlk->flags) ? "" : "not"); | |
953 | + TRACE("Filesystem size %d bytes\n", sBlk->bytes_used); | |
954 | + TRACE("Block size %d\n", sBlk->block_size); | |
955 | + TRACE("Number of inodes %d\n", sBlk->inodes); | |
956 | + if(sBlk->s_major > 1) | |
957 | + TRACE("Number of fragments %d\n", sBlk->fragments); | |
958 | + TRACE("Number of uids %d\n", sBlk->no_uids); | |
959 | + TRACE("Number of gids %d\n", sBlk->no_guids); | |
960 | + TRACE("sBlk->inode_table_start %x\n", sBlk->inode_table_start); | |
961 | + TRACE("sBlk->directory_table_start %x\n", sBlk->directory_table_start); | |
962 | + if(sBlk->s_major > 1) | |
963 | + TRACE("sBlk->fragment_table_start %x\n", sBlk->fragment_table_start); | |
964 | + TRACE("sBlk->uid_start %x\n", sBlk->uid_start); | |
965 | + | |
966 | + s->s_flags |= MS_RDONLY; | |
967 | + s->s_op = &squashfs_ops; | |
968 | + | |
969 | + /* Init inode_table block pointer array */ | |
970 | + if(!(msBlk->block_cache = (squashfs_cache *) kmalloc(sizeof(squashfs_cache) * SQUASHFS_CACHED_BLKS, GFP_KERNEL))) { | |
971 | + ERROR("Failed to allocate block cache\n"); | |
972 | + goto failed_mount; | |
973 | + } | |
974 | + | |
975 | + for(i = 0; i < SQUASHFS_CACHED_BLKS; i++) | |
976 | + msBlk->block_cache[i].block = SQUASHFS_INVALID_BLK; | |
977 | + | |
978 | + msBlk->next_cache = 0; | |
979 | + | |
980 | + /* Allocate read_data block */ | |
981 | + msBlk->read_size = (sBlk->block_size < SQUASHFS_METADATA_SIZE) ? SQUASHFS_METADATA_SIZE : sBlk->block_size; | |
982 | + if(!(msBlk->read_data = (char *) kmalloc(msBlk->read_size, GFP_KERNEL))) { | |
983 | + ERROR("Failed to allocate read_data block\n"); | |
984 | + goto failed_mount1; | |
985 | + } | |
986 | + | |
987 | + /* Allocate read_page block */ | |
988 | + if(sBlk->block_size > PAGE_CACHE_SIZE && | |
989 | + !(msBlk->read_page = (char *) kmalloc(sBlk->block_size, GFP_KERNEL))) { | |
990 | + ERROR("Failed to allocate read_page block\n"); | |
991 | + goto failed_mount2; | |
992 | + } | |
993 | + | |
994 | + /* Allocate uid and gid tables */ | |
995 | + if(!(msBlk->uid = (squashfs_uid *) kmalloc((sBlk->no_uids + | |
996 | + sBlk->no_guids) * sizeof(squashfs_uid), GFP_KERNEL))) { | |
997 | + ERROR("Failed to allocate uid/gid table\n"); | |
998 | + goto failed_mount3; | |
999 | + } | |
1000 | + msBlk->guid = msBlk->uid + sBlk->no_uids; | |
1001 | + | |
1002 | + if(msBlk->swap) { | |
1003 | + squashfs_uid suid[sBlk->no_uids + sBlk->no_guids]; | |
1004 | + | |
1005 | + if(!read_data(s, (char *) &suid, sBlk->uid_start, ((sBlk->no_uids + sBlk->no_guids) * | |
1006 | + sizeof(squashfs_uid)) | SQUASHFS_COMPRESSED_BIT, 0, NULL)) { | |
1007 | + SERROR("unable to read uid/gid table\n"); | |
1008 | + goto failed_mount4; | |
1009 | + } | |
1010 | + SQUASHFS_SWAP_DATA(msBlk->uid, suid, (sBlk->no_uids + sBlk->no_guids), (sizeof(squashfs_uid) * 8)); | |
1011 | + } else | |
1012 | + if(!read_data(s, (char *) msBlk->uid, sBlk->uid_start, ((sBlk->no_uids + sBlk->no_guids) * | |
1013 | + sizeof(squashfs_uid)) | SQUASHFS_COMPRESSED_BIT, 0, NULL)) { | |
1014 | + SERROR("unable to read uid/gid table\n"); | |
1015 | + goto failed_mount4; | |
1016 | + } | |
1017 | + | |
1018 | + | |
1019 | +#ifdef SQUASHFS_1_0_COMPATIBILITY | |
1020 | + if(sBlk->s_major == 1) { | |
1021 | + msBlk->iget = squashfs_iget_1; | |
1022 | + msBlk->read_blocklist = read_blocklist_1; | |
1023 | + msBlk->fragment = (struct squashfs_fragment_cache *) msBlk->fragment_index = NULL; | |
1024 | + goto allocate_root; | |
1025 | + } | |
1026 | +#endif | |
1027 | + msBlk->iget = squashfs_iget; | |
1028 | + msBlk->read_blocklist = read_blocklist; | |
1029 | + | |
1030 | + if(!(msBlk->fragment = (struct squashfs_fragment_cache *) kmalloc(sizeof(struct squashfs_fragment_cache) * SQUASHFS_CACHED_FRAGMENTS, GFP_KERNEL))) { | |
1031 | + ERROR("Failed to allocate fragment block cache\n"); | |
1032 | + goto failed_mount4; | |
1033 | + } | |
1034 | + | |
1035 | + for(i = 0; i < SQUASHFS_CACHED_FRAGMENTS; i++) { | |
1036 | + msBlk->fragment[i].locked = 0; | |
1037 | + msBlk->fragment[i].block = SQUASHFS_INVALID_BLK; | |
1038 | + msBlk->fragment[i].data = NULL; | |
1039 | + } | |
1040 | + | |
1041 | + msBlk->next_fragment = 0; | |
1042 | + | |
1043 | + /* Allocate fragment index table */ | |
1044 | + if(!(msBlk->fragment_index = (squashfs_fragment_index *) kmalloc(SQUASHFS_FRAGMENT_INDEX_BYTES(sBlk->fragments), GFP_KERNEL))) { | |
1045 | + ERROR("Failed to allocate uid/gid table\n"); | |
1046 | + goto failed_mount5; | |
1047 | + } | |
1048 | + | |
1049 | + if(SQUASHFS_FRAGMENT_INDEX_BYTES(sBlk->fragments) && | |
1050 | + !read_data(s, (char *) msBlk->fragment_index, sBlk->fragment_table_start, | |
1051 | + SQUASHFS_FRAGMENT_INDEX_BYTES(sBlk->fragments) | SQUASHFS_COMPRESSED_BIT, 0, NULL)) { | |
1052 | + SERROR("unable to read fragment index table\n"); | |
1053 | + goto failed_mount6; | |
1054 | + } | |
1055 | + | |
1056 | + if(msBlk->swap) { | |
1057 | + int i; | |
1058 | + squashfs_fragment_index fragment; | |
1059 | + | |
1060 | + for(i = 0; i < SQUASHFS_FRAGMENT_INDEXES(sBlk->fragments); i++) { | |
1061 | + SQUASHFS_SWAP_FRAGMENT_INDEXES((&fragment), &msBlk->fragment_index[i], 1); | |
1062 | + msBlk->fragment_index[i] = fragment; | |
1063 | + } | |
1064 | + } | |
1065 | + | |
1066 | +#ifdef SQUASHFS_1_0_COMPATIBILITY | |
1067 | +allocate_root: | |
1068 | +#endif | |
1069 | + if(!(s->s_root = d_alloc_root((msBlk->iget)(s, sBlk->root_inode)))) { | |
1070 | + ERROR("Root inode create failed\n"); | |
1071 | + goto failed_mount5; | |
1072 | + } | |
1073 | + | |
1074 | + TRACE("Leaving squashfs_read_super\n"); | |
1075 | + return 0; | |
1076 | + | |
1077 | +failed_mount6: | |
1078 | + kfree(msBlk->fragment_index); | |
1079 | +failed_mount5: | |
1080 | + kfree(msBlk->fragment); | |
1081 | +failed_mount4: | |
1082 | + kfree(msBlk->uid); | |
1083 | +failed_mount3: | |
1084 | + kfree(msBlk->read_page); | |
1085 | +failed_mount2: | |
1086 | + kfree(msBlk->read_data); | |
1087 | +failed_mount1: | |
1088 | + kfree(msBlk->block_cache); | |
1089 | +failed_mount: | |
1090 | + kfree(s->s_fs_info); | |
1091 | + s->s_fs_info = NULL; | |
1092 | + return -EINVAL; | |
1093 | +} | |
1094 | + | |
1095 | + | |
1096 | +static int squashfs_statfs(struct super_block *s, struct kstatfs *buf) | |
1097 | +{ | |
1098 | + squashfs_super_block *sBlk = &((squashfs_sb_info *)s->s_fs_info)->sBlk; | |
1099 | + | |
1100 | + TRACE("Entered squashfs_statfs\n"); | |
1101 | + buf->f_type = SQUASHFS_MAGIC; | |
1102 | + buf->f_bsize = sBlk->block_size; | |
1103 | + buf->f_blocks = ((sBlk->bytes_used - 1) >> sBlk->block_log) + 1; | |
1104 | + buf->f_bfree = buf->f_bavail = 0; | |
1105 | + buf->f_files = sBlk->inodes; | |
1106 | + buf->f_ffree = 0; | |
1107 | + buf->f_namelen = SQUASHFS_NAME_LEN; | |
1108 | + return 0; | |
1109 | +} | |
1110 | + | |
1111 | + | |
1112 | +static int squashfs_symlink_readpage(struct file *file, struct page *page) | |
1113 | +{ | |
1114 | + struct inode *inode = page->mapping->host; | |
1115 | + int index = page->index << PAGE_CACHE_SHIFT, length, bytes; | |
1116 | + int block = SQUASHFS_I(inode)->start_block; | |
1117 | + int offset = SQUASHFS_I(inode)->offset; | |
1118 | + void *pageaddr = kmap(page); | |
1119 | + | |
1120 | + TRACE("Entered squashfs_symlink_readpage, page index %d, start block %x, offset %x\n", | |
1121 | + page->index, SQUASHFS_I(inode)->start_block, SQUASHFS_I(inode)->offset); | |
1122 | + | |
1123 | + for(length = 0; length < index; length += bytes) { | |
1124 | + if(!(bytes = squashfs_get_cached_block(inode->i_sb, NULL, block, offset, | |
1125 | + PAGE_CACHE_SIZE, &block, &offset))) { | |
1126 | + ERROR("Unable to read symbolic link [%x:%x]\n", block, offset); | |
1127 | + goto skip_read; | |
1128 | + } | |
1129 | + } | |
1130 | + | |
1131 | + if(length != index) { | |
1132 | + ERROR("(squashfs_symlink_readpage) length != index\n"); | |
1133 | + bytes = 0; | |
1134 | + goto skip_read; | |
1135 | + } | |
1136 | + | |
1137 | + bytes = (inode->i_size - length) > PAGE_CACHE_SIZE ? PAGE_CACHE_SIZE : inode->i_size - length; | |
1138 | + if(!(bytes = squashfs_get_cached_block(inode->i_sb, pageaddr, block, offset, bytes, &block, &offset))) | |
1139 | + ERROR("Unable to read symbolic link [%x:%x]\n", block, offset); | |
1140 | + | |
1141 | +skip_read: | |
1142 | + memset(pageaddr + bytes, 0, PAGE_CACHE_SIZE - bytes); | |
1143 | + kunmap(page); | |
1144 | + flush_dcache_page(page); | |
1145 | + SetPageUptodate(page); | |
1146 | + unlock_page(page); | |
1147 | + | |
1148 | + return 0; | |
1149 | +} | |
1150 | + | |
1151 | + | |
1152 | +#define SIZE 256 | |
1153 | + | |
1154 | +#ifdef SQUASHFS_1_0_COMPATIBILITY | |
1155 | +static unsigned int read_blocklist_1(struct inode *inode, int index, int readahead_blks, | |
1156 | + char *block_list, char **block_p, unsigned int *bsize) | |
1157 | +{ | |
1158 | + squashfs_sb_info *msBlk = (squashfs_sb_info *)inode->i_sb->s_fs_info; | |
1159 | + unsigned short *block_listp; | |
1160 | + int i = 0; | |
1161 | + int block_ptr = SQUASHFS_I(inode)->block_list_start; | |
1162 | + int offset = SQUASHFS_I(inode)->offset; | |
1163 | + int block = SQUASHFS_I(inode)->start_block; | |
1164 | + | |
1165 | + for(;;) { | |
1166 | + int blocks = (index + readahead_blks - i); | |
1167 | + if(blocks > (SIZE >> 1)) { | |
1168 | + if((index - i) <= (SIZE >> 1)) | |
1169 | + blocks = index - i; | |
1170 | + else | |
1171 | + blocks = SIZE >> 1; | |
1172 | + } | |
1173 | + | |
1174 | + if(msBlk->swap) { | |
1175 | + unsigned char sblock_list[SIZE]; | |
1176 | + if(!squashfs_get_cached_block(inode->i_sb, (char *) sblock_list, block_ptr, offset, blocks << 1, &block_ptr, &offset)) { | |
1177 | + ERROR("Unable to read block list [%d:%x]\n", block_ptr, offset); | |
1178 | + return 0; | |
1179 | + } | |
1180 | + SQUASHFS_SWAP_SHORTS(((unsigned short *)block_list), ((unsigned short *)sblock_list), blocks); | |
1181 | + } else | |
1182 | + if(!squashfs_get_cached_block(inode->i_sb, (char *) block_list, block_ptr, offset, blocks << 1, &block_ptr, &offset)) { | |
1183 | + ERROR("Unable to read block list [%d:%x]\n", block_ptr, offset); | |
1184 | + return 0; | |
1185 | + } | |
1186 | + for(block_listp = (unsigned short *) block_list; i < index && blocks; i ++, block_listp ++, blocks --) | |
1187 | + block += SQUASHFS_COMPRESSED_SIZE(*block_listp); | |
1188 | + if(blocks >= readahead_blks) | |
1189 | + break; | |
1190 | + } | |
1191 | + | |
1192 | + if(bsize) | |
1193 | + *bsize = SQUASHFS_COMPRESSED_SIZE(*block_listp) | (!SQUASHFS_COMPRESSED(*block_listp) ? SQUASHFS_COMPRESSED_BIT_BLOCK : 0); | |
1194 | + else | |
1195 | + (unsigned short *) *block_p = block_listp; | |
1196 | + return block; | |
1197 | +} | |
1198 | +#endif | |
1199 | + | |
1200 | + | |
1201 | +static unsigned int read_blocklist(struct inode *inode, int index, int readahead_blks, | |
1202 | + char *block_list, char **block_p, unsigned int *bsize) | |
1203 | +{ | |
1204 | + squashfs_sb_info *msBlk = (squashfs_sb_info *)inode->i_sb->s_fs_info; | |
1205 | + unsigned int *block_listp; | |
1206 | + int i = 0; | |
1207 | + int block_ptr = SQUASHFS_I(inode)->block_list_start; | |
1208 | + int offset = SQUASHFS_I(inode)->offset; | |
1209 | + int block = SQUASHFS_I(inode)->start_block; | |
1210 | + | |
1211 | + for(;;) { | |
1212 | + int blocks = (index + readahead_blks - i); | |
1213 | + if(blocks > (SIZE >> 2)) { | |
1214 | + if((index - i) <= (SIZE >> 2)) | |
1215 | + blocks = index - i; | |
1216 | + else | |
1217 | + blocks = SIZE >> 2; | |
1218 | + } | |
1219 | + | |
1220 | + if(msBlk->swap) { | |
1221 | + unsigned char sblock_list[SIZE]; | |
1222 | + if(!squashfs_get_cached_block(inode->i_sb, (char *) sblock_list, block_ptr, offset, blocks << 2, &block_ptr, &offset)) { | |
1223 | + ERROR("Unable to read block list [%d:%x]\n", block_ptr, offset); | |
1224 | + return 0; | |
1225 | + } | |
1226 | + SQUASHFS_SWAP_INTS(((unsigned int *)block_list), ((unsigned int *)sblock_list), blocks); | |
1227 | + } else | |
1228 | + if(!squashfs_get_cached_block(inode->i_sb, (char *) block_list, block_ptr, offset, blocks << 2, &block_ptr, &offset)) { | |
1229 | + ERROR("Unable to read block list [%d:%x]\n", block_ptr, offset); | |
1230 | + return 0; | |
1231 | + } | |
1232 | + for(block_listp = (unsigned int *) block_list; i < index && blocks; i ++, block_listp ++, blocks --) | |
1233 | + block += SQUASHFS_COMPRESSED_SIZE_BLOCK(*block_listp); | |
1234 | + if(blocks >= readahead_blks) | |
1235 | + break; | |
1236 | + } | |
1237 | + | |
1238 | + *bsize = *block_listp; | |
1239 | + return block; | |
1240 | +} | |
1241 | + | |
1242 | + | |
1243 | +static int squashfs_readpage(struct file *file, struct page *page) | |
1244 | +{ | |
1245 | + struct inode *inode = page->mapping->host; | |
1246 | + squashfs_sb_info *msBlk = (squashfs_sb_info *)inode->i_sb->s_fs_info; | |
1247 | + squashfs_super_block *sBlk = &msBlk->sBlk; | |
1248 | + unsigned char block_list[SIZE]; | |
1249 | + unsigned int bsize, block, i = 0, bytes = 0, byte_offset = 0; | |
1250 | + int index = page->index >> (sBlk->block_log - PAGE_CACHE_SHIFT); | |
1251 | + void *pageaddr = kmap(page); | |
1252 | + struct squashfs_fragment_cache *fragment; | |
1253 | + char *data_ptr = msBlk->read_page; | |
1254 | + | |
1255 | + int mask = (1 << (sBlk->block_log - PAGE_CACHE_SHIFT)) - 1; | |
1256 | + int start_index = page->index & ~mask; | |
1257 | + int end_index = start_index | mask; | |
1258 | + | |
1259 | + TRACE("Entered squashfs_readpage, page index %x, start block %x\n", (unsigned int) page->index, | |
1260 | + SQUASHFS_I(inode)->start_block); | |
1261 | + | |
1262 | + if(SQUASHFS_I(inode)->fragment_start_block == SQUASHFS_INVALID_BLK || index < (inode->i_size >> sBlk->block_log)) { | |
1263 | + if((block = (msBlk->read_blocklist)(inode, index, 1, block_list, NULL, &bsize)) == 0) | |
1264 | + goto skip_read; | |
1265 | + | |
1266 | + down(&msBlk->read_page_mutex); | |
1267 | + if(!(bytes = read_data(inode->i_sb, msBlk->read_page, block, bsize, 1, NULL))) { | |
1268 | + ERROR("Unable to read page, block %x, size %x\n", block, bsize); | |
1269 | + up(&msBlk->read_page_mutex); | |
1270 | + goto skip_read; | |
1271 | + } | |
1272 | + } else { | |
1273 | + if((fragment = get_cached_fragment(inode->i_sb, SQUASHFS_I(inode)->fragment_start_block, SQUASHFS_I(inode)->fragment_size)) == NULL) { | |
1274 | + ERROR("Unable to read page, block %x, size %x\n", SQUASHFS_I(inode)->fragment_start_block, (int) SQUASHFS_I(inode)->fragment_size); | |
1275 | + goto skip_read; | |
1276 | + } | |
1277 | + bytes = SQUASHFS_I(inode)->fragment_offset + (inode->i_size & (sBlk->block_size - 1)); | |
1278 | + byte_offset = SQUASHFS_I(inode)->fragment_offset; | |
1279 | + data_ptr = fragment->data; | |
1280 | + } | |
1281 | + | |
1282 | + for(i = start_index; i <= end_index && byte_offset < bytes; i++, byte_offset += PAGE_CACHE_SIZE) { | |
1283 | + struct page *push_page; | |
1284 | + int available_bytes = (bytes - byte_offset) > PAGE_CACHE_SIZE ? PAGE_CACHE_SIZE : bytes - byte_offset; | |
1285 | + | |
1286 | + TRACE("bytes %d, i %d, byte_offset %d, available_bytes %d\n", bytes, i, byte_offset, available_bytes); | |
1287 | + | |
1288 | + if(i == page->index) { | |
1289 | + memcpy(pageaddr, data_ptr + byte_offset, available_bytes); | |
1290 | + memset(pageaddr + available_bytes, 0, PAGE_CACHE_SIZE - available_bytes); | |
1291 | + kunmap(page); | |
1292 | + flush_dcache_page(page); | |
1293 | + SetPageUptodate(page); | |
1294 | + unlock_page(page); | |
1295 | + } else if((push_page = grab_cache_page_nowait(page->mapping, i))) { | |
1296 | + void *pageaddr = kmap(push_page); | |
1297 | + memcpy(pageaddr, data_ptr + byte_offset, available_bytes); | |
1298 | + memset(pageaddr + available_bytes, 0, PAGE_CACHE_SIZE - available_bytes); | |
1299 | + kunmap(push_page); | |
1300 | + flush_dcache_page(push_page); | |
1301 | + SetPageUptodate(push_page); | |
1302 | + unlock_page(push_page); | |
1303 | + page_cache_release(push_page); | |
1304 | + } | |
1305 | + } | |
1306 | + | |
1307 | + if(SQUASHFS_I(inode)->fragment_start_block == SQUASHFS_INVALID_BLK || index < (inode->i_size >> sBlk->block_log)) | |
1308 | + up(&msBlk->read_page_mutex); | |
1309 | + else | |
1310 | + release_cached_fragment(msBlk, fragment); | |
1311 | + | |
1312 | + return 0; | |
1313 | + | |
1314 | +skip_read: | |
1315 | + memset(pageaddr + bytes, 0, PAGE_CACHE_SIZE - bytes); | |
1316 | + kunmap(page); | |
1317 | + flush_dcache_page(page); | |
1318 | + SetPageUptodate(page); | |
1319 | + unlock_page(page); | |
1320 | + | |
1321 | + return 0; | |
1322 | +} | |
1323 | + | |
1324 | + | |
1325 | +static int squashfs_readpage4K(struct file *file, struct page *page) | |
1326 | +{ | |
1327 | + struct inode *inode = page->mapping->host; | |
1328 | + squashfs_sb_info *msBlk = (squashfs_sb_info *)inode->i_sb->s_fs_info; | |
1329 | + squashfs_super_block *sBlk = &msBlk->sBlk; | |
1330 | + unsigned char block_list[SIZE]; | |
1331 | + unsigned int bsize, block, bytes = 0; | |
1332 | + void *pageaddr = kmap(page); | |
1333 | + | |
1334 | + TRACE("Entered squashfs_readpage4K, page index %x, start block %x\n", (unsigned int) page->index, | |
1335 | + SQUASHFS_I(inode)->start_block); | |
1336 | + | |
1337 | + if(page->index < (inode->i_size >> sBlk->block_log)) { | |
1338 | + block = (msBlk->read_blocklist)(inode, page->index, 1, block_list, NULL, &bsize); | |
1339 | + | |
1340 | + if(!(bytes = read_data(inode->i_sb, pageaddr, block, bsize, 1, NULL))) | |
1341 | + ERROR("Unable to read page, block %x, size %x\n", block, bsize); | |
1342 | + } else { | |
1343 | + struct squashfs_fragment_cache *fragment; | |
1344 | + | |
1345 | + if((fragment = get_cached_fragment(inode->i_sb, SQUASHFS_I(inode)->fragment_start_block, SQUASHFS_I(inode)->fragment_size)) == NULL) | |
1346 | + ERROR("Unable to read page, block %x, size %x\n", SQUASHFS_I(inode)->fragment_start_block, (int) SQUASHFS_I(inode)->fragment_size); | |
1347 | + else { | |
1348 | + bytes = inode->i_size & (sBlk->block_size - 1); | |
1349 | + memcpy(pageaddr, fragment->data + SQUASHFS_I(inode)->fragment_offset, bytes); | |
1350 | + release_cached_fragment(msBlk, fragment); | |
1351 | + } | |
1352 | + } | |
1353 | + | |
1354 | + memset(pageaddr + bytes, 0, PAGE_CACHE_SIZE - bytes); | |
1355 | + kunmap(page); | |
1356 | + flush_dcache_page(page); | |
1357 | + SetPageUptodate(page); | |
1358 | + unlock_page(page); | |
1359 | + | |
1360 | + return 0; | |
1361 | +} | |
1362 | + | |
1363 | + | |
1364 | +#ifdef SQUASHFS_1_0_COMPATIBILITY | |
1365 | +static int squashfs_readpage_lessthan4K(struct file *file, struct page *page) | |
1366 | +{ | |
1367 | + struct inode *inode = page->mapping->host; | |
1368 | + squashfs_sb_info *msBlk = (squashfs_sb_info *)inode->i_sb->s_fs_info; | |
1369 | + squashfs_super_block *sBlk = &msBlk->sBlk; | |
1370 | + unsigned char block_list[SIZE]; | |
1371 | + unsigned short *block_listp, block, bytes = 0; | |
1372 | + int index = page->index << (PAGE_CACHE_SHIFT - sBlk->block_log); | |
1373 | + int file_blocks = ((inode->i_size - 1) >> sBlk->block_log) + 1; | |
1374 | + int readahead_blks = 1 << (PAGE_CACHE_SHIFT - sBlk->block_log); | |
1375 | + void *pageaddr = kmap(page); | |
1376 | + | |
1377 | + int i_end = index + (1 << (PAGE_CACHE_SHIFT - sBlk->block_log)); | |
1378 | + int byte; | |
1379 | + | |
1380 | + TRACE("Entered squashfs_readpage_lessthan4K, page index %x, start block %x\n", (unsigned int) page->index, | |
1381 | + SQUASHFS_I(inode)->start_block); | |
1382 | + | |
1383 | + block = read_blocklist_1(inode, index, readahead_blks, block_list, (char **) &block_listp, NULL); | |
1384 | + | |
1385 | + if(i_end > file_blocks) | |
1386 | + i_end = file_blocks; | |
1387 | + | |
1388 | + while(index < i_end) { | |
1389 | + if(!(byte = read_data(inode->i_sb, pageaddr, block, *block_listp, 0, NULL))) { | |
1390 | + ERROR("Unable to read page, block %x, size %x\n", block, *block_listp); | |
1391 | + goto skip_read; | |
1392 | + } | |
1393 | + block += SQUASHFS_COMPRESSED_SIZE(*block_listp); | |
1394 | + pageaddr += byte; | |
1395 | + bytes += byte; | |
1396 | + index ++; | |
1397 | + block_listp ++; | |
1398 | + } | |
1399 | + | |
1400 | +skip_read: | |
1401 | + memset(pageaddr, 0, PAGE_CACHE_SIZE - bytes); | |
1402 | + kunmap(page); | |
1403 | + flush_dcache_page(page); | |
1404 | + SetPageUptodate(page); | |
1405 | + unlock_page(page); | |
1406 | + | |
1407 | + return 0; | |
1408 | +} | |
1409 | +#endif | |
1410 | + | |
1411 | + | |
1412 | +static int squashfs_readdir(struct file *file, void *dirent, filldir_t filldir) | |
1413 | +{ | |
1414 | + struct inode *i = file->f_dentry->d_inode; | |
1415 | + squashfs_sb_info *msBlk = (squashfs_sb_info *)i->i_sb->s_fs_info; | |
1416 | + squashfs_super_block *sBlk = &msBlk->sBlk; | |
1417 | + int next_block = SQUASHFS_I(i)->start_block + sBlk->directory_table_start, next_offset = | |
1418 | + SQUASHFS_I(i)->offset, length = 0, dirs_read = 0, dir_count; | |
1419 | + squashfs_dir_header dirh; | |
1420 | + char buffer[sizeof(squashfs_dir_entry) + SQUASHFS_NAME_LEN + 1]; | |
1421 | + squashfs_dir_entry *dire = (squashfs_dir_entry *) buffer; | |
1422 | + | |
1423 | + TRACE("Entered squashfs_readdir [%x:%x]\n", next_block, next_offset); | |
1424 | + | |
1425 | + lock_kernel(); | |
1426 | + while(length < i->i_size) { | |
1427 | + /* read directory header */ | |
1428 | + if(msBlk->swap) { | |
1429 | + squashfs_dir_header sdirh; | |
1430 | + if(!squashfs_get_cached_block(i->i_sb, (char *) &sdirh, next_block, | |
1431 | + next_offset, sizeof(sdirh), &next_block, &next_offset)) | |
1432 | + goto failed_read; | |
1433 | + length += sizeof(sdirh); | |
1434 | + SQUASHFS_SWAP_DIR_HEADER(&dirh, &sdirh); | |
1435 | + } else { | |
1436 | + if(!squashfs_get_cached_block(i->i_sb, (char *) &dirh, next_block, | |
1437 | + next_offset, sizeof(dirh), &next_block, &next_offset)) | |
1438 | + goto failed_read; | |
1439 | + length += sizeof(dirh); | |
1440 | + } | |
1441 | + | |
1442 | + dir_count = dirh.count + 1; | |
1443 | + while(dir_count--) { | |
1444 | + if(msBlk->swap) { | |
1445 | + squashfs_dir_entry sdire; | |
1446 | + if(!squashfs_get_cached_block(i->i_sb, (char *) &sdire, next_block, | |
1447 | + next_offset, sizeof(sdire), &next_block, &next_offset)) | |
1448 | + goto failed_read; | |
1449 | + length += sizeof(sdire); | |
1450 | + SQUASHFS_SWAP_DIR_ENTRY(dire, &sdire); | |
1451 | + } else { | |
1452 | + if(!squashfs_get_cached_block(i->i_sb, (char *) dire, next_block, | |
1453 | + next_offset, sizeof(*dire), &next_block, &next_offset)) | |
1454 | + goto failed_read; | |
1455 | + length += sizeof(*dire); | |
1456 | + } | |
1457 | + | |
1458 | + if(!squashfs_get_cached_block(i->i_sb, dire->name, next_block, | |
1459 | + next_offset, dire->size + 1, &next_block, &next_offset)) | |
1460 | + goto failed_read; | |
1461 | + length += dire->size + 1; | |
1462 | + | |
1463 | + if(file->f_pos >= length) | |
1464 | + continue; | |
1465 | + | |
1466 | + dire->name[dire->size + 1] = '\0'; | |
1467 | + | |
1468 | + TRACE("Calling filldir(%x, %s, %d, %d, %x:%x, %d)\n", (unsigned int) dirent, | |
1469 | + dire->name, dire->size + 1, (int) file->f_pos, | |
1470 | + dirh.start_block, dire->offset, squashfs_filetype_table[dire->type]); | |
1471 | + | |
1472 | + if(filldir(dirent, dire->name, dire->size + 1, file->f_pos, SQUASHFS_MK_VFS_INODE(dirh.start_block, | |
1473 | + dire->offset), squashfs_filetype_table[dire->type]) < 0) { | |
1474 | + TRACE("Filldir returned less than 0\n"); | |
1475 | + unlock_kernel(); | |
1476 | + return dirs_read; | |
1477 | + } | |
1478 | + | |
1479 | + file->f_pos = length; | |
1480 | + dirs_read ++; | |
1481 | + } | |
1482 | + } | |
1483 | + | |
1484 | + unlock_kernel(); | |
1485 | + return dirs_read; | |
1486 | + | |
1487 | +failed_read: | |
1488 | + unlock_kernel(); | |
1489 | + ERROR("Unable to read directory block [%x:%x]\n", next_block, next_offset); | |
1490 | + return 0; | |
1491 | +} | |
1492 | + | |
1493 | + | |
1494 | +static struct dentry *squashfs_lookup(struct inode *i, struct dentry *dentry, struct nameidata *nd) | |
1495 | +{ | |
1496 | + const char *name =dentry->d_name.name; | |
1497 | + int len = dentry->d_name.len; | |
1498 | + struct inode *inode = NULL; | |
1499 | + squashfs_sb_info *msBlk = (squashfs_sb_info *)i->i_sb->s_fs_info; | |
1500 | + squashfs_super_block *sBlk = &msBlk->sBlk; | |
1501 | + int next_block = SQUASHFS_I(i)->start_block + sBlk->directory_table_start, next_offset = | |
1502 | + SQUASHFS_I(i)->offset, length = 0, dir_count; | |
1503 | + squashfs_dir_header dirh; | |
1504 | + char buffer[sizeof(squashfs_dir_entry) + SQUASHFS_NAME_LEN]; | |
1505 | + squashfs_dir_entry *dire = (squashfs_dir_entry *) buffer; | |
1506 | + | |
1507 | + TRACE("Entered squashfs_lookup [%x:%x]\n", next_block, next_offset); | |
1508 | + | |
1509 | + lock_kernel(); | |
1510 | + while(length < i->i_size) { | |
1511 | + /* read directory header */ | |
1512 | + if(msBlk->swap) { | |
1513 | + squashfs_dir_header sdirh; | |
1514 | + if(!squashfs_get_cached_block(i->i_sb, (char *) &sdirh, next_block, next_offset, | |
1515 | + sizeof(sdirh), &next_block, &next_offset)) | |
1516 | + goto failed_read; | |
1517 | + length += sizeof(sdirh); | |
1518 | + SQUASHFS_SWAP_DIR_HEADER(&dirh, &sdirh); | |
1519 | + } else { | |
1520 | + if(!squashfs_get_cached_block(i->i_sb, (char *) &dirh, next_block, next_offset, | |
1521 | + sizeof(dirh), &next_block, &next_offset)) | |
1522 | + goto failed_read; | |
1523 | + length += sizeof(dirh); | |
1524 | + } | |
1525 | + | |
1526 | + dir_count = dirh.count + 1; | |
1527 | + while(dir_count--) { | |
1528 | + if(msBlk->swap) { | |
1529 | + squashfs_dir_entry sdire; | |
1530 | + if(!squashfs_get_cached_block(i->i_sb, (char *) &sdire, | |
1531 | + next_block,next_offset, sizeof(sdire), &next_block, &next_offset)) | |
1532 | + goto failed_read; | |
1533 | + length += sizeof(sdire); | |
1534 | + SQUASHFS_SWAP_DIR_ENTRY(dire, &sdire); | |
1535 | + } else { | |
1536 | + if(!squashfs_get_cached_block(i->i_sb, (char *) dire, | |
1537 | + next_block,next_offset, sizeof(*dire), &next_block, &next_offset)) | |
1538 | + goto failed_read; | |
1539 | + length += sizeof(*dire); | |
1540 | + } | |
1541 | + | |
1542 | + if(!squashfs_get_cached_block(i->i_sb, dire->name, | |
1543 | + next_block, next_offset, dire->size + 1, &next_block, &next_offset)) | |
1544 | + goto failed_read; | |
1545 | + length += dire->size + 1; | |
1546 | + | |
1547 | + if((len == dire->size + 1) && !strncmp(name, dire->name, len)) { | |
1548 | + squashfs_inode ino = SQUASHFS_MKINODE(dirh.start_block, dire->offset); | |
1549 | + | |
1550 | + TRACE("calling squashfs_iget for directory entry %s, inode %x:%x\n", | |
1551 | + name, dirh.start_block, dire->offset); | |
1552 | + | |
1553 | + inode = (msBlk->iget)(i->i_sb, ino); | |
1554 | + | |
1555 | + goto exit_loop; | |
1556 | + } | |
1557 | + } | |
1558 | + } | |
1559 | + | |
1560 | +exit_loop: | |
1561 | + d_add(dentry, inode); | |
1562 | + unlock_kernel(); | |
1563 | + return ERR_PTR(0); | |
1564 | + | |
1565 | +failed_read: | |
1566 | + ERROR("Unable to read directory block [%x:%x]\n", next_block, next_offset); | |
1567 | + goto exit_loop; | |
1568 | +} | |
1569 | + | |
1570 | + | |
1571 | +static void squashfs_put_super(struct super_block *s) | |
1572 | +{ | |
1573 | + if(s->s_fs_info) { | |
1574 | + squashfs_sb_info *sbi = (squashfs_sb_info *) s->s_fs_info; | |
1575 | + if(sbi->block_cache) kfree(sbi->block_cache); | |
1576 | + if(sbi->read_data) kfree(sbi->read_data); | |
1577 | + if(sbi->read_page) kfree(sbi->read_page); | |
1578 | + if(sbi->uid) kfree(sbi->uid); | |
1579 | + if(sbi->fragment) kfree(sbi->fragment); | |
1580 | + if(sbi->fragment_index) kfree(sbi->fragment_index); | |
1581 | + kfree(s->s_fs_info); | |
1582 | + s->s_fs_info = NULL; | |
1583 | + } | |
1584 | +} | |
1585 | + | |
1586 | + | |
1587 | +static struct super_block *squashfs_get_sb(struct file_system_type *fs_type, int flags, const char *dev_name, void *data) | |
1588 | +{ | |
1589 | + return get_sb_bdev(fs_type, flags, dev_name, data, squashfs_fill_super); | |
1590 | +} | |
1591 | + | |
1592 | + | |
1593 | +static int __init init_squashfs_fs(void) | |
1594 | +{ | |
1595 | + int err = init_inodecache(); | |
1596 | + if(err) | |
1597 | + return err; | |
1598 | + | |
1599 | + if(!(stream.workspace = (char *) vmalloc(zlib_inflate_workspacesize()))) { | |
1600 | + ERROR("Failed to allocate zlib workspace\n"); | |
1601 | + destroy_inodecache(); | |
1602 | + return -ENOMEM; | |
1603 | + } | |
1604 | + | |
1605 | + if((err = register_filesystem(&squashfs_fs_type))) { | |
1606 | + vfree(stream.workspace); | |
1607 | + destroy_inodecache(); | |
1608 | + } | |
1609 | + | |
1610 | + return err; | |
1611 | +} | |
1612 | + | |
1613 | + | |
1614 | +static void __exit exit_squashfs_fs(void) | |
1615 | +{ | |
1616 | + vfree(stream.workspace); | |
1617 | + unregister_filesystem(&squashfs_fs_type); | |
1618 | + destroy_inodecache(); | |
1619 | +} | |
1620 | + | |
1621 | + | |
1622 | +static kmem_cache_t * squashfs_inode_cachep; | |
1623 | + | |
1624 | + | |
1625 | +static struct inode *squashfs_alloc_inode(struct super_block *sb) | |
1626 | +{ | |
1627 | + struct squashfs_inode_info *ei; | |
1628 | + ei = (struct squashfs_inode_info *)kmem_cache_alloc(squashfs_inode_cachep, SLAB_KERNEL); | |
1629 | + if (!ei) | |
1630 | + return NULL; | |
1631 | + return &ei->vfs_inode; | |
1632 | +} | |
1633 | + | |
1634 | + | |
1635 | +static void squashfs_destroy_inode(struct inode *inode) | |
1636 | +{ | |
1637 | + kmem_cache_free(squashfs_inode_cachep, SQUASHFS_I(inode)); | |
1638 | +} | |
1639 | + | |
1640 | + | |
1641 | +static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags) | |
1642 | +{ | |
1643 | + struct squashfs_inode_info *ei = (struct squashfs_inode_info *) foo; | |
1644 | + | |
1645 | + if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) == | |
1646 | + SLAB_CTOR_CONSTRUCTOR) | |
1647 | + inode_init_once(&ei->vfs_inode); | |
1648 | +} | |
1649 | + | |
1650 | + | |
1651 | +static int init_inodecache(void) | |
1652 | +{ | |
1653 | + squashfs_inode_cachep = kmem_cache_create("squashfs_inode_cache", | |
1654 | + sizeof(struct squashfs_inode_info), | |
1655 | + 0, SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT, | |
1656 | + init_once, NULL); | |
1657 | + if (squashfs_inode_cachep == NULL) | |
1658 | + return -ENOMEM; | |
1659 | + return 0; | |
1660 | +} | |
1661 | + | |
1662 | + | |
1663 | +static void destroy_inodecache(void) | |
1664 | +{ | |
1665 | + if (kmem_cache_destroy(squashfs_inode_cachep)) | |
1666 | + printk(KERN_INFO "squashfs_inode_cache: not all structures were freed\n"); | |
1667 | +} | |
1668 | + | |
1669 | + | |
1670 | +module_init(init_squashfs_fs); | |
1671 | +module_exit(exit_squashfs_fs); | |
1672 | +MODULE_DESCRIPTION("squashfs, a compressed read-only filesystem"); | |
1673 | +MODULE_AUTHOR("Phillip Lougher <plougher@users.sourceforge.net>"); | |
1674 | +MODULE_LICENSE("GPL"); | |
1675 | diff --new-file -ur linux-2.6.6/fs/squashfs/Makefile linux-2.6.6-squashfs2.0/fs/squashfs/Makefile | |
1676 | --- linux-2.6.6/fs/squashfs/Makefile 1970-01-01 01:00:00.000000000 +0100 | |
1677 | +++ linux-2.6.6-squashfs2.0/fs/squashfs/Makefile 2004-03-22 00:09:48.000000000 +0000 | |
1678 | @@ -0,0 +1,7 @@ | |
1679 | +# | |
1680 | +# Makefile for the linux squashfs routines. | |
1681 | +# | |
1682 | + | |
1683 | +obj-$(CONFIG_SQUASHFS) += squashfs.o | |
1684 | + | |
1685 | +squashfs-objs := inode.o | |
1686 | diff --new-file -ur linux-2.6.6/include/linux/squashfs_fs.h linux-2.6.6-squashfs2.0/include/linux/squashfs_fs.h | |
1687 | --- linux-2.6.6/include/linux/squashfs_fs.h 1970-01-01 01:00:00.000000000 +0100 | |
1688 | +++ linux-2.6.6-squashfs2.0/include/linux/squashfs_fs.h 2004-05-19 00:20:39.000000000 +0100 | |
1689 | @@ -0,0 +1,474 @@ | |
1690 | +#ifndef SQUASHFS_FS | |
1691 | +#define SQUASHFS_FS | |
1692 | +/* | |
1693 | + * Squashfs | |
1694 | + * | |
1695 | + * Copyright (c) 2002, 2003, 2004 Phillip Lougher <plougher@users.sourceforge.net> | |
1696 | + * | |
1697 | + * This program is free software; you can redistribute it and/or | |
1698 | + * modify it under the terms of the GNU General Public License | |
1699 | + * as published by the Free Software Foundation; either version 2, | |
1700 | + * or (at your option) any later version. | |
1701 | + * | |
1702 | + * This program is distributed in the hope that it will be useful, | |
1703 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
1704 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
1705 | + * GNU General Public License for more details. | |
1706 | + * | |
1707 | + * You should have received a copy of the GNU General Public License | |
1708 | + * along with this program; if not, write to the Free Software | |
1709 | + * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |
1710 | + * | |
1711 | + * squashfs_fs.h | |
1712 | + */ | |
1713 | + | |
1714 | +#define SQUASHFS_MAJOR 2 | |
1715 | +#define SQUASHFS_MINOR 0 | |
1716 | +#define SQUASHFS_MAGIC 0x73717368 | |
1717 | +#define SQUASHFS_MAGIC_SWAP 0x68737173 | |
1718 | +#define SQUASHFS_START 0 | |
1719 | + | |
1720 | +/* size of metadata (inode and directory) blocks */ | |
1721 | +#define SQUASHFS_METADATA_SIZE 8192 | |
1722 | +#define SQUASHFS_METADATA_LOG 13 | |
1723 | + | |
1724 | +/* default size of data blocks */ | |
1725 | +#define SQUASHFS_FILE_SIZE 65536 | |
1726 | +#define SQUASHFS_FILE_LOG 16 | |
1727 | + | |
1728 | +#define SQUASHFS_FILE_MAX_SIZE 65536 | |
1729 | + | |
1730 | +/* Max number of uids and gids */ | |
1731 | +#define SQUASHFS_UIDS 256 | |
1732 | +#define SQUASHFS_GUIDS 255 | |
1733 | + | |
1734 | +/* Max length of filename (not 255) */ | |
1735 | +#define SQUASHFS_NAME_LEN 256 | |
1736 | + | |
1737 | +#define SQUASHFS_INVALID ((long long) 0xffffffffffff) | |
1738 | +#define SQUASHFS_INVALID_BLK ((long long) 0xffffffff) | |
1739 | +#define SQUASHFS_USED_BLK ((long long) 0xfffffffe) | |
1740 | + | |
1741 | +/* Filesystem flags */ | |
1742 | +#define SQUASHFS_NOI 0 | |
1743 | +#define SQUASHFS_NOD 1 | |
1744 | +#define SQUASHFS_CHECK 2 | |
1745 | +#define SQUASHFS_NOF 3 | |
1746 | +#define SQUASHFS_NO_FRAG 4 | |
1747 | +#define SQUASHFS_ALWAYS_FRAG 5 | |
1748 | +#define SQUASHFS_DUPLICATE 6 | |
1749 | +#define SQUASHFS_BIT(flag, bit) ((flag >> bit) & 1) | |
1750 | +#define SQUASHFS_UNCOMPRESSED_INODES(flags) SQUASHFS_BIT(flags, SQUASHFS_NOI) | |
1751 | +#define SQUASHFS_UNCOMPRESSED_DATA(flags) SQUASHFS_BIT(flags, SQUASHFS_NOD) | |
1752 | +#define SQUASHFS_UNCOMPRESSED_FRAGMENTS(flags) SQUASHFS_BIT(flags, SQUASHFS_NOF) | |
1753 | +#define SQUASHFS_NO_FRAGMENTS(flags) SQUASHFS_BIT(flags, SQUASHFS_NO_FRAG) | |
1754 | +#define SQUASHFS_ALWAYS_FRAGMENTS(flags) SQUASHFS_BIT(flags, SQUASHFS_ALWAYS_FRAG) | |
1755 | +#define SQUASHFS_DUPLICATES(flags) SQUASHFS_BIT(flags, SQUASHFS_DUPLICATE) | |
1756 | +#define SQUASHFS_CHECK_DATA(flags) SQUASHFS_BIT(flags, SQUASHFS_CHECK) | |
1757 | +#define SQUASHFS_MKFLAGS(noi, nod, check_data, nof, no_frag, always_frag, duplicate_checking) (noi | (nod << 1) | (check_data << 2) | (nof << 3) | (no_frag << 4) | (always_frag << 5) | (duplicate_checking << 6)) | |
1758 | + | |
1759 | +/* Max number of types and file types */ | |
1760 | +#define SQUASHFS_DIR_TYPE 1 | |
1761 | +#define SQUASHFS_FILE_TYPE 2 | |
1762 | +#define SQUASHFS_SYMLINK_TYPE 3 | |
1763 | +#define SQUASHFS_BLKDEV_TYPE 4 | |
1764 | +#define SQUASHFS_CHRDEV_TYPE 5 | |
1765 | +#define SQUASHFS_FIFO_TYPE 6 | |
1766 | +#define SQUASHFS_SOCKET_TYPE 7 | |
1767 | + | |
1768 | +/* 1.0 filesystem type definitions */ | |
1769 | +#define SQUASHFS_TYPES 5 | |
1770 | +#define SQUASHFS_IPC_TYPE 0 | |
1771 | + | |
1772 | +/* Flag whether block is compressed or uncompressed, bit is set if block is uncompressed */ | |
1773 | +#define SQUASHFS_COMPRESSED_BIT (1 << 15) | |
1774 | +#define SQUASHFS_COMPRESSED_SIZE(B) (((B) & ~SQUASHFS_COMPRESSED_BIT) ? \ | |
1775 | + (B) & ~SQUASHFS_COMPRESSED_BIT : SQUASHFS_COMPRESSED_BIT) | |
1776 | + | |
1777 | +#define SQUASHFS_COMPRESSED(B) (!((B) & SQUASHFS_COMPRESSED_BIT)) | |
1778 | + | |
1779 | +#define SQUASHFS_COMPRESSED_BIT_BLOCK (1 << 24) | |
1780 | +#define SQUASHFS_COMPRESSED_SIZE_BLOCK(B) (((B) & ~SQUASHFS_COMPRESSED_BIT_BLOCK) ? \ | |
1781 | + (B) & ~SQUASHFS_COMPRESSED_BIT_BLOCK : SQUASHFS_COMPRESSED_BIT_BLOCK) | |
1782 | + | |
1783 | +#define SQUASHFS_COMPRESSED_BLOCK(B) (!((B) & SQUASHFS_COMPRESSED_BIT_BLOCK)) | |
1784 | + | |
1785 | +/* | |
1786 | + * Inode number ops. Inodes consist of a compressed block number, and an uncompressed | |
1787 | + * offset within that block | |
1788 | + */ | |
1789 | +#define SQUASHFS_INODE_BLK(a) ((unsigned int) ((a) >> 16)) | |
1790 | +#define SQUASHFS_INODE_OFFSET(a) ((unsigned int) ((a) & 0xffff)) | |
1791 | +#define SQUASHFS_MKINODE(A, B) ((squashfs_inode)(((squashfs_inode) (A) << 16)\ | |
1792 | + + (B))) | |
1793 | + | |
1794 | +/* Compute 32 bit VFS inode number from squashfs inode number */ | |
1795 | +#define SQUASHFS_MK_VFS_INODE(a, b) ((unsigned int) (((a) << 8) + ((b) >> 2) + 1)) | |
1796 | + | |
1797 | +/* Translate between VFS mode and squashfs mode */ | |
1798 | +#define SQUASHFS_MODE(a) ((a) & 0xfff) | |
1799 | + | |
1800 | +/* fragment and fragment table defines */ | |
1801 | +typedef unsigned int squashfs_fragment_index; | |
1802 | +#define SQUASHFS_FRAGMENT_BYTES(A) (A * sizeof(squashfs_fragment_entry)) | |
1803 | +#define SQUASHFS_FRAGMENT_INDEX(A) (SQUASHFS_FRAGMENT_BYTES(A) / SQUASHFS_METADATA_SIZE) | |
1804 | +#define SQUASHFS_FRAGMENT_INDEX_OFFSET(A) (SQUASHFS_FRAGMENT_BYTES(A) % SQUASHFS_METADATA_SIZE) | |
1805 | +#define SQUASHFS_FRAGMENT_INDEXES(A) ((SQUASHFS_FRAGMENT_BYTES(A) + SQUASHFS_METADATA_SIZE - 1) / SQUASHFS_METADATA_SIZE) | |
1806 | +#define SQUASHFS_FRAGMENT_INDEX_BYTES(A) (SQUASHFS_FRAGMENT_INDEXES(A) * sizeof(squashfs_fragment_index)) | |
1807 | +#define SQUASHFS_CACHED_FRAGMENTS 3 | |
1808 | + | |
1809 | +/* cached data constants for filesystem */ | |
1810 | +#define SQUASHFS_CACHED_BLKS 8 | |
1811 | + | |
1812 | +#define SQUASHFS_MAX_FILE_SIZE_LOG 32 | |
1813 | +#define SQUASHFS_MAX_FILE_SIZE ((long long) 1 << (SQUASHFS_MAX_FILE_SIZE_LOG - 1)) | |
1814 | + | |
1815 | +#define SQUASHFS_MARKER_BYTE 0xff | |
1816 | + | |
1817 | +/* | |
1818 | + * definitions for structures on disk | |
1819 | + */ | |
1820 | + | |
1821 | +typedef unsigned int squashfs_block; | |
1822 | +typedef long long squashfs_inode; | |
1823 | + | |
1824 | +typedef unsigned int squashfs_uid; | |
1825 | + | |
1826 | +typedef struct squashfs_super_block { | |
1827 | + unsigned int s_magic; | |
1828 | + unsigned int inodes; | |
1829 | + unsigned int bytes_used; | |
1830 | + unsigned int uid_start; | |
1831 | + unsigned int guid_start; | |
1832 | + unsigned int inode_table_start; | |
1833 | + unsigned int directory_table_start; | |
1834 | + unsigned int s_major:16; | |
1835 | + unsigned int s_minor:16; | |
1836 | + unsigned int block_size_1:16; | |
1837 | + unsigned int block_log:16; | |
1838 | + unsigned int flags:8; | |
1839 | + unsigned int no_uids:8; | |
1840 | + unsigned int no_guids:8; | |
720d8c92 | 1841 | + unsigned int mkfs_time /* time of filesystem creation */; |
9cdc8a28 | 1842 | + squashfs_inode root_inode; |
1843 | + unsigned int block_size; | |
1844 | + unsigned int fragments; | |
1845 | + unsigned int fragment_table_start; | |
1846 | +} __attribute__ ((packed)) squashfs_super_block; | |
1847 | + | |
1848 | +typedef struct { | |
1849 | + unsigned int inode_type:4; | |
1850 | + unsigned int mode:12; /* protection */ | |
1851 | + unsigned int uid:8; /* index into uid table */ | |
1852 | + unsigned int guid:8; /* index into guid table */ | |
1853 | +} __attribute__ ((packed)) squashfs_base_inode_header; | |
1854 | + | |
1855 | +typedef squashfs_base_inode_header squashfs_ipc_inode_header; | |
1856 | + | |
1857 | +typedef struct { | |
1858 | + unsigned int inode_type:4; | |
1859 | + unsigned int mode:12; /* protection */ | |
1860 | + unsigned int uid:8; /* index into uid table */ | |
1861 | + unsigned int guid:8; /* index into guid table */ | |
1862 | + unsigned short rdev; | |
1863 | +} __attribute__ ((packed)) squashfs_dev_inode_header; | |
1864 | + | |
1865 | +typedef struct { | |
1866 | + unsigned int inode_type:4; | |
1867 | + unsigned int mode:12; /* protection */ | |
1868 | + unsigned int uid:8; /* index into uid table */ | |
1869 | + unsigned int guid:8; /* index into guid table */ | |
1870 | + unsigned short symlink_size; | |
1871 | + char symlink[0]; | |
1872 | +} __attribute__ ((packed)) squashfs_symlink_inode_header; | |
1873 | + | |
1874 | +typedef struct { | |
1875 | + unsigned int inode_type:4; | |
1876 | + unsigned int mode:12; /* protection */ | |
1877 | + unsigned int uid:8; /* index into uid table */ | |
1878 | + unsigned int guid:8; /* index into guid table */ | |
720d8c92 | 1879 | + unsigned int mtime; |
9cdc8a28 | 1880 | + squashfs_block start_block; |
1881 | + unsigned int fragment; | |
1882 | + unsigned int offset; | |
1883 | + unsigned int file_size:SQUASHFS_MAX_FILE_SIZE_LOG; | |
1884 | + unsigned short block_list[0]; | |
1885 | +} __attribute__ ((packed)) squashfs_reg_inode_header; | |
1886 | + | |
1887 | +typedef struct { | |
1888 | + unsigned int inode_type:4; | |
1889 | + unsigned int mode:12; /* protection */ | |
1890 | + unsigned int uid:8; /* index into uid table */ | |
1891 | + unsigned int guid:8; /* index into guid table */ | |
1892 | + unsigned int file_size:19; | |
1893 | + unsigned int offset:13; | |
720d8c92 | 1894 | + unsigned int mtime; |
9cdc8a28 | 1895 | + unsigned int start_block:24; |
1896 | +} __attribute__ ((packed)) squashfs_dir_inode_header; | |
1897 | + | |
1898 | +typedef union { | |
1899 | + squashfs_base_inode_header base; | |
1900 | + squashfs_dev_inode_header dev; | |
1901 | + squashfs_symlink_inode_header symlink; | |
1902 | + squashfs_reg_inode_header reg; | |
1903 | + squashfs_dir_inode_header dir; | |
1904 | + squashfs_ipc_inode_header ipc; | |
1905 | +} squashfs_inode_header; | |
1906 | + | |
1907 | +typedef struct { | |
1908 | + unsigned int offset:13; | |
1909 | + unsigned int type:3; | |
1910 | + unsigned int size:8; | |
1911 | + char name[0]; | |
1912 | +} __attribute__ ((packed)) squashfs_dir_entry; | |
1913 | + | |
1914 | +typedef struct { | |
1915 | + unsigned int count:8; | |
1916 | + unsigned int start_block:24; | |
1917 | +} __attribute__ ((packed)) squashfs_dir_header; | |
1918 | + | |
1919 | + | |
1920 | +typedef struct { | |
1921 | + unsigned int start_block; | |
1922 | + unsigned int size; | |
1923 | +} __attribute__ ((packed)) squashfs_fragment_entry; | |
1924 | + | |
1925 | +extern int squashfs_uncompress_block(void *d, int dstlen, void *s, int srclen); | |
1926 | +extern int squashfs_uncompress_init(void); | |
1927 | +extern int squashfs_uncompress_exit(void); | |
1928 | + | |
1929 | +/* | |
1930 | + * macros to convert each packed bitfield structure from little endian to big | |
1931 | + * endian and vice versa. These are needed when creating or using a filesystem on a | |
1932 | + * machine with different byte ordering to the target architecture. | |
1933 | + * | |
1934 | + */ | |
1935 | + | |
1936 | +#define SQUASHFS_SWAP_SUPER_BLOCK(s, d) {\ | |
1937 | + SQUASHFS_MEMSET(s, d, sizeof(squashfs_super_block));\ | |
1938 | + SQUASHFS_SWAP((s)->s_magic, d, 0, 32);\ | |
1939 | + SQUASHFS_SWAP((s)->inodes, d, 32, 32);\ | |
1940 | + SQUASHFS_SWAP((s)->bytes_used, d, 64, 32);\ | |
1941 | + SQUASHFS_SWAP((s)->uid_start, d, 96, 32);\ | |
1942 | + SQUASHFS_SWAP((s)->guid_start, d, 128, 32);\ | |
1943 | + SQUASHFS_SWAP((s)->inode_table_start, d, 160, 32);\ | |
1944 | + SQUASHFS_SWAP((s)->directory_table_start, d, 192, 32);\ | |
1945 | + SQUASHFS_SWAP((s)->s_major, d, 224, 16);\ | |
1946 | + SQUASHFS_SWAP((s)->s_minor, d, 240, 16);\ | |
1947 | + SQUASHFS_SWAP((s)->block_size_1, d, 256, 16);\ | |
1948 | + SQUASHFS_SWAP((s)->block_log, d, 272, 16);\ | |
1949 | + SQUASHFS_SWAP((s)->flags, d, 288, 8);\ | |
1950 | + SQUASHFS_SWAP((s)->no_uids, d, 296, 8);\ | |
1951 | + SQUASHFS_SWAP((s)->no_guids, d, 304, 8);\ | |
1952 | + SQUASHFS_SWAP((s)->mkfs_time, d, 312, 32);\ | |
1953 | + SQUASHFS_SWAP((s)->root_inode, d, 344, 64);\ | |
1954 | + SQUASHFS_SWAP((s)->block_size, d, 408, 32);\ | |
1955 | + SQUASHFS_SWAP((s)->fragments, d, 440, 32);\ | |
1956 | + SQUASHFS_SWAP((s)->fragment_table_start, d, 472, 32);\ | |
1957 | +} | |
1958 | + | |
1959 | +#define SQUASHFS_SWAP_BASE_INODE_HEADER(s, d, n) {\ | |
1960 | + SQUASHFS_MEMSET(s, d, n);\ | |
1961 | + SQUASHFS_SWAP((s)->inode_type, d, 0, 4);\ | |
1962 | + SQUASHFS_SWAP((s)->mode, d, 4, 12);\ | |
1963 | + SQUASHFS_SWAP((s)->uid, d, 16, 8);\ | |
1964 | + SQUASHFS_SWAP((s)->guid, d, 24, 8);\ | |
1965 | +} | |
1966 | + | |
1967 | +#define SQUASHFS_SWAP_IPC_INODE_HEADER(s, d) SQUASHFS_SWAP_BASE_INODE_HEADER(s, d, sizeof(squashfs_ipc_inode_header)) | |
1968 | + | |
1969 | +#define SQUASHFS_SWAP_DEV_INODE_HEADER(s, d) {\ | |
1970 | + SQUASHFS_SWAP_BASE_INODE_HEADER(s, d, sizeof(squashfs_dev_inode_header));\ | |
1971 | + SQUASHFS_SWAP((s)->rdev, d, 32, 16);\ | |
1972 | +} | |
1973 | + | |
1974 | +#define SQUASHFS_SWAP_SYMLINK_INODE_HEADER(s, d) {\ | |
1975 | + SQUASHFS_SWAP_BASE_INODE_HEADER(s, d, sizeof(squashfs_symlink_inode_header));\ | |
1976 | + SQUASHFS_SWAP((s)->symlink_size, d, 32, 16);\ | |
1977 | +} | |
1978 | + | |
1979 | +#define SQUASHFS_SWAP_REG_INODE_HEADER(s, d) {\ | |
1980 | + SQUASHFS_SWAP_BASE_INODE_HEADER(s, d, sizeof(squashfs_reg_inode_header));\ | |
1981 | + SQUASHFS_SWAP((s)->mtime, d, 32, 32);\ | |
1982 | + SQUASHFS_SWAP((s)->start_block, d, 64, 32);\ | |
1983 | + SQUASHFS_SWAP((s)->fragment, d, 96, 32);\ | |
1984 | + SQUASHFS_SWAP((s)->offset, d, 128, 32);\ | |
1985 | + SQUASHFS_SWAP((s)->file_size, d, 160, SQUASHFS_MAX_FILE_SIZE_LOG);\ | |
1986 | +} | |
1987 | + | |
1988 | +#define SQUASHFS_SWAP_DIR_INODE_HEADER(s, d) {\ | |
1989 | + SQUASHFS_SWAP_BASE_INODE_HEADER(s, d, sizeof(squashfs_dir_inode_header));\ | |
1990 | + SQUASHFS_SWAP((s)->file_size, d, 32, 19);\ | |
1991 | + SQUASHFS_SWAP((s)->offset, d, 51, 13);\ | |
1992 | + SQUASHFS_SWAP((s)->mtime, d, 64, 32);\ | |
1993 | + SQUASHFS_SWAP((s)->start_block, d, 96, 24);\ | |
1994 | +} | |
1995 | + | |
1996 | +#define SQUASHFS_SWAP_DIR_HEADER(s, d) {\ | |
1997 | + SQUASHFS_MEMSET(s, d, sizeof(squashfs_dir_header));\ | |
1998 | + SQUASHFS_SWAP((s)->count, d, 0, 8);\ | |
1999 | + SQUASHFS_SWAP((s)->start_block, d, 8, 24);\ | |
2000 | +} | |
2001 | + | |
2002 | +#define SQUASHFS_SWAP_DIR_ENTRY(s, d) {\ | |
2003 | + SQUASHFS_MEMSET(s, d, sizeof(squashfs_dir_entry));\ | |
2004 | + SQUASHFS_SWAP((s)->offset, d, 0, 13);\ | |
2005 | + SQUASHFS_SWAP((s)->type, d, 13, 3);\ | |
2006 | + SQUASHFS_SWAP((s)->size, d, 16, 8);\ | |
2007 | +} | |
2008 | + | |
2009 | +#define SQUASHFS_SWAP_FRAGMENT_ENTRY(s, d) {\ | |
2010 | + SQUASHFS_MEMSET(s, d, sizeof(squashfs_fragment_entry));\ | |
2011 | + SQUASHFS_SWAP((s)->start_block, d, 0, 32);\ | |
2012 | + SQUASHFS_SWAP((s)->size, d, 32, 32);\ | |
2013 | +} | |
2014 | + | |
2015 | +#define SQUASHFS_SWAP_SHORTS(s, d, n) {\ | |
2016 | + int entry;\ | |
2017 | + int bit_position;\ | |
2018 | + SQUASHFS_MEMSET(s, d, n * 2);\ | |
2019 | + for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += 16)\ | |
2020 | + SQUASHFS_SWAP(s[entry], d, bit_position, 16);\ | |
2021 | +} | |
2022 | + | |
2023 | +#define SQUASHFS_SWAP_INTS(s, d, n) {\ | |
2024 | + int entry;\ | |
2025 | + int bit_position;\ | |
2026 | + SQUASHFS_MEMSET(s, d, n * 4);\ | |
2027 | + for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += 32)\ | |
2028 | + SQUASHFS_SWAP(s[entry], d, bit_position, 32);\ | |
2029 | +} | |
2030 | + | |
2031 | +#define SQUASHFS_SWAP_DATA(s, d, n, bits) {\ | |
2032 | + int entry;\ | |
2033 | + int bit_position;\ | |
2034 | + SQUASHFS_MEMSET(s, d, n * bits / 8);\ | |
2035 | + for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += bits)\ | |
2036 | + SQUASHFS_SWAP(s[entry], d, bit_position, bits);\ | |
2037 | +} | |
2038 | + | |
2039 | +#define SQUASHFS_SWAP_FRAGMENT_INDEXES(s, d, n) SQUASHFS_SWAP_INTS(s, d, n) | |
2040 | + | |
2041 | +#ifdef SQUASHFS_1_0_COMPATIBILITY | |
2042 | +typedef struct { | |
2043 | + unsigned int inode_type:4; | |
2044 | + unsigned int mode:12; /* protection */ | |
2045 | + unsigned int uid:4; /* index into uid table */ | |
2046 | + unsigned int guid:4; /* index into guid table */ | |
2047 | +} __attribute__ ((packed)) squashfs_base_inode_header_1; | |
2048 | + | |
2049 | +typedef struct { | |
2050 | + unsigned int inode_type:4; | |
2051 | + unsigned int mode:12; /* protection */ | |
2052 | + unsigned int uid:4; /* index into uid table */ | |
2053 | + unsigned int guid:4; /* index into guid table */ | |
2054 | + unsigned int type:4; | |
2055 | + unsigned int offset:4; | |
2056 | +} __attribute__ ((packed)) squashfs_ipc_inode_header_1; | |
2057 | + | |
2058 | +typedef struct { | |
2059 | + unsigned int inode_type:4; | |
2060 | + unsigned int mode:12; /* protection */ | |
2061 | + unsigned int uid:4; /* index into uid table */ | |
2062 | + unsigned int guid:4; /* index into guid table */ | |
2063 | + unsigned short rdev; | |
2064 | +} __attribute__ ((packed)) squashfs_dev_inode_header_1; | |
2065 | + | |
2066 | +typedef struct { | |
2067 | + unsigned int inode_type:4; | |
2068 | + unsigned int mode:12; /* protection */ | |
2069 | + unsigned int uid:4; /* index into uid table */ | |
2070 | + unsigned int guid:4; /* index into guid table */ | |
2071 | + unsigned short symlink_size; | |
2072 | + char symlink[0]; | |
2073 | +} __attribute__ ((packed)) squashfs_symlink_inode_header_1; | |
2074 | + | |
2075 | +typedef struct { | |
2076 | + unsigned int inode_type:4; | |
2077 | + unsigned int mode:12; /* protection */ | |
2078 | + unsigned int uid:4; /* index into uid table */ | |
2079 | + unsigned int guid:4; /* index into guid table */ | |
720d8c92 | 2080 | + unsigned int mtime; |
9cdc8a28 | 2081 | + squashfs_block start_block; |
2082 | + unsigned int file_size:SQUASHFS_MAX_FILE_SIZE_LOG; | |
2083 | + unsigned short block_list[0]; | |
2084 | +} __attribute__ ((packed)) squashfs_reg_inode_header_1; | |
2085 | + | |
2086 | +typedef struct { | |
2087 | + unsigned int inode_type:4; | |
2088 | + unsigned int mode:12; /* protection */ | |
2089 | + unsigned int uid:4; /* index into uid table */ | |
2090 | + unsigned int guid:4; /* index into guid table */ | |
2091 | + unsigned int file_size:19; | |
2092 | + unsigned int offset:13; | |
720d8c92 | 2093 | + unsigned int mtime; |
9cdc8a28 | 2094 | + unsigned int start_block:24; |
2095 | +} __attribute__ ((packed)) squashfs_dir_inode_header_1; | |
2096 | + | |
2097 | +#define SQUASHFS_SWAP_BASE_INODE_HEADER_1(s, d, n) {\ | |
2098 | + SQUASHFS_MEMSET(s, d, n);\ | |
2099 | + SQUASHFS_SWAP((s)->inode_type, d, 0, 4);\ | |
2100 | + SQUASHFS_SWAP((s)->mode, d, 4, 12);\ | |
2101 | + SQUASHFS_SWAP((s)->uid, d, 16, 4);\ | |
2102 | + SQUASHFS_SWAP((s)->guid, d, 20, 4);\ | |
2103 | +} | |
2104 | + | |
2105 | +#define SQUASHFS_SWAP_IPC_INODE_HEADER_1(s, d) {\ | |
2106 | + SQUASHFS_SWAP_BASE_INODE_HEADER_1(s, d, sizeof(squashfs_ipc_inode_header_1));\ | |
2107 | + SQUASHFS_SWAP((s)->type, d, 24, 4);\ | |
2108 | + SQUASHFS_SWAP((s)->offset, d, 28, 4);\ | |
2109 | +} | |
2110 | + | |
2111 | +#define SQUASHFS_SWAP_DEV_INODE_HEADER_1(s, d) {\ | |
2112 | + SQUASHFS_SWAP_BASE_INODE_HEADER_1(s, d, sizeof(squashfs_dev_inode_header_1));\ | |
2113 | + SQUASHFS_SWAP((s)->rdev, d, 24, 16);\ | |
2114 | +} | |
2115 | + | |
2116 | +#define SQUASHFS_SWAP_SYMLINK_INODE_HEADER_1(s, d) {\ | |
2117 | + SQUASHFS_SWAP_BASE_INODE_HEADER(s, d, sizeof(squashfs_symlink_inode_header_1));\ | |
2118 | + SQUASHFS_SWAP((s)->symlink_size, d, 24, 16);\ | |
2119 | +} | |
2120 | + | |
2121 | +#define SQUASHFS_SWAP_REG_INODE_HEADER_1(s, d) {\ | |
2122 | + SQUASHFS_SWAP_BASE_INODE_HEADER(s, d, sizeof(squashfs_reg_inode_header_1));\ | |
2123 | + SQUASHFS_SWAP((s)->mtime, d, 24, 32);\ | |
2124 | + SQUASHFS_SWAP((s)->start_block, d, 56, 32);\ | |
2125 | + SQUASHFS_SWAP((s)->file_size, d, 88, SQUASHFS_MAX_FILE_SIZE_LOG);\ | |
2126 | +} | |
2127 | + | |
2128 | +#define SQUASHFS_SWAP_DIR_INODE_HEADER_1(s, d) {\ | |
2129 | + SQUASHFS_SWAP_BASE_INODE_HEADER(s, d, sizeof(squashfs_dir_inode_header_1));\ | |
2130 | + SQUASHFS_SWAP((s)->file_size, d, 24, 19);\ | |
2131 | + SQUASHFS_SWAP((s)->offset, d, 43, 13);\ | |
2132 | + SQUASHFS_SWAP((s)->mtime, d, 56, 32);\ | |
2133 | + SQUASHFS_SWAP((s)->start_block, d, 88, 24);\ | |
2134 | +} | |
2135 | +#endif | |
2136 | + | |
2137 | +#ifdef __KERNEL__ | |
2138 | +/* | |
2139 | + * macros used to swap each structure entry, taking into account | |
2140 | + * bitfields and different bitfield placing conventions on differing architectures | |
2141 | + */ | |
2142 | +#include <asm/byteorder.h> | |
2143 | +#ifdef __BIG_ENDIAN | |
2144 | + /* convert from little endian to big endian */ | |
2145 | +#define SQUASHFS_SWAP(value, p, pos, tbits) _SQUASHFS_SWAP(value, p, pos, tbits, b_pos) | |
2146 | +#else | |
2147 | + /* convert from big endian to little endian */ | |
2148 | +#define SQUASHFS_SWAP(value, p, pos, tbits) _SQUASHFS_SWAP(value, p, pos, tbits, 64 - tbits - b_pos) | |
2149 | +#endif | |
2150 | + | |
2151 | +#define _SQUASHFS_SWAP(value, p, pos, tbits, SHIFT) {\ | |
2152 | + int bits;\ | |
2153 | + int b_pos = pos % 8;\ | |
2154 | + unsigned long long val = 0;\ | |
2155 | + unsigned char *s = (unsigned char *)p + (pos / 8);\ | |
2156 | + unsigned char *d = ((unsigned char *) &val) + 7;\ | |
2157 | + for(bits = 0; bits < (tbits + b_pos); bits += 8) \ | |
2158 | + *d-- = *s++;\ | |
2159 | + value = (val >> (SHIFT))/* & ((1 << tbits) - 1)*/;\ | |
2160 | +} | |
2161 | +#define SQUASHFS_MEMSET(s, d, n) memset(s, 0, n); | |
2162 | +#endif | |
2163 | +#endif | |
2164 | diff --new-file -ur linux-2.6.6/include/linux/squashfs_fs_i.h linux-2.6.6-squashfs2.0/include/linux/squashfs_fs_i.h | |
2165 | --- linux-2.6.6/include/linux/squashfs_fs_i.h 1970-01-01 01:00:00.000000000 +0100 | |
2166 | +++ linux-2.6.6-squashfs2.0/include/linux/squashfs_fs_i.h 2004-05-19 00:21:34.000000000 +0100 | |
2167 | @@ -0,0 +1,34 @@ | |
2168 | +#ifndef SQUASHFS_FS_I | |
2169 | +#define SQUASHFS_FS_I | |
2170 | +/* | |
2171 | + * Squashfs | |
2172 | + * | |
2173 | + * Copyright (c) 2002, 2003, 2004 Phillip Lougher <plougher@users.sourceforge.net> | |
2174 | + * | |
2175 | + * This program is free software; you can redistribute it and/or | |
2176 | + * modify it under the terms of the GNU General Public License | |
2177 | + * as published by the Free Software Foundation; either version 2, | |
2178 | + * or (at your option) any later version. | |
2179 | + * | |
2180 | + * This program is distributed in the hope that it will be useful, | |
2181 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
2182 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
2183 | + * GNU General Public License for more details. | |
2184 | + * | |
2185 | + * You should have received a copy of the GNU General Public License | |
2186 | + * along with this program; if not, write to the Free Software | |
2187 | + * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |
2188 | + * | |
2189 | + * squashfs_fs_i.h | |
2190 | + */ | |
2191 | + | |
2192 | +typedef struct squashfs_inode_info { | |
2193 | + unsigned int start_block; | |
2194 | + unsigned int block_list_start; | |
2195 | + unsigned int offset; | |
2196 | + unsigned int fragment_start_block; | |
2197 | + unsigned int fragment_size; | |
2198 | + unsigned int fragment_offset; | |
2199 | + struct inode vfs_inode; | |
2200 | + } squashfs_inode_info; | |
2201 | +#endif | |
2202 | diff --new-file -ur linux-2.6.6/include/linux/squashfs_fs_sb.h linux-2.6.6-squashfs2.0/include/linux/squashfs_fs_sb.h | |
2203 | --- linux-2.6.6/include/linux/squashfs_fs_sb.h 1970-01-01 01:00:00.000000000 +0100 | |
2204 | +++ linux-2.6.6-squashfs2.0/include/linux/squashfs_fs_sb.h 2004-05-19 00:21:53.000000000 +0100 | |
2205 | @@ -0,0 +1,65 @@ | |
2206 | +#ifndef SQUASHFS_FS_SB | |
2207 | +#define SQUASHFS_FS_SB | |
2208 | +/* | |
2209 | + * Squashfs | |
2210 | + * | |
2211 | + * Copyright (c) 2002, 2003, 2004 Phillip Lougher <plougher@users.sourceforge.net> | |
2212 | + * | |
2213 | + * This program is free software; you can redistribute it and/or | |
2214 | + * modify it under the terms of the GNU General Public License | |
2215 | + * as published by the Free Software Foundation; either version 2, | |
2216 | + * or (at your option) any later version. | |
2217 | + * | |
2218 | + * This program is distributed in the hope that it will be useful, | |
2219 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
2220 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
2221 | + * GNU General Public License for more details. | |
2222 | + * | |
2223 | + * You should have received a copy of the GNU General Public License | |
2224 | + * along with this program; if not, write to the Free Software | |
2225 | + * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |
2226 | + * | |
2227 | + * squashfs_fs_sb.h | |
2228 | + */ | |
2229 | + | |
2230 | +#include <linux/squashfs_fs.h> | |
2231 | + | |
2232 | +typedef struct { | |
2233 | + unsigned int block; | |
2234 | + int length; | |
2235 | + unsigned int next_index; | |
2236 | + char *data; | |
2237 | + } squashfs_cache; | |
2238 | + | |
2239 | +struct squashfs_fragment_cache { | |
2240 | + unsigned int block; | |
2241 | + int length; | |
2242 | + unsigned int locked; | |
2243 | + char *data; | |
2244 | + }; | |
2245 | + | |
2246 | +typedef struct squashfs_sb_info { | |
2247 | + squashfs_super_block sBlk; | |
2248 | + int devblksize; | |
2249 | + int devblksize_log2; | |
2250 | + int swap; | |
2251 | + squashfs_cache *block_cache; | |
2252 | + struct squashfs_fragment_cache *fragment; | |
2253 | + int next_cache; | |
2254 | + int next_fragment; | |
2255 | + squashfs_uid *uid; | |
2256 | + squashfs_uid *guid; | |
2257 | + squashfs_fragment_index *fragment_index; | |
2258 | + unsigned int read_size; | |
2259 | + char *read_data; | |
2260 | + char *read_page; | |
2261 | + struct semaphore read_page_mutex; | |
2262 | + struct semaphore block_cache_mutex; | |
2263 | + struct semaphore fragment_mutex; | |
2264 | + wait_queue_head_t waitq; | |
2265 | + wait_queue_head_t fragment_wait_queue; | |
2266 | + struct inode *(*iget)(struct super_block *s, squashfs_inode inode); | |
2267 | + unsigned int (*read_blocklist)(struct inode *inode, int index, int readahead_blks, | |
2268 | + char *block_list, char **block_p, unsigned int *bsize); | |
2269 | + } squashfs_sb_info; | |
2270 | +#endif | |
297384c8 | 2271 | --- linux-2.6.7/init/do_mounts_rd.c.org 2004-06-16 05:19:43.000000000 +0000 |
2272 | +++ linux-2.6.7/init/do_mounts_rd.c 2004-07-07 20:03:33.566556280 +0000 | |
2273 | @@ -5,6 +5,7 @@ | |
2274 | #include <linux/ext2_fs.h> | |
2275 | #include <linux/romfs_fs.h> | |
2276 | #include <linux/cramfs_fs.h> | |
2277 | +#include <linux/squashfs_fs.h> | |
2278 | #include <linux/initrd.h> | |
2279 | #include <linux/string.h> | |
2280 | ||
2281 | @@ -39,6 +40,7 @@ | |
2282 | * numbers could not be found. | |
2283 | * | |
2284 | * We currently check for the following magic numbers: | |
2285 | + * squashfs | |
2286 | * minix | |
2287 | * ext2 | |
2288 | * romfs | |
2289 | @@ -53,6 +55,7 @@ | |
2290 | struct ext2_super_block *ext2sb; | |
2291 | struct romfs_super_block *romfsb; | |
2292 | struct cramfs_super *cramfsb; | |
2293 | + struct squashfs_super_block *squashfsb; | |
2294 | int nblocks = -1; | |
2295 | unsigned char *buf; | |
2296 | ||
2297 | @@ -64,6 +67,7 @@ | |
2298 | ext2sb = (struct ext2_super_block *) buf; | |
2299 | romfsb = (struct romfs_super_block *) buf; | |
2300 | cramfsb = (struct cramfs_super *) buf; | |
2301 | + squashfsb = (struct squashfs_super_block *) buf; | |
2302 | memset(buf, 0xe5, size); | |
2303 | ||
2304 | /* | |
2305 | @@ -101,6 +105,15 @@ | |
2306 | goto done; | |
2307 | } | |
2308 | ||
2309 | + /* squashfs is at block zero too */ | |
2310 | + if (squashfsb->s_magic == SQUASHFS_MAGIC) { | |
2311 | + printk(KERN_NOTICE | |
2312 | + "RAMDISK: squashfs filesystem found at block %d\n", | |
2313 | + start_block); | |
2314 | + nblocks = (squashfsb->bytes_used+BLOCK_SIZE-1)>>BLOCK_SIZE_BITS; | |
2315 | + goto done; | |
2316 | + } | |
2317 | + | |
2318 | /* | |
2319 | * Read block 1 to test for minix and ext2 superblock | |
2320 | */ |