namei.c

来自「基于组件方式开发操作系统的OSKIT源代码」· C语言 代码 · 共 1,434 行 · 第 1/3 页

C
1,434
字号
	/*	 * We try to drop the dentry early: we should have	 * a usage count of 2 if we're the only user of this	 * dentry, and if that is true (possibly after pruning	 * the dcache), then we drop the dentry now.	 *	 * A low-level filesystem can, if it choses, legally	 * do a	 *	 *	if (!list_empty(&dentry->d_hash))	 *		return -EBUSY;	 *	 * if it cannot handle the case of removing a directory	 * that is still in use by something else..	 */	switch (dentry->d_count) {	default:		shrink_dcache_parent(dentry);		if (dentry->d_count != 2)			break;	case 2:		d_drop(dentry);	}	error = dir->i_op->rmdir(dir, dentry);	return error;}#ifdef OSKIT       int do_rmdir(const char * name)#elsestatic inline int do_rmdir(const char * name)#endif{	int error;	struct dentry *dir;	struct dentry *dentry;	dentry = lookup_dentry(name, NULL, 0);	error = PTR_ERR(dentry);	if (IS_ERR(dentry))		goto exit;	error = -ENOENT;	if (!dentry->d_inode)		goto exit_dput;	dir = dget(dentry->d_parent);	/*	 * The dentry->d_count stuff confuses d_delete() enough to	 * not kill the inode from under us while it is locked. This	 * wouldn't be needed, except the dentry semaphore is really	 * in the inode, not in the dentry..	 */	dentry->d_count++;	double_lock(dir, dentry);	error = -ENOENT;	if (check_parent(dir, dentry))		error = vfs_rmdir(dir->d_inode, dentry);	double_unlock(dentry, dir);exit_dput:	dput(dentry);exit:	return error;}asmlinkage int sys_rmdir(const char * pathname){	int error;	char * tmp;	lock_kernel();	tmp = getname(pathname);	error = PTR_ERR(tmp);	if (!IS_ERR(tmp)) {		error = do_rmdir(tmp);		putname(tmp);	}	unlock_kernel();	return error;}int vfs_unlink(struct inode *dir, struct dentry *dentry){	int error;	error = may_delete(dir, dentry, 0);	if (!error) {		error = -EPERM;		if (dir->i_op && dir->i_op->unlink) {			DQUOT_INIT(dir);			error = dir->i_op->unlink(dir, dentry);		}	}	return error;}#ifdef OSKIT       int do_unlink(const char * name)#elsestatic inline int do_unlink(const char * name)#endif{	int error;	struct dentry *dir;	struct dentry *dentry;	dentry = lookup_dentry(name, NULL, 0);	error = PTR_ERR(dentry);	if (IS_ERR(dentry))		goto exit;	dir = lock_parent(dentry);	error = -ENOENT;	if (check_parent(dir, dentry))		error = vfs_unlink(dir->d_inode, dentry);        unlock_dir(dir);	dput(dentry);exit:	return error;}asmlinkage int sys_unlink(const char * pathname){	int error;	char * tmp;	lock_kernel();	tmp = getname(pathname);	error = PTR_ERR(tmp);	if (!IS_ERR(tmp)) {		error = do_unlink(tmp);		putname(tmp);	}	unlock_kernel();	return error;}#ifdef OSKIT       int do_symlink(const char * oldname, const char * newname)#elsestatic inline int do_symlink(const char * oldname, const char * newname)#endif{	int error;	struct dentry *dir;	struct dentry *dentry;	dentry = lookup_dentry(newname, NULL, 0);	error = PTR_ERR(dentry);	if (IS_ERR(dentry))		goto exit;	dir = lock_parent(dentry);	error = -ENOENT;	if (!check_parent(dir, dentry))		goto exit_lock;	error = may_create(dir->d_inode, dentry);	if (error)		goto exit_lock;	error = -EPERM;	if (!dir->d_inode->i_op || !dir->d_inode->i_op->symlink)		goto exit_lock;	DQUOT_INIT(dir->d_inode);	error = dir->d_inode->i_op->symlink(dir->d_inode, dentry, oldname);exit_lock:	unlock_dir(dir);	dput(dentry);exit:	return error;}asmlinkage int sys_symlink(const char * oldname, const char * newname){	int error;	char * from;	lock_kernel();	from = getname(oldname);	error = PTR_ERR(from);	if (!IS_ERR(from)) {		char * to;		to = getname(newname);		error = PTR_ERR(to);		if (!IS_ERR(to)) {			error = do_symlink(from,to);			putname(to);		}		putname(from);	}	unlock_kernel();	return error;}#ifdef OSKIT       int do_link(struct dentry *dentry, const char * newname)#elsestatic inline int do_link(const char * oldname, const char * newname)#endif{	struct dentry *old_dentry, *new_dentry, *dir;	struct inode *inode;	int 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	 */#ifdef OSKIT	dget(dentry);	old_dentry = dentry;#else	old_dentry = lookup_dentry(oldname, NULL, 0);#endif	error = PTR_ERR(old_dentry);	if (IS_ERR(old_dentry))		goto exit;	new_dentry = lookup_dentry(newname, NULL, 0);	error = PTR_ERR(new_dentry);	if (IS_ERR(new_dentry))		goto exit_old;	dir = lock_parent(new_dentry);	error = -ENOENT;	if (!check_parent(dir, new_dentry))		goto exit_lock;	error = -ENOENT;	inode = old_dentry->d_inode;	if (!inode)		goto exit_lock;	error = may_create(dir->d_inode, new_dentry);	if (error)		goto exit_lock;	error = -EXDEV;	if (dir->d_inode->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;	error = -EPERM;	if (!dir->d_inode->i_op || !dir->d_inode->i_op->link)		goto exit_lock;	DQUOT_INIT(dir->d_inode);	error = dir->d_inode->i_op->link(old_dentry, dir->d_inode, new_dentry);exit_lock:	unlock_dir(dir);	dput(new_dentry);exit_old:	dput(old_dentry);exit:	return error;}#ifndef OSKITasmlinkage int sys_link(const char * oldname, const char * newname){	int error;	char * from;	lock_kernel();	from = getname(oldname);	error = PTR_ERR(from);	if (!IS_ERR(from)) {		char * to;		to = getname(newname);		error = PTR_ERR(to);		if (!IS_ERR(to)) {			error = do_link(from,to);			putname(to);		}		putname(from);	}	unlock_kernel();	return error;}#endifint vfs_rename_dir(struct inode *old_dir, struct dentry *old_dentry,	       struct inode *new_dir, struct dentry *new_dentry){	int error;	int need_rehash = 0;	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;	if (new_dentry->d_inode) {		error = -EBUSY;		if (d_invalidate(new_dentry)<0)			goto out_unlock;		need_rehash = 1;	}	error = old_dir->i_op->rename(old_dir, old_dentry, new_dir, new_dentry);	if (need_rehash)		d_rehash(new_dentry);	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);	error = old_dir->i_op->rename(old_dir, old_dentry, new_dir, new_dentry);	if (error)		return error;	/* The following d_move() should become unconditional */	if (!(old_dir->i_sb->s_flags & MS_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){	if (S_ISDIR(old_dentry->d_inode->i_mode))		return vfs_rename_dir(old_dir,old_dentry,new_dir,new_dentry);	else		return vfs_rename_other(old_dir,old_dentry,new_dir,new_dentry);}#ifdef OSKIT       int do_rename(const char * oldname, const char * newname)#elsestatic inline int do_rename(const char * oldname, const char * newname)#endif{	int error;	struct dentry * old_dir, * new_dir;	struct dentry * old_dentry, *new_dentry;	old_dentry = lookup_dentry(oldname, NULL, 0);	error = PTR_ERR(old_dentry);	if (IS_ERR(old_dentry))		goto exit;	error = -ENOENT;	if (!old_dentry->d_inode)		goto exit_old;	{		unsigned int flags = 0;		if (S_ISDIR(old_dentry->d_inode->i_mode))			flags = LOOKUP_SLASHOK;		new_dentry = lookup_dentry(newname, NULL, flags);	}	error = PTR_ERR(new_dentry);	if (IS_ERR(new_dentry))		goto exit_old;	new_dir = get_parent(new_dentry);	old_dir = get_parent(old_dentry);	double_lock(new_dir, old_dir);	error = -ENOENT;	if (check_parent(old_dir, old_dentry) && check_parent(new_dir, new_dentry))		error = vfs_rename(old_dir->d_inode, old_dentry,				   new_dir->d_inode, new_dentry);	double_unlock(new_dir, old_dir);	dput(new_dentry);exit_old:	dput(old_dentry);exit:	return error;}asmlinkage int sys_rename(const char * oldname, const char * newname){	int error;	char * from;	lock_kernel();	from = getname(oldname);	error = PTR_ERR(from);	if (!IS_ERR(from)) {		char * to;		to = getname(newname);		error = PTR_ERR(to);		if (!IS_ERR(to)) {			error = do_rename(from,to);			putname(to);		}		putname(from);	}	unlock_kernel();	return error;}

⌨️ 快捷键说明

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