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

📄 file.c

📁 基于组件方式开发操作系统的OSKIT源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *  linux/fs/affs/file.c * *  (c) 1996  Hans-Joachim Widmaier - Rewritten * *  (C) 1993  Ray Burr - Modified for Amiga FFS filesystem. * *  (C) 1992  Eric Youngdale Modified for ISO 9660 filesystem. * *  (C) 1991  Linus Torvalds - minix filesystem * *  affs regular file handling primitives */#define DEBUG 0#include <asm/uaccess.h>#include <asm/system.h>#include <linux/sched.h>#include <linux/affs_fs.h>#include <linux/fcntl.h>#include <linux/kernel.h>#include <linux/errno.h>#include <linux/malloc.h>#include <linux/stat.h>#include <linux/locks.h>#include <linux/dirent.h>#include <linux/fs.h>#include <linux/amigaffs.h>#include <linux/mm.h>#include <linux/pagemap.h>#define MIN(a,b) (((a)<(b))?(a):(b))#define MAX(a,b) (((a)>(b))?(a):(b))#if PAGE_SIZE < 4096#error PAGE_SIZE must be at least 4096#endifstatic int affs_bmap(struct inode *inode, int block);static struct buffer_head *affs_getblock(struct inode *inode, s32 block);static ssize_t affs_file_read_ofs(struct file *filp, char *buf, size_t count, loff_t *ppos);static ssize_t affs_file_write(struct file *filp, const char *buf, size_t count, loff_t *ppos);static ssize_t affs_file_write_ofs(struct file *filp, const char *buf, size_t cnt, loff_t *ppos);static int alloc_ext_cache(struct inode *inode);static struct file_operations affs_file_operations = {	NULL,			/* lseek - default */	generic_file_read,	/* read */	affs_file_write,	/* write */	NULL,			/* readdir - bad */	NULL,			/* poll - default */	NULL,			/* ioctl - default */	generic_file_mmap,	/* mmap */	NULL,			/* no special open */	NULL,			/* flush */	NULL,			/* release */	file_fsync,		/* brute force, but works */	NULL,			/* fasync */	NULL,			/* check_media_change */	NULL,			/* revalidate */	NULL			/* lock */};struct inode_operations affs_file_inode_operations = {	&affs_file_operations,	/* default file operations */	NULL,			/* create */	NULL,			/* lookup */	NULL,			/* link */	NULL,			/* unlink */	NULL,			/* symlink */	NULL,			/* mkdir */	NULL,			/* rmdir */	NULL,			/* mknod */	NULL,			/* rename */	NULL,			/* readlink */	NULL,			/* follow_link */	generic_readpage,	/* readpage */	NULL,			/* writepage */	affs_bmap,		/* bmap */	affs_truncate,		/* truncate */	NULL,			/* permission */	NULL,			/* smap */	NULL,			/* updatepage */	NULL			/* revalidate */};static struct file_operations affs_file_operations_ofs = {	NULL,			/* lseek - default */	affs_file_read_ofs,	/* read */	affs_file_write_ofs,	/* write */	NULL,			/* readdir - bad */	NULL,			/* poll - default */	NULL,			/* ioctl - default */	NULL,			/* mmap */	NULL,			/* no special open */	NULL,			/* flush */	NULL,			/* release */	file_fsync,		/* brute force, but works */	NULL,			/* fasync */	NULL,			/* check_media_change */	NULL,			/* revalidate */	NULL			/* lock */};struct inode_operations affs_file_inode_operations_ofs = {	&affs_file_operations_ofs,	/* default file operations */	NULL,			/* create */	NULL,			/* lookup */	NULL,			/* link */	NULL,			/* unlink */	NULL,			/* symlink */	NULL,			/* mkdir */	NULL,			/* rmdir */	NULL,			/* mknod */	NULL,			/* rename */	NULL,			/* readlink */	NULL,			/* follow_link */	NULL,			/* readpage */	NULL,			/* writepage */	NULL,			/* bmap */	affs_truncate,		/* truncate */	NULL,			/* permission */	NULL,			/* smap */	NULL,			/* updatepage */	NULL			/* revalidate */};#define AFFS_ISINDEX(x)	((x < 129) ||				\			 (x < 512 && (x & 1) == 0) ||		\			 (x < 1024 && (x & 3) == 0) ||		\			 (x < 2048 && (x & 15) == 0) ||		\			 (x < 4096 && (x & 63) == 0) ||		\			 (x < 20480 && (x & 255) == 0) ||	\			 (x < 36864 && (x & 511) == 0))/* The keys of the extension blocks are stored in a 512-entry * deep cache. In order to save memory, not every key of later * extension blocks is stored - the larger the file gets, the * bigger the holes in between. */static intseqnum_to_index(int seqnum){	/* All of the first 127 keys are stored */	if (seqnum < 128)		return seqnum;	seqnum -= 128;	/* Of the next 384 keys, every 2nd is kept */	if (seqnum < (192 * 2))		return 128 + (seqnum >> 1);	seqnum -= 192 * 2;		/* Every 4th of the next 512 */	if (seqnum < (128 * 4))		return 128 + 192 + (seqnum >> 2);	seqnum -= 128 * 4;	/* Every 16th of the next 1024 */	if (seqnum < (64 * 16))		return 128 + 192 + 128 + (seqnum >> 4);	seqnum -= 64 * 16;	/* Every 64th of the next 2048 */	if (seqnum < (32 * 64))		return 128 + 192 + 128 + 64 + (seqnum >> 6);	seqnum -= 32 * 64;	/* Every 256th of the next 16384 */	if (seqnum < (64 * 256))		return 128 + 192 + 128 + 64 + 32 + (seqnum >> 8);	seqnum -= 64 * 256;	/* Every 512th upto 36479 (1.3 GB with 512 byte blocks).	 * Seeking to positions behind this will get slower	 * than dead snails nailed to the ground. But if	 * someone uses files that large with 512-byte blocks,	 * he or she deserves no better.	 */		if (seqnum > (31 * 512))		seqnum = 31 * 512;	return 128 + 192 + 128 + 64 + 32 + 64 + (seqnum >> 9);}/* Now the other way round: Calculate the sequence * number of an extension block of a key at the * given index in the cache. */static intindex_to_seqnum(int index){	if (index < 128)		return index;	index -= 128;	if (index < 192)		return 128 + (index << 1);	index -= 192;	if (index < 128)		return 128 + 192 * 2 + (index << 2);	index -= 128;	if (index < 64)		return 128 + 192 * 2 + 128 * 4 + (index << 4);	index -= 64;	if (index < 32)		return 128 + 192 * 2 + 128 * 4 + 64 * 16 + (index << 6);	index -= 32;	if (index < 64)		return 128 + 192 * 2 + 128 * 4 + 64 * 16 + 32 * 64 + (index << 8);	index -= 64;	return 128 + 192 * 2 + 128 * 4 + 64 * 16 + 32 * 64 + 64 * 256 + (index << 9);}static s32 __inline__calc_key(struct inode *inode, int *ext){	int		  index;	struct key_cache *kc;	for (index = 0; index < 4; index++) {		kc = &inode->u.affs_i.i_ec->kc[index];		if (*ext == kc->kc_this_seq) {			return kc->kc_this_key;		} else if (*ext == kc->kc_this_seq + 1) {			if (kc->kc_next_key)				return kc->kc_next_key;			else {				(*ext)--;				return kc->kc_this_key;			}		}	}	index = seqnum_to_index(*ext);	if (index > inode->u.affs_i.i_ec->max_ext)		index = inode->u.affs_i.i_ec->max_ext;	*ext = index_to_seqnum(index);	return inode->u.affs_i.i_ec->ec[index];}static intaffs_bmap(struct inode *inode, int block){	struct buffer_head	*bh;	s32			 key, nkey;	s32			 ptype, stype;	int			 ext;	int			 index;	int			 keycount;	struct key_cache	*kc;	struct key_cache	*tkc;	struct timeval		 tv;	s32			*keyp;	int			 i;	pr_debug("AFFS: bmap(%lu,%d)\n",inode->i_ino,block);	if (block < 0) {		affs_error(inode->i_sb,"bmap","Block < 0");		return 0;	}	if (!inode->u.affs_i.i_ec) {		if (alloc_ext_cache(inode)) {			return 0;		}	}	/* Try to find the requested key in the cache.	 * In order to speed this up as much as possible,	 * the cache line lookup is done in a separate	 * step.	 */	for (i = 0; i < 4; i++) {		tkc = &inode->u.affs_i.i_ec->kc[i];		/* Look in any cache if the key is there */		if (block <= tkc->kc_last && block >= tkc->kc_first) {			return tkc->kc_keys[block - tkc->kc_first];		}	}	kc = NULL;#ifdef OSKIT	tv.tv_sec  = CURRENT_TIME;	tv.tv_usec = 0;#else	tv = xtime;#endif	for (i = 0; i < 4; i++) {		tkc = &inode->u.affs_i.i_ec->kc[i];		if (tkc->kc_lru_time.tv_sec > tv.tv_sec)			continue;		if (tkc->kc_lru_time.tv_sec < tv.tv_sec ||		    tkc->kc_lru_time.tv_usec < tv.tv_usec) {			kc = tkc;			tv = tkc->kc_lru_time;		}	}	if (!kc)	/* Really shouldn't happen */		kc = tkc;#ifdef OSKIT	kc->kc_lru_time.tv_sec  = CURRENT_TIME;	kc->kc_lru_time.tv_usec = 0;#else	kc->kc_lru_time = xtime;#endif	keyp            = kc->kc_keys;	kc->kc_first    = block;	kc->kc_last     = -1;	keycount        = AFFS_KCSIZE;	/* Calculate sequence number of the extension block where the	 * number of the requested block is stored. 0 means it's in	 * the file header.	 */	ext    = block / AFFS_I2HSIZE(inode);	key    = calc_key(inode,&ext);	block -= ext * AFFS_I2HSIZE(inode);	for (;;) {		bh = affs_bread(inode->i_dev,key,AFFS_I2BSIZE(inode));		if (!bh) 			return 0;		index = seqnum_to_index(ext);		if (index > inode->u.affs_i.i_ec->max_ext &&		    (affs_checksum_block(AFFS_I2BSIZE(inode),bh->b_data,&ptype,&stype) ||		     (ptype != T_SHORT && ptype != T_LIST) || stype != ST_FILE)) {			affs_brelse(bh);			return 0;		}		nkey = be32_to_cpu(FILE_END(bh->b_data,inode)->extension);		if (block < AFFS_I2HSIZE(inode)) {			/* Fill cache as much as possible */			if (keycount) {				kc->kc_first = ext * AFFS_I2HSIZE(inode) + block;				keycount     = keycount < AFFS_I2HSIZE(inode) - block ? keycount :						AFFS_I2HSIZE(inode) - block;				for (i = 0; i < keycount; i++)					kc->kc_keys[i] = be32_to_cpu(AFFS_BLOCK(bh->b_data,inode,block + i));				kc->kc_last = kc->kc_first + i - 1;			}			break;		}		block -= AFFS_I2HSIZE(inode);		affs_brelse(bh);		ext++;		if (index > inode->u.affs_i.i_ec->max_ext && AFFS_ISINDEX(ext)) {			inode->u.affs_i.i_ec->ec[index] = nkey;			inode->u.affs_i.i_ec->max_ext   = index;		}		key = nkey;	}	kc->kc_this_key = key;	kc->kc_this_seq = ext;	kc->kc_next_key = nkey;	key = be32_to_cpu(AFFS_BLOCK(bh->b_data,inode,block));	affs_brelse(bh);	return key;}/* With the affs, getting a random block from a file is not * a simple business. Since this fs does not allow holes, * it may be necessary to allocate all the missing blocks * in between, as well as some new extension blocks. The OFS * is even worse: All data blocks contain pointers to the * next ones, so you have to fix [n-1] after allocating [n]. * What a mess. */static struct buffer_head *affs_getblock(struct inode *inode, s32 block){	struct super_block	*sb = inode->i_sb;	int			 ofs = sb->u.affs_sb.s_flags & SF_OFS;	int			 ext = block / AFFS_I2HSIZE(inode);	struct buffer_head	*bh, *ebh, *pbh = NULL;	struct key_cache	*kc;	s32			 key, nkey;	int			 cf, j, pt;	int			 index;	int			 err;	pr_debug("AFFS: getblock(%lu,%d)\n",inode->i_ino,block);	if (block < 0)		goto out_fail;	key    = calc_key(inode,&ext);	block -= ext * AFFS_I2HSIZE(inode);	pt     = ext ? T_LIST : T_SHORT;	/* Key refers now to the last known extension block,	 * ext is its sequence number (if 0, key refers to the	 * header block), and block is the block number relative	 * to the first block stored in that extension block.	 */	for (;;) {	/* Loop over header block and extension blocks */		struct file_front *fdp;		bh = affs_bread(inode->i_dev,key,AFFS_I2BSIZE(inode));		if (!bh)			goto out_fail;		fdp = (struct file_front *) bh->b_data;		err = affs_checksum_block(AFFS_I2BSIZE(inode),bh->b_data,&cf,&j);		if (err || cf != pt || j != ST_FILE) {		    	affs_error(sb, "getblock",				"Block %d is not a valid %s", key,				pt == T_SHORT ? "file header" : "ext block");			goto out_free_bh;		}		j  = be32_to_cpu(((struct file_front *)bh->b_data)->block_count);		for (cf = 0; j < AFFS_I2HSIZE(inode) && j <= block; j++) {			if (ofs && !pbh && inode->u.affs_i.i_lastblock >= 0) {				if (j > 0) {					s32 k = AFFS_BLOCK(bh->b_data, inode,								j - 1);					pbh = affs_bread(inode->i_dev,							be32_to_cpu(k),							AFFS_I2BSIZE(inode));				} else					pbh = affs_getblock(inode,inode->u.affs_i.i_lastblock);				if (!pbh) {					affs_error(sb,"getblock",						"Cannot get last block in file");					break;				}			}			nkey = affs_new_data(inode);			if (!nkey)				break;			inode->u.affs_i.i_lastblock++;			if (AFFS_BLOCK(bh->b_data,inode,j)) {				affs_warning(sb,"getblock","Block already allocated");				affs_free_block(sb,nkey);				continue;			}			AFFS_BLOCK(bh->b_data,inode,j) = cpu_to_be32(nkey);			if (ofs) {				ebh = affs_bread(inode->i_dev,nkey,AFFS_I2BSIZE(inode));				if (!ebh) {					affs_error(sb,"getblock",						   "Cannot get block %d",nkey);					affs_free_block(sb,nkey);					AFFS_BLOCK(bh->b_data,inode,j) = 0;					break;				}				DATA_FRONT(ebh)->primary_type    = cpu_to_be32(T_DATA);				DATA_FRONT(ebh)->header_key      = cpu_to_be32(inode->i_ino);				DATA_FRONT(ebh)->sequence_number = cpu_to_be32(inode->u.affs_i.i_lastblock + 1);				affs_fix_checksum(AFFS_I2BSIZE(inode),							ebh->b_data, 5);				mark_buffer_dirty(ebh, 0);				if (pbh) {					DATA_FRONT(pbh)->data_size = cpu_to_be32(AFFS_I2BSIZE(inode) - 24);					DATA_FRONT(pbh)->next_data = cpu_to_be32(nkey);					affs_fix_checksum(AFFS_I2BSIZE(inode),pbh->b_data,5);					mark_buffer_dirty(pbh,0);					affs_brelse(pbh);				}				pbh = ebh;			}			cf = 1;		}		/* N.B. May need to release pbh after here */		if (cf) {			if (pt == T_SHORT)				fdp->first_data = AFFS_BLOCK(bh->b_data,inode,0);			fdp->block_count = cpu_to_be32(j);			affs_fix_checksum(AFFS_I2BSIZE(inode),bh->b_data,5);			mark_buffer_dirty(bh,1);		}		if (block < j) {			if (pbh)				affs_brelse(pbh);			break;		}		if (j < AFFS_I2HSIZE(inode)) {

⌨️ 快捷键说明

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