sys/vfs/union/union_vnops.c
static int
union_access(struct vop_access_args *ap)
{
	struct union_node *un = VTOUNION(ap->a_vp);
	struct thread *td = ap->a_td;
	int error = EACCES;
	struct vnode *vp;

	/*
	 * Disallow write attempts on filesystems mounted read-only.
	 */
	if ((ap->a_mode & VWRITE) && 
	    (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY)) {
		switch (ap->a_vp->v_type) {
		case VREG: 
		case VDIR:
		case VLNK:
			return (EROFS);
		default:
			break;
		}
	}

	if ((vp = union_lock_upper(un, td)) != NULLVP) {
		ap->a_head.a_ops = *vp->v_ops;
		ap->a_vp = vp;
		error = vop_access_ap(ap);
		union_unlock_upper(vp, td);
		return(error);
	}

	if ((vp = un->un_lowervp) != NULLVP) {
		vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
		ap->a_head.a_ops = *vp->v_ops;
		ap->a_vp = vp;

		/*
		 * Remove VWRITE from a_mode if our mount point is RW, because
		 * we want to allow writes and lowervp may be read-only.
		 */
		if ((un->un_vnode->v_mount->mnt_flag & MNT_RDONLY) == 0)
			ap->a_mode &= ~VWRITE;

		error = vop_access_ap(ap);
		if (error == 0) {
			struct union_mount *um;

			um = MOUNTTOUNIONMOUNT(un->un_vnode->v_mount);

			if (um->um_op == UNMNT_BELOW) {
				ap->a_cred = um->um_cred;
				error = vop_access_ap(ap);
			}
		}
		vn_unlock(vp);
	}
	return(error);
}
/*
 * 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.
 *
 * union_access(struct vnode *a_vp, int a_mode,
 *		struct ucred *a_cred, struct thread *a_td)
 */
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.


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 .
static int
union_access(struct vop_access_args *ap)
{
	struct union_node *un = VTOUNION(ap->a_vp);
	struct thread *td = ap->a_td;
	int error = EACCES;
	struct vnode *vp;
	if ((ap->a_mode & VWRITE) && 
	    (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY)) {
		switch (ap->a_vp->v_type) {
		case VREG: 
		case VDIR:
		case VLNK:
			return (EROFS);
		default:
			break;
		}
	}
	if ((vp = union_lock_upper(un, td)) != NULLVP) {
		ap->a_head.a_ops = *vp->v_ops;
		ap->a_vp = vp;
		error = vop_access_ap(ap);
		union_unlock_upper(vp, td);
		return(error);
	}
	if ((vp = un->un_lowervp) != NULLVP) {
		vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
		ap->a_head.a_ops = *vp->v_ops;
		ap->a_vp = vp;
		if ((un->un_vnode->v_mount->mnt_flag & MNT_RDONLY) == 0)
			ap->a_mode &= ~VWRITE;
		error = vop_access_ap(ap);
		if (error == 0) {
			struct union_mount *um;
			um = MOUNTTOUNIONMOUNT(un->un_vnode->v_mount);
			if (um->um_op == UNMNT_BELOW) {
				ap->a_cred = um->um_cred;
				error = vop_access_ap(ap);
			}
		}
		vn_unlock(vp);
	}
	return(error);
}
static int union_access ( struct vop_access_args * ap ) { struct union_node * un = VTOUNION ( ap -> a_vp ) ; struct thread * td = ap -> a_td ; int error = EACCES ; struct vnode * vp ; if ( ( ap -> a_mode & VWRITE ) && ( ap -> a_vp -> v_mount -> mnt_flag & MNT_RDONLY ) ) { switch ( ap -> a_vp -> v_type ) { case VREG : case VDIR : case VLNK : return ( EROFS ) ; default : break ; } } if ( ( vp = union_lock_upper ( un , td ) ) != NULLVP ) { ap -> a_head . a_ops = * vp -> v_ops ; ap -> a_vp = vp ; error = vop_access_ap ( ap ) ; union_unlock_upper ( vp , td ) ; return ( error ) ; } if ( ( vp = un -> un_lowervp ) != NULLVP ) { vn_lock ( vp , LK_EXCLUSIVE | LK_RETRY ) ; ap -> a_head . a_ops = * vp -> v_ops ; ap -> a_vp = vp ; if ( ( un -> un_vnode -> v_mount -> mnt_flag & MNT_RDONLY ) == 0 ) ap -> a_mode &= ~ VWRITE ; error = vop_access_ap ( ap ) ; if ( error == 0 ) { struct union_mount * um ; um = MOUNTTOUNIONMOUNT ( un -> un_vnode -> v_mount ) ; if ( um -> um_op == UNMNT_BELOW ) { ap -> a_cred = um -> um_cred ; error = vop_access_ap ( ap ) ; } } vn_unlock ( vp ) ; } return ( error ) ; }
Check access permission on the union vnode.
Check access permission on the union vnode .
/*
	 * Disallow write attempts on filesystems mounted read-only.
	 */ /*
		 * Remove VWRITE from a_mode if our mount point is RW, because
		 * we want to allow writes and lowervp may be read-only.
		 */