zfs_acl_ids_create(znode_t *dzp, int flag, vattr_t *vap, cred_t *cr,
    vsecattr_t *vsecp, zfs_acl_ids_t *acl_ids)
{
	int		error;
	zfsvfs_t	*zfsvfs = dzp->z_zfsvfs;
	zfs_acl_t	*paclp;
	gid_t		gid;
	boolean_t	need_chmod = B_TRUE;
	boolean_t	trim = B_FALSE;
	boolean_t	inherited = B_FALSE;

	if ((flag & IS_ROOT_NODE) == 0) {
		if (zfsvfs->z_replay == B_FALSE)
			ASSERT_VOP_ELOCKED(ZTOV(dzp), __func__);
	} else
		ASSERT(dzp->z_vnode == NULL);
	bzero(acl_ids, sizeof (zfs_acl_ids_t));
	acl_ids->z_mode = MAKEIMODE(vap->va_type, vap->va_mode);

	if (vsecp)
		if ((error = zfs_vsec_2_aclp(zfsvfs, vap->va_type, vsecp, cr,
		    &acl_ids->z_fuidp, &acl_ids->z_aclp)) != 0)
			return (error);
	/*
	 * Determine uid and gid.
	 */
	if ((flag & IS_ROOT_NODE) || zfsvfs->z_replay ||
	    ((flag & IS_XATTR) && (vap->va_type == VDIR))) {
		acl_ids->z_fuid = zfs_fuid_create(zfsvfs,
		    (uint64_t)vap->va_uid, cr,
		    ZFS_OWNER, &acl_ids->z_fuidp);
		acl_ids->z_fgid = zfs_fuid_create(zfsvfs,
		    (uint64_t)vap->va_gid, cr,
		    ZFS_GROUP, &acl_ids->z_fuidp);
		gid = vap->va_gid;
	} else {
		acl_ids->z_fuid = zfs_fuid_create_cred(zfsvfs, ZFS_OWNER,
		    cr, &acl_ids->z_fuidp);
		acl_ids->z_fgid = 0;
		if (vap->va_mask & AT_GID)  {
			acl_ids->z_fgid = zfs_fuid_create(zfsvfs,
			    (uint64_t)vap->va_gid,
			    cr, ZFS_GROUP, &acl_ids->z_fuidp);
			gid = vap->va_gid;
			if (acl_ids->z_fgid != dzp->z_gid &&
			    !groupmember(vap->va_gid, cr) &&
			    secpolicy_vnode_create_gid(cr) != 0)
				acl_ids->z_fgid = 0;
		}
		if (acl_ids->z_fgid == 0) {
			char		*domain;
			uint32_t	rid;

			acl_ids->z_fgid = dzp->z_gid;
			gid = zfs_fuid_map_id(zfsvfs, acl_ids->z_fgid,
			    cr, ZFS_GROUP);

			if (zfsvfs->z_use_fuids &&
			    IS_EPHEMERAL(acl_ids->z_fgid)) {
				domain =
				    zfs_fuid_idx_domain(&zfsvfs->z_fuid_idx,
				    FUID_INDEX(acl_ids->z_fgid));
				rid = FUID_RID(acl_ids->z_fgid);
				zfs_fuid_node_add(&acl_ids->z_fuidp,
				    domain, rid, FUID_INDEX(acl_ids->z_fgid),
				    acl_ids->z_fgid, ZFS_GROUP);
			}
		}
	}

	/*
	 * If we're creating a directory, and the parent directory has the
	 * set-GID bit set, set in on the new directory.
	 * Otherwise, if the user is neither privileged nor a member of the
	 * file's new group, clear the file's set-GID bit.
	 */

	if (!(flag & IS_ROOT_NODE) && (dzp->z_mode & S_ISGID) &&
	    (vap->va_type == VDIR)) {
		acl_ids->z_mode |= S_ISGID;
	} else {
		if ((acl_ids->z_mode & S_ISGID) &&
		    secpolicy_vnode_setids_setgids(ZTOV(dzp), cr, gid) != 0)
			acl_ids->z_mode &= ~S_ISGID;
	}

	if (acl_ids->z_aclp == NULL) {
		mutex_enter(&dzp->z_acl_lock);
		if (!(flag & IS_ROOT_NODE) &&
		    (dzp->z_pflags & ZFS_INHERIT_ACE) &&
		    !(dzp->z_pflags & ZFS_XATTR)) {
			VERIFY0(zfs_acl_node_read(dzp, B_TRUE,
			    &paclp, B_FALSE));
			acl_ids->z_aclp = zfs_acl_inherit(zfsvfs,
			    vap->va_type, paclp, acl_ids->z_mode, &need_chmod);
			inherited = B_TRUE;
		} else {
			acl_ids->z_aclp =
			    zfs_acl_alloc(zfs_acl_version_zp(dzp));
			acl_ids->z_aclp->z_hints |= ZFS_ACL_TRIVIAL;
		}
		mutex_exit(&dzp->z_acl_lock);

		if (need_chmod) {
			if (vap->va_type == VDIR)
				acl_ids->z_aclp->z_hints |=
				    ZFS_ACL_AUTO_INHERIT;

			if (zfsvfs->z_acl_mode == ZFS_ACL_GROUPMASK &&
			    zfsvfs->z_acl_inherit != ZFS_ACL_PASSTHROUGH &&
			    zfsvfs->z_acl_inherit != ZFS_ACL_PASSTHROUGH_X)
				trim = B_TRUE;
			zfs_acl_chmod(vap->va_type, acl_ids->z_mode, B_FALSE,
			    trim, acl_ids->z_aclp);
		}
	}

	if (inherited || vsecp) {
		acl_ids->z_mode = zfs_mode_compute(acl_ids->z_mode,
		    acl_ids->z_aclp, &acl_ids->z_aclp->z_hints,
		    acl_ids->z_fuid, acl_ids->z_fgid);
		if (ace_trivial_common(acl_ids->z_aclp, 0, zfs_ace_walk) == 0)
			acl_ids->z_aclp->z_hints |= ZFS_ACL_TRIVIAL;
	}

	return (0);
}