diff options
author | Dan Williams <dcbw@redhat.com> | 2011-02-22 23:36:43 -0600 |
---|---|---|
committer | Dan Williams <dcbw@redhat.com> | 2011-02-22 23:36:43 -0600 |
commit | 54918e32e49c26c3f6289a1743e6eb2b02eb215e (patch) | |
tree | 5c8575594ac5908fd483e7b3628afb5bae4c2b6c /libnm-util/nm-setting.c | |
parent | 5444a3569352312118e3ad0b37f61afc5842b190 (diff) | |
download | NetworkManager-54918e32e49c26c3f6289a1743e6eb2b02eb215e.tar.gz |
libnm-util: add nm_connection_diff()
Returns a list of keys that differ between the settings in each
connection. nm_connection_compare() can't do that.
Diffstat (limited to 'libnm-util/nm-setting.c')
-rw-r--r-- | libnm-util/nm-setting.c | 150 |
1 files changed, 137 insertions, 13 deletions
diff --git a/libnm-util/nm-setting.c b/libnm-util/nm-setting.c index b5a8b71f64..f134754b18 100644 --- a/libnm-util/nm-setting.c +++ b/libnm-util/nm-setting.c @@ -332,6 +332,29 @@ nm_setting_verify (NMSetting *setting, GSList *all_settings, GError **error) return TRUE; } +static inline gboolean +should_compare_prop (NMSetting *setting, + const char *prop_name, + NMSettingCompareFlags comp_flags, + GParamFlags prop_flags) +{ + /* Fuzzy compare ignores secrets and properties defined with the FUZZY_IGNORE flag */ + if ( (comp_flags & NM_SETTING_COMPARE_FLAG_FUZZY) + && (prop_flags & (NM_SETTING_PARAM_FUZZY_IGNORE | NM_SETTING_PARAM_SECRET))) + return FALSE; + + if ( (comp_flags & NM_SETTING_COMPARE_FLAG_IGNORE_SECRETS) + && (prop_flags & NM_SETTING_PARAM_SECRET)) + return FALSE; + + if ( (comp_flags & NM_SETTING_COMPARE_FLAG_IGNORE_ID) + && NM_IS_SETTING_CONNECTION (setting) + && !strcmp (prop_name, NM_SETTING_CONNECTION_ID)) + return FALSE; + + return TRUE; +} + /** * nm_setting_compare: * @a: a #NMSetting @@ -370,19 +393,8 @@ nm_setting_compare (NMSetting *a, GValue value1 = { 0 }; GValue value2 = { 0 }; - /* Fuzzy compare ignores secrets and properties defined with the - * FUZZY_IGNORE flag - */ - if ( (flags & NM_SETTING_COMPARE_FLAG_FUZZY) - && (prop_spec->flags & (NM_SETTING_PARAM_FUZZY_IGNORE | NM_SETTING_PARAM_SECRET))) - continue; - - if ((flags & NM_SETTING_COMPARE_FLAG_IGNORE_SECRETS) && (prop_spec->flags & NM_SETTING_PARAM_SECRET)) - continue; - - if ( (flags & NM_SETTING_COMPARE_FLAG_IGNORE_ID) - && !strcmp (nm_setting_get_name (a), NM_SETTING_CONNECTION_SETTING_NAME) - && !strcmp (prop_spec->name, NM_SETTING_CONNECTION_ID)) + /* Handle compare flags */ + if (!should_compare_prop (a, prop_spec->name, flags, prop_spec->flags)) continue; g_value_init (&value1, prop_spec->value_type); @@ -403,6 +415,118 @@ nm_setting_compare (NMSetting *a, } /** + * nm_setting_diff: + * @a: a #NMSetting + * @b: a second #NMSetting to compare with the first + * @flags: compare flags, e.g. %NM_SETTING_COMPARE_FLAG_EXACT + * @invert_results: this parameter is used internally by libnm-util and should + * be set to %FALSE. If %TRUE inverts the meaning of the #NMSettingDiffResult. + * @results: (element-type utf8 guint32): if the settings differ, on return a + * hash table mapping the differing keys to one or more #NMSettingDiffResult + * values OR-ed together. If the settings do not differ, any hash table passed + * in is unmodified. If no hash table is passed in, a new one is created. + * + * Compares two #NMSetting objects for similarity, with comparison behavior + * modified by a set of flags. See the documentation for #NMSettingCompareFlags + * for a description of each flag's behavior. If the settings differ, the keys + * of each setting that differ from the other are added to @results, mapped to + * one or more #NMSettingDiffResult values. + * + * Returns: %TRUE if the settings contain the same values, %FALSE if they do not + **/ +gboolean +nm_setting_diff (NMSetting *a, + NMSetting *b, + NMSettingCompareFlags flags, + gboolean invert_results, + GHashTable **results) +{ + GParamSpec **property_specs; + guint n_property_specs; + guint i; + NMSettingDiffResult a_result = NM_SETTING_DIFF_RESULT_IN_A; + NMSettingDiffResult b_result = NM_SETTING_DIFF_RESULT_IN_B; + gboolean results_created = FALSE; + + g_return_val_if_fail (results != NULL, FALSE); + g_return_val_if_fail (a != NULL, FALSE); + g_return_val_if_fail (NM_IS_SETTING (a), FALSE); + if (b) { + g_return_val_if_fail (NM_IS_SETTING (b), FALSE); + g_return_val_if_fail (G_OBJECT_TYPE (a) == G_OBJECT_TYPE (b), FALSE); + } + + /* If the caller is calling this function in a pattern like this to get + * complete diffs: + * + * nm_setting_diff (A, B, FALSE, &results); + * nm_setting_diff (B, A, TRUE, &results); + * + * and wants us to invert the results so that the second invocation comes + * out correctly, do that here. + */ + if (invert_results) { + a_result = NM_SETTING_DIFF_RESULT_IN_B; + b_result = NM_SETTING_DIFF_RESULT_IN_A; + } + + if (*results == NULL) { + *results = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); + results_created = TRUE; + } + + /* And now all properties */ + property_specs = g_object_class_list_properties (G_OBJECT_GET_CLASS (a), &n_property_specs); + + for (i = 0; i < n_property_specs; i++) { + GParamSpec *prop_spec = property_specs[i]; + GValue a_value = { 0 }, b_value = { 0 }; + NMSettingDiffResult r = NM_SETTING_DIFF_RESULT_UNKNOWN, tmp; + gboolean different = TRUE; + + /* Handle compare flags */ + if (!should_compare_prop (a, prop_spec->name, flags, prop_spec->flags)) + continue; + if (strcmp (prop_spec->name, NM_SETTING_NAME) == 0) + continue; + + if (b) { + g_value_init (&a_value, prop_spec->value_type); + g_object_get_property (G_OBJECT (a), prop_spec->name, &a_value); + + g_value_init (&b_value, prop_spec->value_type); + g_object_get_property (G_OBJECT (b), prop_spec->name, &b_value); + + different = !!g_param_values_cmp (prop_spec, &a_value, &b_value); + if (different) { + if (!g_param_value_defaults (prop_spec, &a_value)) + r |= a_result; + if (!g_param_value_defaults (prop_spec, &b_value)) + r |= b_result; + } + + g_value_unset (&a_value); + g_value_unset (&b_value); + } else + r = a_result; /* only in A */ + + if (different) { + tmp = GPOINTER_TO_UINT (g_hash_table_lookup (*results, prop_spec->name)); + g_hash_table_insert (*results, g_strdup (prop_spec->name), GUINT_TO_POINTER (tmp | r)); + } + } + g_free (property_specs); + + /* Don't return an empty hash table */ + if (results_created && !g_hash_table_size (*results)) { + g_hash_table_destroy (*results); + *results = NULL; + } + + return !(*results); +} + +/** * nm_setting_enumerate_values: * @setting: the #NMSetting * @func: (scope call): user-supplied function called for each property of the setting |