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

📄 namei.c

📁 在VC平台下调试通过的linux 0.11文件系统代码! 对学习文件系统实现的朋友很有帮助
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *  linux/fs/namei.c * *  (C) 1991  Linus Torvalds *//* * Some corrections by tytso. */#include <string.h>#include "errno.h"#include "fs.h"#define ACC_MODE(x) ("\004\002\006\377"[(x)&O_ACCMODE])/* * comment out this line if you want names > NAME_LEN chars to be * truncated. Else they will be disallowed. *//* #define NO_TRUNCATE */#define MAY_EXEC 1#define MAY_WRITE 2#define MAY_READ 4/* *	permission() * * is used to check for read/write/execute permissions on a file. * I don't know if we should look at just the euid or both euid and * uid, but that should be easily changed. */static int permission(struct m_inode * inode,int mask){	int mode = inode->i_mode;/* special case: not even root can read/write a deleted file */	if (inode->i_dev && !inode->i_nlinks)		return 0;
	//我不需要用户检测
	/*else if (current->euid==inode->i_uid)		mode >>= 6;	else if (current->egid==inode->i_gid)		mode >>= 3;
		*/

	/*suser 应该是判断是否是超级权限的用户*/	/*if (((mode & mask & 0007) == mask) || suser())		return 1;*/

	//xly
	if (((mode & mask & 0007) == mask))
		return 1;	return 1;}/* * ok, we cannot use strncmp, as the name is not in our data space. * Thus we'll have to use match. No big problem. Match also makes * some sanity tests. * * NOTE! unlike strncmp, match returns 1 for success, 0 for failure. */static int match(int len,const char * name,struct dir_entry * de){	/*register int same __asm__("ax");*/
	
	int i;	if (!de || !de->inode || len > NAME_LEN)		return 0;	if (len < NAME_LEN && de->name[len])		return 0;

	//xly
	for (i = 0;i < len; i++)
		if (name[i] != de->name[i])
			return 0;

	/*	__asm__("cld\n\t"		"fs ; repe ; cmpsb\n\t"		"setz %%al"		:"=a" (same)		:"0" (0),"S" ((long) name),"D" ((long) de->name),"c" (len)		:"cx","di","si");
		*/
    	//return same;
		return 1;}/* *	find_entry() * * finds an entry in the specified directory with the wanted name. It * returns the cache buffer in which the entry was found, and the entry * itself (as a parameter - res_dir). It does NOT read the inode of the * entry - you'll have to do that yourself if you want to. * * This also takes care of the few special cases due to '..'-traversal * over a pseudo-root and a mount point. */

static struct buffer_head * find_entry(struct m_inode ** dir,	const char * name, int namelen, struct dir_entry ** res_dir){	int entries;	int block,i;	struct buffer_head * bh;	struct dir_entry * de;	struct super_block * sb;#ifdef NO_TRUNCATE	if (namelen > NAME_LEN)		return NULL;#else	if (namelen > NAME_LEN)		namelen = NAME_LEN;#endif	entries = (*dir)->i_size / (sizeof (struct dir_entry));	*res_dir = NULL;	if (!namelen)		return NULL;/* check for '..', as we might have to do some "magic" for it */	if (namelen==2 && get_fs_byte(name)=='.' && get_fs_byte(name+1)=='.') {/* '..' in a pseudo-root results in a faked '.' (just change namelen) */		if ((*dir) == current->root)			namelen=1;		else if ((*dir)->i_num == ROOT_INO) {/* '..' over a mount-point results in 'dir' being exchanged for the mounted   directory-inode. NOTE! We set mounted, so that we can iput the new dir */			sb=get_super((*dir)->i_dev);			if (sb->s_imount) {				iput(*dir);				(*dir)=sb->s_imount;				(*dir)->i_count++;			}		}	}

	//目录项为空,退出去	if (!(block = (*dir)->i_zone[0]))		return NULL;

	if (!(bh = bread((*dir)->i_dev,block)))		return NULL;	i = 0;	de = (struct dir_entry *) bh->b_data;	while (i < entries) {

		//如果当前目录项数据块已经搜索完,还没有找到匹配的目录项,则释放当前目录项数据块。		if ((char *)de >= BLOCK_SIZE+bh->b_data) {			brelse(bh);			bh = NULL;

			// 在读入下一目录项数据块。若这块为空,则只要还没有搜索完目录中的所有目录项,就跳过该块,
			// 继续读下一目录项数据块。若该块不空,就让de 指向该目录项数据块,继续搜索。			if (!(block = bmap(*dir,i/DIR_ENTRIES_PER_BLOCK)) ||			    !(bh = bread((*dir)->i_dev,block))) {				i += DIR_ENTRIES_PER_BLOCK;				continue;			}			de = (struct dir_entry *) bh->b_data;		}

		//是否找到
		if (match(namelen,name,de)) {			*res_dir = de;			return bh;		}		de++;		i++;	}	brelse(bh);	return NULL;}
