libnm: rework compare_property() implementation for NMSetting

NMSetting's compare_property() has and had two callers:
nm_setting_compare() and nm_setting_diff().

compare_property() accepts a NMSettingCompareFlags argument, but
at the same time, both callers have another complex (and
inconsistent!) set of pre-checks for shortcuting the call of
compare_property(): should_compare_prop().

Merge should_compare_prop() into compare_property(). This way,
nm_setting_compare() and nm_setting_diff() has less additional
code, and are simpler to follow. Especially nm_setting_compare()
is now trivial. And nm_setting_diff() is still complicated, but
not related to the question how the property compares or whether
it should be compared at all.

If you want to know whether it should be compared, all you need to do
now is follow NMSettingClass.compare_property().

This changes function pointer NMSettingClass.compare_property(),
which is public API. However, no user can actually use this (and shall
not!), because _nm_setting_class_commit_full() etc. is private API. A
user outside of libnm-core cannot create his/her own subclasses of
NMSetting, and never could in the past. So, this API/ABI change doesn't
matter.
This commit is contained in:
Thomas Haller 2019-01-09 09:08:39 +01:00
parent 5aace3dfea
commit 885c872d5a
14 changed files with 509 additions and 405 deletions

View file

@ -811,15 +811,15 @@ verify (NMSetting *setting, NMConnection *connection, GError **error)
/*****************************************************************************/
static gboolean
options_hash_match (NMSettingBond *s_bond,
GHashTable *options1,
GHashTable *options2,
options_equal_asym (NMSettingBond *s_bond,
NMSettingBond *s_bond2,
NMSettingCompareFlags flags)
{
GHashTable *options2 = NM_SETTING_BOND_GET_PRIVATE (s_bond2)->options;
GHashTableIter iter;
const char *key, *value, *value2;
g_hash_table_iter_init (&iter, options1);
g_hash_table_iter_init (&iter, NM_SETTING_BOND_GET_PRIVATE (s_bond)->options);
while (g_hash_table_iter_next (&iter, (gpointer *) &key, (gpointer *) &value)) {
if (NM_FLAGS_HAS (flags, NM_SETTING_COMPARE_FLAG_INFERRABLE)) {
@ -841,15 +841,10 @@ options_hash_match (NMSettingBond *s_bond,
value2 = g_hash_table_lookup (options2, "num_grat_arp");
}
if (value2) {
if (nm_streq (value, value2))
continue;
} else {
if (nm_streq (value, nm_setting_bond_get_option_default (s_bond, key)))
continue;
}
return FALSE;
if (!value2)
value2 = nm_setting_bond_get_option_default (s_bond2, key);
if (!nm_streq (value, value2))
return FALSE;
}
return TRUE;
@ -857,31 +852,32 @@ options_hash_match (NMSettingBond *s_bond,
static gboolean
options_equal (NMSettingBond *s_bond,
GHashTable *options1,
GHashTable *options2,
NMSettingBond *s_bond2,
NMSettingCompareFlags flags)
{
return options_hash_match (s_bond, options1, options2, flags)
&& options_hash_match (s_bond, options2, options1, flags);
return options_equal_asym (s_bond, s_bond2, flags)
&& options_equal_asym (s_bond2, s_bond, flags);
}
static gboolean
compare_property (NMSetting *setting,
static NMTernary
compare_property (const NMSettInfoSetting *sett_info,
guint property_idx,
NMSetting *setting,
NMSetting *other,
const GParamSpec *prop_spec,
NMSettingCompareFlags flags)
{
NMSettingClass *setting_class;
if (nm_streq0 (prop_spec->name, NM_SETTING_BOND_OPTIONS)) {
return options_equal (NM_SETTING_BOND (setting),
NM_SETTING_BOND_GET_PRIVATE (setting)->options,
NM_SETTING_BOND_GET_PRIVATE (other)->options,
flags);
if (nm_streq (sett_info->property_infos[property_idx].name, NM_SETTING_BOND_OPTIONS)) {
return ( !other
|| options_equal (NM_SETTING_BOND (setting),
NM_SETTING_BOND (other),
flags));
}
setting_class = NM_SETTING_CLASS (nm_setting_bond_parent_class);
return setting_class->compare_property (setting, other, prop_spec, flags);
return NM_SETTING_CLASS (nm_setting_bond_parent_class)->compare_property (sett_info,
property_idx,
setting,
other,
flags);
}
/*****************************************************************************/

View file

@ -1281,23 +1281,26 @@ nm_setting_connection_no_interface_name (NMSetting *setting,
return TRUE;
}
static gboolean
compare_property (NMSetting *setting,
static NMTernary
compare_property (const NMSettInfoSetting *sett_info,
guint property_idx,
NMSetting *setting,
NMSetting *other,
const GParamSpec *prop_spec,
NMSettingCompareFlags flags)
{
/* Handle ignore ID */
if ( (flags & NM_SETTING_COMPARE_FLAG_IGNORE_ID)
&& g_strcmp0 (prop_spec->name, NM_SETTING_CONNECTION_ID) == 0)
return TRUE;
if ( NM_FLAGS_HAS (flags, NM_SETTING_COMPARE_FLAG_IGNORE_ID)
&& nm_streq (sett_info->property_infos[property_idx].name, NM_SETTING_CONNECTION_ID))
return NM_TERNARY_DEFAULT;
/* Handle ignore timestamp */
if ( (flags & NM_SETTING_COMPARE_FLAG_IGNORE_TIMESTAMP)
&& g_strcmp0 (prop_spec->name, NM_SETTING_CONNECTION_TIMESTAMP) == 0)
return TRUE;
if ( NM_FLAGS_HAS(flags, NM_SETTING_COMPARE_FLAG_IGNORE_TIMESTAMP)
&& nm_streq (sett_info->property_infos[property_idx].name, NM_SETTING_CONNECTION_TIMESTAMP))
return NM_TERNARY_DEFAULT;
return NM_SETTING_CLASS (nm_setting_connection_parent_class)->compare_property (setting, other, prop_spec, flags);
return NM_SETTING_CLASS (nm_setting_connection_parent_class)->compare_property (sett_info,
property_idx,
setting,
other,
flags);
}
static void

View file

@ -2612,44 +2612,52 @@ verify (NMSetting *setting, NMConnection *connection, GError **error)
return TRUE;
}
static gboolean
compare_property (NMSetting *setting,
static NMTernary
compare_property (const NMSettInfoSetting *sett_info,
guint property_idx,
NMSetting *setting,
NMSetting *other,
const GParamSpec *prop_spec,
NMSettingCompareFlags flags)
{
NMSettingIPConfigPrivate *a_priv, *b_priv;
NMSettingClass *setting_class;
NMSettingIPConfigPrivate *a_priv;
NMSettingIPConfigPrivate *b_priv;
guint i;
if (nm_streq (prop_spec->name, NM_SETTING_IP_CONFIG_ADDRESSES)) {
a_priv = NM_SETTING_IP_CONFIG_GET_PRIVATE (setting);
b_priv = NM_SETTING_IP_CONFIG_GET_PRIVATE (other);
if (nm_streq (sett_info->property_infos[property_idx].name, NM_SETTING_IP_CONFIG_ADDRESSES)) {
if (other) {
a_priv = NM_SETTING_IP_CONFIG_GET_PRIVATE (setting);
b_priv = NM_SETTING_IP_CONFIG_GET_PRIVATE (other);
if (a_priv->addresses->len != b_priv->addresses->len)
return FALSE;
for (i = 0; i < a_priv->addresses->len; i++) {
if (!_nm_ip_address_equal (a_priv->addresses->pdata[i], b_priv->addresses->pdata[i], TRUE))
if (a_priv->addresses->len != b_priv->addresses->len)
return FALSE;
for (i = 0; i < a_priv->addresses->len; i++) {
if (!_nm_ip_address_equal (a_priv->addresses->pdata[i], b_priv->addresses->pdata[i], TRUE))
return FALSE;
}
}
return TRUE;
}
if (nm_streq (prop_spec->name, NM_SETTING_IP_CONFIG_ROUTES)) {
a_priv = NM_SETTING_IP_CONFIG_GET_PRIVATE (setting);
b_priv = NM_SETTING_IP_CONFIG_GET_PRIVATE (other);
if (nm_streq (sett_info->property_infos[property_idx].name, NM_SETTING_IP_CONFIG_ROUTES)) {
if (other) {
a_priv = NM_SETTING_IP_CONFIG_GET_PRIVATE (setting);
b_priv = NM_SETTING_IP_CONFIG_GET_PRIVATE (other);
if (a_priv->routes->len != b_priv->routes->len)
return FALSE;
for (i = 0; i < a_priv->routes->len; i++) {
if (!nm_ip_route_equal_full (a_priv->routes->pdata[i], b_priv->routes->pdata[i], NM_IP_ROUTE_EQUAL_CMP_FLAGS_WITH_ATTRS))
if (a_priv->routes->len != b_priv->routes->len)
return FALSE;
for (i = 0; i < a_priv->routes->len; i++) {
if (!nm_ip_route_equal_full (a_priv->routes->pdata[i], b_priv->routes->pdata[i], NM_IP_ROUTE_EQUAL_CMP_FLAGS_WITH_ATTRS))
return FALSE;
}
}
return TRUE;
}
setting_class = NM_SETTING_CLASS (nm_setting_ip_config_parent_class);
return setting_class->compare_property (setting, other, prop_spec, flags);
return NM_SETTING_CLASS (nm_setting_ip_config_parent_class)->compare_property (sett_info,
property_idx,
setting,
other,
flags);
}
/*****************************************************************************/

View file

@ -201,6 +201,11 @@ gboolean _nm_setting_use_legacy_property (NMSetting *setting,
GPtrArray *_nm_setting_need_secrets (NMSetting *setting);
gboolean _nm_setting_should_compare_secret_property (NMSetting *setting,
NMSetting *other,
const char *secret_name,
NMSettingCompareFlags flags);
/*****************************************************************************/
#endif /* NM_SETTING_PRIVATE_H */

View file

@ -1188,29 +1188,37 @@ get_property (GObject *object, guint prop_id,
}
}
static gboolean
compare_property (NMSetting *setting,
static NMTernary
compare_property (const NMSettInfoSetting *sett_info,
guint property_idx,
NMSetting *setting,
NMSetting *other,
const GParamSpec *prop_spec,
NMSettingCompareFlags flags)
{
NMSettingSriov *a = NM_SETTING_SRIOV (setting);
NMSettingSriov *b = NM_SETTING_SRIOV (other);
NMSettingClass *setting_class;
NMSettingSriov *a;
NMSettingSriov *b;
guint i;
if (nm_streq (prop_spec->name, NM_SETTING_SRIOV_VFS)) {
if (a->vfs->len != b->vfs->len)
return FALSE;
for (i = 0; i < a->vfs->len; i++) {
if (!nm_sriov_vf_equal (a->vfs->pdata[i], b->vfs->pdata[i]))
if (nm_streq (sett_info->property_infos[property_idx].name, NM_SETTING_SRIOV_VFS)) {
if (other) {
a = NM_SETTING_SRIOV (setting);
b = NM_SETTING_SRIOV (other);
if (a->vfs->len != b->vfs->len)
return FALSE;
for (i = 0; i < a->vfs->len; i++) {
if (!nm_sriov_vf_equal (a->vfs->pdata[i], b->vfs->pdata[i]))
return FALSE;
}
}
return TRUE;
}
setting_class = NM_SETTING_CLASS (nm_setting_sriov_parent_class);
return setting_class->compare_property (setting, other, prop_spec, flags);
return NM_SETTING_CLASS (nm_setting_sriov_parent_class)->compare_property (sett_info,
property_idx,
setting,
other,
flags);
}
static void

View file

@ -1233,39 +1233,46 @@ verify (NMSetting *setting, NMConnection *connection, GError **error)
return TRUE;
}
static gboolean
compare_property (NMSetting *setting,
static NMTernary
compare_property (const NMSettInfoSetting *sett_info,
guint property_idx,
NMSetting *setting,
NMSetting *other,
const GParamSpec *prop_spec,
NMSettingCompareFlags flags)
{
NMSettingTCConfig *a_tc_config = NM_SETTING_TC_CONFIG (setting);
NMSettingTCConfig *b_tc_config = NM_SETTING_TC_CONFIG (other);
NMSettingClass *setting_class;
guint i;
if (nm_streq (prop_spec->name, NM_SETTING_TC_CONFIG_QDISCS)) {
if (a_tc_config->qdiscs->len != b_tc_config->qdiscs->len)
return FALSE;
for (i = 0; i < a_tc_config->qdiscs->len; i++) {
if (!nm_tc_qdisc_equal (a_tc_config->qdiscs->pdata[i], b_tc_config->qdiscs->pdata[i]))
if (nm_streq (sett_info->property_infos[property_idx].name, NM_SETTING_TC_CONFIG_QDISCS)) {
if (other) {
if (a_tc_config->qdiscs->len != b_tc_config->qdiscs->len)
return FALSE;
for (i = 0; i < a_tc_config->qdiscs->len; i++) {
if (!nm_tc_qdisc_equal (a_tc_config->qdiscs->pdata[i], b_tc_config->qdiscs->pdata[i]))
return FALSE;
}
}
return TRUE;
}
if (nm_streq (prop_spec->name, NM_SETTING_TC_CONFIG_TFILTERS)) {
if (a_tc_config->tfilters->len != b_tc_config->tfilters->len)
return FALSE;
for (i = 0; i < a_tc_config->tfilters->len; i++) {
if (!nm_tc_tfilter_equal (a_tc_config->tfilters->pdata[i], b_tc_config->tfilters->pdata[i]))
if (nm_streq (sett_info->property_infos[property_idx].name, NM_SETTING_TC_CONFIG_TFILTERS)) {
if (other) {
if (a_tc_config->tfilters->len != b_tc_config->tfilters->len)
return FALSE;
for (i = 0; i < a_tc_config->tfilters->len; i++) {
if (!nm_tc_tfilter_equal (a_tc_config->tfilters->pdata[i], b_tc_config->tfilters->pdata[i]))
return FALSE;
}
}
return TRUE;
}
setting_class = NM_SETTING_CLASS (nm_setting_tc_config_parent_class);
return setting_class->compare_property (setting, other, prop_spec, flags);
return NM_SETTING_CLASS (nm_setting_tc_config_parent_class)->compare_property (sett_info,
property_idx,
setting,
other,
flags);
}
static void

View file

@ -401,48 +401,68 @@ verify (NMSetting *setting, NMConnection *connection, GError **error)
return TRUE;
}
static gboolean
compare_property (NMSetting *setting,
static NMTernary
compare_property (const NMSettInfoSetting *sett_info,
guint property_idx,
NMSetting *setting,
NMSetting *other,
const GParamSpec *prop_spec,
NMSettingCompareFlags flags)
{
NMSettingClass *setting_class;
NMSettingTeamPortPrivate *a_priv, *b_priv;
NMSettingTeamPortPrivate *a_priv;
NMSettingTeamPortPrivate *b_priv;
guint i, j;
/* If we are trying to match a connection in order to assume it (and thus
* @flags contains INFERRABLE), use the "relaxed" matching for team
* configuration. Otherwise, for all other purposes (including connection
* comparison before an update), resort to the default string comparison.
*/
if ( NM_FLAGS_HAS (flags, NM_SETTING_COMPARE_FLAG_INFERRABLE)
&& nm_streq0 (prop_spec->name, NM_SETTING_TEAM_PORT_CONFIG)) {
return _nm_utils_team_config_equal (NM_SETTING_TEAM_PORT_GET_PRIVATE (setting)->config,
NM_SETTING_TEAM_PORT_GET_PRIVATE (other)->config,
TRUE);
}
if (nm_streq0 (prop_spec->name, NM_SETTING_TEAM_PORT_LINK_WATCHERS)) {
a_priv = NM_SETTING_TEAM_PORT_GET_PRIVATE (setting);
b_priv = NM_SETTING_TEAM_PORT_GET_PRIVATE (other);
if (nm_streq (sett_info->property_infos[property_idx].name, NM_SETTING_TEAM_PORT_LINK_WATCHERS)) {
if (a_priv->link_watchers->len != b_priv->link_watchers->len)
return FALSE;
for (i = 0; i < a_priv->link_watchers->len; i++) {
for (j = 0; j < b_priv->link_watchers->len; j++) {
if (nm_team_link_watcher_equal (a_priv->link_watchers->pdata[i],
b_priv->link_watchers->pdata[j])) {
break;
}
}
if (j == b_priv->link_watchers->len)
if (NM_FLAGS_HAS (flags, NM_SETTING_COMPARE_FLAG_INFERRABLE))
return NM_TERNARY_DEFAULT;
if (other) {
a_priv = NM_SETTING_TEAM_PORT_GET_PRIVATE (setting);
b_priv = NM_SETTING_TEAM_PORT_GET_PRIVATE (other);
if (a_priv->link_watchers->len != b_priv->link_watchers->len)
return FALSE;
for (i = 0; i < a_priv->link_watchers->len; i++) {
for (j = 0; j < b_priv->link_watchers->len; j++) {
if (nm_team_link_watcher_equal (a_priv->link_watchers->pdata[i],
b_priv->link_watchers->pdata[j])) {
break;
}
}
if (j == b_priv->link_watchers->len)
return FALSE;
}
}
return TRUE;
}
setting_class = NM_SETTING_CLASS (nm_setting_team_port_parent_class);
return setting_class->compare_property (setting, other, prop_spec, flags);
if (nm_streq (sett_info->property_infos[property_idx].name, NM_SETTING_TEAM_PORT_CONFIG)) {
if (other) {
a_priv = NM_SETTING_TEAM_PORT_GET_PRIVATE (setting);
b_priv = NM_SETTING_TEAM_PORT_GET_PRIVATE (other);
if (NM_FLAGS_HAS (flags, NM_SETTING_COMPARE_FLAG_INFERRABLE)) {
/* If we are trying to match a connection in order to assume it (and thus
* @flags contains INFERRABLE), use the "relaxed" matching for team
* configuration. Otherwise, for all other purposes (including connection
* comparison before an update), resort to the default string comparison. */
return _nm_utils_team_config_equal (a_priv->config,
b_priv->config,
TRUE);
}
return nm_streq0 (a_priv->config, b_priv->config);
}
return TRUE;
}
return NM_SETTING_CLASS (nm_setting_team_port_parent_class)->compare_property (sett_info,
property_idx,
setting,
other,
flags);
}
static void

View file

@ -1297,38 +1297,33 @@ verify (NMSetting *setting, NMConnection *connection, GError **error)
return TRUE;
}
static gboolean
compare_property (NMSetting *setting,
static NMTernary
compare_property (const NMSettInfoSetting *sett_info,
guint property_idx,
NMSetting *setting,
NMSetting *other,
const GParamSpec *prop_spec,
NMSettingCompareFlags flags)
{
NMSettingTeamPrivate *a_priv, *b_priv;
NMSettingClass *setting_class;
guint i, j;
/* If we are trying to match a connection in order to assume it (and thus
* @flags contains INFERRABLE), use the "relaxed" matching for team
* configuration. Otherwise, for all other purposes (including connection
* comparison before an update), resort to the default string comparison.
*/
if ( NM_FLAGS_HAS (flags, NM_SETTING_COMPARE_FLAG_INFERRABLE)
&& nm_streq0 (prop_spec->name, NM_SETTING_TEAM_CONFIG)) {
return _nm_utils_team_config_equal (NM_SETTING_TEAM_GET_PRIVATE (setting)->config,
NM_SETTING_TEAM_GET_PRIVATE (other)->config,
FALSE);
}
if (nm_streq0 (prop_spec->name, NM_SETTING_TEAM_LINK_WATCHERS)) {
a_priv = NM_SETTING_TEAM_GET_PRIVATE (setting);
b_priv = NM_SETTING_TEAM_GET_PRIVATE (other);
if (nm_streq (sett_info->property_infos[property_idx].name, NM_SETTING_TEAM_LINK_WATCHERS)) {
if (a_priv->link_watchers->len != b_priv->link_watchers->len)
return FALSE;
for (i = 0; i < a_priv->link_watchers->len; i++) {
for (j = 0; j < b_priv->link_watchers->len; j++) {
if (nm_team_link_watcher_equal (a_priv->link_watchers->pdata[i],
b_priv->link_watchers->pdata[j])) {
break;
if (NM_FLAGS_HAS (flags, NM_SETTING_COMPARE_FLAG_INFERRABLE))
return NM_TERNARY_DEFAULT;
if (other) {
a_priv = NM_SETTING_TEAM_GET_PRIVATE (setting);
b_priv = NM_SETTING_TEAM_GET_PRIVATE (other);
if (a_priv->link_watchers->len != b_priv->link_watchers->len)
return FALSE;
for (i = 0; i < a_priv->link_watchers->len; i++) {
for (j = 0; j < b_priv->link_watchers->len; j++) {
if (nm_team_link_watcher_equal (a_priv->link_watchers->pdata[i],
b_priv->link_watchers->pdata[j])) {
break;
}
}
if (j == b_priv->link_watchers->len)
return FALSE;
@ -1337,8 +1332,32 @@ compare_property (NMSetting *setting,
return TRUE;
}
setting_class = NM_SETTING_CLASS (nm_setting_team_parent_class);
return setting_class->compare_property (setting, other, prop_spec, flags);
if (nm_streq (sett_info->property_infos[property_idx].name, NM_SETTING_TEAM_CONFIG)) {
if (other) {
a_priv = NM_SETTING_TEAM_GET_PRIVATE (setting);
b_priv = NM_SETTING_TEAM_GET_PRIVATE (other);
if (NM_FLAGS_HAS (flags, NM_SETTING_COMPARE_FLAG_INFERRABLE)) {
/* If we are trying to match a connection in order to assume it (and thus
* @flags contains INFERRABLE), use the "relaxed" matching for team
* configuration. Otherwise, for all other purposes (including connection
* comparison before an update), resort to the default string comparison. */
return _nm_utils_team_config_equal (a_priv->config,
b_priv->config,
TRUE);
}
return nm_streq0 (a_priv->config, b_priv->config);
}
return TRUE;
}
return NM_SETTING_CLASS (nm_setting_team_parent_class)->compare_property (sett_info,
property_idx,
setting,
other,
flags);
}
static void

View file

@ -395,33 +395,34 @@ verify (NMSetting *setting, NMConnection *connection, GError **error)
return TRUE;
}
static gboolean
compare_property (NMSetting *setting,
static NMTernary
compare_property (const NMSettInfoSetting *sett_info,
guint property_idx,
NMSetting *setting,
NMSetting *other,
const GParamSpec *prop_spec,
NMSettingCompareFlags flags)
{
NMSettingUserPrivate *priv, *pri2;
g_return_val_if_fail (NM_IS_SETTING_USER (setting), FALSE);
g_return_val_if_fail (NM_IS_SETTING_USER (other), FALSE);
if (nm_streq (sett_info->property_infos[property_idx].name, NM_SETTING_USER_DATA)) {
if (!nm_streq0 (prop_spec->name, NM_SETTING_USER_DATA))
goto call_parent;
if (NM_FLAGS_HAS (flags, NM_SETTING_COMPARE_FLAG_INFERRABLE))
return NM_TERNARY_DEFAULT;
priv = NM_SETTING_USER_GET_PRIVATE (NM_SETTING_USER (setting));
pri2 = NM_SETTING_USER_GET_PRIVATE (NM_SETTING_USER (other));
if (!other)
return TRUE;
if (!nm_utils_hash_table_equal (priv->data, pri2->data, TRUE, g_str_equal))
return FALSE;
priv = NM_SETTING_USER_GET_PRIVATE (NM_SETTING_USER (setting));
pri2 = NM_SETTING_USER_GET_PRIVATE (NM_SETTING_USER (other));
return nm_utils_hash_table_equal (priv->data, pri2->data, TRUE, g_str_equal)
&& nm_utils_hash_table_equal (priv->data_invalid, pri2->data_invalid, TRUE, g_str_equal);
}
if (!nm_utils_hash_table_equal (priv->data_invalid, pri2->data_invalid, TRUE, g_str_equal))
return FALSE;
return TRUE;
call_parent:
return NM_SETTING_CLASS (nm_setting_user_parent_class)->compare_property (setting, other, prop_spec, flags);
return NM_SETTING_CLASS (nm_setting_user_parent_class)->compare_property (sett_info,
property_idx,
setting,
other,
flags);
}
/*****************************************************************************/

View file

@ -765,77 +765,63 @@ need_secrets (NMSetting *setting)
return g_ptr_array_sized_new (1);
}
static gboolean
_compare_secrets (NMSettingVpn *a,
NMSettingVpn *b,
NMSettingCompareFlags flags)
static NMTernary
compare_property_secrets (NMSettingVpn *a,
NMSettingVpn *b,
NMSettingCompareFlags flags)
{
GHashTable *a_secrets;
GHashTableIter iter;
const char *key, *val;
int run;
a_secrets = NM_SETTING_VPN_GET_PRIVATE (a)->secrets;
g_hash_table_iter_init (&iter, a_secrets);
while (g_hash_table_iter_next (&iter, (gpointer) &key, (gpointer) &val)) {
NMSettingSecretFlags a_secret_flags = NM_SETTING_SECRET_FLAG_NONE;
NMSettingSecretFlags b_secret_flags = NM_SETTING_SECRET_FLAG_NONE;
if (NM_FLAGS_HAS (flags, NM_SETTING_COMPARE_FLAG_FUZZY))
return NM_TERNARY_DEFAULT;
if (NM_FLAGS_HAS (flags, NM_SETTING_COMPARE_FLAG_IGNORE_SECRETS))
return NM_TERNARY_DEFAULT;
nm_setting_get_secret_flags (NM_SETTING (a), key, &a_secret_flags, NULL);
nm_setting_get_secret_flags (NM_SETTING (b), key, &b_secret_flags, NULL);
if (!b)
return TRUE;
for (run = 0; run < 2; run++) {
NMSettingVpn *current_a = (run == 0) ? a : b;
NMSettingVpn *current_b = (run == 0) ? b : a;
g_hash_table_iter_init (&iter, NM_SETTING_VPN_GET_PRIVATE (current_a)->secrets);
while (g_hash_table_iter_next (&iter, (gpointer) &key, (gpointer) &val)) {
if (nm_streq0 (val, nm_setting_vpn_get_secret (current_b, key)))
continue;
if (!_nm_setting_should_compare_secret_property (NM_SETTING (current_a),
NM_SETTING (current_b),
key,
flags))
continue;
/* If the secret flags aren't the same, the settings aren't the same */
if (a_secret_flags != b_secret_flags)
return FALSE;
if ( (flags & NM_SETTING_COMPARE_FLAG_IGNORE_AGENT_OWNED_SECRETS)
&& (a_secret_flags & NM_SETTING_SECRET_FLAG_AGENT_OWNED))
continue;
if ( (flags & NM_SETTING_COMPARE_FLAG_IGNORE_NOT_SAVED_SECRETS)
&& (a_secret_flags & NM_SETTING_SECRET_FLAG_NOT_SAVED))
continue;
/* Now compare the values themselves */
if (g_strcmp0 (val, nm_setting_vpn_get_secret (b, key)) != 0)
return FALSE;
}
}
return TRUE;
}
static gboolean
compare_one_secret (NMSettingVpn *a,
NMSettingVpn *b,
NMSettingCompareFlags flags)
{
if (!_compare_secrets (a, b, flags))
return FALSE;
if (!_compare_secrets (b, a, flags))
return FALSE;
return TRUE;
}
static gboolean
compare_property (NMSetting *setting,
static NMTernary
compare_property (const NMSettInfoSetting *sett_info,
guint property_idx,
NMSetting *setting,
NMSetting *other,
const GParamSpec *prop_spec,
NMSettingCompareFlags flags)
{
gboolean same;
/* We only need to treat the 'secrets' property specially */
if (g_strcmp0 (prop_spec->name, NM_SETTING_VPN_SECRETS) != 0)
return NM_SETTING_CLASS (nm_setting_vpn_parent_class)->compare_property (setting, other, prop_spec, flags);
/* Compare A to B to ensure everything in A is found in B */
same = compare_one_secret (NM_SETTING_VPN (setting), NM_SETTING_VPN (other), flags);
if (same) {
/* And then B to A to ensure everything in B is also found in A */
same = compare_one_secret (NM_SETTING_VPN (other), NM_SETTING_VPN (setting), flags);
if (nm_streq (sett_info->property_infos[property_idx].name, NM_SETTING_VPN_SECRETS)) {
if (NM_FLAGS_HAS (flags, NM_SETTING_COMPARE_FLAG_INFERRABLE))
return NM_TERNARY_DEFAULT;
return compare_property_secrets (NM_SETTING_VPN (setting), NM_SETTING_VPN (other), flags);
}
return same;
return NM_SETTING_CLASS (nm_setting_vpn_parent_class)->compare_property (sett_info,
property_idx,
setting,
other,
flags);
}
static gboolean

View file

@ -775,21 +775,25 @@ verify (NMSetting *setting, NMConnection *connection, GError **error)
return TRUE;
}
static gboolean
compare_property (NMSetting *setting,
static NMTernary
compare_property (const NMSettInfoSetting *sett_info,
guint property_idx,
NMSetting *setting,
NMSetting *other,
const GParamSpec *prop_spec,
NMSettingCompareFlags flags)
{
NMSettingClass *setting_class;
if (nm_streq (prop_spec->name, NM_SETTING_WIRED_CLONED_MAC_ADDRESS)) {
return nm_streq0 (NM_SETTING_WIRED_GET_PRIVATE (setting)->cloned_mac_address,
NM_SETTING_WIRED_GET_PRIVATE (other)->cloned_mac_address);
if (nm_streq (sett_info->property_infos[property_idx].name, NM_SETTING_WIRED_CLONED_MAC_ADDRESS)) {
return !other
|| nm_streq0 (NM_SETTING_WIRED_GET_PRIVATE (setting)->cloned_mac_address,
NM_SETTING_WIRED_GET_PRIVATE (other)->cloned_mac_address);
}
setting_class = NM_SETTING_CLASS (nm_setting_wired_parent_class);
return setting_class->compare_property (setting, other, prop_spec, flags);
return NM_SETTING_CLASS (nm_setting_wired_parent_class)->compare_property (sett_info,
property_idx,
setting,
other,
flags);
}
static GVariant *

View file

@ -929,21 +929,24 @@ mac_addr_rand_ok:
return TRUE;
}
static gboolean
compare_property (NMSetting *setting,
static NMTernary
compare_property (const NMSettInfoSetting *sett_info,
guint property_idx,
NMSetting *setting,
NMSetting *other,
const GParamSpec *prop_spec,
NMSettingCompareFlags flags)
{
NMSettingClass *setting_class;
if (nm_streq (prop_spec->name, NM_SETTING_WIRELESS_CLONED_MAC_ADDRESS)) {
return nm_streq0 (NM_SETTING_WIRELESS_GET_PRIVATE (setting)->cloned_mac_address,
NM_SETTING_WIRELESS_GET_PRIVATE (other)->cloned_mac_address);
if (nm_streq (sett_info->property_infos[property_idx].name, NM_SETTING_WIRELESS_CLONED_MAC_ADDRESS)) {
return !other
|| nm_streq0 (NM_SETTING_WIRELESS_GET_PRIVATE (setting)->cloned_mac_address,
NM_SETTING_WIRELESS_GET_PRIVATE (other)->cloned_mac_address);
}
setting_class = NM_SETTING_CLASS (nm_setting_wireless_parent_class);
return setting_class->compare_property (setting, other, prop_spec, flags);
return NM_SETTING_CLASS (nm_setting_wireless_parent_class)->compare_property (sett_info,
property_idx,
setting,
other,
flags);
}
/*****************************************************************************/

View file

@ -86,11 +86,6 @@ G_DEFINE_ABSTRACT_TYPE (NMSetting, nm_setting, G_TYPE_OBJECT)
static GenData *_gendata_hash (NMSetting *setting, gboolean create_if_necessary);
static gboolean should_compare_prop (gboolean for_diff,
NMSetting *setting,
const NMSettInfoProperty *property_info,
NMSettingCompareFlags comp_flags);
/*****************************************************************************/
static NMSettingPriority
@ -1246,58 +1241,148 @@ _nm_setting_verify_secret_string (const char *str,
return TRUE;
}
static gboolean
compare_property (NMSetting *setting,
NMSetting *other,
const GParamSpec *prop_spec,
NMSettingCompareFlags flags)
gboolean
_nm_setting_should_compare_secret_property (NMSetting *setting,
NMSetting *other,
const char *secret_name,
NMSettingCompareFlags flags)
{
const NMSettInfoProperty *property;
GVariant *value1, *value2;
int cmp;
NMSettingSecretFlags a_secret_flags = NM_SETTING_SECRET_FLAG_NONE;
NMSettingSecretFlags b_secret_flags = NM_SETTING_SECRET_FLAG_NONE;
/* Handle compare flags */
if (prop_spec->flags & NM_SETTING_PARAM_SECRET) {
NMSettingSecretFlags a_secret_flags = NM_SETTING_SECRET_FLAG_NONE;
NMSettingSecretFlags b_secret_flags = NM_SETTING_SECRET_FLAG_NONE;
nm_assert (NM_IS_SETTING (setting));
nm_assert (!other || G_OBJECT_TYPE (setting) == G_OBJECT_TYPE (other));
g_return_val_if_fail (!NM_IS_SETTING_VPN (setting), FALSE);
/* secret_name must be a valid secret for @setting. */
nm_assert (nm_setting_get_secret_flags (setting, secret_name, NULL, NULL));
if (!nm_setting_get_secret_flags (setting, prop_spec->name, &a_secret_flags, NULL))
g_return_val_if_reached (FALSE);
if (!nm_setting_get_secret_flags (other, prop_spec->name, &b_secret_flags, NULL))
g_return_val_if_reached (FALSE);
if (!NM_FLAGS_ANY (flags, NM_SETTING_COMPARE_FLAG_IGNORE_AGENT_OWNED_SECRETS
| NM_SETTING_COMPARE_FLAG_IGNORE_NOT_SAVED_SECRETS))
return TRUE;
/* If the secret flags aren't the same the settings aren't the same */
if (a_secret_flags != b_secret_flags)
return FALSE;
/* Check for various secret flags that might cause us to ignore comparing
* this property.
*/
if ( (flags & NM_SETTING_COMPARE_FLAG_IGNORE_AGENT_OWNED_SECRETS)
&& (a_secret_flags & NM_SETTING_SECRET_FLAG_AGENT_OWNED))
return TRUE;
if ( (flags & NM_SETTING_COMPARE_FLAG_IGNORE_NOT_SAVED_SECRETS)
&& (a_secret_flags & NM_SETTING_SECRET_FLAG_NOT_SAVED))
return TRUE;
nm_setting_get_secret_flags (setting, secret_name, &a_secret_flags, NULL);
if (other) {
if (!nm_setting_get_secret_flags (other, secret_name, &b_secret_flags, NULL)) {
/* secret-name may not be a valid secret for @other. That is fine, we ignore that
* and treat @b_secret_flags as NM_SETTING_SECRET_FLAG_NONE.
*
* This can happen with VPN secrets, where the caller knows that @secret_name
* is a secret for setting, but it may not be a secret for @other. Accept that.
*
* Mark @other as missing. */
other = NULL;
}
}
property = _nm_sett_info_property_get (NM_SETTING_GET_CLASS (setting), prop_spec->name);
g_return_val_if_fail (property != NULL, FALSE);
/* when @setting has the secret-flags that should be ignored,
* we skip the comparisong if:
*
* - @other is not present,
* - @other does not have a secret named @secret_name
* - @other also has the secret flat to be ignored.
*
* This makes the check symmetric (aside the fact that @setting must
* have the secret while @other may not -- which is asymetric). */
if ( NM_FLAGS_HAS (flags, NM_SETTING_COMPARE_FLAG_IGNORE_AGENT_OWNED_SECRETS)
&& NM_FLAGS_HAS (a_secret_flags, NM_SETTING_SECRET_FLAG_AGENT_OWNED)
&& ( !other
|| NM_FLAGS_HAS (b_secret_flags, NM_SETTING_SECRET_FLAG_AGENT_OWNED)))
return FALSE;
value1 = get_property_for_dbus (setting, property, TRUE);
value2 = get_property_for_dbus (other, property, TRUE);
if ( NM_FLAGS_HAS (flags, NM_SETTING_COMPARE_FLAG_IGNORE_NOT_SAVED_SECRETS)
&& NM_FLAGS_HAS (a_secret_flags, NM_SETTING_SECRET_FLAG_NOT_SAVED)
&& ( !other
|| NM_FLAGS_HAS (b_secret_flags, NM_SETTING_SECRET_FLAG_NOT_SAVED)))
return FALSE;
cmp = nm_property_compare (value1, value2);
return TRUE;
}
if (value1)
g_variant_unref (value1);
if (value2)
g_variant_unref (value2);
static NMTernary
compare_property (const NMSettInfoSetting *sett_info,
guint property_idx,
NMSetting *setting,
NMSetting *other,
NMSettingCompareFlags flags)
{
const NMSettInfoProperty *property_info = &sett_info->property_infos[property_idx];
const GParamSpec *param_spec = property_info->param_spec;
return cmp == 0;
if (!param_spec)
return NM_TERNARY_DEFAULT;
if ( NM_FLAGS_HAS (flags, NM_SETTING_COMPARE_FLAG_FUZZY)
&& NM_FLAGS_ANY (param_spec->flags, NM_SETTING_PARAM_FUZZY_IGNORE | NM_SETTING_PARAM_SECRET))
return NM_TERNARY_DEFAULT;
if ( NM_FLAGS_HAS (flags, NM_SETTING_COMPARE_FLAG_INFERRABLE)
&& !NM_FLAGS_HAS (param_spec->flags, NM_SETTING_PARAM_INFERRABLE))
return NM_TERNARY_DEFAULT;
if ( NM_FLAGS_HAS (flags, NM_SETTING_COMPARE_FLAG_IGNORE_REAPPLY_IMMEDIATELY)
&& NM_FLAGS_HAS (param_spec->flags, NM_SETTING_PARAM_REAPPLY_IMMEDIATELY))
return NM_TERNARY_DEFAULT;
if ( NM_FLAGS_HAS (flags, NM_SETTING_COMPARE_FLAG_IGNORE_SECRETS)
&& NM_FLAGS_HAS (param_spec->flags, NM_SETTING_PARAM_SECRET))
return NM_TERNARY_DEFAULT;
if (nm_streq (param_spec->name, NM_SETTING_NAME))
return NM_TERNARY_DEFAULT;
if ( NM_FLAGS_HAS (param_spec->flags, NM_SETTING_PARAM_SECRET)
&& !_nm_setting_should_compare_secret_property (setting,
other,
param_spec->name,
flags))
return NM_TERNARY_DEFAULT;
if (other) {
gs_unref_variant GVariant *value1 = NULL;
gs_unref_variant GVariant *value2 = NULL;
value1 = get_property_for_dbus (setting, property_info, TRUE);
value2 = get_property_for_dbus (other, property_info, TRUE);
if (nm_property_compare (value1, value2) != 0)
return NM_TERNARY_FALSE;
}
return NM_TERNARY_TRUE;
}
static NMTernary
_compare_property (const NMSettInfoSetting *sett_info,
guint property_idx,
NMSetting *setting,
NMSetting *other,
NMSettingCompareFlags flags)
{
NMTernary compare_result;
nm_assert (sett_info);
nm_assert (NM_IS_SETTING_CLASS (sett_info->setting_class));
nm_assert (property_idx < sett_info->property_infos_len);
nm_assert (NM_SETTING_GET_CLASS (setting) == sett_info->setting_class);
nm_assert (!other || NM_SETTING_GET_CLASS (other) == sett_info->setting_class);
compare_result = NM_SETTING_GET_CLASS (setting)->compare_property (sett_info,
property_idx,
setting,
other,
flags);
nm_assert (NM_IN_SET (compare_result, NM_TERNARY_DEFAULT,
NM_TERNARY_FALSE,
NM_TERNARY_TRUE));
/* check that the inferable flag and the GObject property flag corresponds. */
nm_assert ( !NM_FLAGS_HAS (flags, NM_SETTING_COMPARE_FLAG_INFERRABLE)
|| !sett_info->property_infos[property_idx].param_spec
|| NM_FLAGS_HAS (sett_info->property_infos[property_idx].param_spec->flags, NM_SETTING_PARAM_INFERRABLE)
|| compare_result == NM_TERNARY_DEFAULT);
return compare_result;
}
/**
@ -1340,89 +1425,13 @@ nm_setting_compare (NMSetting *a,
}
for (i = 0; i < sett_info->property_infos_len; i++) {
const NMSettInfoProperty *property_info = &sett_info->property_infos[i];
if (!should_compare_prop (FALSE, a, property_info, flags))
continue;
if (!NM_SETTING_GET_CLASS (a)->compare_property (a, b, property_info->param_spec, flags))
if (_compare_property (sett_info, i, a, b, flags) == NM_TERNARY_FALSE)
return FALSE;
}
return TRUE;
}
static gboolean
should_compare_prop (gboolean for_diff,
NMSetting *setting,
const NMSettInfoProperty *property_info,
NMSettingCompareFlags comp_flags)
{
const GParamSpec *param_spec = property_info->param_spec;
if (!param_spec)
return FALSE;
if ( NM_FLAGS_HAS (comp_flags, NM_SETTING_COMPARE_FLAG_FUZZY)
&& NM_FLAGS_ANY (param_spec->flags, NM_SETTING_PARAM_FUZZY_IGNORE | NM_SETTING_PARAM_SECRET))
return FALSE;
if ( NM_FLAGS_HAS (comp_flags, NM_SETTING_COMPARE_FLAG_INFERRABLE)
&& !NM_FLAGS_HAS (param_spec->flags, NM_SETTING_PARAM_INFERRABLE))
return FALSE;
if ( NM_FLAGS_HAS (comp_flags, NM_SETTING_COMPARE_FLAG_IGNORE_REAPPLY_IMMEDIATELY)
&& NM_FLAGS_HAS (param_spec->flags, NM_SETTING_PARAM_REAPPLY_IMMEDIATELY))
return FALSE;
if ( NM_FLAGS_HAS (comp_flags, NM_SETTING_COMPARE_FLAG_IGNORE_SECRETS)
&& NM_FLAGS_HAS (param_spec->flags, NM_SETTING_PARAM_SECRET))
return FALSE;
if (nm_streq (param_spec->name, NM_SETTING_NAME))
return FALSE;
if ( for_diff
&& NM_FLAGS_ANY (comp_flags, NM_SETTING_COMPARE_FLAG_IGNORE_AGENT_OWNED_SECRETS
| NM_SETTING_COMPARE_FLAG_IGNORE_NOT_SAVED_SECRETS)
&& NM_FLAGS_HAS (param_spec->flags, NM_SETTING_PARAM_SECRET)) {
NMSettingSecretFlags secret_flags = NM_SETTING_SECRET_FLAG_NONE;
if ( NM_IS_SETTING_VPN (setting)
&& nm_streq (param_spec->name, NM_SETTING_VPN_SECRETS)) {
/* FIXME: NMSettingVPN:NM_SETTING_VPN_SECRETS has NM_SETTING_PARAM_SECRET.
* nm_setting_get_secret_flags() quite possibly fails, but it might succeed if the
* setting accidentally uses a key "secrets". */
return TRUE;
}
if (!nm_setting_get_secret_flags (setting, param_spec->name, &secret_flags, NULL))
g_return_val_if_reached (FALSE);
if ( NM_FLAGS_HAS (comp_flags, NM_SETTING_COMPARE_FLAG_IGNORE_AGENT_OWNED_SECRETS)
&& NM_FLAGS_HAS (secret_flags, NM_SETTING_SECRET_FLAG_AGENT_OWNED))
return FALSE;
if ( NM_FLAGS_HAS (comp_flags, NM_SETTING_COMPARE_FLAG_IGNORE_NOT_SAVED_SECRETS)
&& NM_FLAGS_HAS (secret_flags, NM_SETTING_SECRET_FLAG_NOT_SAVED))
return FALSE;
}
if ( for_diff
&& NM_FLAGS_HAS (comp_flags, NM_SETTING_COMPARE_FLAG_IGNORE_ID)
&& NM_IS_SETTING_CONNECTION (setting)
&& nm_streq (param_spec->name, NM_SETTING_CONNECTION_ID))
return FALSE;
if ( for_diff
&& NM_FLAGS_HAS (comp_flags, NM_SETTING_COMPARE_FLAG_IGNORE_TIMESTAMP)
&& NM_IS_SETTING_CONNECTION (setting)
&& nm_streq (param_spec->name, NM_SETTING_CONNECTION_TIMESTAMP))
return FALSE;
return TRUE;
}
static void
_setting_diff_add_result (GHashTable *results, const char *prop_name, NMSettingDiffResult r)
{
@ -1554,65 +1563,92 @@ nm_setting_diff (NMSetting *a,
}
} else {
for (i = 0; i < sett_info->property_infos_len; i++) {
const NMSettInfoProperty *property_info = &sett_info->property_infos[i];
GParamSpec *prop_spec;
NMSettingDiffResult r = NM_SETTING_DIFF_RESULT_UNKNOWN;
const NMSettInfoProperty *property_info;
NMTernary compare_result;
GParamSpec *prop_spec;
if (!should_compare_prop (TRUE, a, property_info, flags))
compare_result = _compare_property (sett_info, i, a, b, flags);
if (compare_result == NM_TERNARY_DEFAULT)
continue;
prop_spec = property_info->param_spec;
if ( NM_FLAGS_ANY (flags, NM_SETTING_COMPARE_FLAG_IGNORE_AGENT_OWNED_SECRETS
| NM_SETTING_COMPARE_FLAG_IGNORE_NOT_SAVED_SECRETS)
&& b
&& compare_result == NM_TERNARY_FALSE) {
/* we have setting @b and the property is not the same. But we also are instructed
* to ignore secrets based on the flags.
*
* Note that compare_property() called with two settings will ignore secrets
* based on the flags, but it will do so if *both* settings have the flag we
* look for. So that is symetric behavior and good.
*
* But for the purpose of diff(), we do a asymmetric comparison because and
* we want to skip testing the property if setting @a alone indicates to do
* so.
*
* We need to double-check whether the property should be ignored by
* looking at @a alone. */
if (_compare_property (sett_info, i, a, NULL, flags) == NM_TERNARY_DEFAULT)
continue;
}
compared_any = TRUE;
property_info = &sett_info->property_infos[i];
prop_spec = property_info->param_spec;
if (b) {
gboolean different;
if (compare_result == NM_TERNARY_FALSE) {
if (prop_spec) {
gboolean a_is_default, b_is_default;
GValue value = G_VALUE_INIT;
different = !NM_SETTING_GET_CLASS (a)->compare_property (a, b, prop_spec, flags);
if (different) {
gboolean a_is_default, b_is_default;
GValue value = G_VALUE_INIT;
g_value_init (&value, prop_spec->value_type);
g_object_get_property (G_OBJECT (a), prop_spec->name, &value);
a_is_default = g_param_value_defaults (prop_spec, &value);
g_value_init (&value, prop_spec->value_type);
g_object_get_property (G_OBJECT (a), prop_spec->name, &value);
a_is_default = g_param_value_defaults (prop_spec, &value);
g_value_reset (&value);
g_object_get_property (G_OBJECT (b), prop_spec->name, &value);
b_is_default = g_param_value_defaults (prop_spec, &value);
g_value_reset (&value);
g_object_get_property (G_OBJECT (b), prop_spec->name, &value);
b_is_default = g_param_value_defaults (prop_spec, &value);
g_value_unset (&value);
if ((flags & NM_SETTING_COMPARE_FLAG_DIFF_RESULT_WITH_DEFAULT) == 0) {
if (!a_is_default)
r |= a_result;
if (!b_is_default)
r |= b_result;
} else {
g_value_unset (&value);
if (!NM_FLAGS_HAS (flags, NM_SETTING_COMPARE_FLAG_DIFF_RESULT_WITH_DEFAULT)) {
if (!a_is_default)
r |= a_result;
if (!b_is_default)
r |= b_result;
} else {
r |= a_result | b_result;
if (a_is_default)
r |= a_result_default;
if (b_is_default)
r |= b_result_default;
}
} else
r |= a_result | b_result;
if (a_is_default)
r |= a_result_default;
if (b_is_default)
r |= b_result_default;
}
}
} else if ((flags & (NM_SETTING_COMPARE_FLAG_DIFF_RESULT_WITH_DEFAULT | NM_SETTING_COMPARE_FLAG_DIFF_RESULT_NO_DEFAULT)) == 0)
r = a_result; /* only in A */
else {
GValue value = G_VALUE_INIT;
if (prop_spec) {
GValue value = G_VALUE_INIT;
g_value_init (&value, prop_spec->value_type);
g_object_get_property (G_OBJECT (a), prop_spec->name, &value);
if (!g_param_value_defaults (prop_spec, &value))
g_value_init (&value, prop_spec->value_type);
g_object_get_property (G_OBJECT (a), prop_spec->name, &value);
if (!g_param_value_defaults (prop_spec, &value))
r |= a_result;
else if (flags & NM_SETTING_COMPARE_FLAG_DIFF_RESULT_WITH_DEFAULT)
r |= a_result | a_result_default;
g_value_unset (&value);
} else
r |= a_result;
else if (flags & NM_SETTING_COMPARE_FLAG_DIFF_RESULT_WITH_DEFAULT)
r |= a_result | a_result_default;
g_value_unset (&value);
}
if (r != NM_SETTING_DIFF_RESULT_UNKNOWN) {
diff_found = TRUE;
_setting_diff_add_result (*results, prop_spec->name, r);
_setting_diff_add_result (*results, property_info->name, r);
}
}
}

View file

@ -169,6 +169,7 @@ typedef gboolean (*NMSettingClearSecretsWithFlagsFn) (NMSetting *setting,
gpointer user_data);
struct _NMMetaSettingInfo;
struct _NMSettInfoSetting;
typedef struct {
GObjectClass parent;
@ -204,11 +205,18 @@ typedef struct {
NMSettingClearSecretsWithFlagsFn func,
gpointer user_data);
/* Returns TRUE if the given property contains the same value in both settings */
gboolean (*compare_property) (NMSetting *setting,
NMSetting *other,
const GParamSpec *prop_spec,
NMSettingCompareFlags flags);
/* compare_property() returns a ternary, where DEFAULT means that the property should not
* be compared due to the compare @flags. A TRUE/FALSE result means that the property is
* equal/not-equal.
*
* @other may be %NULL, in which case the function only determines whether
* the setting should be compared (TRUE) or not (DEFAULT). */
/*< private >*/
NMTernary (*compare_property) (const struct _NMSettInfoSetting *sett_info,
guint property_idx,
NMSetting *setting,
NMSetting *other,
NMSettingCompareFlags flags);
/*< private >*/
const struct _NMMetaSettingInfo *setting_info;