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

📄 inode.c

📁 这是Linux系统下的对UDF文件系统新增的功能
💻 C
📖 第 1 页 / 共 4 页
字号:
/* * inode.c * * PURPOSE *  Inode handling routines for the OSTA-UDF(tm) filesystem. * * CONTACTS *  E-mail regarding any portion of the Linux UDF file system should be *  directed to the development team mailing list (run by majordomo): *    linux_udf@hpesjro.fc.hp.com * * COPYRIGHT *  This file is distributed under the terms of the GNU General Public *  License (GPL). Copies of the GPL can be obtained from: *    ftp://prep.ai.mit.edu/pub/gnu/GPL *  Each contributing author retains all rights to their own work. * *  (C) 1998 Dave Boynton *  (C) 1998-2003 Ben Fennema *  (C) 1999-2000 Stelias Computing Inc * * HISTORY * *  10/04/98 dgb  Added rudimentary directory functions *  10/07/98      Fully working udf_bmap! It works! *  11/25/98      bmap altered to better support extents *  12/06/98 blf  partition support in udf_iget, udf_bmap and udf_read_inode *  12/12/98      rewrote udf_bmap to handle next extents and descs across *                block boundaries (which is not actually allowed) *  12/20/98      added support for strategy 4096 *  03/07/99      rewrote udf_bmap (again) *                New funcs, inode_bmap, udf_next_aext *  04/19/99      Support for writing device EA's for major/minor # */#include "udfdecl.h"#include <linux/locks.h>#include <linux/mm.h>#include <linux/malloc.h>#include "udf_i.h"#include "udf_sb.h"#define EXTENT_MERGE_SIZE 5static mode_t udf_convert_permissions(struct fileEntry *);static int udf_update_inode(struct inode *, int);static void udf_fill_inode(struct inode *, struct buffer_head *);static struct buffer_head *inode_getblk(struct inode *, long, int, int *);static void udf_split_extents(struct inode *, int *, int, int,	long_ad [EXTENT_MERGE_SIZE], int *);static void udf_prealloc_extents(struct inode *, int, int,	 long_ad [EXTENT_MERGE_SIZE], int *);static void udf_merge_extents(struct inode *,	 long_ad [EXTENT_MERGE_SIZE], int *);static void udf_update_extents(struct inode *,	long_ad [EXTENT_MERGE_SIZE], int, int,	lb_addr, uint32_t, struct buffer_head **);/* * udf_put_inode * * PURPOSE * * DESCRIPTION *	This routine is called whenever the kernel no longer needs the inode. * * HISTORY *	July 1, 1997 - Andrew E. Mileski *	Written, tested, and released. * *  Called at each iput() */void udf_put_inode(struct inode * inode){	if (!(inode->i_sb->s_flags & MS_RDONLY))	{		udf_discard_prealloc(inode);		/* write the root inode on put, if dirty */		if (!inode->i_sb->s_root && inode->i_state & I_DIRTY)			udf_update_inode(inode, IS_SYNC(inode));	}}/* * udf_delete_inode * * PURPOSE *	Clean-up before the specified inode is destroyed. * * DESCRIPTION *	This routine is called when the kernel destroys an inode structure *	ie. when iput() finds i_count == 0. * * HISTORY *	July 1, 1997 - Andrew E. Mileski *	Written, tested, and released. * *  Called at the last iput() if i_nlink is zero. */void udf_delete_inode(struct inode * inode){	if (is_bad_inode(inode))		return;	inode->i_size = 0;	udf_truncate(inode);	udf_update_inode(inode, IS_SYNC(inode));	udf_free_inode(inode);}void udf_clear_inode(struct inode *inode){	kfree(UDF_I_DATA(inode));	UDF_I_DATA(inode) = NULL;}void udf_expand_file_adinicb(struct inode * inode, int newsize, int * err){	int block, newblock;	struct buffer_head *sbh = NULL, *dbh = NULL;	lb_addr bloc, eloc;	uint32_t elen, extoffset;	if (!UDF_I_LENALLOC(inode))	{		if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_USE_SHORT_AD))			UDF_I_ALLOCTYPE(inode) = ICBTAG_FLAG_AD_SHORT;		else			UDF_I_ALLOCTYPE(inode) = ICBTAG_FLAG_AD_LONG;		mark_inode_dirty(inode);		inode->i_op = &udf_file_inode_operations;		return;	}	/* alloc block, and copy data to it */	block = udf_new_block(inode->i_sb, inode,		UDF_I_LOCATION(inode).partitionReferenceNum,		UDF_I_LOCATION(inode).logicalBlockNum, err);	if (!(block))		return;	newblock = udf_get_pblock(inode->i_sb, block,		UDF_I_LOCATION(inode).partitionReferenceNum, 0);	if (!newblock)		return;	dbh = udf_tread(inode->i_sb, newblock);	if (!dbh)		return;	memcpy(dbh->b_data, UDF_I_DATA(inode) + UDF_I_LENEATTR(inode),		UDF_I_LENALLOC(inode));			mark_buffer_dirty(dbh, 1);	udf_release_data(dbh);	memset(UDF_I_DATA(inode) + UDF_I_LENEATTR(inode), 0x00,		UDF_I_LENALLOC(inode));	UDF_I_LENALLOC(inode) = 0;	if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_USE_SHORT_AD))		UDF_I_ALLOCTYPE(inode) = ICBTAG_FLAG_AD_SHORT;	else		UDF_I_ALLOCTYPE(inode) = ICBTAG_FLAG_AD_LONG;	bloc = UDF_I_LOCATION(inode);	eloc.logicalBlockNum = block;	eloc.partitionReferenceNum = UDF_I_LOCATION(inode).partitionReferenceNum;	elen = newsize > inode->i_sb->s_blocksize ?		inode->i_sb->s_blocksize : newsize;	extoffset = udf_file_entry_alloc_offset(inode);	udf_add_aext(inode, &bloc, &extoffset, eloc, elen, &sbh, 0);	/* UniqueID stuff */	inode->i_blocks = inode->i_sb->s_blocksize / 512;	udf_release_data(sbh);	mark_inode_dirty(inode);	inode->i_version ++;	inode->i_op = &udf_file_inode_operations;}struct buffer_head * udf_expand_dir_adinicb(struct inode *inode, int *block, int *err){	int newblock;	struct buffer_head *sbh = NULL, *dbh = NULL;	lb_addr bloc, eloc;	uint32_t elen, extoffset;	uint8_t alloctype;	struct udf_fileident_bh sfibh, dfibh;	loff_t f_pos = udf_ext0_offset(inode) >> 2;	int size = (udf_ext0_offset(inode) + inode->i_size) >> 2;	struct fileIdentDesc cfi, *sfi, *dfi;	if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_USE_SHORT_AD))		alloctype = ICBTAG_FLAG_AD_SHORT;	else		alloctype = ICBTAG_FLAG_AD_LONG;	if (!inode->i_size)	{		UDF_I_ALLOCTYPE(inode) = alloctype;		mark_inode_dirty(inode);		return NULL;	}	/* alloc block, and copy data to it */	*block = udf_new_block(inode->i_sb, inode,		UDF_I_LOCATION(inode).partitionReferenceNum,		UDF_I_LOCATION(inode).logicalBlockNum, err);	if (!(*block))		return NULL;	newblock = udf_get_pblock(inode->i_sb, *block,		UDF_I_LOCATION(inode).partitionReferenceNum, 0);	if (!newblock)		return NULL;	dbh = udf_tread(inode->i_sb, newblock);	if (!dbh)		return NULL;	sfibh.soffset = sfibh.eoffset = (f_pos & ((inode->i_sb->s_blocksize - 1) >> 2)) << 2;	sbh = sfibh.sbh = sfibh.ebh = NULL;	dfibh.soffset = dfibh.eoffset = 0;	dfibh.sbh = dfibh.ebh = dbh;	while ( (f_pos < size) )	{		UDF_I_ALLOCTYPE(inode) = ICBTAG_FLAG_AD_IN_ICB;		sfi = udf_fileident_read(inode, &f_pos, &sfibh, &cfi, NULL, NULL, NULL, NULL, NULL, NULL);		if (!sfi)		{			udf_release_data(dbh);			return NULL;		}		UDF_I_ALLOCTYPE(inode) = alloctype;		sfi->descTag.tagLocation = *block;		dfibh.soffset = dfibh.eoffset;		dfibh.eoffset += (sfibh.eoffset - sfibh.soffset);		dfi = (struct fileIdentDesc *)(dbh->b_data + dfibh.soffset);		if (udf_write_fi(inode, sfi, dfi, &dfibh, sfi->impUse,			sfi->fileIdent + sfi->lengthOfImpUse))		{			UDF_I_ALLOCTYPE(inode) = ICBTAG_FLAG_AD_IN_ICB;			udf_release_data(dbh);			return NULL;		}	}	mark_buffer_dirty(dbh, 1);	memset(UDF_I_DATA(inode) + UDF_I_LENEATTR(inode), 0, UDF_I_LENALLOC(inode));	UDF_I_LENALLOC(inode) = 0;	bloc = UDF_I_LOCATION(inode);	eloc.logicalBlockNum = *block;	eloc.partitionReferenceNum = UDF_I_LOCATION(inode).partitionReferenceNum;	elen = inode->i_size;	UDF_I_LENEXTENTS(inode) = elen;	extoffset = udf_file_entry_alloc_offset(inode);	udf_add_aext(inode, &bloc, &extoffset, eloc, elen, &sbh, 0);	/* UniqueID stuff */	inode->i_blocks = inode->i_sb->s_blocksize / 512;	udf_release_data(sbh);	mark_inode_dirty(inode);	inode->i_version ++;	return dbh;}struct buffer_head * udf_getblk(struct inode * inode, long block,	int create, int * err){	*err = -EIO;	if (block < 0)	{		udf_warning(inode->i_sb, "udf_getblk", "block < 0");		return NULL;	}	if (block == UDF_I_NEXT_ALLOC_BLOCK(inode) + 1)	{		UDF_I_NEXT_ALLOC_BLOCK(inode) ++;		UDF_I_NEXT_ALLOC_GOAL(inode) ++;	}	*err = -ENOSPC;	return inode_getblk(inode, block, create, err);}static struct buffer_head * inode_getblk(struct inode * inode, long block,	int create, int * err){	struct buffer_head *pbh = NULL, *cbh = NULL, *nbh = NULL, *result = NULL;	long_ad laarr[EXTENT_MERGE_SIZE];	uint32_t pextoffset = 0, cextoffset = 0, nextoffset = 0;	int count = 0, startnum = 0, endnum = 0;	uint32_t elen = 0;	lb_addr eloc, pbloc, cbloc, nbloc;	int c = 1;	uint64_t lbcount = 0, b_off = 0;	uint32_t newblocknum, newblock, offset = 0;	int8_t etype;	int goal = 0, pgoal = UDF_I_LOCATION(inode).logicalBlockNum;	char lastblock = 0;	pextoffset = cextoffset = nextoffset = udf_file_entry_alloc_offset(inode);	b_off = (uint64_t)block << inode->i_sb->s_blocksize_bits;	pbloc = cbloc = nbloc = UDF_I_LOCATION(inode);	/* find the extent which contains the block we are looking for.       alternate between laarr[0] and laarr[1] for locations of the       current extent, and the previous extent */	do	{		if (pbh != cbh)		{			udf_release_data(pbh);			cbh->b_count ++;			pbh = cbh;		}		if (cbh != nbh)		{			udf_release_data(cbh);			nbh->b_count ++;			cbh = nbh;		}		lbcount += elen;		pbloc = cbloc;		cbloc = nbloc;		pextoffset = cextoffset;		cextoffset = nextoffset;		if ((etype = udf_next_aext(inode, &nbloc, &nextoffset, &eloc, &elen, &nbh, 1)) == -1)			break;		c = !c;		laarr[c].extLength = (etype << 30) | elen;		laarr[c].extLocation = eloc;		if (etype != (EXT_NOT_RECORDED_NOT_ALLOCATED >> 30))			pgoal = eloc.logicalBlockNum +				((elen + inode->i_sb->s_blocksize - 1) >>				inode->i_sb->s_blocksize_bits);		count ++;	} while (lbcount + elen <= b_off);	b_off -= lbcount;	offset = b_off >> inode->i_sb->s_blocksize_bits;	/* if the extent is allocated and recorded, return the block       if the extent is not a multiple of the blocksize, round up */	if (etype == (EXT_RECORDED_ALLOCATED >> 30))	{		if (elen & (inode->i_sb->s_blocksize - 1))		{			elen = EXT_RECORDED_ALLOCATED |				((elen + inode->i_sb->s_blocksize - 1) &				~(inode->i_sb->s_blocksize - 1));			etype = udf_write_aext(inode, nbloc, &cextoffset, eloc, elen, nbh, 1);		}		udf_release_data(pbh);		udf_release_data(cbh);		udf_release_data(nbh);		newblock = udf_get_lb_pblock(inode->i_sb, eloc, offset);		return sb_getblk(inode->i_sb, newblock);	}	if (etype == -1)	{		endnum = startnum = ((count > 1) ? 1 : count);		if (laarr[c].extLength & (inode->i_sb->s_blocksize - 1))		{			laarr[c].extLength =				(laarr[c].extLength & UDF_EXTENT_FLAG_MASK) |				(((laarr[c].extLength & UDF_EXTENT_LENGTH_MASK) +					inode->i_sb->s_blocksize - 1) &				~(inode->i_sb->s_blocksize - 1));			UDF_I_LENEXTENTS(inode) =				(UDF_I_LENEXTENTS(inode) + inode->i_sb->s_blocksize - 1) &					~(inode->i_sb->s_blocksize - 1);		}		c = !c;		laarr[c].extLength = EXT_NOT_RECORDED_NOT_ALLOCATED |			((offset + 1) << inode->i_sb->s_blocksize_bits);		memset(&laarr[c].extLocation, 0x00, sizeof(lb_addr));		count ++;		endnum ++;		lastblock = 1;	}	else		endnum = startnum = ((count > 2) ? 2 : count);	/* if the current extent is in position 0, swap it with the previous */	if (!c && count != 1)	{		laarr[2] = laarr[0];		laarr[0] = laarr[1];		laarr[1] = laarr[2];		c = 1;	}	/* if the current block is located in a extent, read the next extent */	if (etype != -1)	{		if ((etype = udf_next_aext(inode, &nbloc, &nextoffset, &eloc, &elen, &nbh, 0)) != -1)		{			laarr[c+1].extLength = (etype << 30) | elen;			laarr[c+1].extLocation = eloc;			count ++;			startnum ++;			endnum ++;		}		else			lastblock = 1;	}	udf_release_data(cbh);	udf_release_data(nbh);	*err = -EFBIG;	if (!create && etype != (EXT_NOT_RECORDED_ALLOCATED >> 30))		goto dont_create;	{		unsigned long limit = current->rlim[RLIMIT_FSIZE].rlim_cur;		if (limit < RLIM_INFINITY)		{			limit >>= inode->i_sb->s_blocksize_bits;			if (block >= limit)			{				send_sig(SIGXFSZ, current, 0);dont_create:				*err = -EFBIG;				return NULL;			}		}	}	/* if the current extent is not recorded but allocated, get the		block in the extent corresponding to the requested block */	if ((laarr[c].extLength >> 30) == (EXT_NOT_RECORDED_ALLOCATED >> 30))		newblocknum = laarr[c].extLocation.logicalBlockNum + offset;	else /* otherwise, allocate a new block */	{		if (UDF_I_NEXT_ALLOC_BLOCK(inode) == block)			goal = UDF_I_NEXT_ALLOC_GOAL(inode);		if (!goal)		{			if (!(goal = pgoal))				goal = UDF_I_LOCATION(inode).logicalBlockNum + 1;		}		if (!(newblocknum = udf_new_block(inode->i_sb, inode,			UDF_I_LOCATION(inode).partitionReferenceNum, goal, err)))		{			udf_release_data(pbh);			*err = -ENOSPC;			return NULL;		}		UDF_I_LENEXTENTS(inode) += inode->i_sb->s_blocksize;	}	/* if the extent the requsted block is located in contains multiple blocks,       split the extent into at most three extents. blocks prior to requested       block, requested block, and blocks after requested block */	udf_split_extents(inode, &c, offset, newblocknum, laarr, &endnum);#ifdef UDF_PREALLOCATE	/* preallocate blocks */	udf_prealloc_extents(inode, c, lastblock, laarr, &endnum);#endif	/* merge any continuous blocks in laarr */	udf_merge_extents(inode, laarr, &endnum);	/* write back the new extents, inserting new extents if the new number       of extents is greater than the old number, and deleting extents if       the new number of extents is less than the old number */	udf_update_extents(inode, laarr, startnum, endnum, pbloc, pextoffset, &pbh);	udf_release_data(pbh);	if (!(newblock = udf_get_pblock(inode->i_sb, newblocknum,		UDF_I_LOCATION(inode).partitionReferenceNum, 0)))	{		return NULL;	}	if ((result = sb_getblk(inode->i_sb, newblock)))	{		memset(result->b_data, 0x00, inode->i_sb->s_blocksize);		mark_buffer_uptodate(result, 1);		mark_buffer_dirty(result, 1);	}	UDF_I_NEXT_ALLOC_BLOCK(inode) = block;	UDF_I_NEXT_ALLOC_GOAL(inode) = newblocknum;	inode->i_ctime = CURRENT_TIME;	UDF_I_UCTIME(inode) = CURRENT_UTIME;	inode->i_blocks += inode->i_sb->s_blocksize / 512;	if (IS_SYNC(inode))		udf_sync_inode(inode);	else		mark_inode_dirty(inode);

⌨️ 快捷键说明

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