diff --git a/src/libnm-core-impl/nm-setting.c b/src/libnm-core-impl/nm-setting.c index 35139ebadd..f3399d58c8 100644 --- a/src/libnm-core-impl/nm-setting.c +++ b/src/libnm-core-impl/nm-setting.c @@ -729,6 +729,24 @@ out_take: return nm_strdup_reset_take(dst, s); } +static gboolean +_property_direct_set_strv(const NMSettInfoSetting *sett_info, + const NMSettInfoProperty *property_info, + NMSetting *setting, + const char *const *strv) +{ + NMValueStrv *p_val = _nm_setting_get_private_field(setting, sett_info, property_info); + + if (!property_info->direct_strv_preserve_empty && strv && !strv[0]) + strv = NULL; + + if (nm_strvarray_equal_strv(p_val->arr, strv, -1)) + return FALSE; + + nm_strvarray_set_strv_full(&p_val->arr, strv, property_info->direct_strv_preserve_empty); + return TRUE; +} + void _nm_setting_property_get_property_direct(GObject *object, guint prop_id, @@ -817,7 +835,12 @@ _nm_setting_property_get_property_direct(GObject *object, { const NMValueStrv *p_val = _nm_setting_get_private_field(setting, sett_info, property_info); - g_value_take_boxed(value, nm_strvarray_get_strv_notempty_dup(p_val->arr, NULL)); + g_value_take_boxed( + value, + nm_strvarray_get_strv_full_dup(p_val->arr, + NULL, + FALSE, + property_info->direct_strv_preserve_empty)); return; } default: @@ -956,17 +979,9 @@ _nm_setting_property_set_property_direct(GObject *object, goto out_notify; } case NM_VALUE_TYPE_STRV: - { - NMValueStrv *p_val = _nm_setting_get_private_field(setting, sett_info, property_info); - const char *const *v; - - v = g_value_get_boxed(value); - if (nm_strvarray_equal_strv(p_val->arr, v, -1)) + if (!_property_direct_set_strv(sett_info, property_info, setting, g_value_get_boxed(value))) return; - - nm_strvarray_set_strv(&p_val->arr, v); goto out_notify; - } default: goto out_fail; } @@ -1281,7 +1296,7 @@ _nm_setting_property_to_dbus_fcn_direct(_NM_SETT_INFO_PROP_TO_DBUS_FCN_ARGS _nm_ (const NMValueStrv *) _nm_setting_get_private_field(setting, sett_info, property_info); if (!val->arr) return NULL; - if (val->arr->len == 0) { + if (!property_info->direct_strv_preserve_empty && val->arr->len == 0) { /* This property does not treat empty strv arrays special. No need * to export the value on D-Bus. */ return NULL; @@ -1650,7 +1665,6 @@ _nm_setting_property_from_dbus_fcn_direct(_NM_SETT_INFO_PROP_FROM_DBUS_FCN_ARGS } case NM_VALUE_TYPE_STRV: { - NMValueStrv *p_val; gs_free const char **ss = NULL; gsize ss_len; @@ -1661,13 +1675,10 @@ _nm_setting_property_from_dbus_fcn_direct(_NM_SETT_INFO_PROP_FROM_DBUS_FCN_ARGS ss = g_variant_get_strv(value, &ss_len); nm_assert(ss_len <= G_MAXUINT); + nm_assert(NM_PTRARRAY_LEN(ss) == ss_len); - p_val = _nm_setting_get_private_field(setting, sett_info, property_info); - - if (nm_strvarray_equal_strv(p_val->arr, ss, ss_len)) + if (!_property_direct_set_strv(sett_info, property_info, setting, ss)) goto out_unchanged; - - nm_strvarray_set_strv(&p_val->arr, ss); goto out_notify; } default: @@ -2590,11 +2601,13 @@ _nm_setting_property_compare_fcn_direct(_NM_SETT_INFO_PROP_COMPARE_FCN_ARGS _nm_ const GArray *a = v_a->arr; const GArray *b = v_b->arr; - /* NULL and empty are treated identical. Coerce to NULL. */ - if (a && a->len == 0) - a = NULL; - if (b && b->len == 0) - b = NULL; + if (!property_info->direct_strv_preserve_empty) { + /* NULL and empty are treated identical. Coerce to NULL. */ + if (a && a->len == 0) + a = NULL; + if (b && b->len == 0) + b = NULL; + } return nm_strvarray_equal(a, b); } default: diff --git a/src/libnm-core-impl/tests/test-setting.c b/src/libnm-core-impl/tests/test-setting.c index 53a7acd2fc..e9aa99819f 100644 --- a/src/libnm-core-impl/tests/test-setting.c +++ b/src/libnm-core-impl/tests/test-setting.c @@ -4736,6 +4736,8 @@ test_setting_metadata(void) g_assert(sip->param_spec); g_assert(!NM_FLAGS_HAS(sip->param_spec->flags, NM_SETTING_PARAM_SECRET)); } + if (sip->direct_strv_preserve_empty) + g_assert(sip->property_type->direct_type == NM_VALUE_TYPE_STRV); if (sip->direct_set_string_mac_address_len != 0) { g_assert(NM_IN_SET(sip->property_type, diff --git a/src/libnm-core-intern/nm-core-internal.h b/src/libnm-core-intern/nm-core-internal.h index 1679a724f2..2d42025a61 100644 --- a/src/libnm-core-intern/nm-core-internal.h +++ b/src/libnm-core-intern/nm-core-internal.h @@ -818,6 +818,14 @@ struct _NMSettInfoProperty { /* Whether the string property is implemented as a (downcast) NMRefString. */ bool direct_string_is_refstr : 1; + /* Usually, for strv arrays (NM_VALUE_TYPE_STRV, NMValueStrv) there is little + * difference between NULL/unset and empty arrays. E.g. g_object_get() will + * return NULL and never an empty strv array. + * + * By setting this flag, this property treats a NULL array different from + * an empty array. */ + bool direct_strv_preserve_empty : 1; + /* Usually, properties that are set to the default value for the GParamSpec * are not serialized to GVariant (and NULL is returned by to_dbus_data(). * Set this flag to force always converting the property even if the value