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

📄 namei.c

📁 嵌入式系统设计与实例开发实验教材二源码 多线程应用程序设计 串行端口程序设计 AD接口实验 CAN总线通信实验 GPS通信实验 Linux内核移植与编译实验 IC卡读写实验 SD驱动使
💻 C
📖 第 1 页 / 共 4 页
字号:
	DQUOT_INIT(dir);	lock_kernel();	error = dir->i_op->symlink(dir, dentry, oldname);	unlock_kernel();exit_lock:	up(&dir->i_zombie);	if (!error)		inode_dir_notify(dir, DN_CREATE);	return error;}asmlinkage long sys_symlink(const char * oldname, const char * newname){	int error = 0;	char * from;	char * to;	from = getname(oldname);	if(IS_ERR(from))		return PTR_ERR(from);	to = getname(newname);	error = PTR_ERR(to);	if (!IS_ERR(to)) {		struct dentry *dentry;		struct nameidata nd;		if (path_init(to, LOOKUP_PARENT, &nd))			error = path_walk(to, &nd);		if (error)			goto out;		dentry = lookup_create(&nd, 0);		error = PTR_ERR(dentry);		if (!IS_ERR(dentry)) {			error = vfs_symlink(nd.dentry->d_inode, dentry, from);			dput(dentry);		}		up(&nd.dentry->d_inode->i_sem);		path_release(&nd);out:		putname(to);	}	putname(from);	return error;}int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry){	struct inode *inode;	int error;	down(&dir->i_zombie);	error = -ENOENT;	inode = old_dentry->d_inode;	if (!inode)		goto exit_lock;	error = may_create(dir, new_dentry);	if (error)		goto exit_lock;	error = -EXDEV;	if (dir->i_dev != inode->i_dev)		goto exit_lock;	/*	 * A link to an append-only or immutable file cannot be created.	 */	error = -EPERM;	if (IS_APPEND(inode) || IS_IMMUTABLE(inode))		goto exit_lock;	if (!dir->i_op || !dir->i_op->link)		goto exit_lock;	DQUOT_INIT(dir);	lock_kernel();	error = dir->i_op->link(old_dentry, dir, new_dentry);	unlock_kernel();exit_lock:	up(&dir->i_zombie);	if (!error)		inode_dir_notify(dir, DN_CREATE);	return error;}/* * Hardlinks are often used in delicate situations.  We avoid * security-related surprises by not following symlinks on the * newname.  --KAB * * We don't follow them on the oldname either to be compatible * with linux 2.0, and to avoid hard-linking to directories * and other special files.  --ADM */asmlinkage long sys_link(const char * oldname, const char * newname){	int error;	char * from;	char * to;	from = getname(oldname);	if(IS_ERR(from))		return PTR_ERR(from);	to = getname(newname);	error = PTR_ERR(to);	if (!IS_ERR(to)) {		struct dentry *new_dentry;		struct nameidata nd, old_nd;		error = 0;		if (path_init(from, LOOKUP_POSITIVE, &old_nd))			error = path_walk(from, &old_nd);		if (error)			goto exit;		if (path_init(to, LOOKUP_PARENT, &nd))			error = path_walk(to, &nd);		if (error)			goto out;		error = -EXDEV;		if (old_nd.mnt != nd.mnt)			goto out_release;		new_dentry = lookup_create(&nd, 0);		error = PTR_ERR(new_dentry);		if (!IS_ERR(new_dentry)) {			error = vfs_link(old_nd.dentry, nd.dentry->d_inode, new_dentry);			dput(new_dentry);		}		up(&nd.dentry->d_inode->i_sem);out_release:		path_release(&nd);out:		path_release(&old_nd);exit:		putname(to);	}	putname(from);	return error;}/* * The worst of all namespace operations - renaming directory. "Perverted" * doesn't even start to describe it. Somebody in UCB had a heck of a trip... * Problems: *	a) we can get into loop creation. Check is done in is_subdir(). *	b) race potential - two innocent renames can create a loop together. *	   That's where 4.4 screws up. Current fix: serialization on *	   sb->s_vfs_rename_sem. We might be more accurate, but that's another *	   story. *	c) we have to lock _three_ objects - parents and victim (if it exists). *	   And that - after we got ->i_sem on parents (until then we don't know *	   whether the target exists at all, let alone whether it is a directory *	   or not). Solution: ->i_zombie. Taken only after ->i_sem. Always taken *	   on link creation/removal of any kind. And taken (without ->i_sem) on *	   directory that will be removed (both in rmdir() and here). *	d) some filesystems don't support opened-but-unlinked directories, *	   either because of layout or because they are not ready to deal with *	   all cases correctly. The latter will be fixed (taking this sort of *	   stuff into VFS), but the former is not going away. Solution: the same *	   trick as in rmdir(). *	e) conversion from fhandle to dentry may come in the wrong moment - when *	   we are removing the target. Solution: we will have to grab ->i_zombie *	   in the fhandle_to_dentry code. [FIXME - current nfsfh.c relies on *	   ->i_sem on parents, which works but leads to some truely excessive *	   locking]. */int vfs_rename_dir(struct inode *old_dir, struct dentry *old_dentry,	       struct inode *new_dir, struct dentry *new_dentry){	int error;	struct inode *target;	if (old_dentry->d_inode == new_dentry->d_inode)		return 0;	error = may_delete(old_dir, old_dentry, 1);	if (error)		return error;	if (new_dir->i_dev != old_dir->i_dev)		return -EXDEV;	if (!new_dentry->d_inode)		error = may_create(new_dir, new_dentry);	else		error = may_delete(new_dir, new_dentry, 1);	if (error)		return error;	if (!old_dir->i_op || !old_dir->i_op->rename)		return -EPERM;	/*	 * If we are going to change the parent - check write permissions,	 * we'll need to flip '..'.	 */	if (new_dir != old_dir) {		error = permission(old_dentry->d_inode, MAY_WRITE);	}	if (error)		return error;	DQUOT_INIT(old_dir);	DQUOT_INIT(new_dir);	down(&old_dir->i_sb->s_vfs_rename_sem);	error = -EINVAL;	if (is_subdir(new_dentry, old_dentry))		goto out_unlock;	/* Don't eat your daddy, dear... */	/* This also avoids locking issues */	if (old_dentry->d_parent == new_dentry)		goto out_unlock;	target = new_dentry->d_inode;	if (target) { /* Hastur! Hastur! Hastur! */		triple_down(&old_dir->i_zombie,			    &new_dir->i_zombie,			    &target->i_zombie);		d_unhash(new_dentry);	} else		double_down(&old_dir->i_zombie,			    &new_dir->i_zombie);	if (IS_DEADDIR(old_dir)||IS_DEADDIR(new_dir))		error = -ENOENT;	else if (d_mountpoint(old_dentry)||d_mountpoint(new_dentry))		error = -EBUSY;	else 		error = old_dir->i_op->rename(old_dir, old_dentry, new_dir, new_dentry);	if (target) {		if (!error)			target->i_flags |= S_DEAD;		triple_up(&old_dir->i_zombie,			  &new_dir->i_zombie,			  &target->i_zombie);		if (d_unhashed(new_dentry))			d_rehash(new_dentry);		dput(new_dentry);	} else		double_up(&old_dir->i_zombie,			  &new_dir->i_zombie);			if (!error)		d_move(old_dentry,new_dentry);out_unlock:	up(&old_dir->i_sb->s_vfs_rename_sem);	return error;}int vfs_rename_other(struct inode *old_dir, struct dentry *old_dentry,	       struct inode *new_dir, struct dentry *new_dentry){	int error;	if (old_dentry->d_inode == new_dentry->d_inode)		return 0;	error = may_delete(old_dir, old_dentry, 0);	if (error)		return error;	if (new_dir->i_dev != old_dir->i_dev)		return -EXDEV;	if (!new_dentry->d_inode)		error = may_create(new_dir, new_dentry);	else		error = may_delete(new_dir, new_dentry, 0);	if (error)		return error;	if (!old_dir->i_op || !old_dir->i_op->rename)		return -EPERM;	DQUOT_INIT(old_dir);	DQUOT_INIT(new_dir);	double_down(&old_dir->i_zombie, &new_dir->i_zombie);	if (d_mountpoint(old_dentry)||d_mountpoint(new_dentry))		error = -EBUSY;	else		error = old_dir->i_op->rename(old_dir, old_dentry, new_dir, new_dentry);	double_up(&old_dir->i_zombie, &new_dir->i_zombie);	if (error)		return error;	/* The following d_move() should become unconditional */	if (!(old_dir->i_sb->s_type->fs_flags & FS_ODD_RENAME)) {		d_move(old_dentry, new_dentry);	}	return 0;}int vfs_rename(struct inode *old_dir, struct dentry *old_dentry,	       struct inode *new_dir, struct dentry *new_dentry){	int error;	if (S_ISDIR(old_dentry->d_inode->i_mode))		error = vfs_rename_dir(old_dir,old_dentry,new_dir,new_dentry);	else		error = vfs_rename_other(old_dir,old_dentry,new_dir,new_dentry);	if (!error) {		if (old_dir == new_dir)			inode_dir_notify(old_dir, DN_RENAME);		else {			inode_dir_notify(old_dir, DN_DELETE);			inode_dir_notify(new_dir, DN_CREATE);		}	}	return error;}static inline int do_rename(const char * oldname, const char * newname){	int error = 0;	struct dentry * old_dir, * new_dir;	struct dentry * old_dentry, *new_dentry;	struct nameidata oldnd, newnd;	if (path_init(oldname, LOOKUP_PARENT, &oldnd))		error = path_walk(oldname, &oldnd);	if (error)		goto exit;	if (path_init(newname, LOOKUP_PARENT, &newnd))		error = path_walk(newname, &newnd);	if (error)		goto exit1;	error = -EXDEV;	if (oldnd.mnt != newnd.mnt)		goto exit2;	old_dir = oldnd.dentry;	error = -EBUSY;	if (oldnd.last_type != LAST_NORM)		goto exit2;	new_dir = newnd.dentry;	if (newnd.last_type != LAST_NORM)		goto exit2;	double_lock(new_dir, old_dir);	old_dentry = lookup_hash(&oldnd.last, old_dir);	error = PTR_ERR(old_dentry);	if (IS_ERR(old_dentry))		goto exit3;	/* source must exist */	error = -ENOENT;	if (!old_dentry->d_inode)		goto exit4;	/* unless the source is a directory trailing slashes give -ENOTDIR */	if (!S_ISDIR(old_dentry->d_inode->i_mode)) {		error = -ENOTDIR;		if (oldnd.last.name[oldnd.last.len])			goto exit4;		if (newnd.last.name[newnd.last.len])			goto exit4;	}	new_dentry = lookup_hash(&newnd.last, new_dir);	error = PTR_ERR(new_dentry);	if (IS_ERR(new_dentry))		goto exit4;	lock_kernel();	error = vfs_rename(old_dir->d_inode, old_dentry,				   new_dir->d_inode, new_dentry);	unlock_kernel();	dput(new_dentry);exit4:	dput(old_dentry);exit3:	double_up(&new_dir->d_inode->i_sem, &old_dir->d_inode->i_sem);exit2:	path_release(&newnd);exit1:	path_release(&oldnd);exit:	return error;}asmlinkage long sys_rename(const char * oldname, const char * newname){	int error;	char * from;	char * to;	from = getname(oldname);	if(IS_ERR(from))		return PTR_ERR(from);	to = getname(newname);	error = PTR_ERR(to);	if (!IS_ERR(to)) {		error = do_rename(from,to);		putname(to);	}	putname(from);	return error;}int vfs_readlink(struct dentry *dentry, char *buffer, int buflen, const char *link){	int len;	len = PTR_ERR(link);	if (IS_ERR(link))		goto out;	len = strlen(link);	if (len > (unsigned) buflen)		len = buflen;	if (copy_to_user(buffer, link, len))		len = -EFAULT;out:	return len;}static inline int__vfs_follow_link(struct nameidata *nd, const char *link){	int res = 0;	char *name;	if (IS_ERR(link))		goto fail;	if (*link == '/') {		path_release(nd);		if (!walk_init_root(link, nd))			/* weird __emul_prefix() stuff did it */			goto out;	}	res = link_path_walk(link, nd);out:	if (current->link_count || res || nd->last_type!=LAST_NORM)		return res;	/*	 * If it is an iterative symlinks resolution in open_namei() we	 * have to copy the last component. And all that crap because of	 * bloody create() on broken symlinks. Furrfu...	 */	name = __getname();	if (!name)		return -ENOMEM;	strcpy(name, nd->last.name);	nd->last.name = name;	return 0;fail:	path_release(nd);	return PTR_ERR(link);}int vfs_follow_link(struct nameidata *nd, const char *link){	return __vfs_follow_link(nd, link);}/* get the link contents into pagecache */static char *page_getlink(struct dentry * dentry, struct page **ppage){	struct page * page;	struct address_space *mapping = dentry->d_inode->i_mapping;	page = read_cache_page(mapping, 0, (filler_t *)mapping->a_ops->readpage,				NULL);	if (IS_ERR(page))		goto sync_fail;	wait_on_page(page);	if (!Page_Uptodate(page))		goto async_fail;	*ppage = page;	return kmap(page);async_fail:	page_cache_release(page);	return ERR_PTR(-EIO);sync_fail:	return (char*)page;}int page_readlink(struct dentry *dentry, char *buffer, int buflen){	struct page *page = NULL;	char *s = page_getlink(dentry, &page);	int res = vfs_readlink(dentry,buffer,buflen,s);	if (page) {		kunmap(page);		page_cache_release(page);	}	return res;}int page_follow_link(struct dentry *dentry, struct nameidata *nd){	struct page *page = NULL;	char *s = page_getlink(dentry, &page);	int res = __vfs_follow_link(nd, s);	if (page) {		kunmap(page);		page_cache_release(page);	}	return res;}struct inode_operations page_symlink_inode_operations = {	readlink:	page_readlink,	follow_link:	page_follow_link,};

⌨️ 快捷键说明

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