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

📄 namei.c

📁 嵌入式系统设计与实例开发实验教材二源码 多线程应用程序设计 串行端口程序设计 AD接口实验 CAN总线通信实验 GPS通信实验 Linux内核移植与编译实验 IC卡读写实验 SD驱动使
💻 C
📖 第 1 页 / 共 4 页
字号:
		up(&dir->d_inode->i_sem);		goto exit;	}	/* Negative dentry, just create the file */	if (!dentry->d_inode) {		error = vfs_create(dir->d_inode, dentry,				   mode & ~current->fs->umask);		up(&dir->d_inode->i_sem);		dput(nd->dentry);		nd->dentry = dentry;		if (error)			goto exit;		/* Don't check for write permission, don't truncate */		acc_mode = 0;		flag &= ~O_TRUNC;		goto ok;	}	/*	 * It already exists.	 */	up(&dir->d_inode->i_sem);	error = -EEXIST;	if (flag & O_EXCL)		goto exit_dput;	if (d_mountpoint(dentry)) {		error = -ELOOP;		if (flag & O_NOFOLLOW)			goto exit_dput;		while (__follow_down(&nd->mnt,&dentry) && d_mountpoint(dentry));	}	error = -ENOENT;	if (!dentry->d_inode)		goto exit_dput;	if (dentry->d_inode->i_op && dentry->d_inode->i_op->follow_link)		goto do_link;	dput(nd->dentry);	nd->dentry = dentry;	error = -EISDIR;	if (dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode))		goto exit;ok:	error = -ENOENT;	inode = dentry->d_inode;	if (!inode)		goto exit;	error = -ELOOP;	if (S_ISLNK(inode->i_mode))		goto exit;		error = -EISDIR;	if (S_ISDIR(inode->i_mode) && (flag & FMODE_WRITE))		goto exit;	error = permission(inode,acc_mode);	if (error)		goto exit;	/*	 * FIFO's, sockets and device files are special: they don't	 * actually live on the filesystem itself, and as such you	 * can write to them even if the filesystem is read-only.	 */	if (S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) {	    	flag &= ~O_TRUNC;	} else if (S_ISBLK(inode->i_mode) || S_ISCHR(inode->i_mode)) {		error = -EACCES;		if (nd->mnt->mnt_flags & MNT_NODEV)			goto exit;		flag &= ~O_TRUNC;	} else {		error = -EROFS;		if (IS_RDONLY(inode) && (flag & 2))			goto exit;	}	/*	 * An append-only file must be opened in append mode for writing.	 */	error = -EPERM;	if (IS_APPEND(inode)) {		if  ((flag & FMODE_WRITE) && !(flag & O_APPEND))			goto exit;		if (flag & O_TRUNC)			goto exit;	}	/*	 * Ensure there are no outstanding leases on the file.	 */	error = get_lease(inode, flag);	if (error)		goto exit;	if (flag & O_TRUNC) {		error = get_write_access(inode);		if (error)			goto exit;		/*		 * Refuse to truncate files with mandatory locks held on them.		 */		error = locks_verify_locked(inode);		if (!error) {			DQUOT_INIT(inode);						error = do_truncate(dentry, 0);		}		put_write_access(inode);		if (error)			goto exit;	} else		if (flag & FMODE_WRITE)			DQUOT_INIT(inode);	return 0;exit_dput:	dput(dentry);exit:	path_release(nd);	return error;do_link:	error = -ELOOP;	if (flag & O_NOFOLLOW)		goto exit_dput;	/*	 * This is subtle. Instead of calling do_follow_link() we do the	 * thing by hands. The reason is that this way we have zero link_count	 * and path_walk() (called from ->follow_link) honoring LOOKUP_PARENT.	 * After that we have the parent and last component, i.e.	 * we are in the same situation as after the first path_walk().	 * Well, almost - if the last component is normal we get its copy	 * stored in nd->last.name and we will have to putname() it when we	 * are done. Procfs-like symlinks just set LAST_BIND.	 */	UPDATE_ATIME(dentry->d_inode);	error = dentry->d_inode->i_op->follow_link(dentry, nd);	dput(dentry);	if (error)		return error;	if (nd->last_type == LAST_BIND) {		dentry = nd->dentry;		goto ok;	}	error = -EISDIR;	if (nd->last_type != LAST_NORM)		goto exit;	if (nd->last.name[nd->last.len]) {		putname(nd->last.name);		goto exit;	}	error = -ELOOP;	if (count++==32) {		putname(nd->last.name);		goto exit;	}	dir = nd->dentry;	down(&dir->d_inode->i_sem);	dentry = lookup_hash(&nd->last, nd->dentry);	putname(nd->last.name);	goto do_last;}/* SMP-safe */static struct dentry *lookup_create(struct nameidata *nd, int is_dir){	struct dentry *dentry;	down(&nd->dentry->d_inode->i_sem);	dentry = ERR_PTR(-EEXIST);	if (nd->last_type != LAST_NORM)		goto fail;	dentry = lookup_hash(&nd->last, nd->dentry);	if (IS_ERR(dentry))		goto fail;	if (!is_dir && nd->last.name[nd->last.len] && !dentry->d_inode)		goto enoent;	return dentry;enoent:	dput(dentry);	dentry = ERR_PTR(-ENOENT);fail:	return dentry;}int vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev){	int error = -EPERM;	down(&dir->i_zombie);	if ((S_ISCHR(mode) || S_ISBLK(mode)) && !capable(CAP_MKNOD))		goto exit_lock;	error = may_create(dir, dentry);	if (error)		goto exit_lock;	error = -EPERM;	if (!dir->i_op || !dir->i_op->mknod)		goto exit_lock;	DQUOT_INIT(dir);	lock_kernel();	error = dir->i_op->mknod(dir, dentry, mode, dev);	unlock_kernel();exit_lock:	up(&dir->i_zombie);	if (!error)		inode_dir_notify(dir, DN_CREATE);	return error;}asmlinkage long sys_mknod(const char * filename, int mode, dev_t dev){	int error = 0;	char * tmp;	struct dentry * dentry;	struct nameidata nd;	if (S_ISDIR(mode))		return -EPERM;	tmp = getname(filename);	if (IS_ERR(tmp))		return PTR_ERR(tmp);	if (path_init(tmp, LOOKUP_PARENT, &nd))		error = path_walk(tmp, &nd);	if (error)		goto out;	dentry = lookup_create(&nd, 0);	error = PTR_ERR(dentry);	mode &= ~current->fs->umask;	if (!IS_ERR(dentry)) {		switch (mode & S_IFMT) {		case 0: case S_IFREG:			error = vfs_create(nd.dentry->d_inode,dentry,mode);			break;		case S_IFCHR: case S_IFBLK: case S_IFIFO: case S_IFSOCK:			error = vfs_mknod(nd.dentry->d_inode,dentry,mode,dev);			break;		case S_IFDIR:			error = -EPERM;			break;		default:			error = -EINVAL;		}		dput(dentry);	}	up(&nd.dentry->d_inode->i_sem);	path_release(&nd);out:	putname(tmp);	return error;}int vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode){	int error;	down(&dir->i_zombie);	error = may_create(dir, dentry);	if (error)		goto exit_lock;	error = -EPERM;	if (!dir->i_op || !dir->i_op->mkdir)		goto exit_lock;	DQUOT_INIT(dir);	mode &= (S_IRWXUGO|S_ISVTX);	lock_kernel();	error = dir->i_op->mkdir(dir, dentry, mode);	unlock_kernel();exit_lock:	up(&dir->i_zombie);	if (!error)		inode_dir_notify(dir, DN_CREATE);	return error;}asmlinkage long sys_mkdir(const char * pathname, int mode){	int error = 0;	char * tmp;	tmp = getname(pathname);	error = PTR_ERR(tmp);	if (!IS_ERR(tmp)) {		struct dentry *dentry;		struct nameidata nd;		if (path_init(tmp, LOOKUP_PARENT, &nd))			error = path_walk(tmp, &nd);		if (error)			goto out;		dentry = lookup_create(&nd, 1);		error = PTR_ERR(dentry);		if (!IS_ERR(dentry)) {			error = vfs_mkdir(nd.dentry->d_inode, dentry,					  mode & ~current->fs->umask);			dput(dentry);		}		up(&nd.dentry->d_inode->i_sem);		path_release(&nd);out:		putname(tmp);	}	return error;}/* * 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 (!d_unhashed(dentry)) *		return -EBUSY; * * if it cannot handle the case of removing a directory * that is still in use by something else.. */static void d_unhash(struct dentry *dentry){	dget(dentry);	switch (atomic_read(&dentry->d_count)) {	default:		shrink_dcache_parent(dentry);		if (atomic_read(&dentry->d_count) != 2)			break;	case 2:		d_drop(dentry);	}}int vfs_rmdir(struct inode *dir, struct dentry *dentry){	int error;	error = may_delete(dir, dentry, 1);	if (error)		return error;	if (!dir->i_op || !dir->i_op->rmdir)		return -EPERM;	DQUOT_INIT(dir);	double_down(&dir->i_zombie, &dentry->d_inode->i_zombie);	d_unhash(dentry);	if (IS_DEADDIR(dir))		error = -ENOENT;	else if (d_mountpoint(dentry))		error = -EBUSY;	else {		lock_kernel();		error = dir->i_op->rmdir(dir, dentry);		unlock_kernel();		if (!error)			dentry->d_inode->i_flags |= S_DEAD;	}	double_up(&dir->i_zombie, &dentry->d_inode->i_zombie);	if (!error) {		inode_dir_notify(dir, DN_DELETE);		d_delete(dentry);	}	dput(dentry);	return error;}asmlinkage long sys_rmdir(const char * pathname){	int error = 0;	char * name;	struct dentry *dentry;	struct nameidata nd;	name = getname(pathname);	if(IS_ERR(name))		return PTR_ERR(name);	if (path_init(name, LOOKUP_PARENT, &nd))		error = path_walk(name, &nd);	if (error)		goto exit;	switch(nd.last_type) {		case LAST_DOTDOT:			error = -ENOTEMPTY;			goto exit1;		case LAST_DOT:			error = -EINVAL;			goto exit1;		case LAST_ROOT:			error = -EBUSY;			goto exit1;	}	down(&nd.dentry->d_inode->i_sem);	dentry = lookup_hash(&nd.last, nd.dentry);	error = PTR_ERR(dentry);	if (!IS_ERR(dentry)) {		error = vfs_rmdir(nd.dentry->d_inode, dentry);		dput(dentry);	}	up(&nd.dentry->d_inode->i_sem);exit1:	path_release(&nd);exit:	putname(name);	return error;}int vfs_unlink(struct inode *dir, struct dentry *dentry){	int error;	down(&dir->i_zombie);	error = may_delete(dir, dentry, 0);	if (!error) {		error = -EPERM;		if (dir->i_op && dir->i_op->unlink) {			DQUOT_INIT(dir);			if (d_mountpoint(dentry))				error = -EBUSY;			else {				lock_kernel();				error = dir->i_op->unlink(dir, dentry);				unlock_kernel();				if (!error)					d_delete(dentry);			}		}	}	up(&dir->i_zombie);	if (!error)		inode_dir_notify(dir, DN_DELETE);	return error;}asmlinkage long sys_unlink(const char * pathname){	int error = 0;	char * name;	struct dentry *dentry;	struct nameidata nd;	name = getname(pathname);	if(IS_ERR(name))		return PTR_ERR(name);	if (path_init(name, LOOKUP_PARENT, &nd))		error = path_walk(name, &nd);	if (error)		goto exit;	error = -EISDIR;	if (nd.last_type != LAST_NORM)		goto exit1;	down(&nd.dentry->d_inode->i_sem);	dentry = lookup_hash(&nd.last, nd.dentry);	error = PTR_ERR(dentry);	if (!IS_ERR(dentry)) {		/* Why not before? Because we want correct error value */		if (nd.last.name[nd.last.len])			goto slashes;		error = vfs_unlink(nd.dentry->d_inode, dentry);	exit2:		dput(dentry);	}	up(&nd.dentry->d_inode->i_sem);exit1:	path_release(&nd);exit:	putname(name);	return error;slashes:	error = !dentry->d_inode ? -ENOENT :		S_ISDIR(dentry->d_inode->i_mode) ? -EISDIR : -ENOTDIR;	goto exit2;}int vfs_symlink(struct inode *dir, struct dentry *dentry, const char *oldname){	int error;	down(&dir->i_zombie);	error = may_create(dir, dentry);	if (error)		goto exit_lock;	error = -EPERM;	if (!dir->i_op || !dir->i_op->symlink)		goto exit_lock;

⌨️ 快捷键说明

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