Esempio n. 1
0
static int
devfs_vop_nrmdir(struct vop_nrmdir_args *ap)
{
	struct devfs_node *dnode = DEVFS_NODE(ap->a_dvp);
	struct devfs_node *node;
	struct namecache *ncp;
	int error = ENOENT;

	ncp = ap->a_nch->ncp;

	if (!devfs_node_is_accessible(dnode))
		return ENOENT;

	lockmgr(&devfs_lock, LK_EXCLUSIVE);

	if ((dnode->node_type != Nroot) && (dnode->node_type != Ndir))
		goto out;

	TAILQ_FOREACH(node, DEVFS_DENODE_HEAD(dnode), link) {
		if (ncp->nc_nlen != node->d_dir.d_namlen)
			continue;
		if (memcmp(ncp->nc_name, node->d_dir.d_name, ncp->nc_nlen))
			continue;

		/*
		 * only allow removal of user created dirs
		 */
		if ((node->flags & DEVFS_USER_CREATED) == 0) {
			error = EPERM;
			goto out;
		} else if (node->node_type != Ndir) {
			error = ENOTDIR;
			goto out;
		} else if (node->nchildren > 2) {
			error = ENOTEMPTY;
			goto out;
		} else {
			if (node->v_node)
				cache_inval_vp(node->v_node, CINV_DESTROY);
			devfs_unlinkp(node);
			error = 0;
			break;
		}
	}

	cache_unlink(ap->a_nch);
out:
	lockmgr(&devfs_lock, LK_RELEASE);
	return error;
}
Esempio n. 2
0
/*
 * vop_compat_nrmdir { struct nchandle *a_nch, 	XXX STOPGAP FUNCTION
 *		       struct vnode *dvp,
 *		       struct ucred *a_cred }
 */
int
vop_compat_nrmdir(struct vop_nrmdir_args *ap)
{
	struct thread *td = curthread;
	struct componentname cnp;
	struct nchandle *nch;
	struct namecache *ncp;
	struct vnode *dvp;
	struct vnode *vp;
	int error;

	/*
	 * Sanity checks, get a locked directory vnode.
	 */
	nch = ap->a_nch;		/* locked namecache node */
	ncp = nch->ncp;
	dvp = ap->a_dvp;

	if ((error = vget(dvp, LK_EXCLUSIVE)) != 0) {
		kprintf("[diagnostic] vop_compat_resolve: EAGAIN on ncp %p %s\n",
			ncp, ncp->nc_name);
		return(EAGAIN);
	}

	/*
	 * Setup the cnp for a traditional vop_old_lookup() call.  The lookup
	 * caches all information required to delete the entry in the
	 * directory inode.  We expect a return code of 0 for the DELETE
	 * case (meaning that a vp has been found).  The cnp must simulated
	 * a saved-name situation.
	 */
	bzero(&cnp, sizeof(cnp));
	cnp.cn_nameiop = NAMEI_DELETE;
	cnp.cn_flags = CNP_LOCKPARENT;
	cnp.cn_nameptr = ncp->nc_name;
	cnp.cn_namelen = ncp->nc_nlen;
	cnp.cn_cred = ap->a_cred;
	cnp.cn_td = td;

	/*
	 * The vnode must be a directory and must not represent the
	 * current directory.
	 */
	vp = NULL;
	error = vop_old_lookup(ap->a_head.a_ops, dvp, &vp, &cnp);
	if (error == 0 && vp->v_type != VDIR)
		error = ENOTDIR;
	if (error == 0 && vp == dvp)
		error = EINVAL;
	if (error == 0 && (vp->v_flag & VROOT))
		error = EBUSY;
	if (error == 0) {
		KKASSERT((cnp.cn_flags & CNP_PDIRUNLOCK) == 0);
		error = VOP_OLD_RMDIR(dvp, vp, &cnp);

		/*
		 * Note that this invalidation will cause any process
		 * currently CD'd into the directory being removed to be
		 * disconnected from the topology and not be able to ".."
		 * back out.
		 */
		if (error == 0) {
			cache_inval(nch, CINV_DESTROY);
			cache_inval_vp(vp, CINV_DESTROY);
		}
	}
	if (vp) {
		if (dvp == vp)
			vrele(vp);
		else	
			vput(vp);
	}
	if ((cnp.cn_flags & CNP_PDIRUNLOCK) == 0)
		vn_unlock(dvp);
	vrele(dvp);
	return (error);
}
Esempio n. 3
0
/*
 * vop_compat_nremove { struct nchandle *a_nch, 	XXX STOPGAP FUNCTION
 *			struct vnode *a_dvp,
 *			struct ucred *a_cred }
 */
int
vop_compat_nremove(struct vop_nremove_args *ap)
{
	struct thread *td = curthread;
	struct componentname cnp;
	struct nchandle *nch;
	struct namecache *ncp;
	struct vnode *dvp;
	struct vnode *vp;
	int error;

	/*
	 * Sanity checks, get a locked directory vnode.
	 */
	nch = ap->a_nch;		/* locked namecache node */
	ncp = nch->ncp;
	dvp = ap->a_dvp;

	if ((error = vget(dvp, LK_EXCLUSIVE)) != 0) {
		kprintf("[diagnostic] vop_compat_resolve: EAGAIN on ncp %p %s\n",
			ncp, ncp->nc_name);
		return(EAGAIN);
	}

	/*
	 * Setup the cnp for a traditional vop_old_lookup() call.  The lookup
	 * caches all information required to delete the entry in the
	 * directory inode.  We expect a return code of 0 for the DELETE
	 * case (meaning that a vp has been found).  The cnp must simulated
	 * a saved-name situation.
	 */
	bzero(&cnp, sizeof(cnp));
	cnp.cn_nameiop = NAMEI_DELETE;
	cnp.cn_flags = CNP_LOCKPARENT;
	cnp.cn_nameptr = ncp->nc_name;
	cnp.cn_namelen = ncp->nc_nlen;
	cnp.cn_cred = ap->a_cred;
	cnp.cn_td = td;

	/*
	 * The vnode must be a directory and must not represent the
	 * current directory.
	 */
	vp = NULL;
	error = vop_old_lookup(ap->a_head.a_ops, dvp, &vp, &cnp);
	if (error == 0 && vp->v_type == VDIR)
		error = EPERM;
	if (error == 0) {
		KKASSERT((cnp.cn_flags & CNP_PDIRUNLOCK) == 0);
		error = VOP_OLD_REMOVE(dvp, vp, &cnp);
		if (error == 0) {
			cache_setunresolved(nch);
			cache_setvp(nch, NULL);
			cache_inval_vp(vp, CINV_DESTROY);
		}
	}
	if (vp) {
		if (dvp == vp)
			vrele(vp);
		else	
			vput(vp);
	}
	if ((cnp.cn_flags & CNP_PDIRUNLOCK) == 0)
		vn_unlock(dvp);
	vrele(dvp);
	return (error);
}