⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 inode.c

📁 一款linux的文件系统
💻 C
📖 第 1 页 / 共 4 页
字号:
/* * Squashfs - a compressed read only filesystem for Linux * * Copyright (c) 2002, 2003, 2004 Phillip Lougher <plougher@users.sourceforge.net> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2, * or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * Squashfs - a compressed read only filesystem for Linux * * inode.c */#define SQUASHFS_1_0_COMPATIBILITY#include <linux/types.h>#include <linux/squashfs_fs.h>#include <linux/module.h>#include <linux/errno.h>#include <linux/slab.h>#include <linux/fs.h>#include <linux/locks.h>#include <linux/init.h>#include <linux/dcache.h>#include <asm/uaccess.h>#include <linux/wait.h>#include <asm/semaphore.h>#include <linux/zlib.h>#include <linux/blkdev.h>#include <linux/vmalloc.h>#ifdef SQUASHFS_TRACE#define TRACE(s, args...)				printk(KERN_NOTICE "SQUASHFS: "s, ## args)#else#define TRACE(s, args...)				{}#endif#define ERROR(s, args...)				printk(KERN_ERR "SQUASHFS error: "s, ## args)#define SERROR(s, args...)				if(!silent) printk(KERN_ERR "SQUASHFS error: "s, ## args)#define WARNING(s, args...)				printk(KERN_WARNING "SQUASHFS: "s, ## args)static struct super_block *squashfs_read_super(struct super_block *, void *, int);static void squashfs_put_super(struct super_block *);static int squashfs_statfs(struct super_block *, struct statfs *);static int squashfs_symlink_readpage(struct file *file, struct page *page);static int squashfs_readpage(struct file *file, struct page *page);static int squashfs_readpage4K(struct file *file, struct page *page);static int squashfs_readdir(struct file *, void *, filldir_t);static struct dentry *squashfs_lookup(struct inode *, struct dentry *);static unsigned int read_data(struct super_block *s, char *buffer,		unsigned int index, unsigned int length, unsigned int *next_index);static int squashfs_get_cached_block(struct super_block *s, char *buffer,		unsigned int block, unsigned int offset, int length,		unsigned int *next_block, unsigned int *next_offset);static struct inode *squashfs_iget(struct super_block *s, squashfs_inode inode);static unsigned int read_blocklist(struct inode *inode, int index, int readahead_blks,		char *block_list, unsigned short **block_p, unsigned int *bsize);static void squashfs_put_super(struct super_block *s);#ifdef SQUASHFS_1_0_COMPATIBILITYstatic int squashfs_readpage_lessthan4K(struct file *file, struct page *page);static struct inode *squashfs_iget_1(struct super_block *s, squashfs_inode inode);static unsigned int read_blocklist_1(struct inode *inode, int index, int readahead_blks,		char *block_list, unsigned short **block_p, unsigned int *bsize);#endifDECLARE_MUTEX(read_data_mutex);static z_stream stream;static DECLARE_FSTYPE_DEV(squashfs_fs_type, "squashfs", squashfs_read_super);static unsigned char squashfs_filetype_table[] = {	DT_UNKNOWN, DT_DIR, DT_REG, DT_LNK, DT_BLK, DT_CHR, DT_FIFO, DT_SOCK};static struct super_operations squashfs_ops = {	statfs: squashfs_statfs,	put_super: squashfs_put_super,};static struct address_space_operations squashfs_symlink_aops = {	readpage: squashfs_symlink_readpage};static struct address_space_operations squashfs_aops = {	readpage: squashfs_readpage};static struct address_space_operations squashfs_aops_4K = {	readpage: squashfs_readpage4K};#ifdef SQUASHFS_1_0_COMPATIBILITYstatic struct address_space_operations squashfs_aops_lessthan4K = {	readpage: squashfs_readpage_lessthan4K};#endifstatic struct file_operations squashfs_dir_ops = {	read: generic_read_dir,	readdir: squashfs_readdir};static struct inode_operations squashfs_dir_inode_ops = {	lookup: squashfs_lookup};static struct buffer_head *get_block_length(struct super_block *s, int *cur_index, int *offset, int *c_byte){	squashfs_sb_info *msBlk = &s->u.squashfs_sb;	unsigned short temp;	struct buffer_head *bh;	if(!(bh = sb_bread(s, *cur_index)))		return NULL;	if(msBlk->devblksize - *offset == 1) {		if(msBlk->swap)			((unsigned char *) &temp)[1] = *((unsigned char *) (bh->b_data + *offset));		else			((unsigned char *) &temp)[0] = *((unsigned char *) (bh->b_data + *offset));		brelse(bh);		if(!(bh = sb_bread(s, ++(*cur_index))))			return NULL;		if(msBlk->swap)			((unsigned char *) &temp)[0] = *((unsigned char *) bh->b_data); 		else			((unsigned char *) &temp)[1] = *((unsigned char *) bh->b_data); 		*c_byte = temp;		*offset = 1;	}	else {		if(msBlk->swap) {			unsigned short temp;			((unsigned char *) &temp)[1] = *((unsigned char *) (bh->b_data + *offset));			((unsigned char *) &temp)[0] = *((unsigned char *) (bh->b_data + *offset + 1)); 			*c_byte = temp;		} else			*c_byte = *((unsigned short *) (bh->b_data + *offset));		*offset += 2;	}	if(SQUASHFS_CHECK_DATA(msBlk->sBlk.flags)) {		if(*offset == msBlk->devblksize) {			brelse(bh);			if(!(bh = sb_bread(s, ++(*cur_index))))				return NULL;			offset = 0;		}		if(*((unsigned char *) (bh->b_data + *offset)) != SQUASHFS_MARKER_BYTE) {			ERROR("Metadata block marker corrupt @ %x\n", *cur_index);			brelse(bh);			return NULL;		}		*offset ++;	}	return bh;}static unsigned int read_data(struct super_block *s, char *buffer,		unsigned int index, unsigned int length, unsigned int *next_index){	squashfs_sb_info *msBlk = &s->u.squashfs_sb;	struct buffer_head *bh[((SQUASHFS_FILE_MAX_SIZE - 1) >> msBlk->devblksize_log2) + 2];	unsigned int offset = index & ((1 << msBlk->devblksize_log2) - 1);	unsigned int cur_index = index >> msBlk->devblksize_log2;	int bytes, avail_bytes, b = 0, k;	char *c_buffer;	unsigned int compressed;	unsigned int c_byte = length;	if(c_byte) {		bytes = msBlk->devblksize - offset;		compressed = SQUASHFS_COMPRESSED_BLOCK(c_byte);		c_buffer = compressed ? msBlk->read_data : buffer;		c_byte = SQUASHFS_COMPRESSED_SIZE_BLOCK(c_byte);		TRACE("Block @ 0x%x, %scompressed size %d\n", index, compressed ? "" : "un", (unsigned int) c_byte);		if(!(bh[0] = sb_getblk(s, cur_index)))			goto block_release;		for(b = 1; bytes < c_byte; b++) {			if(!(bh[b] = sb_getblk(s, ++cur_index)))				goto block_release;			bytes += msBlk->devblksize;		}		ll_rw_block(READ, b, bh);	} else {		if(!(bh[0] = get_block_length(s, &cur_index, &offset, &c_byte)))			goto read_failure;		bytes = msBlk->devblksize - offset;		compressed = SQUASHFS_COMPRESSED(c_byte);		c_buffer = compressed ? msBlk->read_data : buffer;		c_byte = SQUASHFS_COMPRESSED_SIZE(c_byte);		TRACE("Block @ 0x%x, %scompressed size %d\n", index, compressed ? "" : "un", (unsigned int) c_byte);		for(b = 1; bytes < c_byte; b++) {			if(!(bh[b] = sb_getblk(s, ++cur_index)))				goto block_release;			bytes += msBlk->devblksize;		}		ll_rw_block(READ, b - 1, bh + 1);	}	if(compressed)		down(&read_data_mutex);	for(bytes = 0, k = 0; k < b; k++) {		avail_bytes = (c_byte - bytes) > (msBlk->devblksize - offset) ? msBlk->devblksize - offset : c_byte - bytes;		wait_on_buffer(bh[k]);		memcpy(c_buffer + bytes, bh[k]->b_data + offset, avail_bytes);		bytes += avail_bytes;		offset = 0;		brelse(bh[k]);	}	/*	 * uncompress block	 */	if(compressed) {		int zlib_err;		stream.next_in = c_buffer;		stream.avail_in = c_byte;		stream.next_out = buffer;		stream.avail_out = msBlk->read_size;		if(((zlib_err = zlib_inflateInit(&stream)) != Z_OK) ||				((zlib_err = zlib_inflate(&stream, Z_FINISH)) != Z_STREAM_END) ||				((zlib_err = zlib_inflateEnd(&stream)) != Z_OK)) {			ERROR("zlib_fs returned unexpected result 0x%x\n", zlib_err);			bytes = 0;		} else			bytes = stream.total_out;		up(&read_data_mutex);	}	if(next_index)		*next_index = index + c_byte + (length ? 0 : (SQUASHFS_CHECK_DATA(msBlk->sBlk.flags) ? 3 : 2));	return bytes;block_release:	while(--b >= 0) brelse(bh[b]);read_failure:	ERROR("sb_bread failed reading block 0x%x\n", cur_index);	return 0;}static int squashfs_get_cached_block(struct super_block *s, char *buffer,		unsigned int block, unsigned int offset, int length,		unsigned int *next_block, unsigned int *next_offset){	squashfs_sb_info *msBlk = &s->u.squashfs_sb;	int n, i, bytes, return_length = length;	unsigned int next_index;	TRACE("Entered squashfs_get_cached_block [%x:%x]\n", block, offset);	for(;;) {		for(i = 0; i < SQUASHFS_CACHED_BLKS; i++) 			if(msBlk->block_cache[i].block == block)				break; 				down(&msBlk->block_cache_mutex);		if(i == SQUASHFS_CACHED_BLKS) {			/* read inode header block */			for(i = msBlk->next_cache, n = SQUASHFS_CACHED_BLKS; n ; n --, i = (i + 1) % SQUASHFS_CACHED_BLKS)				if(msBlk->block_cache[i].block != SQUASHFS_USED_BLK)					break;			if(n == 0) {				up(&msBlk->block_cache_mutex);				sleep_on(&msBlk->waitq);				continue;			}			msBlk->next_cache = (i + 1) % SQUASHFS_CACHED_BLKS;			if(msBlk->block_cache[i].block == SQUASHFS_INVALID_BLK) {				if(!(msBlk->block_cache[i].data = (unsigned char *)							kmalloc(SQUASHFS_METADATA_SIZE, GFP_KERNEL))) {					ERROR("Failed to allocate cache block\n");					up(&msBlk->block_cache_mutex);					return 0;				}			}				msBlk->block_cache[i].block = SQUASHFS_USED_BLK;			up(&msBlk->block_cache_mutex);			if(!(msBlk->block_cache[i].length = read_data(s, msBlk->block_cache[i].data, block, 0,							&next_index))) {				ERROR("Unable to read cache block [%x:%x]\n", block, offset);				return 0;			}			down(&msBlk->block_cache_mutex);			wake_up(&msBlk->waitq);			msBlk->block_cache[i].block = block;			msBlk->block_cache[i].next_index = next_index;			TRACE("Read cache block [%x:%x]\n", block, offset);		}		if(msBlk->block_cache[i].block != block) {			up(&msBlk->block_cache_mutex);			continue;		}		if((bytes = msBlk->block_cache[i].length - offset) >= length) {			if(buffer)				memcpy(buffer, msBlk->block_cache[i].data + offset, length);			if(msBlk->block_cache[i].length - offset == length) {				*next_block = msBlk->block_cache[i].next_index;				*next_offset = 0;			} else {				*next_block = block;				*next_offset = offset + length;			}				up(&msBlk->block_cache_mutex);			return return_length;		} else {			if(buffer) {				memcpy(buffer, msBlk->block_cache[i].data + offset, bytes);				buffer += bytes;			}			block = msBlk->block_cache[i].next_index;			up(&msBlk->block_cache_mutex);			length -= bytes;			offset = 0;		}	}}static int get_fragment_location(struct super_block *s, unsigned int fragment, unsigned int *fragment_start_block, unsigned int *fragment_size){	squashfs_sb_info *msBlk = &s->u.squashfs_sb;	unsigned int start_block = msBlk->fragment_index[SQUASHFS_FRAGMENT_INDEX(fragment)];	int offset = SQUASHFS_FRAGMENT_INDEX_OFFSET(fragment);	squashfs_fragment_entry fragment_entry;	if(msBlk->swap) {		squashfs_fragment_entry sfragment_entry;		if(!squashfs_get_cached_block(s, (char *) &sfragment_entry, start_block, offset,					sizeof(sfragment_entry), &start_block, &offset))			return 0;		SQUASHFS_SWAP_FRAGMENT_ENTRY(&fragment_entry, &sfragment_entry);	} else		if(!squashfs_get_cached_block(s, (char *) &fragment_entry, start_block, offset,					sizeof(fragment_entry), &start_block, &offset))			return 0;	*fragment_start_block = fragment_entry.start_block;	*fragment_size = fragment_entry.size;	return 1;}void release_cached_fragment(squashfs_sb_info *msBlk, struct squashfs_fragment_cache *fragment){	down(&msBlk->fragment_mutex);	fragment->locked --;	wake_up(&msBlk->fragment_wait_queue);	up(&msBlk->fragment_mutex);}struct squashfs_fragment_cache *get_cached_fragment(struct super_block *s, unsigned int start_block, int length){	int i, n;	squashfs_sb_info *msBlk = &s->u.squashfs_sb;	for(;;) {		down(&msBlk->fragment_mutex);		for(i = 0; i < SQUASHFS_CACHED_FRAGMENTS && msBlk->fragment[i].block != start_block; i++);		if(i == SQUASHFS_CACHED_FRAGMENTS) {			for(i = msBlk->next_fragment, n = SQUASHFS_CACHED_FRAGMENTS;				n && msBlk->fragment[i].locked; n--, i = (i + 1) % SQUASHFS_CACHED_FRAGMENTS);			if(n == 0) {				up(&msBlk->fragment_mutex);				sleep_on(&msBlk->fragment_wait_queue);				continue;			}			msBlk->next_fragment = (msBlk->next_fragment + 1) % SQUASHFS_CACHED_FRAGMENTS;						if(msBlk->fragment[i].data == NULL)				if(!(msBlk->fragment[i].data = (unsigned char *)							kmalloc(SQUASHFS_FILE_MAX_SIZE, GFP_KERNEL))) {					ERROR("Failed to allocate fragment cache block\n");					up(&msBlk->fragment_mutex);					return NULL;				}			msBlk->fragment[i].block = SQUASHFS_INVALID_BLK;			msBlk->fragment[i].locked = 1;			up(&msBlk->fragment_mutex);			if(!(msBlk->fragment[i].length = read_data(s, msBlk->fragment[i].data, start_block, length,							NULL))) {				ERROR("Unable to read fragment cache block [%x]\n", start_block);				msBlk->fragment[i].locked = 0;				return NULL;			}			msBlk->fragment[i].block = start_block;			TRACE("New fragment %d, start block %d, locked %d\n", i, msBlk->fragment[i].block, msBlk->fragment[i].locked);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -