From cb34f72a4045b9beade1222cb393a141746e227c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Thu, 25 Nov 2021 12:33:11 +0000 Subject: osinfo: allow tree matching code to report multiple entries MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Refactor the tree matching code so that it can be told to return all matching entries, rather than only the first. The original behaviour can be requested to short-circuit matching if the caller only requires the first match. Signed-off-by: Daniel P. Berrangé --- osinfo/osinfo_db.c | 70 +++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 59 insertions(+), 11 deletions(-) diff --git a/osinfo/osinfo_db.c b/osinfo/osinfo_db.c index 6cca925..13ff04f 100644 --- a/osinfo/osinfo_db.c +++ b/osinfo/osinfo_db.c @@ -821,19 +821,41 @@ gboolean osinfo_db_identify_media(OsinfoDb *db, OsinfoMedia *media) return TRUE; } +/* + * Fill @matched_tree with all OsinfoOs in @oss + * that match @tree. + * + * If @onlyFirstMatch is TRUE then will return as soon as + * one matching tree is found + * + * If @onlyFirstMatch is FALSE then will return matching + * trees from all OsinfoOs, potentially with multiple trees + * per OsinfoOs reported. + * + * @fallback_os will be filled with any OsinfoOs that + * can be used as fallbacks matches. It will never contain + * any OsinfoOs that had tree added to @matched_tree. + * + * If @ret_os is non-NULL it will be filled with the first + * matching OsinfoOs. + */ static gboolean compare_tree(OsinfoTree *tree, GList *oss, OsinfoTreeList *matched_tree, + gboolean onlyFirstMatch, OsinfoOs **ret_os, GList **fallback_oss) { GList *os_iter; + gboolean matched = FALSE; for (os_iter = oss; os_iter; os_iter = os_iter->next) { OsinfoOs *os = OSINFO_OS(os_iter->data); OsinfoTreeList *tree_list = osinfo_os_get_tree_list(os); GList *trees = osinfo_list_get_elements(OSINFO_LIST(tree_list)); GList *tree_iter; + gboolean useFallback = TRUE; + gboolean haveFallback = FALSE; for (tree_iter = trees; tree_iter; tree_iter = tree_iter->next) { OsinfoTree *os_tree = OSINFO_TREE(tree_iter->data); @@ -842,32 +864,39 @@ static gboolean compare_tree(OsinfoTree *tree, os_tree_arch = osinfo_tree_get_architecture(os_tree); if (fallback_oss != NULL) { if (g_str_equal(os_tree_arch, "all")) { - *fallback_oss = g_list_prepend(*fallback_oss, os); + haveFallback = TRUE; continue; } } if (osinfo_tree_matches(tree, os_tree)) { - *ret_os = os; + if (ret_os && !*ret_os) + *ret_os = os; osinfo_list_add(OSINFO_LIST(matched_tree), OSINFO_ENTITY(os_tree)); - break; + useFallback = FALSE; + matched = TRUE; + if (onlyFirstMatch) + break; } } g_list_free(trees); g_object_unref(tree_list); - if (*ret_os) - return TRUE; + if (useFallback && haveFallback) + *fallback_oss = g_list_prepend(*fallback_oss, os); + if (onlyFirstMatch && matched) + break; } - return FALSE; + return matched; } static gboolean osinfo_db_guess_os_from_tree_internal(OsinfoDb *db, OsinfoTree *tree, OsinfoTreeList *matched_tree, + gboolean onlyFirstMatch, OsinfoOs **matched_os) { GList *oss = NULL; @@ -880,12 +909,31 @@ osinfo_db_guess_os_from_tree_internal(OsinfoDb *db, g_return_val_if_fail(OSINFO_IS_DB(db), FALSE); g_return_val_if_fail(tree != NULL, FALSE); + + /* + * If we're looking for the first match only: + * + * - Try to get a preferred match + * - If that doesn't work, then try fallback matches + * + * If we're looking for all matches: + * + * - Add all preferred matches first + * - Add remaining fallback matches secon + * + * This ensures that if the caller requests all matches + * but then blindly picks the first match, they will + * not accidentally get a fallback match when a preferred + * match was available. + */ oss = osinfo_list_get_elements(OSINFO_LIST(db->priv->oses)); - if (compare_tree(tree, oss, matched_tree, matched_os, &fallback_oss)) + if (compare_tree(tree, oss, matched_tree, + onlyFirstMatch, matched_os, &fallback_oss)) matched = TRUE; - if (!matched && - compare_tree(tree, fallback_oss, matched_tree, matched_os, NULL)) + if ((!onlyFirstMatch || !matched) && + compare_tree(tree, fallback_oss, matched_tree, + onlyFirstMatch, matched_os, NULL)) matched = TRUE; g_list_free(oss); @@ -913,7 +961,7 @@ OsinfoOs *osinfo_db_guess_os_from_tree(OsinfoDb *db, g_autoptr(OsinfoTreeList) all_matched_tree = osinfo_treelist_new(); OsinfoOs *ret; - if (!osinfo_db_guess_os_from_tree_internal(db, tree, all_matched_tree, &ret)) + if (!osinfo_db_guess_os_from_tree_internal(db, tree, all_matched_tree, TRUE, &ret)) return NULL; return ret; @@ -1017,7 +1065,7 @@ gboolean osinfo_db_identify_tree(OsinfoDb *db, g_return_val_if_fail(OSINFO_IS_DB(db), FALSE); if (!osinfo_db_guess_os_from_tree_internal(db, tree, all_matched_tree, - &matched_os)) { + TRUE, &matched_os)) { return FALSE; } -- cgit v1.2.1