Gentoo Websites Logo
Go to: Gentoo Home Documentation Forums Lists Bugs Planet Store Wiki Get Gentoo!
View | Details | Raw Unified | Return to bug 218169 | Differences between
and this patch

Collapse All | Expand All

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

Return to bug 218169