diff --git a/compose/asc-directory-unit.c b/compose/asc-directory-unit.c
index 80698e873..10c9c3de1 100644
--- a/compose/asc-directory-unit.c
+++ b/compose/asc-directory-unit.c
@@ -81,11 +81,12 @@ asc_directory_unit_class_init (AscDirectoryUnitClass *klass)
}
static gboolean
-asc_directory_unit_find_files_recursive (GPtrArray *files,
- const gchar *path_orig,
- guint path_orig_len,
- const gchar *path,
- GError **error)
+asc_directory_unit_find_files_recursive_internal (GPtrArray *files,
+ const gchar *path_orig,
+ guint path_orig_len,
+ const gchar *path,
+ GHashTable *visited_dirs,
+ GError **error)
{
const gchar *tmp;
g_autoptr(GDir) dir = NULL;
@@ -104,14 +105,38 @@ asc_directory_unit_find_files_recursive (GPtrArray *files,
g_autofree gchar *path_new = NULL;
path_new = g_build_filename (path, tmp, NULL);
- /* search recursively, don't follow symlinks */
- if (g_file_test (path_new, G_FILE_TEST_IS_DIR) &&
- !g_file_test (path_new, G_FILE_TEST_IS_SYMLINK)) {
- if (!asc_directory_unit_find_files_recursive (files,
- path_orig,
- path_orig_len,
- path_new,
- error))
+ /* search recursively */
+ if (g_file_test (path_new, G_FILE_TEST_IS_DIR)) {
+ if (g_file_test (path_new, G_FILE_TEST_IS_SYMLINK)) {
+ g_autofree gchar *real_path = realpath (path_new, NULL);
+
+ if (!real_path) {
+ /* error if realpath fails (like memory allocation error or invalid path) */
+ g_set_error (error,
+ G_FILE_ERROR,
+ g_file_error_from_errno (errno),
+ "Failed to resolve real path");
+ return FALSE;
+ }
+
+ /* don't visit paths twice to avoid loops */
+ if (g_hash_table_contains (visited_dirs, real_path))
+ return TRUE;
+
+ g_hash_table_add (visited_dirs, g_steal_pointer (&real_path));
+ } else {
+ if (g_hash_table_contains (visited_dirs, path_new))
+ return TRUE;
+
+ g_hash_table_add (visited_dirs, g_strdup (path_new));
+ }
+
+ if (!asc_directory_unit_find_files_recursive_internal (files,
+ path_orig,
+ path_orig_len,
+ path_new,
+ visited_dirs,
+ error))
return FALSE;
} else {
g_ptr_array_add (files, g_strdup (path_new + path_orig_len));
@@ -121,6 +146,24 @@ asc_directory_unit_find_files_recursive (GPtrArray *files,
return TRUE;
}
+static gboolean
+asc_directory_unit_find_files_recursive (GPtrArray *files,
+ const gchar *path_orig,
+ guint path_orig_len,
+ const gchar *path,
+ GError **error)
+{
+ g_autoptr(GHashTable) visited_dirs = NULL;
+ visited_dirs = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+
+ return asc_directory_unit_find_files_recursive_internal (files,
+ path_orig,
+ path_orig_len,
+ path,
+ visited_dirs,
+ error);
+}
+
static gboolean
asc_directory_unit_open (AscUnit *unit, GError **error)
{
diff --git a/tests/samples/compose/usr/share/locale/dir_loop/loop b/tests/samples/compose/usr/share/locale/dir_loop/loop
new file mode 120000
index 000000000..5a2ea7b42
--- /dev/null
+++ b/tests/samples/compose/usr/share/locale/dir_loop/loop
@@ -0,0 +1 @@
+../dir_loop
\ No newline at end of file
diff --git a/tests/samples/compose/usr/share/metainfo/org.example.nonexistent-badlink.metainfo.xml b/tests/samples/compose/usr/share/metainfo/org.example.nonexistent-badlink.metainfo.xml
new file mode 120000
index 000000000..bfda748b9
--- /dev/null
+++ b/tests/samples/compose/usr/share/metainfo/org.example.nonexistent-badlink.metainfo.xml
@@ -0,0 +1 @@
+/nonexistent
\ No newline at end of file
diff --git a/tests/test-compose.c b/tests/test-compose.c
index cf8de26fd..fb2ca8ee9 100644
--- a/tests/test-compose.c
+++ b/tests/test-compose.c
@@ -703,7 +703,7 @@ test_compose_directory_unit (void)
g_assert_true (ret);
contents = asc_unit_get_contents (ASC_UNIT (dirunit));
- g_assert_cmpint (contents->len, ==, 15);
+ g_assert_cmpint (contents->len, ==, 16);
as_sort_strings (contents);
g_assert_cmpstr (g_ptr_array_index (contents, 0), ==, "/Raleway-Regular.ttf");
diff --git a/tests/test-xmldata.c b/tests/test-xmldata.c
index c5b5f1db1..6f68e9d12 100644
--- a/tests/test-xmldata.c
+++ b/tests/test-xmldata.c
@@ -2293,13 +2293,12 @@ test_xml_rw_branding (void)
static void
test_xml_rw_developer (void)
{
- static const gchar
- *xmldata_tags = "\n"
- " org.example.DeveloperTest\n"
- " \n"
- " FreeDesktop.org Project\n"
- " \n"
- "\n";
+ static const gchar *xmldata_tags = "\n"
+ " org.example.DeveloperTest\n"
+ " \n"
+ " FreeDesktop.org Project\n"
+ " \n"
+ "\n";
g_autoptr(AsComponent) cpt = NULL;
g_autofree gchar *res = NULL;
AsDeveloper *devp;