FreeBSD/sys/fs/unionfs/union_subr.c
/*
 * Create a new shadow dir.
 * 
 * udvp should be locked on entry and will be locked on return.
 * 
 * If no error returned, unp will be updated.
 */
Create a new shadow dir.

udvp should be locked on entry and will be locked on return.

If no error returned, unp will be updated.
Create a new shadow dir . udvp should be locked on entry and will be locked on return . If no error returned unp will be updated .
int
unionfs_mkshadowdir(struct unionfs_mount *ump, struct vnode *udvp,
		    struct unionfs_node *unp, struct componentname *cnp,
		    struct thread *td)
{
	int		error;
	struct vnode   *lvp;
	struct vnode   *uvp;
	struct vattr	va;
	struct vattr	lva;
	struct componentname cn;
	struct mount   *mp;
	struct ucred   *cred;
	struct ucred   *credbk;
	struct uidinfo *rootinfo;
	if (unp->un_uppervp != NULLVP)
		return (EEXIST);
	lvp = unp->un_lowervp;
	uvp = NULLVP;
	credbk = cnp->cn_cred;
	rootinfo = uifind((uid_t)0);
	cred = crdup(cnp->cn_cred);
	chgproccnt(cred->cr_ruidinfo, 1, 0);
	change_euid(cred, rootinfo);
	change_ruid(cred, rootinfo);
	change_svuid(cred, (uid_t)0);
	uifree(rootinfo);
	cnp->cn_cred = cred;
	memset(&cn, 0, sizeof(cn));
	if ((error = VOP_GETATTR(lvp, &lva, cnp->cn_cred)))
		goto unionfs_mkshadowdir_abort;
	if ((error = unionfs_relookup(udvp, &uvp, cnp, &cn, td, cnp->cn_nameptr, cnp->cn_namelen, CREATE)))
		goto unionfs_mkshadowdir_abort;
	if (uvp != NULLVP) {
		if (udvp == uvp)
			vrele(uvp);
		else
			vput(uvp);
		error = EEXIST;
		goto unionfs_mkshadowdir_free_out;
	}
	if ((error = vn_start_write(udvp, &mp, V_WAIT | PCATCH)))
		goto unionfs_mkshadowdir_free_out;
	unionfs_create_uppervattr_core(ump, &lva, &va, td);
	error = VOP_MKDIR(udvp, &uvp, &cn, &va);
	if (!error) {
		unionfs_node_update(unp, uvp, td);
		va.va_type = VNON;
		VOP_SETATTR(uvp, &va, cn.cn_cred);
	}
	vn_finished_write(mp);
unionfs_mkshadowdir_free_out:
	if (cn.cn_flags & HASBUF) {
		uma_zfree(namei_zone, cn.cn_pnbuf);
		cn.cn_flags &= ~HASBUF;
	}
unionfs_mkshadowdir_abort:
	cnp->cn_cred = credbk;
	chgproccnt(cred->cr_ruidinfo, -1, 0);
	crfree(cred);
	return (error);
}
int unionfs_mkshadowdir ( struct unionfs_mount * ump , struct vnode * udvp , struct unionfs_node * unp , struct componentname * cnp , struct thread * td ) { int error ; struct vnode * lvp ; struct vnode * uvp ; struct vattr va ; struct vattr lva ; struct componentname cn ; struct mount * mp ; struct ucred * cred ; struct ucred * credbk ; struct uidinfo * rootinfo ; if ( unp -> un_uppervp != NULLVP ) return ( EEXIST ) ; lvp = unp -> un_lowervp ; uvp = NULLVP ; credbk = cnp -> cn_cred ; rootinfo = uifind ( ( uid_t ) 0 ) ; cred = crdup ( cnp -> cn_cred ) ; chgproccnt ( cred -> cr_ruidinfo , 1 , 0 ) ; change_euid ( cred , rootinfo ) ; change_ruid ( cred , rootinfo ) ; change_svuid ( cred , ( uid_t ) 0 ) ; uifree ( rootinfo ) ; cnp -> cn_cred = cred ; memset ( & cn , 0 , sizeof ( cn ) ) ; if ( ( error = VOP_GETATTR ( lvp , & lva , cnp -> cn_cred ) ) ) goto unionfs_mkshadowdir_abort ; if ( ( error = unionfs_relookup ( udvp , & uvp , cnp , & cn , td , cnp -> cn_nameptr , cnp -> cn_namelen , CREATE ) ) ) goto unionfs_mkshadowdir_abort ; if ( uvp != NULLVP ) { if ( udvp == uvp ) vrele ( uvp ) ; else vput ( uvp ) ; error = EEXIST ; goto unionfs_mkshadowdir_free_out ; } if ( ( error = vn_start_write ( udvp , & mp , V_WAIT | PCATCH ) ) ) goto unionfs_mkshadowdir_free_out ; unionfs_create_uppervattr_core ( ump , & lva , & va , td ) ; error = VOP_MKDIR ( udvp , & uvp , & cn , & va ) ; if ( ! error ) { unionfs_node_update ( unp , uvp , td ) ; va . va_type = VNON ; VOP_SETATTR ( uvp , & va , cn . cn_cred ) ; } vn_finished_write ( mp ) ; unionfs_mkshadowdir_free_out : if ( cn . cn_flags & HASBUF ) { uma_zfree ( namei_zone , cn . cn_pnbuf ) ; cn . cn_flags &= ~ HASBUF ; } unionfs_mkshadowdir_abort : cnp -> cn_cred = credbk ; chgproccnt ( cred -> cr_ruidinfo , -1 , 0 ) ; crfree ( cred ) ; return ( error ) ; }
Create a new shadow dir.
Create a new shadow dir .
/* Authority change to root */ /*
	 * The calls to chgproccnt() are needed to compensate for change_ruid()
	 * calling chgproccnt().
	 */ /*
		 * XXX The bug which cannot set uid/gid was corrected.
		 * Ignore errors.
		 */