union_vnops.c

来自「早期freebsd实现」· C语言 代码 · 共 1,496 行 · 第 1/3 页

C
1,496
字号
				(void) VOP_OPEN(un->un_uppervp, FREAD, cred, p);			}			un->un_openl = 0;			if (error == 0)				error = VOP_OPEN(un->un_uppervp, mode, cred, p);			return (error);		}		/*		 * Just open the lower vnode		 */		un->un_openl++;		VOP_LOCK(tvp);		error = VOP_OPEN(tvp, mode, cred, p);		VOP_UNLOCK(tvp);		return (error);	}	FIXUP(un);	error = VOP_OPEN(tvp, mode, cred, p);	return (error);}intunion_close(ap)	struct vop_close_args /* {		struct vnode *a_vp;		int  a_fflag;		struct ucred *a_cred;		struct proc *a_p;	} */ *ap;{	struct union_node *un = VTOUNION(ap->a_vp);	struct vnode *vp;	if (un->un_uppervp) {		vp = un->un_uppervp;	} else {#ifdef UNION_DIAGNOSTIC		if (un->un_openl <= 0)			panic("union: un_openl cnt");#endif		--un->un_openl;		vp = un->un_lowervp;	}	return (VOP_CLOSE(vp, ap->a_fflag, ap->a_cred, ap->a_p));}/* * Check access permission on the union vnode. * The access check being enforced is to check * against both the underlying vnode, and any * copied vnode.  This ensures that no additional * file permissions are given away simply because * the user caused an implicit file copy. */intunion_access(ap)	struct vop_access_args /* {		struct vnodeop_desc *a_desc;		struct vnode *a_vp;		int a_mode;		struct ucred *a_cred;		struct proc *a_p;	} */ *ap;{	struct union_node *un = VTOUNION(ap->a_vp);	int error = EACCES;	struct vnode *vp;	if (vp = un->un_uppervp) {		FIXUP(un);		return (VOP_ACCESS(vp, ap->a_mode, ap->a_cred, ap->a_p));	}	if (vp = un->un_lowervp) {		VOP_LOCK(vp);		error = VOP_ACCESS(vp, ap->a_mode, ap->a_cred, ap->a_p);		if (error == 0) {			struct union_mount *um = MOUNTTOUNIONMOUNT(vp->v_mount);			if (um->um_op == UNMNT_BELOW)				error = VOP_ACCESS(vp, ap->a_mode,						um->um_cred, ap->a_p);		}		VOP_UNLOCK(vp);		if (error)			return (error);	}	return (error);}/* *  We handle getattr only to change the fsid. */intunion_getattr(ap)	struct vop_getattr_args /* {		struct vnode *a_vp;		struct vattr *a_vap;		struct ucred *a_cred;		struct proc *a_p;	} */ *ap;{	int error;	struct union_node *un = VTOUNION(ap->a_vp);	struct vnode *vp = un->un_uppervp;	struct vattr *vap;	struct vattr va;	/*	 * Some programs walk the filesystem hierarchy by counting	 * links to directories to avoid stat'ing all the time.	 * This means the link count on directories needs to be "correct".	 * The only way to do that is to call getattr on both layers	 * and fix up the link count.  The link count will not necessarily	 * be accurate but will be large enough to defeat the tree walkers.	 */	vap = ap->a_vap;	vp = un->un_uppervp;	if (vp != NULLVP) {		FIXUP(un);		error = VOP_GETATTR(vp, vap, ap->a_cred, ap->a_p);		if (error)			return (error);	}	if (vp == NULLVP) {		vp = un->un_lowervp;	} else if (vp->v_type == VDIR) {		vp = un->un_lowervp;		vap = &va;	} else {		vp = NULLVP;	}	if (vp != NULLVP) {		VOP_LOCK(vp);		error = VOP_GETATTR(vp, vap, ap->a_cred, ap->a_p);		VOP_UNLOCK(vp);		if (error)			return (error);	}	if ((vap != ap->a_vap) && (vap->va_type == VDIR))		ap->a_vap->va_nlink += vap->va_nlink;	vap->va_fsid = ap->a_vp->v_mount->mnt_stat.f_fsid.val[0];	return (0);}intunion_setattr(ap)	struct vop_setattr_args /* {		struct vnode *a_vp;		struct vattr *a_vap;		struct ucred *a_cred;		struct proc *a_p;	} */ *ap;{	struct union_node *un = VTOUNION(ap->a_vp);	int error;	/*	 * Handle case of truncating lower object to zero size,	 * by creating a zero length upper object.  This is to	 * handle the case of open with O_TRUNC and O_CREAT.	 */	if ((un->un_uppervp == NULLVP) &&	    /* assert(un->un_lowervp != NULLVP) */	    (un->un_lowervp->v_type == VREG) &&	    (ap->a_vap->va_size == 0)) {		struct vnode *vp;		error = union_vn_create(&vp, un, ap->a_p);		if (error)			return (error);		/* at this point, uppervp is locked */		union_newupper(un, vp);		VOP_UNLOCK(vp);		union_vn_close(un->un_uppervp, FWRITE, ap->a_cred, ap->a_p);		VOP_LOCK(vp);		un->un_flags |= UN_ULOCK;	}	/*	 * Try to set attributes in upper layer,	 * otherwise return read-only filesystem error.	 */	if (un->un_uppervp != NULLVP) {		FIXUP(un);		error = VOP_SETATTR(un->un_uppervp, ap->a_vap,					ap->a_cred, ap->a_p);	} else {		error = EROFS;	}	return (error);}intunion_read(ap)	struct vop_read_args /* {		struct vnode *a_vp;		struct uio *a_uio;		int  a_ioflag;		struct ucred *a_cred;	} */ *ap;{	int error;	struct vnode *vp = OTHERVP(ap->a_vp);	int dolock = (vp == LOWERVP(ap->a_vp));	if (dolock)		VOP_LOCK(vp);	else		FIXUP(VTOUNION(ap->a_vp));	error = VOP_READ(vp, ap->a_uio, ap->a_ioflag, ap->a_cred);	if (dolock)		VOP_UNLOCK(vp);	return (error);}intunion_write(ap)	struct vop_read_args /* {		struct vnode *a_vp;		struct uio *a_uio;		int  a_ioflag;		struct ucred *a_cred;	} */ *ap;{	int error;	struct vnode *vp = OTHERVP(ap->a_vp);	int dolock = (vp == LOWERVP(ap->a_vp));	if (dolock)		VOP_LOCK(vp);	else		FIXUP(VTOUNION(ap->a_vp));	error = VOP_WRITE(vp, ap->a_uio, ap->a_ioflag, ap->a_cred);	if (dolock)		VOP_UNLOCK(vp);	return (error);}intunion_ioctl(ap)	struct vop_ioctl_args /* {		struct vnode *a_vp;		int  a_command;		caddr_t  a_data;		int  a_fflag;		struct ucred *a_cred;		struct proc *a_p;	} */ *ap;{	return (VOP_IOCTL(OTHERVP(ap->a_vp), ap->a_command, ap->a_data,				ap->a_fflag, ap->a_cred, ap->a_p));}intunion_select(ap)	struct vop_select_args /* {		struct vnode *a_vp;		int  a_which;		int  a_fflags;		struct ucred *a_cred;		struct proc *a_p;	} */ *ap;{	return (VOP_SELECT(OTHERVP(ap->a_vp), ap->a_which, ap->a_fflags,				ap->a_cred, ap->a_p));}intunion_mmap(ap)	struct vop_mmap_args /* {		struct vnode *a_vp;		int  a_fflags;		struct ucred *a_cred;		struct proc *a_p;	} */ *ap;{	return (VOP_MMAP(OTHERVP(ap->a_vp), ap->a_fflags,				ap->a_cred, ap->a_p));}intunion_fsync(ap)	struct vop_fsync_args /* {		struct vnode *a_vp;		struct ucred *a_cred;		int  a_waitfor;		struct proc *a_p;	} */ *ap;{	int error = 0;	struct vnode *targetvp = OTHERVP(ap->a_vp);	if (targetvp) {		int dolock = (targetvp == LOWERVP(ap->a_vp));		if (dolock)			VOP_LOCK(targetvp);		else			FIXUP(VTOUNION(ap->a_vp));		error = VOP_FSYNC(targetvp, ap->a_cred,					ap->a_waitfor, ap->a_p);		if (dolock)			VOP_UNLOCK(targetvp);	}	return (error);}intunion_seek(ap)	struct vop_seek_args /* {		struct vnode *a_vp;		off_t  a_oldoff;		off_t  a_newoff;		struct ucred *a_cred;	} */ *ap;{	return (VOP_SEEK(OTHERVP(ap->a_vp), ap->a_oldoff, ap->a_newoff, ap->a_cred));}intunion_remove(ap)	struct vop_remove_args /* {		struct vnode *a_dvp;		struct vnode *a_vp;		struct componentname *a_cnp;	} */ *ap;{	int error;	struct union_node *dun = VTOUNION(ap->a_dvp);	struct union_node *un = VTOUNION(ap->a_vp);	if (dun->un_uppervp && un->un_uppervp) {		struct vnode *dvp = dun->un_uppervp;		struct vnode *vp = un->un_uppervp;		FIXUP(dun);		VREF(dvp);		dun->un_flags |= UN_KLOCK;		vput(ap->a_dvp);		FIXUP(un);		VREF(vp);		un->un_flags |= UN_KLOCK;		vput(ap->a_vp);		error = VOP_REMOVE(dvp, vp, ap->a_cnp);		if (!error)			union_removed_upper(un);		/*		 * XXX: should create a whiteout here		 */	} else {		/*		 * XXX: should create a whiteout here		 */		vput(ap->a_dvp);		vput(ap->a_vp);		error = EROFS;	}	return (error);}intunion_link(ap)	struct vop_link_args /* {		struct vnode *a_vp;		struct vnode *a_tdvp;		struct componentname *a_cnp;	} */ *ap;{	int error;	struct union_node *dun = VTOUNION(ap->a_vp);	struct union_node *un = VTOUNION(ap->a_tdvp);	if (dun->un_uppervp && un->un_uppervp) {		struct vnode *dvp = dun->un_uppervp;		struct vnode *vp = un->un_uppervp;		FIXUP(dun);		VREF(dvp);		dun->un_flags |= UN_KLOCK;		vput(ap->a_vp);		FIXUP(un);		VREF(vp);		vrele(ap->a_tdvp);		error = VOP_LINK(dvp, vp, ap->a_cnp);	} else {		/*		 * XXX: need to copy to upper layer		 * and do the link there.		 */		vput(ap->a_vp);		vrele(ap->a_tdvp);		error = EROFS;	}	return (error);}intunion_rename(ap)	struct vop_rename_args  /* {		struct vnode *a_fdvp;		struct vnode *a_fvp;		struct componentname *a_fcnp;		struct vnode *a_tdvp;		struct vnode *a_tvp;		struct componentname *a_tcnp;	} */ *ap;{	int error;	struct vnode *fdvp = ap->a_fdvp;	struct vnode *fvp = ap->a_fvp;	struct vnode *tdvp = ap->a_tdvp;	struct vnode *tvp = ap->a_tvp;	if (fdvp->v_op == union_vnodeop_p) {	/* always true */		struct union_node *un = VTOUNION(fdvp);		if (un->un_uppervp == NULLVP) {			error = EROFS;			goto bad;		}		FIXUP(un);		fdvp = un->un_uppervp;		VREF(fdvp);		vrele(ap->a_fdvp);	}	if (fvp->v_op == union_vnodeop_p) {	/* always true */		struct union_node *un = VTOUNION(fvp);		if (un->un_uppervp == NULLVP) {			error = EROFS;			goto bad;		}		FIXUP(un);		fvp = un->un_uppervp;		VREF(fvp);		vrele(ap->a_fvp);	}	if (tdvp->v_op == union_vnodeop_p) {		struct union_node *un = VTOUNION(tdvp);		if (un->un_uppervp == NULLVP) {			error = EROFS;			goto bad;		}		tdvp = un->un_uppervp;		VREF(tdvp);		un->un_flags |= UN_KLOCK;		vput(ap->a_tdvp);	}	if (tvp && tvp->v_op == union_vnodeop_p) {		struct union_node *un = VTOUNION(tvp);		if (un->un_uppervp == NULLVP) {			error = EROFS;			goto bad;		}		tvp = un->un_uppervp;		VREF(tvp);		un->un_flags |= UN_KLOCK;		vput(ap->a_tvp);	}	return (VOP_RENAME(fdvp, fvp, ap->a_fcnp, tdvp, tvp, ap->a_tcnp));

⌨️ 快捷键说明

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