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

📄 namei.c

📁 自已看吧
💻 C
📖 第 1 页 / 共 2 页
字号:
#include <linux/sched.h>
#include <linux/kernel.h>
#include <asm/segment.h>

#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <const.h>
#include <sys/stat.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;
	if (!(current->uid && current->euid))			//uid和euid都为0,表示最高权限
		mode=0777;
	else if (current->uid==inode->i_uid || current->euid==inode->i_uid)		//用户权限检查
		mode >>= 6;
	else if (current->gid==inode->i_gid || current->egid==inode->i_gid)		//用户组权限检查
		mode >>= 3;
	return mode & mask & 0007;
}

/*
 * 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");

	if (!de || !de->inode || len > NAME_LEN)		//如果目录指针为空或节点不存在或长度太长
		return 0;
	if (len < NAME_LEN && de->name[len])
		return 0;
//下面内嵌汇编的意思是:
//	movl	0	%eax
//	movl	name	%esi
//	movl	de->name	%edi
//	cld
//	repe				//ZF=1
//	cmpsb
//	setz	%al
//	movl	%eax	same
	__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;
}

/*
 *	find_entry()
 *
 * finds and 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.
 */
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;

#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;
	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;			//de指向目录文件数据区的开始
	while (i < entries) {
		if ((char *)de >= BLOCK_SIZE+bh->b_data) {	//如果该目录文件中一个块读完仍未找到,就读该目录文件的下一个块
			brelse(bh);					//释放bh
			bh = NULL;
			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)) {			//对比目录文件中的一个元素,返回1是找到
			*res_dir = de;				//指向所找数据的偏移量
			return bh;
		}
		de++;
		i++;
	}
	brelse(bh);
	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;		//de指向第一块的数据区
	while (1) {
		if ((char *)de >= BLOCK_SIZE+bh->b_data) {	//如果de指向了该块的末尾
			brelse(bh);
			bh = NULL;
			block = create_block(dir,i/DIR_ENTRIES_PER_BLOCK);	//取得目录文件的下一个块号,如果需要,就创建新块
			if (!block)
				return NULL;
			if (!(bh = bread(dir->i_dev,block))) {	//将此块读入buffer
				i += DIR_ENTRIES_PER_BLOCK;
				continue;
			}
			de = (struct dir_entry *) bh->b_data;	//de指向该块的数据区
		}
		if (i*sizeof(struct dir_entry) >= dir->i_size) {	//在目录文件的末尾创建新的节点,初始化为0,并修改该目录文件的尺寸
			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;	//将文件名写入de->name
			bh->b_dirt = 1;
			*res_dir = de;			//这时de是一个inode=0和name=文件名的结构
			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");
	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;				//取得目录的inode
		idev = inode->i_dev;
		brelse(bh);
		iput(inode);
		if (!(inode = iget(idev,inr)))		//取得该目录的内存inode,为寻找下一个子目录做准备
			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)))			//取得该目录的最后子目录的内存inode
		return NULL;
	basename = pathname;					//两个指针指向同一地址,即文件全名的起始地址
	while (c=get_fs_byte(pathname++))
		if (c=='/')
			basename=pathname;			//basename最终将是要运行的程序名
	*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)))		//取得目录的内存inode
		return NULL;
	if (!namelen)			/* special case: '/usr/' etc */
		return dir;
	bh = find_entry(dir,basename,namelen,&de);			//取得需要运行或打开的inode
	if (!bh) {					//如果没有这个文件,释放该目录的buffer
		iput(dir);
		return NULL;
	}
	inr = de->inode;				//取得该文件的硬盘inode
	dev = dir->i_dev;
	brelse(bh);
	iput(dir);
	dir=iget(dev,inr);				//取得该文件的内存inode
	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.
 */
int open_namei(const char * pathname, int flag, int mode,
	struct m_inode ** res_inode)
{
	const char * basename;
	int inr,dev,namelen;
	struct m_inode * dir, *inode;
	struct buffer_head * bh;
	struct dir_entry * de;

	if ((flag & O_TRUNC) && !(flag & O_ACCMODE))		//如果flag是可修剪的或可访问的
		flag |= O_WRONLY;					//那么加上可写位
	mode &= 0777 & ~current->umask;				//mode必须接受当前进程掩码的约束
	mode |= I_REGULAR;
	if (!(dir = dir_namei(pathname,&namelen,&basename)))
		return -ENOENT;
	if (!namelen) {			/* special case: '/usr/' etc */	//如果pathname只是目录,而没有文件名
		if (!(flag & (O_ACCMODE|O_CREAT|O_TRUNC))) {
			*res_inode=dir;
			return 0;
		}
		iput(dir);
		return -EISDIR;
	}
	bh = find_entry(dir,basename,namelen,&de);
	if (!bh) {					//如果在目录中没有发现该文件的入口点
		if (!(flag & O_CREAT)) {		//如果flag中没有建立位,返回
			iput(dir);
			return -ENOENT;
		}

⌨️ 快捷键说明

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