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

📄 namei.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * linux/fs/ufs/namei.c * * Copyright (C) 1998 * Daniel Pirkl <daniel.pirkl@email.cz> * Charles University, Faculty of Mathematics and Physics * *  from * *  linux/fs/ext2/namei.c * * Copyright (C) 1992, 1993, 1994, 1995 * 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 * *  Big-endian to little-endian byte-swapping/bitmaps by *        David S. Miller (davem@caip.rutgers.edu), 1995 */#include <asm/uaccess.h>#include <linux/errno.h>#include <linux/fs.h>#include <linux/ufs_fs.h>#include <linux/fcntl.h>#include <linux/sched.h>#include <linux/stat.h>#include <linux/string.h>#include <linux/locks.h>#include <linux/quotaops.h>#include "swab.h"#include "util.h"#undef UFS_NAMEI_DEBUG#ifdef UFS_NAMEI_DEBUG#define UFSD(x) printk("(%s, %d), %s: ", __FILE__, __LINE__, __FUNCTION__); printk x;#else#define UFSD(x)#endif/* * 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, ufs_match returns 1 for success, 0 for failure. * * len <= UFS_MAXNAMLEN and de != NULL are guaranteed by caller. */static inline int ufs_match (int len, const char * const name,	struct ufs_dir_entry * de, unsigned flags, unsigned swab){	if (len != ufs_get_de_namlen(de))		return 0;	if (!de->d_ino)		return 0;	return !memcmp(name, de->d_name, len);}/* *	ufs_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 * ufs_find_entry (struct inode * dir,	const char * const name, int namelen, struct ufs_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;	unsigned flags, swab;	UFSD(("ENTER, dir_ino %lu, name %s, namlen %u\n", dir->i_ino, name, namelen))		*res_dir = NULL;		sb = dir->i_sb;	flags = sb->u.ufs_sb.s_flags;	swab = sb->u.ufs_sb.s_swab;		if (namelen > UFS_MAXNAMLEN)		return NULL;	memset (bh_use, 0, sizeof (bh_use));	toread = 0;	for (block = 0; block < NAMEI_RA_SIZE; ++block) {		struct buffer_head * bh;		if ((block << sb->s_blocksize_bits) >= dir->i_size)			break;		bh = ufs_getfrag (dir, block, 0, &err);		bh_use[block] = bh;		if (bh && !buffer_uptodate(bh))			bh_read[toread++] = bh;	}	for (block = 0, offset = 0; offset < dir->i_size; block++) {		struct buffer_head * bh;		struct ufs_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) {			ufs_error (sb, "ufs_find_entry", 				"directory #%lu contains a hole at offset %lu",				dir->i_ino, offset);			offset += sb->s_blocksize;			continue;		}		wait_on_buffer (bh);		if (!buffer_uptodate(bh)) {			/*			 * read error: all bets are off			 */			break;		}		de = (struct ufs_dir_entry *) bh->b_data;		dlimit = bh->b_data + sb->s_blocksize;		while ((char *) de < dlimit && offset < dir->i_size) {			/* this code is executed quadratically often */			/* do minimal checking by hand */			int de_len;			if ((char *) de + namelen <= dlimit &&			    ufs_match (namelen, name, de, flags, swab)) {				/* found a match -				just to be sure, do a full check */				if (!ufs_check_dir_entry("ufs_find_entry",				    dir, de, bh, offset))					goto failed;				for (i = 0; i < NAMEI_RA_SIZE; ++i) {					if (bh_use[i] != bh)						brelse (bh_use[i]);				}				*res_dir = de;				return bh;			}                        /* prevent looping on a bad block */			de_len = SWAB16(de->d_reclen);			if (de_len <= 0)				goto failed;			offset += de_len;			de = (struct ufs_dir_entry *) ((char *) de + de_len);		}		brelse (bh);		if (((block + NAMEI_RA_SIZE) << sb->s_blocksize_bits ) >=		    dir->i_size)			bh = NULL;		else			bh = ufs_getfrag (dir, block + NAMEI_RA_SIZE, 0, &err);		bh_use[block % NAMEI_RA_SIZE] = bh;		if (bh && !buffer_uptodate(bh))			bh_read[toread++] = bh;	}failed:	for (i = 0; i < NAMEI_RA_SIZE; ++i) brelse (bh_use[i]);	UFSD(("EXIT\n"))	return NULL;}static struct dentry *ufs_lookup(struct inode * dir, struct dentry *dentry){	struct super_block * sb;	struct inode * inode;	struct ufs_dir_entry * de;	struct buffer_head * bh;	unsigned swab;		UFSD(("ENTER\n"))		sb = dir->i_sb;	swab = sb->u.ufs_sb.s_swab;		if (dentry->d_name.len > UFS_MAXNAMLEN)		return ERR_PTR(-ENAMETOOLONG);	bh = ufs_find_entry (dir, dentry->d_name.name, dentry->d_name.len, &de);	inode = NULL;	if (bh) {		unsigned long ino = SWAB32(de->d_ino);		brelse (bh);		inode = iget(sb, ino);		if (!inode) 			return ERR_PTR(-EACCES);	}	d_add(dentry, inode);	UFSD(("EXIT\n"))	return NULL;}/* *	ufs_add_entry() * * adds a file entry to the specified directory, using the same * semantics as ufs_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 * ufs_add_entry (struct inode * dir,	const char * name, int namelen, struct ufs_dir_entry ** res_dir, 	int *err ){	struct super_block * sb;	struct ufs_sb_private_info * uspi;	unsigned long offset;	unsigned fragoff;	unsigned short rec_len;	struct buffer_head * bh;	struct ufs_dir_entry * de, * de1;	unsigned flags, swab;	UFSD(("ENTER, name %s, namelen %u\n", name, namelen))		*err = -EINVAL;	*res_dir = NULL;			sb = dir->i_sb;	flags = sb->u.ufs_sb.s_flags;	swab = sb->u.ufs_sb.s_swab;	uspi = sb->u.ufs_sb.s_uspi;	if (!namelen)		return NULL;	bh = ufs_bread (dir, 0, 0, err);	if (!bh)		return NULL;	rec_len = UFS_DIR_REC_LEN(namelen);	offset = 0;	de = (struct ufs_dir_entry *) bh->b_data;	*err = -ENOSPC;	while (1) {		if ((char *)de >= UFS_SECTOR_SIZE + bh->b_data) {			fragoff = offset & ~uspi->s_fmask;			if (fragoff != 0 && fragoff != UFS_SECTOR_SIZE)				ufs_error (sb, "ufs_add_entry", "internal error"					" fragoff %u", fragoff);			if (!fragoff) {				brelse (bh);				bh = NULL;				bh = ufs_bread (dir, offset >> sb->s_blocksize_bits, 1, err);			}			if (!bh)				return NULL;			if (dir->i_size <= offset) {				if (dir->i_size == 0) {					*err = -ENOENT;					return NULL;				}				de = (struct ufs_dir_entry *) (bh->b_data + fragoff);				de->d_ino = SWAB32(0);				de->d_reclen = SWAB16(UFS_SECTOR_SIZE);				ufs_set_de_namlen(de,0);				dir->i_size = offset + UFS_SECTOR_SIZE;				mark_inode_dirty(dir);			} else {				de = (struct ufs_dir_entry *) bh->b_data;			}		}		if (!ufs_check_dir_entry ("ufs_add_entry", dir, de, bh, offset)) {			*err = -ENOENT;			brelse (bh);			return NULL;		}		if (ufs_match (namelen, name, de, flags, swab)) {				*err = -EEXIST;				brelse (bh);				return NULL;		}		if ((SWAB32(de->d_ino) == 0 && SWAB16(de->d_reclen) >= rec_len) ||		    (SWAB16(de->d_reclen) >= UFS_DIR_REC_LEN(ufs_get_de_namlen(de)) + rec_len)) {			offset += SWAB16(de->d_reclen);			if (SWAB32(de->d_ino)) {				de1 = (struct ufs_dir_entry *) ((char *) de +					UFS_DIR_REC_LEN(ufs_get_de_namlen(de)));				de1->d_reclen = SWAB16(SWAB16(de->d_reclen) -					UFS_DIR_REC_LEN(ufs_get_de_namlen(de)));				de->d_reclen = SWAB16(UFS_DIR_REC_LEN(ufs_get_de_namlen(de)));				de = de1;			}			de->d_ino = SWAB32(0);			ufs_set_de_namlen(de, namelen);			memcpy (de->d_name, name, namelen + 1);			/*			 * 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			 * ufs_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;			mark_inode_dirty(dir);			dir->i_version = ++event;			mark_buffer_dirty(bh);			*res_dir = de;			*err = 0;						UFSD(("EXIT\n"))			return bh;		}		offset += SWAB16(de->d_reclen);		de = (struct ufs_dir_entry *) ((char *) de + SWAB16(de->d_reclen));	}	brelse (bh);	UFSD(("EXIT (FAILED)\n"))	return NULL;}/* * ufs_delete_entry deletes a directory entry by merging it with the * previous entry. */static int ufs_delete_entry (struct inode * inode, struct ufs_dir_entry * dir,	struct buffer_head * bh )	{	struct super_block * sb;	struct ufs_dir_entry * de, * pde;	unsigned i;	unsigned flags, swab;		UFSD(("ENTER\n"))	sb = inode->i_sb;	flags = sb->u.ufs_sb.s_flags;	swab = sb->u.ufs_sb.s_swab;	i = 0;	pde = NULL;	de = (struct ufs_dir_entry *) bh->b_data;		UFSD(("ino %u, reclen %u, namlen %u, name %s\n", SWAB32(de->d_ino),		SWAB16(de->d_reclen), ufs_get_de_namlen(de), de->d_name))	while (i < bh->b_size) {		if (!ufs_check_dir_entry ("ufs_delete_entry", inode, de, bh, i))			return -EIO;		if (de == dir)  {			if (pde)				pde->d_reclen =				    SWAB16(SWAB16(pde->d_reclen) +				    SWAB16(dir->d_reclen));			dir->d_ino = SWAB32(0);			UFSD(("EXIT\n"))			return 0;		}		i += SWAB16(de->d_reclen);		if (i == UFS_SECTOR_SIZE) pde = NULL;		else pde = de;		de = (struct ufs_dir_entry *)		    ((char *) de + SWAB16(de->d_reclen));		if (i == UFS_SECTOR_SIZE && SWAB16(de->d_reclen) == 0)			break;	}	UFSD(("EXIT\n"))	return -ENOENT;}/* * By the time this is called, we already have created * the directory cache entry for the new file, but it * is so far negative - it has no inode. * * If the create succeeds, we fill in the inode information * with d_instantiate().  */static int ufs_create (struct inode * dir, struct dentry * dentry, int mode){	struct super_block * sb;	struct inode * inode;	struct buffer_head * bh;	struct ufs_dir_entry * de;	int err = -EIO;	unsigned flags, swab;		sb = dir->i_sb;	swab = sb->u.ufs_sb.s_swab;	flags = sb->u.ufs_sb.s_flags;	/*	 * N.B. Several error exits in ufs_new_inode don't set err.	 */	UFSD(("ENTER\n"))		inode = ufs_new_inode (dir, mode, &err);	if (!inode)		return err;	inode->i_op = &ufs_file_inode_operations;	inode->i_fop = &ufs_file_operations;	inode->i_mapping->a_ops = &ufs_aops;	inode->i_mode = mode;	mark_inode_dirty(inode);	bh = ufs_add_entry (dir, dentry->d_name.name, dentry->d_name.len, &de, &err);	if (!bh) {		inode->i_nlink--;		mark_inode_dirty(inode);		iput (inode);		return err;	}	de->d_ino = SWAB32(inode->i_ino);	ufs_set_de_type (de, inode->i_mode);	dir->i_version = ++event;	mark_buffer_dirty(bh);	if (IS_SYNC(dir)) {		ll_rw_block (WRITE, 1, &bh);		wait_on_buffer (bh);	}	brelse (bh);	d_instantiate(dentry, inode);		UFSD(("EXIT\n"))		return 0;}static int ufs_mknod (struct inode * dir, struct dentry *dentry, int mode, int rdev){	struct super_block * sb;	struct inode * inode;	struct buffer_head * bh;	struct ufs_dir_entry * de;	int err = -EIO;	unsigned flags, swab;		sb = dir->i_sb;	flags = sb->u.ufs_sb.s_flags;	swab = sb->u.ufs_sb.s_swab;	inode = ufs_new_inode (dir, mode, &err);	if (!inode)		goto out;	inode->i_uid = current->fsuid;	init_special_inode(inode, mode, rdev);	mark_inode_dirty(inode);	bh = ufs_add_entry (dir, dentry->d_name.name, dentry->d_name.len, &de, &err);	if (!bh)		goto out_no_entry;	de->d_ino = SWAB32(inode->i_ino);	ufs_set_de_type (de, inode->i_mode);	dir->i_version = ++event;	mark_buffer_dirty(bh);	if (IS_SYNC(dir)) {		ll_rw_block (WRITE, 1, &bh);		wait_on_buffer (bh);	}	d_instantiate(dentry, inode);	brelse(bh);	err = 0;out:	return err;out_no_entry:	inode->i_nlink--;	mark_inode_dirty(inode);	iput(inode);	goto out;}static int ufs_mkdir(struct inode * dir, struct dentry * dentry, int mode){

⌨️ 快捷键说明

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