flatpak_dir_list_refs (FlatpakDir   *self,
                       FlatpakKinds kinds,
                       GCancellable *cancellable,
                       GError      **error)
{
  g_autoptr(GPtrArray) refs = NULL;

  refs = g_ptr_array_new_with_free_func ((GDestroyNotify)flatpak_decomposed_unref);

  if (kinds & FLATPAK_KINDS_APP)
    {
      g_autoptr(GFile) base = NULL;
      g_autoptr(GFileEnumerator) dir_enum = NULL;
      g_autoptr(GFileInfo) child_info = NULL;
      GError *temp_error = NULL;

      base = g_file_get_child (flatpak_dir_get_path (self), "app");

      if (g_file_query_exists (base, cancellable))
        {
          dir_enum = g_file_enumerate_children (base, OSTREE_GIO_FAST_QUERYINFO,
                                                G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
                                                cancellable, error);
          if (!dir_enum)
            return NULL;

          while ((child_info = g_file_enumerator_next_file (dir_enum, cancellable, &temp_error)))
            {
              const char *name = g_file_info_get_name (child_info);

              if (g_file_info_get_file_type (child_info) != G_FILE_TYPE_DIRECTORY)
                {
                  g_clear_object (&child_info);
                  continue;
                }

              if (!_flatpak_dir_list_refs_for_name (self, base, FLATPAK_KINDS_APP, name, refs, cancellable, error))
                return NULL;

              g_clear_object (&child_info);
            }

          if (temp_error != NULL)
            {
              g_propagate_error (error, temp_error);
              return NULL;
            }
        }
    }

  if (kinds & FLATPAK_KINDS_RUNTIME)
    {
      g_autoptr(GFile) base = NULL;
      g_autoptr(GFileEnumerator) dir_enum = NULL;
      g_autoptr(GFileInfo) child_info = NULL;
      GError *temp_error = NULL;

      base = g_file_get_child (flatpak_dir_get_path (self), "runtime");

      if (g_file_query_exists (base, cancellable))
        {
          dir_enum = g_file_enumerate_children (base, OSTREE_GIO_FAST_QUERYINFO,
                                                G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
                                                cancellable, error);
          if (!dir_enum)
            return NULL;

          while ((child_info = g_file_enumerator_next_file (dir_enum, cancellable, &temp_error)))
            {
              const char *name = g_file_info_get_name (child_info);

              if (g_file_info_get_file_type (child_info) != G_FILE_TYPE_DIRECTORY)
                {
                  g_clear_object (&child_info);
                  continue;
                }

              if (!_flatpak_dir_list_refs_for_name (self, base, FLATPAK_KINDS_RUNTIME, name, refs, cancellable, error))
                return NULL;

              g_clear_object (&child_info);
            }

          if (temp_error != NULL)
            {
              g_propagate_error (error, temp_error);
              return NULL;
            }
        }
    }

  g_ptr_array_sort (refs, (GCompareFunc)flatpak_decomposed_strcmp_p);

  return g_steal_pointer (&refs);
}
flatpak_dir_list_refs (FlatpakDir   *self,
                       FlatpakKinds kinds,
                       GCancellable *cancellable,
                       GError      **error)
{
  g_autoptr(GPtrArray) refs = NULL;

  refs = g_ptr_array_new_with_free_func ((GDestroyNotify)flatpak_decomposed_unref);

  if (kinds & FLATPAK_KINDS_APP)
    {
      g_autoptr(GFile) base = NULL;
      g_autoptr(GFileEnumerator) dir_enum = NULL;
      g_autoptr(GFileInfo) child_info = NULL;
      GError *temp_error = NULL;

      base = g_file_get_child (flatpak_dir_get_path (self), "app");

      if (g_file_query_exists (base, cancellable))
        {
          dir_enum = g_file_enumerate_children (base, OSTREE_GIO_FAST_QUERYINFO,
                                                G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
                                                cancellable, error);
          if (!dir_enum)
            return NULL;

          while ((child_info = g_file_enumerator_next_file (dir_enum, cancellable, &temp_error)))
            {
              const char *name = g_file_info_get_name (child_info);

              if (g_file_info_get_file_type (child_info) != G_FILE_TYPE_DIRECTORY)
                {
                  g_clear_object (&child_info);
                  continue;
                }

              if (!_flatpak_dir_list_refs_for_name (self, base, FLATPAK_KINDS_APP, name, refs, cancellable, error))
                return NULL;

              g_clear_object (&child_info);
            }

          if (temp_error != NULL)
            {
              g_propagate_error (error, temp_error);
              return NULL;
            }
        }
    }

  if (kinds & FLATPAK_KINDS_RUNTIME)
    {
      g_autoptr(GFile) base = NULL;
      g_autoptr(GFileEnumerator) dir_enum = NULL;
      g_autoptr(GFileInfo) child_info = NULL;
      GError *temp_error = NULL;

      base = g_file_get_child (flatpak_dir_get_path (self), "runtime");

      if (g_file_query_exists (base, cancellable))
        {
          dir_enum = g_file_enumerate_children (base, OSTREE_GIO_FAST_QUERYINFO,
                                                G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
                                                cancellable, error);
          if (!dir_enum)
            return NULL;

          while ((child_info = g_file_enumerator_next_file (dir_enum, cancellable, &temp_error)))
            {
              const char *name = g_file_info_get_name (child_info);

              if (g_file_info_get_file_type (child_info) != G_FILE_TYPE_DIRECTORY)
                {
                  g_clear_object (&child_info);
                  continue;
                }

              if (!_flatpak_dir_list_refs_for_name (self, base, FLATPAK_KINDS_RUNTIME, name, refs, cancellable, error))
                return NULL;

              g_clear_object (&child_info);
            }

          if (temp_error != NULL)
            {
              g_propagate_error (error, temp_error);
              return NULL;
            }
        }
    }

  g_ptr_array_sort (refs, (GCompareFunc)flatpak_decomposed_strcmp_p);

  return g_steal_pointer (&refs);
}