From afa12b6ba502e5acaa431415aa3b939ddb377382 Mon Sep 17 00:00:00 2001 From: Milan Crha Date: Mon, 16 Feb 2026 18:20:34 +0100 Subject: [PATCH] I#627 - Canonicalize path before local cache file removal Closes https://gitlab.gnome.org/GNOME/evolution-data-server/-/issues/627 --- .../backends/file/e-book-backend-file.c | 2 +- .../libedata-book/e-book-meta-backend.c | 2 +- src/calendar/libedata-cal/e-cal-cache.c | 2 +- src/libedataserver/e-data-server-util.c | 42 ++++++++++++++++++ src/libedataserver/e-data-server-util.h | 2 + tests/libedataserver/libedataserver-test.c | 43 +++++++++++++++++++ 6 files changed, 90 insertions(+), 3 deletions(-) diff -urp evolution-data-server-3.58.3.orig/src/addressbook/backends/file/e-book-backend-file.c evolution-data-server-3.58.3/src/addressbook/backends/file/e-book-backend-file.c --- evolution-data-server-3.58.3.orig/src/addressbook/backends/file/e-book-backend-file.c 2026-02-23 13:52:32.688903333 -0600 +++ evolution-data-server-3.58.3/src/addressbook/backends/file/e-book-backend-file.c 2026-02-23 14:07:47.807663557 -0600 @@ -392,7 +392,7 @@ maybe_delete_uri (EBookBackendFile *bf, /* If the file is in our path it belongs to us and we need to delete it. */ if (bf->priv->photo_dirname && - !strncmp (bf->priv->photo_dirname, filename, strlen (bf->priv->photo_dirname))) { + e_util_filename_is_in_path (filename, bf->priv->photo_dirname)) { d (g_print ("Deleting uri file: %s\n", filename)); diff -urp evolution-data-server-3.58.3.orig/src/addressbook/libedata-book/e-book-meta-backend.c evolution-data-server-3.58.3/src/addressbook/libedata-book/e-book-meta-backend.c --- evolution-data-server-3.58.3.orig/src/addressbook/libedata-book/e-book-meta-backend.c 2026-02-23 13:52:32.702903481 -0600 +++ evolution-data-server-3.58.3/src/addressbook/libedata-book/e-book-meta-backend.c 2026-02-23 14:07:47.808137174 -0600 @@ -586,7 +586,7 @@ ebmb_gather_photos_local_filenames (EBoo gchar *filename; filename = g_filename_from_uri (url, NULL, NULL); - if (filename && g_str_has_prefix (filename, cache_path)) + if (filename && e_util_filename_is_in_path (filename, cache_path)) filenames = g_slist_prepend (filenames, filename); else g_free (filename); diff -urp evolution-data-server-3.58.3.orig/src/calendar/libedata-cal/e-cal-cache.c evolution-data-server-3.58.3/src/calendar/libedata-cal/e-cal-cache.c --- evolution-data-server-3.58.3.orig/src/calendar/libedata-cal/e-cal-cache.c 2026-02-23 13:52:32.722903693 -0600 +++ evolution-data-server-3.58.3/src/calendar/libedata-cal/e-cal-cache.c 2026-02-23 14:07:47.808526161 -0600 @@ -3707,7 +3707,7 @@ e_cal_cache_delete_attachments (ECalCach if (!cache_dirname) cache_dirname = g_path_get_dirname (e_cache_get_filename (E_CACHE (cal_cache))); - if (g_str_has_prefix (filename, cache_dirname) && + if (e_util_filename_is_in_path (filename, cache_dirname) && g_unlink (filename) == -1) { /* Ignore these errors */ } diff -urp evolution-data-server-3.58.3.orig/src/libedataserver/e-data-server-util.c evolution-data-server-3.58.3/src/libedataserver/e-data-server-util.c --- evolution-data-server-3.58.3.orig/src/libedataserver/e-data-server-util.c 2026-02-23 13:52:32.784904350 -0600 +++ evolution-data-server-3.58.3/src/libedataserver/e-data-server-util.c 2026-02-23 14:07:47.809739409 -0600 @@ -3152,3 +3152,45 @@ e_util_guess_source_is_readonly (ESource return res; } + +/** + * e_util_filename_is_in_path: + * @filename: a filename + * @path: an expected path + * + * Checks whether the @filename is stored under @path. + * It use canonicalized form of the paths before comparing them. + * Both the @filename and @path are expected to be absolute paths, + * is not, %FALSE is returned. + * + * Returns: whether the @filename is stored under @path + * + * Since: 3.60 + **/ +gboolean +e_util_filename_is_in_path (const gchar *filename, + const gchar *path) +{ + gchar *canon_filename, *canon_path; + gsize path_len; + gboolean res; + + g_return_val_if_fail (filename != NULL, FALSE); + g_return_val_if_fail (path != NULL, FALSE); + + if (!g_path_is_absolute (filename) || + !g_path_is_absolute (path)) + return FALSE; + + canon_filename = g_canonicalize_filename (filename, NULL); + canon_path = g_canonicalize_filename (path, NULL); + path_len = strlen (canon_path); + + res = path_len > 0 && g_str_has_prefix (canon_filename, canon_path) && + canon_filename[path_len] == G_DIR_SEPARATOR; + + g_free (canon_filename); + g_free (canon_path); + + return res; +} diff -urp evolution-data-server-3.58.3.orig/src/libedataserver/e-data-server-util.h evolution-data-server-3.58.3/src/libedataserver/e-data-server-util.h --- evolution-data-server-3.58.3.orig/src/libedataserver/e-data-server-util.h 2026-02-23 13:52:32.784904350 -0600 +++ evolution-data-server-3.58.3/src/libedataserver/e-data-server-util.h 2026-02-23 14:09:07.455490246 -0600 @@ -265,6 +265,8 @@ void e_util_change_uri_port (GUri **in gint port); void e_util_call_malloc_trim (void); gboolean e_util_guess_source_is_readonly (struct _ESource *source); +gboolean e_util_filename_is_in_path (const gchar *filename, + const gchar *path); G_END_DECLS diff -urp evolution-data-server-3.58.3.orig/tests/libedataserver/libedataserver-test.c evolution-data-server-3.58.3/tests/libedataserver/libedataserver-test.c --- evolution-data-server-3.58.3.orig/tests/libedataserver/libedataserver-test.c 2026-02-23 13:52:32.825904785 -0600 +++ evolution-data-server-3.58.3/tests/libedataserver/libedataserver-test.c 2026-02-23 14:07:47.810198389 -0600 @@ -119,6 +119,43 @@ test_parse_date (ETestServerFixture *fix } } +static void +test_filename_is_in_path (ETestServerFixture *fixture, + gconstpointer user_data) +{ + struct _tests { + const gchar *filename; + const gchar *path; + gboolean expected; + } tests[] = { + { "/home/user/.cache/dir/", "/home/user/.cache/dir", FALSE }, + { "/home/user/.cache/dir", "/home/user/.cache/dir", FALSE }, + { "/home/user/.cache/dir", "/home/user/.cache/dir/", FALSE }, + { "/home/user/.cache/dir/", "/home/user/.cache/dir/", FALSE }, + { "/home/user/.cache/dir/file.txt", "/home/user/.cache/dir/", TRUE }, + { "/home/user/.cache/dir/file.txt", "/home/user/.cache/dir", TRUE }, + { "/home/user/.cache/dir/subdir/file.txt", "/home/user/.cache/dir/", TRUE }, + { "/home/user/.cache/dir/subdir/file.txt", "/home/user/.cache/dir", TRUE }, + { "/home/user/.cache/dir/./file.txt", "/home/user/.cache/dir/", TRUE }, + { "/home/user/.cache/dir/./file.txt", "/home/user/.cache/dir", TRUE }, + { "/home/user/.cache/dir/../file.txt", "/home/user/.cache/dir/", FALSE }, + { "/home/user/.cache/dir/../file.txt", "/home/user/.cache/dir", FALSE }, + { "/home/user/.cache/dir/.././dir/../../.cache/./dir/file.txt", "/home/user/.cache/dir/", TRUE }, + { "/home/user/.cache/dir/.././dir/../../.cache/./dir/file.txt", "/home/user/.cache/dir", TRUE }, + { "/home/user/.cache/dir/../../../../var/lib/file.txt", "/home/user/.cache/dir/", FALSE }, + { "/home/user/.cache/dir/../../../../var/lib/file.txt", "/home/user/.cache/dir", FALSE }, + { "./file.txt", "/home/user/.cache/dir", FALSE }, + { "../file.txt", "/home/user/.cache/dir", FALSE } + }; + gint ii; + + for (ii = 0; ii < G_N_ELEMENTS (tests); ii++) { + gboolean result = e_util_filename_is_in_path (tests[ii].filename, tests[ii].path); + + g_assert_cmpint ((result ? 1 : 0), ==, (tests[ii].expected ? 1 : 0)); + } +} + gint main (gint argc, gchar **argv) @@ -138,6 +175,12 @@ main (gint argc, e_test_server_utils_setup, test_parse_date, e_test_server_utils_teardown); + g_test_add ( + "/libedataserver-test/FilenameIsInPath", + ETestServerFixture, &test_closure, + e_test_server_utils_setup, + test_filename_is_in_path, + e_test_server_utils_teardown); return e_test_server_utils_run (argc, argv); }