char * iname(struct m_inode * inode, char * name)
{
	/**/
	struct m_inode * dir;
	int  entries;
	int block, i;
	struct buffer_head * bh;
	struct dir_entry * de;

	//偷懒,换一下pwd
	struct m_inode * old_pwd = current->pwd = inode;
	current->pwd = inode;

	if (!(dir = namei("..")))
		return NULL;
		//目录项为空,退出去
	entries = dir->i_size / (sizeof (struct dir_entry));
	if (!(block = dir->i_zone[0]))
		return NULL;


	if (!(bh = bread(dir->i_dev,block)))
		return NULL;
	i = 0;
	de = (struct dir_entry *) bh->b_data;

	while (i < entries) {

		//如果当前目录项数据块已经搜索完,还没有找到匹配的目录项,则释放当前目录项数据块。
		if ((char *)de >= BLOCK_SIZE+bh->b_data) {
			brelse(bh);
			bh = NULL;

			// 在读入下一目录项数据块。若这块为空,则只要还没有搜索完目录中的所有目录项,就跳过该块,
			// 继续读下一目录项数据块。若该块不空,就让de 指向该目录项数据块,继续搜索。
			if (!(block = bmap(dir,i/DIR_ENTRIES_PER_BLOCK)) ||
			    !(bh = bread((dir)->i_dev,block))) {
				i += DIR_ENTRIES_PER_BLOCK;
				continue;
			}
			de = (struct dir_entry *) bh->b_data;
		}

		//是否找到

		if (de->inode == inode->i_num) {
			memcpy(name, de->name, NAME_LEN-1);
			brelse(bh);
			current->pwd = old_pwd;
			return de->name;
		}
		de++;
		i++;
	}

	brelse(bh);

	current->pwd = old_pwd;
	return NULL;

}/* *	add_entry() * * adds a file entry to the specified directory, using the same * semantics as find_entry(). It returns NULL if it failed. * * NOTE!! The inode part of 'de' is left at 0 - which means you * may not sleep between calling this and putting something into * the entry, as someone else might have used it while you slept. */static struct buffer_head * add_entry(struct m_inode * dir,	const char * name, int namelen, struct dir_entry ** res_dir){	int block,i;	struct buffer_head * bh;	struct dir_entry * de;	*res_dir = NULL;#ifdef NO_TRUNCATE	if (namelen > NAME_LEN)		return NULL;#else	if (namelen > NAME_LEN)		namelen = NAME_LEN;#endif	if (!namelen)		return NULL;	if (!(block = dir->i_zone[0]))		return NULL;	if (!(bh = bread(dir->i_dev,block)))		return NULL;	i = 0;	de = (struct dir_entry *) bh->b_data;	while (1) {		if ((char *)de >= BLOCK_SIZE+bh->b_data) {			brelse(bh);			bh = NULL;			block = create_block(dir,i/DIR_ENTRIES_PER_BLOCK);			if (!block)				return NULL;			if (!(bh = bread(dir->i_dev,block))) {				i += DIR_ENTRIES_PER_BLOCK;				continue;			}			de = (struct dir_entry *) bh->b_data;		}		if (i*sizeof(struct dir_entry) >= dir->i_size) {			de->inode=0;			dir->i_size = (i+1)*sizeof(struct dir_entry);			dir->i_dirt = 1;			dir->i_ctime = CURRENT_TIME;		}		if (!de->inode) {			dir->i_mtime = CURRENT_TIME;			for (i=0; i < NAME_LEN ; i++)				de->name[i]=(i<namelen)?get_fs_byte(name+i):0;			bh->b_dirt = 1;			*res_dir = de;			return bh;		}		de++;		i++;	}	brelse(bh);	return NULL;}/* *	get_dir() * * Getdir traverses the pathname until it hits the topmost directory. * It returns NULL on failure. */static struct m_inode * get_dir(const char * pathname){	char c;	const char * thisname;	struct m_inode * inode;	struct buffer_head * bh;	int namelen,inr,idev;	struct dir_entry * de;
	//和进程相关,判断权限之类操作	if (!current->root || !current->root->i_count)		panic("No root inode");	if (!current->pwd || !current->pwd->i_count)		panic("No cwd inode");


	//如果pathname第一个字符为'/',表示给出的是绝对路径	if ((c=get_fs_byte(pathname))=='/') {		inode = current->root;		pathname++;

		//否则相对路径	} else if (c)		inode = current->pwd;
	   //空名	else		return NULL;	/* empty name is bad */


	inode->i_count++;	while (1) {		thisname = pathname;

		//判断该节点是否为目录,有访问权限		if (!S_ISDIR(inode->i_mode) || !permission(inode,MAY_EXEC)) {			iput(inode);			return NULL;		}

		for(namelen=0;(c=get_fs_byte(pathname++))&&(c!='/');namelen++)			/* nothing */ ;		if (!c)			return inode;		if (!(bh = find_entry(&inode,thisname,namelen,&de))) {			iput(inode);			return NULL;		}		inr = de->inode;		idev = inode->i_dev;		brelse(bh);		iput(inode);		if (!(inode = iget(idev,inr)))			return NULL;	}}/* *	dir_namei() * * dir_namei() returns the inode of the directory of the * specified name, and the name within that directory. */static struct m_inode * dir_namei(const char * pathname,	int * namelen, const char ** name){	char c;	const char * basename;	struct m_inode * dir;	if (!(dir = get_dir(pathname)))		return NULL;	basename = pathname;	while (c=get_fs_byte(pathname++))		if (c=='/')			basename=pathname;	*namelen = pathname-basename-1;	*name = basename;	return dir;}/* *	namei() * * is used by most simple commands to get the inode of a specified name. * Open, link etc use their own routines, but this is enough for things * like 'chmod' etc. */struct m_inode * namei(const char * pathname){	const char * basename;	int inr,dev,namelen;	struct m_inode * dir;	struct buffer_head * bh;	struct dir_entry * de;	if (!(dir = dir_namei(pathname,&namelen,&basename)))		return NULL;	if (!namelen)			/* special case: '/usr/' etc */		return dir;	bh = find_entry(&dir,basename,namelen,&de);	if (!bh) {		iput(dir);		return NULL;	}	inr = de->inode;	dev = dir->i_dev;	brelse(bh);	iput(dir);	dir=iget(dev,inr);	if (dir) {		dir->i_atime=CURRENT_TIME;		dir->i_dirt=1;	}	return dir;}/* *	open_namei() * * namei for open - this is in fact almost the whole open-routine. */

⌨️ 快捷键说明

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