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

📄 namei.c

📁 LINUX1.0内核源代码,学习LINUX编程的一定要看。
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *  linux/fs/ext/namei.c * *  Copyright (C) 1992  Remy Card (card@masi.ibp.fr) * *  from * *  linux/fs/minix/namei.c * *  Copyright (C) 1991, 1992  Linus Torvalds */#include <linux/sched.h>#include <linux/ext_fs.h>#include <linux/kernel.h>#include <linux/string.h>#include <linux/stat.h>#include <linux/fcntl.h>#include <linux/errno.h>#include <asm/segment.h>/* * comment out this line if you want names > EXT_NAME_LEN chars to be * truncated. Else they will be disallowed. *//* #define NO_TRUNCATE *//* * EXT_DIR_PAD defines the directory entries boundaries * * NOTE: It must be a power of 2 and must be greater or equal than 8 * because a directory entry needs 8 bytes for its fixed part * (4 bytes for the inode, 2 bytes for the entry length and 2 bytes * for the name length) */#define EXT_DIR_PAD 8/* * * EXT_DIR_MIN_SIZE is the minimal size of a directory entry * * During allocations, a directory entry is split into 2 ones * *ONLY* if the size of the unused part is greater than or  * equal to EXT_DIR_MIN_SIZE */#define EXT_DIR_MIN_SIZE 12/* * ok, we cannot use strncmp, as the name is not in our data space. * Thus we'll have to use ext_match. No big problem. Match also makes * some sanity tests. * * NOTE! unlike strncmp, ext_match returns 1 for success, 0 for failure. */static int ext_match(int len,const char * name,struct ext_dir_entry * de){	register int same __asm__("ax");	if (!de || !de->inode || len > EXT_NAME_LEN)		return 0;	/* "" means "." ---> so paths like "/usr/lib//libc.a" work */	if (!len && (de->name[0]=='.') && (de->name[1]=='\0'))		return 1;	if (len < EXT_NAME_LEN && len != de->name_len)		return 0;	__asm__("cld\n\t"		"repe ; cmpsb\n\t"		"setz %%al"		:"=a" (same)		:"0" (0),"S" ((long) name),"D" ((long) de->name),"c" (len)		:"cx","di","si");	return same;}/* *	ext_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. * * addition for the ext file system : this function returns the previous * and next directory entries in the parameters prev_dir and next_dir */static struct buffer_head * ext_find_entry(struct inode * dir,	const char * name, int namelen, struct ext_dir_entry ** res_dir,	struct ext_dir_entry ** prev_dir, struct ext_dir_entry ** next_dir){	long offset;	struct buffer_head * bh;	struct ext_dir_entry * de;	*res_dir = NULL;	if (!dir)		return NULL;#ifdef NO_TRUNCATE	if (namelen > EXT_NAME_LEN)		return NULL;#else	if (namelen > EXT_NAME_LEN)		namelen = EXT_NAME_LEN;#endif	bh = ext_bread(dir,0,0);	if (!bh)		return NULL;	if (prev_dir)		*prev_dir = NULL;	if (next_dir)		*next_dir = NULL;	offset = 0;	de = (struct ext_dir_entry *) bh->b_data;	while (offset < dir->i_size) {		if ((char *)de >= BLOCK_SIZE+bh->b_data) {			brelse(bh);			bh = NULL;			bh = ext_bread(dir,offset>>BLOCK_SIZE_BITS,0);			if (!bh)				continue;			de = (struct ext_dir_entry *) bh->b_data;			if (prev_dir)				*prev_dir = NULL;		}		if (de->rec_len < 8 || de->rec_len % 8 != 0 ||		    de->rec_len < de->name_len + 8 ||		    (((char *) de) + de->rec_len-1 >= BLOCK_SIZE+bh->b_data)) {			printk ("ext_find_entry: bad dir entry\n");			printk ("dev=%d, dir=%d, offset=%d, rec_len=%d, name_len=%d\n",				dir->i_dev, dir->i_ino, offset, de->rec_len, de->name_len);			de = (struct ext_dir_entry *) (bh->b_data+BLOCK_SIZE);			offset = ((offset / BLOCK_SIZE) + 1) * BLOCK_SIZE;			continue;/*			brelse (bh);			return NULL; */		}		if (ext_match(namelen,name,de)) {			*res_dir = de;			if (next_dir)				if (offset + de->rec_len < dir->i_size &&				    ((char *)de) + de->rec_len < BLOCK_SIZE+bh->b_data)					*next_dir = (struct ext_dir_entry *)						((char *) de + de->rec_len);				else					*next_dir = NULL;			return bh;		}		offset += de->rec_len;		if (prev_dir)			*prev_dir = de;		de = (struct ext_dir_entry *) ((char *) de + de->rec_len);	}	brelse(bh);	return NULL;}int ext_lookup(struct inode * dir,const char * name, int len,	struct inode ** result){	int ino;	struct ext_dir_entry * de;	struct buffer_head * bh;	*result = NULL;	if (!dir)		return -ENOENT;	if (!S_ISDIR(dir->i_mode)) {		iput(dir);		return -ENOENT;	}	if (!(bh = ext_find_entry(dir,name,len,&de,NULL,NULL))) {		iput(dir);		return -ENOENT;	}	ino = de->inode;	brelse(bh);	if (!(*result = iget(dir->i_sb,ino))) {		iput(dir);		return -EACCES;	}	iput(dir);	return 0;}/* *	ext_add_entry() * * adds a file entry to the specified directory, using the same * semantics as ext_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 * ext_add_entry(struct inode * dir,	const char * name, int namelen, struct ext_dir_entry ** res_dir){	int i;	long offset;	unsigned short rec_len;	struct buffer_head * bh;	struct ext_dir_entry * de, * de1;	*res_dir = NULL;	if (!dir)		return NULL;#ifdef NO_TRUNCATE	if (namelen > EXT_NAME_LEN)		return NULL;#else	if (namelen > EXT_NAME_LEN)		namelen = EXT_NAME_LEN;#endif	if (!namelen)		return NULL;	bh = ext_bread(dir,0,0);	if (!bh)		return NULL;	rec_len = ((8 + namelen + EXT_DIR_PAD - 1) / EXT_DIR_PAD) * EXT_DIR_PAD;	offset = 0;	de = (struct ext_dir_entry *) bh->b_data;	while (1) {		if ((char *)de >= BLOCK_SIZE+bh->b_data && offset < dir->i_size) {#ifdef EXTFS_DEBUGprintk ("ext_add_entry: skipping to next block\n");#endif			brelse(bh);			bh = NULL;			bh = ext_bread(dir,offset>>BLOCK_SIZE_BITS,0);			if (!bh)				return NULL;			de = (struct ext_dir_entry *) bh->b_data;		}		if (offset >= dir->i_size) {			/* Check that the directory entry fits in the block */			if (offset % BLOCK_SIZE == 0  ||			    (BLOCK_SIZE - (offset % BLOCK_SIZE)) < rec_len) {				if ((offset % BLOCK_SIZE) != 0) {					/* If the entry does not fit in the					   block, the remainder of the block					   becomes an unused entry */					de->inode = 0;					de->rec_len = BLOCK_SIZE						- (offset & (BLOCK_SIZE - 1));					de->name_len = 0;					offset += de->rec_len;					dir->i_size += de->rec_len;					dir->i_dirt = 1;#if 0					dir->i_ctime = CURRENT_TIME;#endif					bh->b_dirt = 1;				}				brelse (bh);				bh = NULL;#ifdef EXTFS_DEBUGprintk ("ext_add_entry : creating next block\n");#endif				bh = ext_bread(dir,offset>>BLOCK_SIZE_BITS,1);				if (!bh)					return NULL; /* Other thing to do ??? */				de = (struct ext_dir_entry *) bh->b_data;			}			/* Allocate the entry */			de->inode=0;			de->rec_len = rec_len;			dir->i_size += de->rec_len;			dir->i_dirt = 1;#if 0			dir->i_ctime = CURRENT_TIME;#endif		}		if (de->rec_len < 8 || de->rec_len % 4 != 0 ||		    de->rec_len < de->name_len + 8 ||		    (((char *) de) + de->rec_len-1 >= BLOCK_SIZE+bh->b_data)) {			printk ("ext_addr_entry: bad dir entry\n");			printk ("dev=%d, dir=%d, offset=%d, rec_len=%d, name_len=%d\n",				dir->i_dev, dir->i_ino, offset, de->rec_len, de->name_len);			brelse (bh);			return NULL;		}		if (!de->inode && de->rec_len >= rec_len) {			if (de->rec_len > rec_len			    && de->rec_len - rec_len >= EXT_DIR_MIN_SIZE) {				/* The found entry is too big : it is split				   into 2 ones :				   - the 1st one will be used to hold the name,				   - the 2nd one is unused */				de1 = (struct ext_dir_entry *) ((char *) de + rec_len);				de1->inode = 0;				de1->rec_len = de->rec_len - rec_len;				de1->name_len = 0;				de->rec_len = rec_len;			}			dir->i_mtime = dir->i_ctime = CURRENT_TIME;			de->name_len = namelen;			for (i=0; i < namelen ; i++)				de->name[i] = name[i];			bh->b_dirt = 1;			*res_dir = de;			return bh;		}		offset += de->rec_len;		de = (struct ext_dir_entry *) ((char *) de + de->rec_len);	}	brelse(bh);	return NULL;}int ext_create(struct inode * dir,const char * name, int len, int mode,	struct inode ** result){	struct inode * inode;	struct buffer_head * bh;	struct ext_dir_entry * de;	*result = NULL;	if (!dir)		return -ENOENT;	inode = ext_new_inode(dir);	if (!inode) {		iput(dir);		return -ENOSPC;	}	inode->i_op = &ext_file_inode_operations;	inode->i_mode = mode;	inode->i_dirt = 1;	bh = ext_add_entry(dir,name,len,&de);	if (!bh) {		inode->i_nlink--;		inode->i_dirt = 1;		iput(inode);		iput(dir);		return -ENOSPC;	}	de->inode = inode->i_ino;	bh->b_dirt = 1;	brelse(bh);	iput(dir);	*result = inode;	return 0;}int ext_mknod(struct inode * dir, const char * name, int len, int mode, int rdev){	struct inode * inode;	struct buffer_head * bh;	struct ext_dir_entry * de;	if (!dir)		return -ENOENT;	bh = ext_find_entry(dir,name,len,&de,NULL,NULL);	if (bh) {		brelse(bh);		iput(dir);		return -EEXIST;	}	inode = ext_new_inode(dir);	if (!inode) {		iput(dir);		return -ENOSPC;	}	inode->i_uid = current->euid;	inode->i_mode = mode;	inode->i_op = NULL;	if (S_ISREG(inode->i_mode))		inode->i_op = &ext_file_inode_operations;	else if (S_ISDIR(inode->i_mode)) {		inode->i_op = &ext_dir_inode_operations;		if (dir->i_mode & S_ISGID)			inode->i_mode |= S_ISGID;	}	else if (S_ISLNK(inode->i_mode))		inode->i_op = &ext_symlink_inode_operations;	else if (S_ISCHR(inode->i_mode))		inode->i_op = &chrdev_inode_operations;	else if (S_ISBLK(inode->i_mode))		inode->i_op = &blkdev_inode_operations;	else if (S_ISFIFO(inode->i_mode))		init_fifo(inode);	if (S_ISBLK(mode) || S_ISCHR(mode))		inode->i_rdev = rdev;#if 0	inode->i_mtime = inode->i_atime = CURRENT_TIME;#endif	inode->i_dirt = 1;	bh = ext_add_entry(dir,name,len,&de);	if (!bh) {		inode->i_nlink--;		inode->i_dirt = 1;		iput(inode);		iput(dir);		return -ENOSPC;	}	de->inode = inode->i_ino;	bh->b_dirt = 1;	brelse(bh);	iput(dir);	iput(inode);	return 0;}int ext_mkdir(struct inode * dir, const char * name, int len, int mode){	struct inode * inode;	struct buffer_head * bh, *dir_block;	struct ext_dir_entry * de;		bh = ext_find_entry(dir,name,len,&de,NULL,NULL);	if (bh) {		brelse(bh);		iput(dir);		return -EEXIST;	}	inode = ext_new_inode(dir);	if (!inode) {		iput(dir);		return -ENOSPC;	}	inode->i_op = &ext_dir_inode_operations;	inode->i_size = 2 * 16; /* Each entry is coded on 16 bytes for "." and ".."					- 4 bytes for the inode number,					- 2 bytes for the record length					- 2 bytes for the name length					- 8 bytes for the name */#if 0	inode->i_mtime = inode->i_atime = CURRENT_TIME;#endif	dir_block = ext_bread(inode,0,1);	if (!dir_block) {		iput(dir);		inode->i_nlink--;		inode->i_dirt = 1;		iput(inode);		return -ENOSPC;	}	de = (struct ext_dir_entry *) dir_block->b_data;	de->inode=inode->i_ino;	de->rec_len=16;	de->name_len=1;	strcpy(de->name,".");	de = (struct ext_dir_entry *) ((char *) de + de->rec_len);	de->inode = dir->i_ino;	de->rec_len=16;	de->name_len=2;	strcpy(de->name,"..");	inode->i_nlink = 2;	dir_block->b_dirt = 1;	brelse(dir_block);	inode->i_mode = S_IFDIR | (mode & 0777 & ~current->umask);	if (dir->i_mode & S_ISGID)

⌨️ 快捷键说明

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