FreeBSD/sys/fs/unionfs/union_subr.c
/*
 * It checks whether vp can rmdir. (check empty)
 *
 * vp is unionfs vnode.
 * vp should be locked.
 */
It checks whether vp can rmdir. (check empty)
vp is unionfs vnode.
vp should be locked.
It checks whether vp can rmdir . ( check empty ) vp is unionfs vnode . vp should be locked .
int
unionfs_check_rmdir(struct vnode *vp, struct ucred *cred, struct thread *td)
{
	int		error;
	int		eofflag;
	int		lookuperr;
	struct vnode   *uvp;
	struct vnode   *lvp;
	struct vnode   *tvp;
	struct vattr	va;
	struct componentname cn;
	char		buf[256 * 6];
	struct dirent  *dp;
	struct dirent  *edp;
	struct uio	uio;
	struct iovec	iov;
	ASSERT_VOP_ELOCKED(vp, "unionfs_check_rmdir");
	eofflag = 0;
	uvp = UNIONFSVPTOUPPERVP(vp);
	lvp = UNIONFSVPTOLOWERVP(vp);
	if ((error = VOP_GETATTR(uvp, &va, cred)) != 0)
		return (error);
	if (va.va_flags & OPAQUE)
		return (0);
#ifdef MAC
	if ((error = mac_vnode_check_open(cred, vp, VEXEC|VREAD)) != 0)
		return (error);
#endif
	if ((error = VOP_ACCESS(vp, VEXEC|VREAD, cred, td)) != 0)
		return (error);
	if ((error = VOP_OPEN(vp, FREAD, cred, td, NULL)) != 0)
		return (error);
	uio.uio_rw = UIO_READ;
	uio.uio_segflg = UIO_SYSSPACE;
	uio.uio_td = td;
	uio.uio_offset = 0;
#ifdef MAC
	error = mac_vnode_check_readdir(td->td_ucred, lvp);
#endif
	while (!error && !eofflag) {
		iov.iov_base = buf;
		iov.iov_len = sizeof(buf);
		uio.uio_iov = &iov;
		uio.uio_iovcnt = 1;
		uio.uio_resid = iov.iov_len;
		error = VOP_READDIR(lvp, &uio, cred, &eofflag, NULL, NULL);
		if (error != 0)
			break;
		if (eofflag == 0 && uio.uio_resid == sizeof(buf)) {
#ifdef DIAGNOSTIC
			panic("bad readdir response from lower FS.");
#endif
			break;
		}
		edp = (struct dirent*)&buf[sizeof(buf) - uio.uio_resid];
		for (dp = (struct dirent*)buf; !error && dp < edp;
		     dp = (struct dirent*)((caddr_t)dp + dp->d_reclen)) {
			if (dp->d_type == DT_WHT || dp->d_fileno == 0 ||
			    (dp->d_namlen == 1 && dp->d_name[0] == '.') ||
			    (dp->d_namlen == 2 && !bcmp(dp->d_name, "..", 2)))
				continue;
			cn.cn_namelen = dp->d_namlen;
			cn.cn_pnbuf = NULL;
			cn.cn_nameptr = dp->d_name;
			cn.cn_nameiop = LOOKUP;
			cn.cn_flags = (LOCKPARENT | LOCKLEAF | SAVENAME | RDONLY | ISLASTCN);
			cn.cn_lkflags = LK_EXCLUSIVE;
			cn.cn_thread = td;
			cn.cn_cred = cred;
			lookuperr = VOP_LOOKUP(lvp, &tvp, &cn);
			if (!lookuperr)
				vput(tvp);
			else
				continue; 
			cn.cn_flags = (LOCKPARENT | LOCKLEAF | SAVENAME | RDONLY | ISLASTCN);
			lookuperr = VOP_LOOKUP(uvp, &tvp, &cn);
			if (!lookuperr)
				vput(tvp);
			if (!lookuperr ||
			    (lookuperr == ENOENT && (cn.cn_flags & ISWHITEOUT)))
				continue;
			error = ENOTEMPTY;
		}
	}
	VOP_CLOSE(vp, FREAD, cred, td);
	return (error);
}
int unionfs_check_rmdir ( struct vnode * vp , struct ucred * cred , struct thread * td ) { int error ; int eofflag ; int lookuperr ; struct vnode * uvp ; struct vnode * lvp ; struct vnode * tvp ; struct vattr va ; struct componentname cn ; char buf [ 256 * 6 ] ; struct dirent * dp ; struct dirent * edp ; struct uio uio ; struct iovec iov ; ASSERT_VOP_ELOCKED ( vp , " " ) ; eofflag = 0 ; uvp = UNIONFSVPTOUPPERVP ( vp ) ; lvp = UNIONFSVPTOLOWERVP ( vp ) ; if ( ( error = VOP_GETATTR ( uvp , & va , cred ) ) != 0 ) return ( error ) ; if ( va . va_flags & OPAQUE ) return ( 0 ) ; #ifdef MAC if ( ( error = mac_vnode_check_open ( cred , vp , VEXEC | VREAD ) ) != 0 ) return ( error ) ; #endif if ( ( error = VOP_ACCESS ( vp , VEXEC | VREAD , cred , td ) ) != 0 ) return ( error ) ; if ( ( error = VOP_OPEN ( vp , FREAD , cred , td , NULL ) ) != 0 ) return ( error ) ; uio . uio_rw = UIO_READ ; uio . uio_segflg = UIO_SYSSPACE ; uio . uio_td = td ; uio . uio_offset = 0 ; #ifdef MAC error = mac_vnode_check_readdir ( td -> td_ucred , lvp ) ; #endif while ( ! error && ! eofflag ) { iov . iov_base = buf ; iov . iov_len = sizeof ( buf ) ; uio . uio_iov = & iov ; uio . uio_iovcnt = 1 ; uio . uio_resid = iov . iov_len ; error = VOP_READDIR ( lvp , & uio , cred , & eofflag , NULL , NULL ) ; if ( error != 0 ) break ; if ( eofflag == 0 && uio . uio_resid == sizeof ( buf ) ) { #ifdef DIAGNOSTIC panic ( " " ) ; #endif break ; } edp = ( struct dirent * ) & buf [ sizeof ( buf ) - uio . uio_resid ] ; for ( dp = ( struct dirent * ) buf ; ! error && dp < edp ; dp = ( struct dirent * ) ( ( caddr_t ) dp + dp -> d_reclen ) ) { if ( dp -> d_type == DT_WHT || dp -> d_fileno == 0 || ( dp -> d_namlen == 1 && dp -> d_name [ 0 ] == ' ' ) || ( dp -> d_namlen == 2 && ! bcmp ( dp -> d_name , " " , 2 ) ) ) continue ; cn . cn_namelen = dp -> d_namlen ; cn . cn_pnbuf = NULL ; cn . cn_nameptr = dp -> d_name ; cn . cn_nameiop = LOOKUP ; cn . cn_flags = ( LOCKPARENT | LOCKLEAF | SAVENAME | RDONLY | ISLASTCN ) ; cn . cn_lkflags = LK_EXCLUSIVE ; cn . cn_thread = td ; cn . cn_cred = cred ; lookuperr = VOP_LOOKUP ( lvp , & tvp , & cn ) ; if ( ! lookuperr ) vput ( tvp ) ; else continue ; cn . cn_flags = ( LOCKPARENT | LOCKLEAF | SAVENAME | RDONLY | ISLASTCN ) ; lookuperr = VOP_LOOKUP ( uvp , & tvp , & cn ) ; if ( ! lookuperr ) vput ( tvp ) ; if ( ! lookuperr || ( lookuperr == ENOENT && ( cn . cn_flags & ISWHITEOUT ) ) ) continue ; error = ENOTEMPTY ; } } VOP_CLOSE ( vp , FREAD , cred , td ) ; return ( error ) ; }
It checks whether vp can rmdir.
It checks whether vp can rmdir .
/*
	 * The size of buf needs to be larger than DIRBLKSIZ.
	 */ /* check opaque */ /* open vnode */ /*
			 * check entry in lower.
			 * Sometimes, readdir function returns
			 * wrong entry.
			 */ /* skip entry */ /*
			 * check entry
			 * If it has no exist/whiteout entry in upper,
			 * directory is not empty.
			 */ /* ignore exist or whiteout entry */ /* close vnode */