diff options
-rw-r--r-- | osinfo/osinfo_loader.c | 15 | ||||
-rw-r--r-- | tests/test-loader.c | 105 |
2 files changed, 120 insertions, 0 deletions
diff --git a/osinfo/osinfo_loader.c b/osinfo/osinfo_loader.c index 96ca6ee..e244b3f 100644 --- a/osinfo/osinfo_loader.c +++ b/osinfo/osinfo_loader.c @@ -2377,6 +2377,21 @@ static void osinfo_loader_find_files(OsinfoLoader *loader, } else if (type == G_FILE_TYPE_UNKNOWN) { g_autofree gchar *path = g_file_get_path(file); g_autofree gchar *msg = g_strdup_printf("Can't read path %s", path); + if (skipMissing) { + /* This is a work-around for + * <https://gitlab.gnome.org/GNOME/glib/-/issues/1237>. If the + * lstat() call underlying our g_file_query_info() call at the top + * of this function fails for "path" with EACCES, then + * g_file_query_info() should fail, and the "skipMissing" branch up + * there should suppress the error and return cleanly. + * Unfortunately, _g_local_file_info_get() masks the lstat() + * failure, g_file_info_get_attribute_uint32() is reached above, + * and returns G_FILE_TYPE_UNKNOWN for the file that could never be + * accessed. So we need to consider "skipMissing" here too. + */ + g_warning("%s", msg); + return; + } OSINFO_LOADER_SET_ERROR(&error, msg); g_propagate_error(err, error); } else { diff --git a/tests/test-loader.c b/tests/test-loader.c index 6644943..bb86585 100644 --- a/tests/test-loader.c +++ b/tests/test-loader.c @@ -16,6 +16,8 @@ */ #include <osinfo/osinfo.h> +#include <glib/gstdio.h> +#include <unistd.h> static void test_basic(void) @@ -31,6 +33,101 @@ test_basic(void) g_object_unref(loader); } +typedef struct { + gchar *tmp_parent; + gchar *tmp_child; + gchar *orig_userdir; + gchar *expected_warning; +} TestEaccesFixture; + +static void +eacces_fixture_setup(TestEaccesFixture *fixture, gconstpointer user_data) +{ + gpointer rp; + gint ri; + gboolean rb; + + /* create a temporary directory with permissions 0700 */ + fixture->tmp_parent = g_strdup_printf("%s/%s", g_get_tmp_dir(), + "test_eacces.XXXXXX"); + rp = g_mkdtemp_full(fixture->tmp_parent, 0700); + g_assert_nonnull(rp); + + /* create a child directory called "osinfo" in it, with permissions 0700 */ + fixture->tmp_child = g_strdup_printf("%s/osinfo", fixture->tmp_parent); + ri = g_mkdir(fixture->tmp_child, 0700); + g_assert_cmpint(ri, ==, 0); + + /* revoke the search permission (0100) from the parent */ + ri = g_chmod(fixture->tmp_parent, 0600); + g_assert_cmpint(ri, ==, 0); + + /* stash the current value of OSINFO_USER_DIR */ + fixture->orig_userdir = g_strdup(g_getenv("OSINFO_USER_DIR")); + + /* point osinfo_loader_get_user_path() inside + * osinfo_loader_process_default_path() to the child directory + */ + rb = g_setenv("OSINFO_USER_DIR", fixture->tmp_child, TRUE); + g_assert_true(rb); + + /* format the pattern for the warning expected later on */ + fixture->expected_warning = g_strdup_printf("Can't read path %s", + fixture->tmp_child); +} + +static void +eacces_fixture_teardown(TestEaccesFixture *fixture, gconstpointer user_data) +{ + gboolean rb; + gint ri; + + /* free the expected warning pattern */ + g_free(fixture->expected_warning); + + /* restore the OSINFO_USER_DIR variable */ + if (fixture->orig_userdir) { + rb = g_setenv("OSINFO_USER_DIR", fixture->orig_userdir, TRUE); + g_assert_true(rb); + g_free(fixture->orig_userdir); + } else { + g_unsetenv("OSINFO_USER_DIR"); + } + + /* restore search permission on the parent */ + ri = g_chmod(fixture->tmp_parent, 0700); + g_assert_cmpint(ri, ==, 0); + + /* remove both directories */ + ri = g_rmdir(fixture->tmp_child); + g_assert_cmpint(ri, ==, 0); + g_free(fixture->tmp_child); + + ri = g_rmdir(fixture->tmp_parent); + g_assert_cmpint(ri, ==, 0); + g_free(fixture->tmp_parent); +} + +static void +test_eacces(TestEaccesFixture *fixture, gconstpointer user_data) +{ + OsinfoLoader *loader = osinfo_loader_new(); + GError *error = NULL; + + g_assert_true(OSINFO_IS_LOADER(loader)); + + /* this should trigger an EACCES in glib's lstat(), but not break db + * loading; also we expect the warning here + */ + g_test_expect_message(G_LOG_DOMAIN, G_LOG_LEVEL_WARNING, + fixture->expected_warning); + osinfo_loader_process_default_path(loader, &error); + g_assert_no_error(error); + g_test_assert_expected_messages(); + + g_object_unref(loader); +} + int main(int argc, char *argv[]) { @@ -38,6 +135,14 @@ main(int argc, char *argv[]) g_test_add_func("/loader/basic", test_basic); + /* the following test depends on a directory with file mode bits 0600 being + * unsearchable for the owner, so skip it if the test is running as root + */ + if (geteuid() != 0) { + g_test_add("/loader/eacces", TestEaccesFixture, NULL, + eacces_fixture_setup, test_eacces, eacces_fixture_teardown); + } + /* Upfront so we don't confuse valgrind */ osinfo_entity_get_type(); osinfo_db_get_type(); |