From d7bc26031c6984080ff2a3ca8927de07ddc28d70 Mon Sep 17 00:00:00 2001 From: Alexander Larsson Date: Wed, 8 May 2019 15:05:20 +0200 Subject: [PATCH] filters: Make a backup copy of the filter when it is set and use when needed We still look at the regular file to pick up changes, but to avoid issues if the file disappears (for example if it was in a package that was uninstalled) then we still have something to show so we don't start accidentally showing unfiltered stuff. Closes: #2890 Approved by: alexlarsson --- common/flatpak-dir.c | 45 ++++++++++++++++++++++++++++++++++++++++++++ tests/test-repo.sh | 23 ++++++++++++++++++++-- 2 files changed, 66 insertions(+), 2 deletions(-) diff --git a/common/flatpak-dir.c b/common/flatpak-dir.c index 0783ede0..e1ba91d4 100644 --- a/common/flatpak-dir.c +++ b/common/flatpak-dir.c @@ -10302,6 +10302,7 @@ flatpak_dir_lookup_remote_filter (FlatpakDir *self, { RemoteFilter *filter = NULL; const char *filter_path; + gboolean handled_fallback = FALSE; g_autoptr(GFile) filter_file = NULL; if (checksum_out) @@ -10331,6 +10332,15 @@ flatpak_dir_lookup_remote_filter (FlatpakDir *self, 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)) + { + 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 || @@ -10354,6 +10364,14 @@ flatpak_dir_lookup_remote_filter (FlatpakDir *self, 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)) + { + 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; @@ -12741,6 +12759,7 @@ flatpak_dir_modify_remote (FlatpakDir *self, g_autofree char *url = NULL; g_autofree char *metalink = NULL; g_autoptr(GKeyFile) new_config = NULL; + g_autofree gchar *filter_path = NULL; gboolean has_remote; if (strchr (remote_name, '/') != NULL) @@ -12819,6 +12838,32 @@ flatpak_dir_modify_remote (FlatpakDir *self, imported, (imported == 1) ? "" : "s", remote_name); } + filter_path = g_key_file_get_value (new_config, group, "xa.filter", NULL); + if (filter_path && *filter_path && g_file_test (filter_path, G_FILE_TEST_EXISTS)) + { + /* Make a backup filter copy in case it goes away later */ + char *filter_name = g_strconcat (remote_name, ".filter", NULL); + g_autoptr(GFile) filter_file = g_file_new_for_path (filter_path); + g_autoptr(GFile) filter_copy = flatpak_build_file (self->basedir, "repo", filter_name, NULL); + g_autoptr(GError) local_error = NULL; + g_autofree char *backup_data = NULL; + gsize backup_data_size; + + if (g_file_load_contents (filter_file, cancellable, &backup_data, &backup_data_size, NULL, &local_error)) + { + g_autofree char *backup_data_copy = + g_strdup_printf ("# backup copy of %s, do not edit!\n%s", filter_path, backup_data); + + if (!g_file_replace_contents (filter_copy, backup_data_copy, strlen (backup_data_copy), + NULL, FALSE, G_FILE_CREATE_REPLACE_DESTINATION, NULL, cancellable, &local_error)) + g_debug ("Failed to save backup copy of filter file %s: %s\n", filter_path, local_error->message); + } + else + { + g_debug ("Failed to read filter %s file while making a backup copy: %s\n", filter_path, local_error->message); + } + } + if (!flatpak_dir_mark_changed (self, error)) return FALSE; diff --git a/tests/test-repo.sh b/tests/test-repo.sh index c0db3a92..028a3f10 100644 --- a/tests/test-repo.sh +++ b/tests/test-repo.sh @@ -620,8 +620,9 @@ assert_file_has_content remote-ref-info "ID: org\.test\.Hello" ${FLATPAK} ${U} update --appstream test-repo assert_file_has_content $FL_DIR/appstream/test-repo/$ARCH/active/appstream.xml "app/org\.test\.Hello" - -${FLATPAK} ${U} remote-modify test-repo --filter ${test_builddir}/test.filter +# Make a copy so we can remove it later +cp ${test_builddir}/test.filter test.filter +${FLATPAK} ${U} remote-modify test-repo --filter $(pwd)/test.filter ${FLATPAK} ${U} remote-ls -d -a test-repo > remote-ls-log @@ -640,6 +641,24 @@ fi ${FLATPAK} ${U} update --appstream test-repo assert_not_file_has_content $FL_DIR/appstream/test-repo/$ARCH/active/appstream.xml "app/org\.test\.Hello" +# Ensure that filter works even when the filter file is removed (uses the backup) +rm test.filter +${FLATPAK} ${U} remote-ls -d -a test-repo > remote-ls-log +assert_not_file_has_content remote-ls-log "app/org\.test\.Hello" +assert_not_file_has_content remote-ls-log "runtime/org\.test\.Hello\.Locale" +assert_file_has_content remote-ls-log "runtime/org\.test\.Platform" +if ${FLATPAK} ${U} remote-info test-repo org.test.Hello > remote-ref-info; then + assert_not_reached "flatpak remote-info test-repo org.test.Hello should fail due to filter" +fi +if ${FLATPAK} ${U} install -y test-repo org.test.Hello; then + assert_not_reached "should not be able to install org.test.Hello should fail due to filter" +fi + +${FLATPAK} ${U} update --appstream test-repo +assert_not_file_has_content $FL_DIR/appstream/test-repo/$ARCH/active/appstream.xml "app/org\.test\.Hello" + +# Remove filter + ${FLATPAK} ${U} remote-modify test-repo --no-filter ${FLATPAK} ${U} remote-ls -d -a test-repo > remote-ls-log