translate_acl(struct archive_read_disk *a,
    struct archive_entry *entry, void *aclp, int aclcnt,
    int default_entry_acl_type)
{
	int e, i;
	int ae_id, ae_tag, ae_perm;
	int entry_acl_type;
	const char *ae_name;
	aclent_t *aclent;
#if ARCHIVE_ACL_SUNOS_NFS4
	ace_t *ace;
#endif

	if (aclcnt <= 0)
		return (ARCHIVE_OK);

	for (e = 0; e < aclcnt; e++) {
		ae_name = NULL;
		ae_tag = 0;
		ae_perm = 0;

#if ARCHIVE_ACL_SUNOS_NFS4
		if (default_entry_acl_type == ARCHIVE_ENTRY_ACL_TYPE_NFS4) {
			ace = &((ace_t *)aclp)[e];
			ae_id = ace->a_who;

			switch(ace->a_type) {
			case ACE_ACCESS_ALLOWED_ACE_TYPE:
				entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ALLOW;
				break;
			case ACE_ACCESS_DENIED_ACE_TYPE:
				entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_DENY;
				break;
			case ACE_SYSTEM_AUDIT_ACE_TYPE:
				entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS;
				break;
			case ACE_SYSTEM_ALARM_ACE_TYPE:
				entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ALARM;
				break;
			default:
				/* Unknown entry type, skip */
				continue;
			}

			if ((ace->a_flags & ACE_OWNER) != 0)
				ae_tag = ARCHIVE_ENTRY_ACL_USER_OBJ;
			else if ((ace->a_flags & ACE_GROUP) != 0)
				ae_tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ;
			else if ((ace->a_flags & ACE_EVERYONE) != 0)
				ae_tag = ARCHIVE_ENTRY_ACL_EVERYONE;
			else if ((ace->a_flags & ACE_IDENTIFIER_GROUP) != 0) {
				ae_tag = ARCHIVE_ENTRY_ACL_GROUP;
				ae_name = archive_read_disk_gname(&a->archive,
				    ae_id);
			} else {
				ae_tag = ARCHIVE_ENTRY_ACL_USER;
				ae_name = archive_read_disk_uname(&a->archive,
				    ae_id);
			}

			for (i = 0; i < acl_nfs4_flag_map_size; ++i) {
				if ((ace->a_flags &
				    acl_nfs4_flag_map[i].p_perm) != 0)
					ae_perm |= acl_nfs4_flag_map[i].a_perm;
			}

			for (i = 0; i < acl_nfs4_perm_map_size; ++i) {
				if ((ace->a_access_mask &
				    acl_nfs4_perm_map[i].p_perm) != 0)
					ae_perm |= acl_nfs4_perm_map[i].a_perm;
			}
		} else
#endif	/* ARCHIVE_ACL_SUNOS_NFS4 */
		if (default_entry_acl_type == ARCHIVE_ENTRY_ACL_TYPE_ACCESS) {
			aclent = &((aclent_t *)aclp)[e];
			if ((aclent->a_type & ACL_DEFAULT) != 0)
				entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_DEFAULT;
			else
				entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS;
			ae_id = aclent->a_id;

			switch(aclent->a_type) {
			case DEF_USER:
			case USER:
				ae_name = archive_read_disk_uname(&a->archive,
				    ae_id);
				ae_tag = ARCHIVE_ENTRY_ACL_USER;
				break;
			case DEF_GROUP:
			case GROUP:
				ae_name = archive_read_disk_gname(&a->archive,
				    ae_id);
				ae_tag = ARCHIVE_ENTRY_ACL_GROUP;
				break;
			case DEF_CLASS_OBJ:
			case CLASS_OBJ:
				ae_tag = ARCHIVE_ENTRY_ACL_MASK;
				break;
			case DEF_USER_OBJ:
			case USER_OBJ:
				ae_tag = ARCHIVE_ENTRY_ACL_USER_OBJ;
				break;
			case DEF_GROUP_OBJ:
			case GROUP_OBJ:
				ae_tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ;
				break;
			case DEF_OTHER_OBJ:
			case OTHER_OBJ:
				ae_tag = ARCHIVE_ENTRY_ACL_OTHER;
				break;
			default:
				/* Unknown tag type, skip */
				continue;
			}

			for (i = 0; i < acl_posix_perm_map_size; ++i) {
				if ((aclent->a_perm &
				    acl_posix_perm_map[i].p_perm) != 0)
					ae_perm |= acl_posix_perm_map[i].a_perm;
			}
		} else
			return (ARCHIVE_WARN);

		archive_entry_acl_add_entry(entry, entry_acl_type,
		    ae_perm, ae_tag, ae_id, ae_name);
	}
	return (ARCHIVE_OK);
}