flatpak_dir_lookup_remote_filter (FlatpakDir *self,
                                  const char *name,
                                  gboolean    force_load,
                                  char      **checksum_out,
                                  GRegex    **allow_regex,
                                  GRegex    **deny_regex,
                                  GError **error)
{
  RemoteFilter *filter = NULL;
  g_autofree char *filter_path = NULL;
  gboolean handled_fallback = FALSE;
  g_autoptr(GFile) filter_file = NULL;

  if (checksum_out)
    *checksum_out = NULL;
  *allow_regex = NULL;
  *deny_regex = NULL;

  filter_path = flatpak_dir_get_remote_filter (self, name);

  if (filter_path == NULL)
    return TRUE;

  filter_file = g_file_new_for_path (filter_path);

  G_LOCK (filters);

  if (self->remote_filters == NULL)
    self->remote_filters = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) remote_filter_free);

  filter = g_hash_table_lookup (self->remote_filters, name);
  if (filter)
    {
      guint64 now = g_get_monotonic_time ();
      GTimeVal mtime;

      if (g_file_equal (filter->path, filter_file) != 0)
        filter = NULL; /* New path, reload */
      else if ((now - filter->last_mtime_check) > (1000 * (FILTER_MTIME_CHECK_TIMEOUT_MSEC)))
        {
          /* Fall back to backup copy if remote filter disappears */
          handled_fallback = TRUE;
          if (!g_file_query_exists (filter_file, NULL))
            {
              g_autofree char *basename = g_strconcat (name, ".filter", NULL);
              g_object_unref (filter_file);
              filter_file = flatpak_build_file (self->basedir, "repo", basename, NULL);
            }

          filter->last_mtime_check = now;
          if (!get_mtime (filter_file, &mtime, NULL, NULL) ||
              mtime.tv_sec != filter->mtime.tv_sec ||
              mtime.tv_usec != filter->mtime.tv_usec)
            filter = NULL; /* Different mtime, reload */
        }
    }

  if (filter)
    {
      if (checksum_out)
        *checksum_out = g_strdup (filter->checksum);
      if (filter->allow)
        *allow_regex = g_regex_ref (filter->allow);
      if (filter->deny)
        *deny_regex = g_regex_ref (filter->deny);
    }

  G_UNLOCK (filters);

  if (filter) /* This is outside the lock, but we already copied the returned data, and we're not dereferencing filter */
    return TRUE;

  /* Fall back to backup copy if remote filter disappears */
  if (!handled_fallback && !g_file_query_exists (filter_file, NULL))
    {
      g_autofree char *basename = g_strconcat (name, ".filter", NULL);
      g_object_unref (filter_file);
      filter_file = flatpak_build_file (self->basedir, "repo", basename, NULL);
    }

  filter = remote_filter_load (filter_file, error);
  if (filter == NULL)
    return FALSE;

  if (checksum_out)
    *checksum_out = g_strdup (filter->checksum);
  if (filter->allow)
    *allow_regex = g_regex_ref (filter->allow);
  if (filter->deny)
    *deny_regex = g_regex_ref (filter->deny);

  G_LOCK (filters);
  g_hash_table_replace (self->remote_filters, g_strdup (name), filter);
  G_UNLOCK (filters);

  return TRUE;
}
flatpak_dir_lookup_remote_filter (FlatpakDir *self,
                                  const char *name,
                                  gboolean    force_load,
                                  char      **checksum_out,
                                  GRegex    **allow_regex,
                                  GRegex    **deny_regex,
                                  GError **error)
{
  RemoteFilter *filter = NULL;
  g_autofree char *filter_path = NULL;
  gboolean handled_fallback = FALSE;
  g_autoptr(GFile) filter_file = NULL;

  if (checksum_out)
    *checksum_out = NULL;
  *allow_regex = NULL;
  *deny_regex = NULL;

  filter_path = flatpak_dir_get_remote_filter (self, name);

  if (filter_path == NULL)
    return TRUE;

  filter_file = g_file_new_for_path (filter_path);

  G_LOCK (filters);

  if (self->remote_filters == NULL)
    self->remote_filters = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) remote_filter_free);

  filter = g_hash_table_lookup (self->remote_filters, name);
  if (filter)
    {
      guint64 now = g_get_monotonic_time ();
      GTimeVal mtime;

      if (g_file_equal (filter->path, filter_file) != 0)
        filter = NULL;  
      else if ((now - filter->last_mtime_check) > (1000 * (FILTER_MTIME_CHECK_TIMEOUT_MSEC)))
        {
           
          handled_fallback = TRUE;
          if (!g_file_query_exists (filter_file, NULL))
            {
              g_autofree char *basename = g_strconcat (name, ".filter", NULL);
              g_object_unref (filter_file);
              filter_file = flatpak_build_file (self->basedir, "repo", basename, NULL);
            }

          filter->last_mtime_check = now;
          if (!get_mtime (filter_file, &mtime, NULL, NULL) ||
              mtime.tv_sec != filter->mtime.tv_sec ||
              mtime.tv_usec != filter->mtime.tv_usec)
            filter = NULL;  
        }
    }

  if (filter)
    {
      if (checksum_out)
        *checksum_out = g_strdup (filter->checksum);
      if (filter->allow)
        *allow_regex = g_regex_ref (filter->allow);
      if (filter->deny)
        *deny_regex = g_regex_ref (filter->deny);
    }

  G_UNLOCK (filters);

  if (filter)  
    return TRUE;

   
  if (!handled_fallback && !g_file_query_exists (filter_file, NULL))
    {
      g_autofree char *basename = g_strconcat (name, ".filter", NULL);
      g_object_unref (filter_file);
      filter_file = flatpak_build_file (self->basedir, "repo", basename, NULL);
    }

  filter = remote_filter_load (filter_file, error);
  if (filter == NULL)
    return FALSE;

  if (checksum_out)
    *checksum_out = g_strdup (filter->checksum);
  if (filter->allow)
    *allow_regex = g_regex_ref (filter->allow);
  if (filter->deny)
    *deny_regex = g_regex_ref (filter->deny);

  G_LOCK (filters);
  g_hash_table_replace (self->remote_filters, g_strdup (name), filter);
  G_UNLOCK (filters);

  return TRUE;
}