flatpak_dir_gc_cached_digested_summaries (FlatpakDir   *self,
                                          const char   *remote_name,
                                          const char   *dont_prune_file,
                                          GCancellable *cancellable,
                                          GError      **error)
{
  g_autoptr(GHashTable) cached_data_for_arch = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify)cached_summary_data_free);
  g_autoptr(GFile) cache_dir = flatpak_build_file (self->cache_dir, "summaries", NULL);
  g_auto(GLnxDirFdIterator) iter = {0};
  struct dirent *dent;
  g_autoptr(GError) local_error = NULL;

  if (!glnx_dirfd_iterator_init_at (AT_FDCWD, flatpak_file_get_path_cached (cache_dir), FALSE, &iter, &local_error))
    {
      if (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
        return TRUE;

      g_propagate_error (error, g_steal_pointer (&local_error));
      return FALSE;
    }

  g_autofree char *prefix = g_strconcat (remote_name, "-", NULL);

  while (TRUE)
    {
      struct stat stbuf;
      const char *arch_start, *arch_end;
      g_autofree char *arch = NULL;

      if (!glnx_dirfd_iterator_next_dent_ensure_dtype (&iter, &dent, cancellable, error))
        return FALSE;

      if (dent == NULL)
        break;

      /* Cached are regular file named "${remote-name}-${arch}-${sha256}.sub", ignore anything else */
      if (dent->d_type != DT_REG ||
          !g_str_has_prefix (dent->d_name, prefix) ||
          !g_str_has_suffix (dent->d_name, ".sub"))
        continue;

      arch_start = dent->d_name + strlen (prefix);
      arch_end = strchr (arch_start, '-');
      if (arch_end == NULL)
        continue;

      /* Keep the latest subsummary for each remote-name + arch so we can use it for deltas */
      if (fstatat (iter.fd, dent->d_name, &stbuf, AT_SYMLINK_NOFOLLOW) == -1)
        {
          glnx_set_error_from_errno (error);
          return FALSE;
        }

      arch = g_strndup (arch_start, arch_end - arch_start);

      CachedSummaryData *old_data = g_hash_table_lookup (cached_data_for_arch, arch);
      if (old_data == NULL || stbuf.st_mtime > old_data->mtime)
        {
          CachedSummaryData *new_data;

          if (old_data &&
              strcmp (dont_prune_file, old_data->filename) != 0 &&
              unlinkat (iter.fd, old_data->filename, 0) != 0)
            {
              glnx_set_error_from_errno (error);
              return FALSE;
            }

          new_data = g_new0 (CachedSummaryData, 1);
          new_data->filename = g_strdup (dent->d_name);
          new_data->mtime = stbuf.st_mtime;
          g_hash_table_insert (cached_data_for_arch, g_steal_pointer (&arch), new_data);
        }
      else /* stbuf.st_mtime <= old_data->mtime */
        {
          if (stbuf.st_mtime < old_data->mtime &&
              strcmp (dont_prune_file, dent->d_name) != 0 &&
              unlinkat (iter.fd, dent->d_name, 0) != 0)
            {
              glnx_set_error_from_errno (error);
              return FALSE;
            }
        }
    }

  return TRUE;
}
flatpak_dir_gc_cached_digested_summaries (FlatpakDir   *self,
                                          const char   *remote_name,
                                          const char   *dont_prune_file,
                                          GCancellable *cancellable,
                                          GError      **error)
{
  g_autoptr(GHashTable) cached_data_for_arch = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify)cached_summary_data_free);
  g_autoptr(GFile) cache_dir = flatpak_build_file (self->cache_dir, "summaries", NULL);
  g_auto(GLnxDirFdIterator) iter = {0};
  struct dirent *dent;
  g_autoptr(GError) local_error = NULL;

  if (!glnx_dirfd_iterator_init_at (AT_FDCWD, flatpak_file_get_path_cached (cache_dir), FALSE, &iter, &local_error))
    {
      if (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
        return TRUE;

      g_propagate_error (error, g_steal_pointer (&local_error));
      return FALSE;
    }

  g_autofree char *prefix = g_strconcat (remote_name, "-", NULL);

  while (TRUE)
    {
      struct stat stbuf;
      const char *arch_start, *arch_end;
      g_autofree char *arch = NULL;

      if (!glnx_dirfd_iterator_next_dent_ensure_dtype (&iter, &dent, cancellable, error))
        return FALSE;

      if (dent == NULL)
        break;

       
      if (dent->d_type != DT_REG ||
          !g_str_has_prefix (dent->d_name, prefix) ||
          !g_str_has_suffix (dent->d_name, ".sub"))
        continue;

      arch_start = dent->d_name + strlen (prefix);
      arch_end = strchr (arch_start, '-');
      if (arch_end == NULL)
        continue;

       
      if (fstatat (iter.fd, dent->d_name, &stbuf, AT_SYMLINK_NOFOLLOW) == -1)
        {
          glnx_set_error_from_errno (error);
          return FALSE;
        }

      arch = g_strndup (arch_start, arch_end - arch_start);

      CachedSummaryData *old_data = g_hash_table_lookup (cached_data_for_arch, arch);
      if (old_data == NULL || stbuf.st_mtime > old_data->mtime)
        {
          CachedSummaryData *new_data;

          if (old_data &&
              strcmp (dont_prune_file, old_data->filename) != 0 &&
              unlinkat (iter.fd, old_data->filename, 0) != 0)
            {
              glnx_set_error_from_errno (error);
              return FALSE;
            }

          new_data = g_new0 (CachedSummaryData, 1);
          new_data->filename = g_strdup (dent->d_name);
          new_data->mtime = stbuf.st_mtime;
          g_hash_table_insert (cached_data_for_arch, g_steal_pointer (&arch), new_data);
        }
      else  
        {
          if (stbuf.st_mtime < old_data->mtime &&
              strcmp (dont_prune_file, dent->d_name) != 0 &&
              unlinkat (iter.fd, dent->d_name, 0) != 0)
            {
              glnx_set_error_from_errno (error);
              return FALSE;
            }
        }
    }

  return TRUE;
}