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

📄 namei.c

📁 linux0.01内核源代码,让linux初学者对linux内核有清晰的了解并且掌握。
💻 C
字号:
#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))		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;	__asm__("cld\n\t"		"fs ; repe ; cmpsb\n\t"		"setz %%al"		:"=a" (same)		:"0" (0),"S" ((long) name),"D" ((long) de->name),"c" (len)		);	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;	while (i < entries) {		if ((char *)de >= BLOCK_SIZE+bh->b_data) {			brelse(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)) {			*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;	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");	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. */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 |= O_WRONLY;	mode &= 0777 & ~current->umask;	mode |= I_REGULAR;	if (!(dir = dir_namei(pathname,&namelen,&basename)))		return -ENOENT;	if (!namelen) {			/* special case: '/usr/' etc */		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)) {			iput(dir);			return -ENOENT;		}		if (!permission(dir,MAY_WRITE)) {			iput(dir);			return -EACCES;		}		inode = new_inode(dir->i_dev);		if (!inode) {			iput(dir);			return -ENOSPC;		}		inode->i_mode = mode;		inode->i_dirt = 1;		bh = add_entry(dir,basename,namelen,&de);		if (!bh) {			inode->i_nlinks--;			iput(inode);			iput(dir);			return -ENOSPC;		}		de->inode = inode->i_num;		bh->b_dirt = 1;		brelse(bh);		iput(dir);		*res_inode = inode;		return 0;	}	inr = de->inode;	dev = dir->i_dev;	brelse(bh);	iput(dir);	if (flag & O_EXCL)		return -EEXIST;	if (!(inode=iget(dev,inr)))		return -EACCES;	if ((S_ISDIR(inode->i_mode) && (flag & O_ACCMODE)) ||	    permission(inode,ACC_MODE(flag))!=ACC_MODE(flag)) {		iput(inode);		return -EPERM;	}	inode->i_atime = CURRENT_TIME;	if (flag & O_TRUNC)		truncate(inode);	*res_inode = inode;	return 0;}int sys_mkdir(const char * pathname, int mode){	const char * basename;	int namelen;	struct m_inode * dir, * inode;	struct buffer_head * bh, *dir_block;	struct dir_entry * de;	if (current->euid && current->uid)		return -EPERM;	if (!(dir = dir_namei(pathname,&namelen,&basename)))		return -ENOENT;	if (!namelen) {		iput(dir);		return -ENOENT;	}	if (!permission(dir,MAY_WRITE)) {		iput(dir);		return -EPERM;	}	bh = find_entry(dir,basename,namelen,&de);	if (bh) {		brelse(bh);		iput(dir);		return -EEXIST;	}	inode = new_inode(dir->i_dev);	if (!inode) {		iput(dir);		return -ENOSPC;	}	inode->i_size = 32;	inode->i_dirt = 1;	inode->i_mtime = inode->i_atime = CURRENT_TIME;	if (!(inode->i_zone[0]=new_block(inode->i_dev))) {		iput(dir);		inode->i_nlinks--;		iput(inode);		return -ENOSPC;	}	inode->i_dirt = 1;	if (!(dir_block=bread(inode->i_dev,inode->i_zone[0]))) {		iput(dir);		free_block(inode->i_dev,inode->i_zone[0]);		inode->i_nlinks--;		iput(inode);		return -ERROR;	}	de = (struct dir_entry *) dir_block->b_data;	de->inode=inode->i_num;	strcpy(de->name,".");	de++;	de->inode = dir->i_num;	strcpy(de->name,"..");	inode->i_nlinks = 2;	dir_block->b_dirt = 1;	brelse(dir_block);	inode->i_mode = I_DIRECTORY | (mode & 0777 & ~current->umask);	inode->i_dirt = 1;	bh = add_entry(dir,basename,namelen,&de);	if (!bh) {		iput(dir);		free_block(inode->i_dev,inode->i_zone[0]);		inode->i_nlinks=0;		iput(inode);		return -ENOSPC;	}	de->inode = inode->i_num;	bh->b_dirt = 1;	dir->i_nlinks++;	dir->i_dirt = 1;	iput(dir);	iput(inode);	brelse(bh);	return 0;}/* * routine to check that the specified directory is empty (for rmdir) */static int empty_dir(struct m_inode * inode){	int nr,block;	int len;	struct buffer_head * bh;	struct dir_entry * de;	len = inode->i_size / sizeof (struct dir_entry);	if (len<2 || !inode->i_zone[0] ||	    !(bh=bread(inode->i_dev,inode->i_zone[0]))) {	    	printk("warning - bad directory on dev %04x\n",inode->i_dev);		return 0;	}	de = (struct dir_entry *) bh->b_data;	if (de[0].inode != inode->i_num || !de[1].inode || 	    strcmp(".",de[0].name) || strcmp("..",de[1].name)) {	    	printk("warning - bad directory on dev %04x\n",inode->i_dev);		return 0;	}	nr = 2;	de += 2;	while (nr<len) {		if ((void *) de >= (void *) (bh->b_data+BLOCK_SIZE)) {			brelse(bh);			block=bmap(inode,nr/DIR_ENTRIES_PER_BLOCK);			if (!block) {				nr += DIR_ENTRIES_PER_BLOCK;				continue;			}			if (!(bh=bread(inode->i_dev,block)))				return 0;			de = (struct dir_entry *) bh->b_data;		}		if (de->inode) {			brelse(bh);			return 0;		}		de++;		nr++;	}	brelse(bh);	return 1;}int sys_rmdir(const char * name){	const char * basename;	int namelen;	struct m_inode * dir, * inode;	struct buffer_head * bh;	struct dir_entry * de;	if (current->euid && current->uid)		return -EPERM;	if (!(dir = dir_namei(name,&namelen,&basename)))		return -ENOENT;	if (!namelen) {		iput(dir);		return -ENOENT;	}	bh = find_entry(dir,basename,namelen,&de);	if (!bh) {		iput(dir);		return -ENOENT;	}	if (!permission(dir,MAY_WRITE)) {		iput(dir);		brelse(bh);		return -EPERM;	}	if (!(inode = iget(dir->i_dev, de->inode))) {		iput(dir);		brelse(bh);		return -EPERM;	}	if (inode == dir) {	/* we may not delete ".", but "../dir" is ok */		iput(inode);		iput(dir);		brelse(bh);		return -EPERM;	}	if (!S_ISDIR(inode->i_mode)) {		iput(inode);		iput(dir);		brelse(bh);		return -ENOTDIR;	}	if (!empty_dir(inode)) {		iput(inode);		iput(dir);		brelse(bh);		return -ENOTEMPTY;	}	if (inode->i_nlinks != 2)		printk("empty directory has nlink!=2 (%d)",inode->i_nlinks);	de->inode = 0;	bh->b_dirt = 1;	brelse(bh);	inode->i_nlinks=0;	inode->i_dirt=1;	dir->i_nlinks--;	dir->i_ctime = dir->i_mtime = CURRENT_TIME;	dir->i_dirt=1;	iput(dir);	iput(inode);	return 0;}int sys_unlink(const char * name){	const char * basename;	int namelen;	struct m_inode * dir, * inode;	struct buffer_head * bh;	struct dir_entry * de;	if (!(dir = dir_namei(name,&namelen,&basename)))		return -ENOENT;	if (!namelen) {		iput(dir);		return -ENOENT;	}	if (!permission(dir,MAY_WRITE)) {		iput(dir);		return -EPERM;	}	bh = find_entry(dir,basename,namelen,&de);	if (!bh) {		iput(dir);		return -ENOENT;	}	inode = iget(dir->i_dev, de->inode);	if (!inode) {		printk("iget failed in delete (%04x:%d)",dir->i_dev,de->inode);		iput(dir);		brelse(bh);		return -ENOENT;	}	if (!S_ISREG(inode->i_mode)) {		iput(inode);		iput(dir);		brelse(bh);		return -EPERM;	}	if (!inode->i_nlinks) {		printk("Deleting nonexistent file (%04x:%d), %d\n",			inode->i_dev,inode->i_num,inode->i_nlinks);		inode->i_nlinks=1;	}	de->inode = 0;	bh->b_dirt = 1;	brelse(bh);	inode->i_nlinks--;	inode->i_dirt = 1;	inode->i_ctime = CURRENT_TIME;	iput(inode);	iput(dir);	return 0;}int sys_link(const char * oldname, const char * newname){	struct dir_entry * de;	struct m_inode * oldinode, * dir;	struct buffer_head * bh;	const char * basename;	int namelen;	oldinode=namei(oldname);	if (!oldinode)		return -ENOENT;	if (!S_ISREG(oldinode->i_mode)) {		iput(oldinode);		return -EPERM;	}	dir = dir_namei(newname,&namelen,&basename);	if (!dir) {		iput(oldinode);		return -EACCES;	}	if (!namelen) {		iput(oldinode);		iput(dir);		return -EPERM;	}	if (dir->i_dev != oldinode->i_dev) {		iput(dir);		iput(oldinode);		return -EXDEV;	}	if (!permission(dir,MAY_WRITE)) {		iput(dir);		iput(oldinode);		return -EACCES;	}	bh = find_entry(dir,basename,namelen,&de);	if (bh) {		brelse(bh);		iput(dir);		iput(oldinode);		return -EEXIST;	}	bh = add_entry(dir,basename,namelen,&de);	if (!bh) {		iput(dir);		iput(oldinode);		return -ENOSPC;	}	de->inode = oldinode->i_num;	bh->b_dirt = 1;	brelse(bh);	iput(dir);	oldinode->i_nlinks++;	oldinode->i_ctime = CURRENT_TIME;	oldinode->i_dirt = 1;	iput(oldinode);	return 0;}

⌨️ 快捷键说明

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