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

📄 namei.c

📁 这是Linux系统下的对UDF文件系统新增的功能
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * namei.c * * PURPOSE *      Inode name 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-2003 Ben Fennema *  (C) 1999-2000 Stelias Computing Inc * * HISTORY * *  12/12/98 blf  Created. Split out the lookup code from dir.c *  04/19/99 blf  link, mknod, symlink support */#include "udfdecl.h"#include "udf_i.h"#include "udf_sb.h"#include <linux/string.h>#include <linux/errno.h>#include <linux/mm.h>#include <linux/slab.h>#include <linux/quotaops.h>#include <linux/smp_lock.h>#include <linux/buffer_head.h>static inline int udf_match(int len1, const char *name1, int len2, const char *name2){	if (len1 != len2)		return 0;	return !memcmp(name1, name2, len1);}int udf_write_fi(struct inode *inode, struct fileIdentDesc *cfi,	struct fileIdentDesc *sfi, struct udf_fileident_bh *fibh,	uint8_t *impuse, uint8_t *fileident){	uint16_t crclen = fibh->eoffset - fibh->soffset - sizeof(tag);	uint16_t crc;	uint8_t checksum = 0;	int i;	int offset;	uint16_t liu = le16_to_cpu(cfi->lengthOfImpUse);	uint8_t lfi = cfi->lengthFileIdent;	int padlen = fibh->eoffset - fibh->soffset - liu - lfi -		sizeof(struct fileIdentDesc);	int adinicb = 0;	if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_IN_ICB)		adinicb = 1;	offset = fibh->soffset + sizeof(struct fileIdentDesc);	if (impuse)	{		if (adinicb || (offset + liu < 0))			memcpy((uint8_t *)sfi->impUse, impuse, liu);		else if (offset >= 0)			memcpy(fibh->ebh->b_data + offset, impuse, liu);		else		{			memcpy((uint8_t *)sfi->impUse, impuse, -offset);			memcpy(fibh->ebh->b_data, impuse - offset, liu + offset);		}	}	offset += liu;	if (fileident)	{		if (adinicb || (offset + lfi < 0))			memcpy((uint8_t *)sfi->fileIdent + liu, fileident, lfi);		else if (offset >= 0)			memcpy(fibh->ebh->b_data + offset, fileident, lfi);		else		{			memcpy((uint8_t *)sfi->fileIdent + liu, fileident, -offset);			memcpy(fibh->ebh->b_data, fileident - offset, lfi + offset);		}	}	offset += lfi;	if (adinicb || (offset + padlen < 0))		memset((uint8_t *)sfi->padding + liu + lfi, 0x00, padlen);	else if (offset >= 0)		memset(fibh->ebh->b_data + offset, 0x00, padlen);	else	{		memset((uint8_t *)sfi->padding + liu + lfi, 0x00, -offset);		memset(fibh->ebh->b_data, 0x00, padlen + offset);	}	crc = udf_crc((uint8_t *)cfi + sizeof(tag), sizeof(struct fileIdentDesc) -		sizeof(tag), 0);	if (fibh->sbh == fibh->ebh)		crc = udf_crc((uint8_t *)sfi->impUse,			crclen + sizeof(tag) - sizeof(struct fileIdentDesc), crc);	else if (sizeof(struct fileIdentDesc) >= -fibh->soffset)		crc = udf_crc(fibh->ebh->b_data + sizeof(struct fileIdentDesc) + fibh->soffset,			crclen + sizeof(tag) - sizeof(struct fileIdentDesc), crc);	else	{		crc = udf_crc((uint8_t *)sfi->impUse,			-fibh->soffset - sizeof(struct fileIdentDesc), crc);		crc = udf_crc(fibh->ebh->b_data, fibh->eoffset, crc);	}	cfi->descTag.descCRC = cpu_to_le32(crc);	cfi->descTag.descCRCLength = cpu_to_le16(crclen);	for (i=0; i<16; i++)		if (i != 4)			checksum += ((uint8_t *)&cfi->descTag)[i];	cfi->descTag.tagChecksum = checksum;	if (adinicb || (sizeof(struct fileIdentDesc) <= -fibh->soffset))		memcpy((uint8_t *)sfi, (uint8_t *)cfi, sizeof(struct fileIdentDesc));	else	{		memcpy((uint8_t *)sfi, (uint8_t *)cfi, -fibh->soffset);		memcpy(fibh->ebh->b_data, (uint8_t *)cfi - fibh->soffset,			sizeof(struct fileIdentDesc) + fibh->soffset);	}	if (adinicb)		mark_inode_dirty(inode);	else	{		if (fibh->sbh != fibh->ebh)			mark_buffer_dirty_inode(fibh->ebh, inode);		mark_buffer_dirty_inode(fibh->sbh, inode);	}	return 0;}static struct fileIdentDesc *udf_find_entry(struct inode *dir, struct dentry *dentry,	struct udf_fileident_bh *fibh,	struct fileIdentDesc *cfi){	struct fileIdentDesc *fi=NULL;	loff_t f_pos;	int block, namelen;	char name[UDF_NAME_LEN], fname[UDF_NAME_LEN];	char *nameptr;	uint8_t lfi;	uint16_t liu;	loff_t size = (udf_ext0_offset(dir) + dir->i_size) >> 2;	lb_addr bloc, eloc;	uint32_t extoffset, elen, offset;	struct buffer_head *bh = NULL;	if (!dir)		return NULL;	if ( !(namelen = udf_put_filename(dir->i_sb, dentry->d_name.name, name, dentry->d_name.len)))		return NULL;	f_pos = (udf_ext0_offset(dir) >> 2);	fibh->soffset = fibh->eoffset = (f_pos & ((dir->i_sb->s_blocksize - 1) >> 2)) << 2;	if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB)		fibh->sbh = fibh->ebh = NULL;	else if (inode_bmap(dir, f_pos >> (dir->i_sb->s_blocksize_bits - 2),		&bloc, &extoffset, &eloc, &elen, &offset, &bh) == (EXT_RECORDED_ALLOCATED >> 30))	{		offset >>= dir->i_sb->s_blocksize_bits;		block = udf_get_lb_pblock(dir->i_sb, eloc, offset);		if ((++offset << dir->i_sb->s_blocksize_bits) < elen)		{			if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_SHORT)				extoffset -= sizeof(short_ad);			else if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_LONG)				extoffset -= sizeof(long_ad);		}		else			offset = 0;		if (!(fibh->sbh = fibh->ebh = udf_tread(dir->i_sb, block)))		{			udf_release_data(bh);			return NULL;		}	}	else	{		udf_release_data(bh);		return NULL;	}	while ( (f_pos < size) )	{		fi = udf_fileident_read(dir, &f_pos, fibh, cfi, &bloc, &extoffset, &eloc, &elen, &offset, &bh);		if (!fi)		{			if (fibh->sbh != fibh->ebh)				udf_release_data(fibh->ebh);			udf_release_data(fibh->sbh);			udf_release_data(bh);			return NULL;		}		liu = le16_to_cpu(cfi->lengthOfImpUse);		lfi = cfi->lengthFileIdent;		if (fibh->sbh == fibh->ebh)		{			nameptr = fi->fileIdent + liu;		}		else		{			int poffset;	/* Unpaded ending offset */			poffset = fibh->soffset + sizeof(struct fileIdentDesc) + liu + lfi;			if (poffset >= lfi)				nameptr = (uint8_t *)(fibh->ebh->b_data + poffset - lfi);			else			{				nameptr = fname;				memcpy(nameptr, fi->fileIdent + liu, lfi - poffset);				memcpy(nameptr + lfi - poffset, fibh->ebh->b_data, poffset);			}		}		if ( (cfi->fileCharacteristics & FID_FILE_CHAR_DELETED) != 0 )		{			if ( !UDF_QUERY_FLAG(dir->i_sb, UDF_FLAG_UNDELETE) )				continue;		}	    		if ( (cfi->fileCharacteristics & FID_FILE_CHAR_HIDDEN) != 0 )		{			if ( !UDF_QUERY_FLAG(dir->i_sb, UDF_FLAG_UNHIDE) )				continue;		}		if (!lfi)			continue;		if (udf_match(namelen, name, lfi, nameptr))		{			udf_release_data(bh);			return fi;		}	}	if (fibh->sbh != fibh->ebh)		udf_release_data(fibh->ebh);	udf_release_data(fibh->sbh);	udf_release_data(bh);	return NULL;}/* * udf_lookup * * PURPOSE *	Look-up the inode for a given name. * * DESCRIPTION *	Required - lookup_dentry() will return -ENOTDIR if this routine is not *	available for a directory. The filesystem is useless if this routine is *	not available for at least the filesystem's root directory. * *	This routine is passed an incomplete dentry - it must be completed by *	calling d_add(dentry, inode). If the name does not exist, then the *	specified inode must be set to null. An error should only be returned *	when the lookup fails for a reason other than the name not existing. *	Note that the directory inode semaphore is held during the call. * *	Refer to lookup_dentry() in fs/namei.c *	lookup_dentry() -> lookup() -> real_lookup() -> . * * PRE-CONDITIONS *	dir			Pointer to inode of parent directory. *	dentry			Pointer to dentry to complete. *	nd			Pointer to lookup nameidata * * POST-CONDITIONS *	<return>		Zero on success. * * HISTORY *	July 1, 1997 - Andrew E. Mileski *	Written, tested, and released. */static struct dentry *udf_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd){	struct inode *inode = NULL;	struct fileIdentDesc cfi, *fi;	struct udf_fileident_bh fibh;	if (dentry->d_name.len > UDF_NAME_LEN-2)		return ERR_PTR(-ENAMETOOLONG);	lock_kernel();#ifdef UDF_RECOVERY	/* temporary shorthand for specifying files by inode number */	if (!strncmp(dentry->d_name.name, ".B=", 3) )	{		lb_addr lb = { 0, simple_strtoul(dentry->d_name.name+3, NULL, 0) };		inode = udf_iget(dir->i_sb, lb);		if (!inode)		{			unlock_kernel();			return ERR_PTR(-EACCES);		}	}	else#endif /* UDF_RECOVERY */	if ((fi = udf_find_entry(dir, dentry, &fibh, &cfi)))	{		if (fibh.sbh != fibh.ebh)			udf_release_data(fibh.ebh);		udf_release_data(fibh.sbh);		inode = udf_iget(dir->i_sb, lelb_to_cpu(cfi.icb.extLocation));		if ( !inode )		{			unlock_kernel();			return ERR_PTR(-EACCES);		}	}	unlock_kernel();	d_add(dentry, inode);	return NULL;}static struct fileIdentDesc *udf_add_entry(struct inode *dir, struct dentry *dentry,	struct udf_fileident_bh *fibh,	struct fileIdentDesc *cfi, int *err){	struct super_block *sb;	struct fileIdentDesc *fi=NULL;	char name[UDF_NAME_LEN], fname[UDF_NAME_LEN];	int namelen;	loff_t f_pos;	char *nameptr;	loff_t size = (udf_ext0_offset(dir) + dir->i_size) >> 2;	int nfidlen;	uint8_t lfi;	uint16_t liu;	int block;	lb_addr bloc, eloc;	uint32_t extoffset, elen, offset;	struct buffer_head *bh = NULL;	sb = dir->i_sb;	if (dentry)	{		if (!dentry->d_name.len)		{			*err = -EINVAL;			return NULL;		}		if ( !(namelen = udf_put_filename(sb, dentry->d_name.name, name, dentry->d_name.len)))		{			*err = -ENAMETOOLONG;			return NULL;		}	}	else		namelen = 0;	nfidlen = (sizeof(struct fileIdentDesc) + namelen + 3) & ~3;	f_pos = (udf_ext0_offset(dir) >> 2);	fibh->soffset = fibh->eoffset = (f_pos & ((dir->i_sb->s_blocksize - 1) >> 2)) << 2;	if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB)		fibh->sbh = fibh->ebh = NULL;	else if (inode_bmap(dir, f_pos >> (dir->i_sb->s_blocksize_bits - 2),		&bloc, &extoffset, &eloc, &elen, &offset, &bh) == (EXT_RECORDED_ALLOCATED >> 30))	{		offset >>= dir->i_sb->s_blocksize_bits;		block = udf_get_lb_pblock(dir->i_sb, eloc, offset);		if ((++offset << dir->i_sb->s_blocksize_bits) < elen)		{			if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_SHORT)				extoffset -= sizeof(short_ad);			else if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_LONG)				extoffset -= sizeof(long_ad);		}		else			offset = 0;		if (!(fibh->sbh = fibh->ebh = udf_tread(dir->i_sb, block)))		{			udf_release_data(bh);			*err = -EIO;			return NULL;		}		block = UDF_I_LOCATION(dir).logicalBlockNum;	}	else	{		block = udf_get_lb_pblock(dir->i_sb, UDF_I_LOCATION(dir), 0);		fibh->sbh = fibh->ebh = NULL;		fibh->soffset = fibh->eoffset = sb->s_blocksize;		goto add;	}	while ( (f_pos < size) )	{		fi = udf_fileident_read(dir, &f_pos, fibh, cfi, &bloc, &extoffset, &eloc, &elen, &offset, &bh);		if (!fi)		{			if (fibh->sbh != fibh->ebh)				udf_release_data(fibh->ebh);			udf_release_data(fibh->sbh);			udf_release_data(bh);			*err = -EIO;			return NULL;		}		liu = le16_to_cpu(cfi->lengthOfImpUse);		lfi = cfi->lengthFileIdent;		if (fibh->sbh == fibh->ebh)			nameptr = fi->fileIdent + liu;		else		{

⌨️ 快捷键说明

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