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

📄 namei.c

📁 LINUX1.0内核源代码,学习LINUX编程的一定要看。
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *  linux/fs/ext2/namei.c * *  Copyright (C) 1992, 1993, 1994  Remy Card (card@masi.ibp.fr) *                                  Laboratoire MASI - Institut Blaise Pascal *                                  Universite Pierre et Marie Curie (Paris VI) * *  from * *  linux/fs/minix/namei.c * *  Copyright (C) 1991, 1992  Linus Torvalds */#include <asm/segment.h>#include <linux/errno.h>#include <linux/fs.h>#include <linux/ext2_fs.h>#include <linux/fcntl.h>#include <linux/sched.h>#include <linux/stat.h>#include <linux/string.h>#include <linux/locks.h>/* * comment out this line if you want names > EXT2_NAME_LEN chars to be * truncated. Else they will be disallowed. *//* #define NO_TRUNCATE *//* * define how far ahead to read directories while searching them. */#define NAMEI_RA_CHUNKS  2#define NAMEI_RA_BLOCKS  4#define NAMEI_RA_SIZE        (NAMEI_RA_CHUNKS * NAMEI_RA_BLOCKS)#define NAMEI_RA_INDEX(c,b)  (((c) * NAMEI_RA_BLOCKS) + (b))/* * NOTE! unlike strncmp, ext2_match returns 1 for success, 0 for failure. */static int ext2_match (int len, const char * const name,		       struct ext2_dir_entry * de){	unsigned char same;	if (!de || !de->inode || len > EXT2_NAME_LEN)		return 0;	/*	 * "" means "." ---> so paths like "/usr/lib//libc.a" work	 */	if (!len && de->name_len == 1 && (de->name[0] == '.') &&	   (de->name[1] == '\0'))		return 1;	if (len != de->name_len)		return 0;	__asm__("cld\n\t"		"repe ; cmpsb\n\t"		"setz %0"		:"=q" (same)		:"S" ((long) name), "D" ((long) de->name), "c" (len)		:"cx", "di", "si");	return (int) same;}/* *	ext2_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. */static struct buffer_head * ext2_find_entry (struct inode * dir,					     const char * const name, int namelen,					     struct ext2_dir_entry ** res_dir){	struct super_block * sb;	struct buffer_head * bh_use[NAMEI_RA_SIZE];	struct buffer_head * bh_read[NAMEI_RA_SIZE];	unsigned long offset;	int block, toread, i, err;	*res_dir = NULL;	if (!dir)		return NULL;	sb = dir->i_sb;#ifdef NO_TRUNCATE	if (namelen > EXT2_NAME_LEN)		return NULL;#else	if (namelen > EXT2_NAME_LEN)		namelen = EXT2_NAME_LEN;#endif	memset (bh_use, 0, sizeof (bh_use));	toread = 0;	for (block = 0; block < NAMEI_RA_SIZE; ++block) {		struct buffer_head * bh;		if ((block << EXT2_BLOCK_SIZE_BITS (sb)) >= dir->i_size)			break;		bh = ext2_getblk (dir, block, 0, &err);		bh_use[block] = bh;		if (bh && !bh->b_uptodate)			bh_read[toread++] = bh;	}	block = 0;	offset = 0;	while (offset < dir->i_size) {		struct buffer_head * bh;		struct ext2_dir_entry * de;		char * dlimit;		if ((block % NAMEI_RA_BLOCKS) == 0 && toread) {			ll_rw_block (READ, toread, bh_read);			toread = 0;		}		bh = bh_use[block % NAMEI_RA_SIZE];		if (!bh)			ext2_panic (sb, "ext2_find_entry",				    "buffer head pointer is NULL");		wait_on_buffer (bh);		if (!bh->b_uptodate) {			/*			 * read error: all bets are off			 */			break;		}		de = (struct ext2_dir_entry *) bh->b_data;		dlimit = bh->b_data + sb->s_blocksize;		while ((char *) de < dlimit) {			if (!ext2_check_dir_entry ("ext2_find_entry", dir,						   de, bh, offset))				goto failure;			if (de->inode != 0 && ext2_match (namelen, name, de)) {				for (i = 0; i < NAMEI_RA_SIZE; ++i) {					if (bh_use[i] != bh)						brelse (bh_use[i]);				}				*res_dir = de;				return bh;			}			offset += de->rec_len;			de = (struct ext2_dir_entry *)				((char *) de + de->rec_len);		}		brelse (bh);		if (((block + NAMEI_RA_SIZE) << EXT2_BLOCK_SIZE_BITS (sb)) >=		    dir->i_size)			bh = NULL;		else			bh = ext2_getblk (dir, block + NAMEI_RA_SIZE, 0, &err);		bh_use[block++ % NAMEI_RA_SIZE] = bh;		if (bh && !bh->b_uptodate)			bh_read[toread++] = bh;	}failure:	for (i = 0; i < NAMEI_RA_SIZE; ++i)		brelse (bh_use[i]);	return NULL;}int ext2_lookup (struct inode * dir, const char * name, int len,		 struct inode ** result){	unsigned long ino;	struct ext2_dir_entry * de;	struct buffer_head * bh;	*result = NULL;	if (!dir)		return -ENOENT;	if (!S_ISDIR(dir->i_mode)) {		iput (dir);		return -ENOENT;	}#ifndef DONT_USE_DCACHE	if (!(ino = ext2_dcache_lookup (dir->i_dev, dir->i_ino, name, len))) {#endif		if (!(bh = ext2_find_entry (dir, name, len, &de))) {			iput (dir);			return -ENOENT;		}		ino = de->inode;#ifndef DONT_USE_DCACHE		ext2_dcache_add (dir->i_dev, dir->i_ino, de->name,				 de->name_len, ino);#endif		brelse (bh);#ifndef DONT_USE_DCACHE	}#endif	if (!(*result = iget (dir->i_sb, ino))) {		iput (dir);		return -EACCES;	}	iput (dir);	return 0;}/* *	ext2_add_entry() * * adds a file entry to the specified directory, using the same * semantics as ext2_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 * ext2_add_entry (struct inode * dir,					    const char * name, int namelen,					    struct ext2_dir_entry ** res_dir,					    int *err){	unsigned long offset;	unsigned short rec_len;	struct buffer_head * bh;	struct ext2_dir_entry * de, * de1;	struct super_block * sb;	*err = -EINVAL;	*res_dir = NULL;	if (!dir)		return NULL;	sb = dir->i_sb;#ifdef NO_TRUNCATE	if (namelen > EXT2_NAME_LEN)		return NULL;#else	if (namelen > EXT2_NAME_LEN)		namelen = EXT2_NAME_LEN;#endif	if (!namelen)		return NULL;	/*	 * Is this a busy deleted directory?  Can't create new files if so	 */	if (dir->i_size == 0)	{		*err = -ENOENT;		return NULL;	}	bh = ext2_bread (dir, 0, 0, err);	if (!bh)		return NULL;	rec_len = EXT2_DIR_REC_LEN(namelen);	offset = 0;	de = (struct ext2_dir_entry *) bh->b_data;	*err = -ENOSPC;	while (1) {		if ((char *)de >= sb->s_blocksize + bh->b_data) {			brelse (bh);			bh = NULL;			bh = ext2_bread (dir, offset >> EXT2_BLOCK_SIZE_BITS(sb), 1, err);			if (!bh)				return NULL;			if (dir->i_size <= offset) {				if (dir->i_size == 0) {					*err = -ENOENT;					return NULL;				}				ext2_debug ("creating next block\n");				de = (struct ext2_dir_entry *) bh->b_data;				de->inode = 0;				de->rec_len = sb->s_blocksize;				dir->i_size = offset + sb->s_blocksize;				dir->i_dirt = 1;#if 0 /* XXX don't update any times until successful completion of syscall */				dir->i_ctime = CURRENT_TIME;#endif			} else {				ext2_debug ("skipping to next block\n");				de = (struct ext2_dir_entry *) bh->b_data;			}		}		if (!ext2_check_dir_entry ("ext2_add_entry", dir, de, bh,					   offset)) {			*err = -ENOENT;			brelse (bh);			return NULL;		}		if (de->inode != 0 && ext2_match (namelen, name, de)) {				*err = -EEXIST;				brelse (bh);				return NULL;		}		if ((de->inode == 0 && de->rec_len >= rec_len) ||		    (de->rec_len >= EXT2_DIR_REC_LEN(de->name_len) + rec_len)) {			offset += de->rec_len;			if (de->inode) {				de1 = (struct ext2_dir_entry *) ((char *) de +					EXT2_DIR_REC_LEN(de->name_len));				de1->rec_len = de->rec_len -					EXT2_DIR_REC_LEN(de->name_len);				de->rec_len = EXT2_DIR_REC_LEN(de->name_len);				de = de1;			}			de->inode = 0;			de->name_len = namelen;			memcpy (de->name, name, namelen);			/*			 * XXX shouldn't update any times until successful			 * completion of syscall, but too many callers depend			 * on this.			 *			 * XXX similarly, too many callers depend on			 * ext2_new_inode() setting the times, but error			 * recovery deletes the inode, so the worst that can			 * happen is that the times are slightly out of date			 * and/or different from the directory change time.			 */			dir->i_mtime = dir->i_ctime = CURRENT_TIME;			dir->i_dirt = 1;			bh->b_dirt = 1;			*res_dir = de;			*err = 0;			return bh;		}		offset += de->rec_len;		de = (struct ext2_dir_entry *) ((char *) de + de->rec_len);	}	brelse (bh);	return NULL;}/* * ext2_delete_entry deletes a directory entry by merging it with the * previous entry */static int ext2_delete_entry (struct ext2_dir_entry * dir,			      struct buffer_head * bh){	struct ext2_dir_entry * de, * pde;	int i;	i = 0;	pde = NULL;	de = (struct ext2_dir_entry *) bh->b_data;	while (i < bh->b_size) {		if (!ext2_check_dir_entry ("ext2_delete_entry", NULL, 					   de, bh, i))			return -EIO;		if (de == dir)  {			if (pde)				pde->rec_len += dir->rec_len;			dir->inode = 0;			return 0;		}		i += de->rec_len;		pde = de;		de = (struct ext2_dir_entry *) ((char *) de + de->rec_len);	}	return -ENOENT;}int ext2_create (struct inode * dir,const char * name, int len, int mode,		 struct inode ** result){	struct inode * inode;	struct buffer_head * bh;	struct ext2_dir_entry * de;	int err;	*result = NULL;	if (!dir)		return -ENOENT;	inode = ext2_new_inode (dir, mode);	if (!inode) {		iput (dir);		return -ENOSPC;	}	inode->i_op = &ext2_file_inode_operations;	inode->i_mode = mode;	inode->i_dirt = 1;	bh = ext2_add_entry (dir, name, len, &de, &err);	if (!bh) {		inode->i_nlink--;		inode->i_dirt = 1;		iput (inode);		iput (dir);		return err;	}	de->inode = inode->i_ino;#ifndef DONT_USE_DCACHE	ext2_dcache_add (dir->i_dev, dir->i_ino, de->name, de->name_len,			 de->inode);#endif	bh->b_dirt = 1;	if (IS_SYNC(dir)) {		ll_rw_block (WRITE, 1, &bh);		wait_on_buffer (bh);	}	brelse (bh);	iput (dir);	*result = inode;	return 0;}int ext2_mknod (struct inode * dir, const char * name, int len, int mode,		int rdev){	struct inode * inode;	struct buffer_head * bh;	struct ext2_dir_entry * de;	int err;	if (!dir)		return -ENOENT;	bh = ext2_find_entry (dir, name, len, &de);	if (bh) {		brelse (bh);		iput (dir);		return -EEXIST;	}	inode = ext2_new_inode (dir, mode);	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 = &ext2_file_inode_operations;	else if (S_ISDIR(inode->i_mode)) {		inode->i_op = &ext2_dir_inode_operations;		if (dir->i_mode & S_ISGID)			inode->i_mode |= S_ISGID;	}	else if (S_ISLNK(inode->i_mode))		inode->i_op = &ext2_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	/*	 * XXX we may as well use the times set by ext2_new_inode().  The	 * following usually does nothing, but sometimes it invalidates	 * inode->i_ctime.	 */	inode->i_mtime = inode->i_atime = CURRENT_TIME;#endif	inode->i_dirt = 1;	bh = ext2_add_entry (dir, name, len, &de, &err);	if (!bh) {		inode->i_nlink--;		inode->i_dirt = 1;		iput (inode);		iput (dir);		return err;	}	de->inode = inode->i_ino;#ifndef DONT_USE_DCACHE	ext2_dcache_add (dir->i_dev, dir->i_ino, de->name, de->name_len,			 de->inode);#endif	bh->b_dirt = 1;	if (IS_SYNC(dir)) {		ll_rw_block (WRITE, 1, &bh);		wait_on_buffer (bh);	}	brelse (bh);	iput (dir);	iput (inode);	return 0;}int ext2_mkdir (struct inode * dir, const char * name, int len, int mode){	struct inode * inode;	struct buffer_head * bh, * dir_block;	struct ext2_dir_entry * de;	int err;	if (!dir)		return -ENOENT;	bh = ext2_find_entry (dir, name, len, &de);	if (bh) {		brelse (bh);		iput (dir);		return -EEXIST;	}	if (dir->i_nlink >= EXT2_LINK_MAX) {		iput (dir);		return -EMLINK;	}	inode = ext2_new_inode (dir, S_IFDIR);	if (!inode) {		iput (dir);		return -ENOSPC;	}	inode->i_op = &ext2_dir_inode_operations;	inode->i_size = inode->i_sb->s_blocksize;#if 0 /* XXX as above */	inode->i_mtime = inode->i_atime = CURRENT_TIME;#endif	dir_block = ext2_bread (inode, 0, 1, &err);	if (!dir_block) {		iput (dir);		inode->i_nlink--;		inode->i_dirt = 1;		iput (inode);		return err;	}	inode->i_blocks = inode->i_sb->s_blocksize / 512;	de = (struct ext2_dir_entry *) dir_block->b_data;	de->inode = inode->i_ino;	de->name_len = 1;	de->rec_len = EXT2_DIR_REC_LEN(de->name_len);	strcpy (de->name, ".");	de = (struct ext2_dir_entry *) ((char *) de + de->rec_len);	de->inode = dir->i_ino;	de->rec_len = inode->i_sb->s_blocksize - EXT2_DIR_REC_LEN(1);	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 & S_IRWXUGO & ~current->umask);	if (dir->i_mode & S_ISGID)		inode->i_mode |= S_ISGID;	inode->i_dirt = 1;	bh = ext2_add_entry (dir, name, len, &de, &err);	if (!bh) {		iput (dir);		inode->i_nlink = 0;		inode->i_dirt = 1;		iput (inode);		return err;	}	de->inode = inode->i_ino;#ifndef DONT_USE_DCACHE	ext2_dcache_add (dir->i_dev, dir->i_ino, de->name, de->name_len,			 de->inode);#endif	bh->b_dirt = 1;	if (IS_SYNC(dir)) {		ll_rw_block (WRITE, 1, &bh);		wait_on_buffer (bh);	}	dir->i_nlink++;	dir->i_dirt = 1;	iput (dir);	iput (inode);

⌨️ 快捷键说明

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