summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libnm-core/nm-core-internal.h52
-rw-r--r--libnm-core/nm-keyfile.c147
-rw-r--r--libnm-core/nm-setting-private.h11
-rw-r--r--libnm-core/nm-setting.c586
-rw-r--r--libnm-core/nm-setting.h8
5 files changed, 708 insertions, 96 deletions
diff --git a/libnm-core/nm-core-internal.h b/libnm-core/nm-core-internal.h
index 21c45ab425..7338cd27af 100644
--- a/libnm-core/nm-core-internal.h
+++ b/libnm-core/nm-core-internal.h
@@ -173,6 +173,34 @@ NMSettingPriority _nm_setting_get_setting_priority (NMSetting *setting);
gboolean _nm_setting_get_property (NMSetting *setting, const char *name, GValue *value);
+/*****************************************************************************/
+
+GHashTable *_nm_setting_gendata_hash (NMSetting *setting,
+ gboolean create_if_necessary);
+
+void _nm_setting_gendata_notify (NMSetting *setting,
+ gboolean keys_changed);
+
+guint _nm_setting_gendata_get_all (NMSetting *setting,
+ const char *const**out_names,
+ GVariant *const**out_values);
+
+gboolean _nm_setting_gendata_reset_from_hash (NMSetting *setting,
+ GHashTable *new);
+
+void _nm_setting_gendata_to_gvalue (NMSetting *setting,
+ GValue *value);
+
+GVariant *nm_setting_gendata_get (NMSetting *setting,
+ const char *name);
+
+const char *const*nm_setting_gendata_get_all_names (NMSetting *setting,
+ guint *out_len);
+
+GVariant *const*nm_setting_gendata_get_all_values (NMSetting *setting);
+
+/*****************************************************************************/
+
#define NM_UTILS_HWADDR_LEN_MAX_STR (NM_UTILS_HWADDR_LEN_MAX * 3)
guint8 *_nm_utils_hwaddr_aton (const char *asc, gpointer buffer, gsize buffer_length, gsize *out_length);
@@ -481,6 +509,8 @@ gboolean _nm_setting_sriov_sort_vfs (NMSettingSriov *setting);
/*****************************************************************************/
+typedef struct _NMSettInfoSetting NMSettInfoSetting;
+
typedef GVariant *(*NMSettingPropertyGetFunc) (NMSetting *setting,
const char *property);
typedef GVariant *(*NMSettingPropertySynthFunc) (NMSetting *setting,
@@ -516,14 +546,32 @@ typedef struct {
} NMSettInfoProperty;
typedef struct {
-} NMSettInfoSettDetail;
+ const GVariantType *(*get_variant_type) (const struct _NMSettInfoSetting *sett_info,
+ const char *name,
+ GError **error);
+} NMSettInfoSettGendata;
typedef struct {
+ /* if set, then this setting class has no own fields. Instead, its
+ * data is entirely based on gendata. Meaning: it tracks all data
+ * as native GVariants.
+ * It might have some GObject properties, but these are merely accessors
+ * to the underlying gendata.
+ *
+ * Note, that at the moment there are few hooks, to customize the behavior
+ * of the setting further. They are currently unneeded. This is desired,
+ * but could be added when there is a good reason.
+ *
+ * However, a few hooks there are... see NMSettInfoSettGendata. */
+ const NMSettInfoSettGendata *gendata_info;
+} NMSettInfoSettDetail;
+
+struct _NMSettInfoSetting {
NMSettingClass *setting_class;
const NMSettInfoProperty *property_infos;
guint property_infos_len;
NMSettInfoSettDetail detail;
-} NMSettInfoSetting;
+};
const NMSettInfoSetting *_nm_sett_info_setting_get (NMSettingClass *setting_class);
diff --git a/libnm-core/nm-keyfile.c b/libnm-core/nm-keyfile.c
index 6ea42d13bc..3f9d60bbb7 100644
--- a/libnm-core/nm-keyfile.c
+++ b/libnm-core/nm-keyfile.c
@@ -2684,6 +2684,8 @@ read_one_setting_value (NMSetting *setting,
static NMSetting *
read_setting (KeyfileReaderInfo *info)
{
+ const NMSettInfoSetting *sett_info;
+ gs_unref_object NMSetting *setting = NULL;
const char *alias;
GType type;
@@ -2692,22 +2694,92 @@ read_setting (KeyfileReaderInfo *info)
alias = info->group;
type = nm_setting_lookup_type (alias);
- if (type) {
- NMSetting *setting = g_object_new (type, NULL);
-
- info->setting = setting;
- nm_setting_enumerate_values (setting, read_one_setting_value, info);
- info->setting = NULL;
- if (!info->error)
- return setting;
-
- g_object_unref (setting);
- } else {
+ if (!type) {
handle_warn (info, NULL, NM_KEYFILE_WARN_SEVERITY_WARN,
_("invalid setting name '%s'"), info->group);
+ return NULL;
}
- return NULL;
+ setting = g_object_new (type, NULL);
+
+ info->setting = setting;
+
+ sett_info = _nm_sett_info_setting_get (NM_SETTING_GET_CLASS (setting));
+
+ if (sett_info->detail.gendata_info) {
+ gs_free char **keys = NULL;
+ gsize i, n_keys;
+
+ keys = g_key_file_get_keys (info->keyfile, info->group, &n_keys, NULL);
+ if (n_keys > 0) {
+ GHashTable *h = _nm_setting_gendata_hash (setting, TRUE);
+
+ nm_utils_strv_sort (keys, n_keys);
+ for (i = 0; i < n_keys; i++) {
+ gs_free char *key = keys[i];
+ gs_free_error GError *local = NULL;
+ const GVariantType *variant_type;
+ GVariant *variant;
+
+ /* a GKeyfile can return duplicate keys, there is just no API to make sense
+ * of them. Skip them. */
+ if ( i + 1 < n_keys
+ && nm_streq (key, keys[i + 1]))
+ continue;
+
+ /* currently, the API is very simple. The setting class just returns
+ * the desired variant type, and keyfile reader will try to parse
+ * it accordingly. Note, that this does currently not allow, that
+ * a particular key can contain different variant types, nor is it
+ * very flexible in general.
+ *
+ * We add flexibility when we need it. Keep it simple for now. */
+ variant_type = sett_info->detail.gendata_info->get_variant_type (sett_info,
+ key,
+ &local);
+ if (!variant_type) {
+ if (!handle_warn (info, key, NM_KEYFILE_WARN_SEVERITY_WARN,
+ _("invalid key '%s.%s'"),
+ info->group, key))
+ break;
+ continue;
+ }
+
+ if (g_variant_type_equal (variant_type, G_VARIANT_TYPE_BOOLEAN)) {
+ gboolean v;
+
+ v = g_key_file_get_boolean (info->keyfile,
+ info->group,
+ key,
+ &local);
+ if (local) {
+ if (!handle_warn (info, key, NM_KEYFILE_WARN_SEVERITY_WARN,
+ _("key '%s.%s' is not boolean"),
+ info->group, key))
+ break;
+ continue;
+ }
+ variant = g_variant_new_boolean (v);
+ } else {
+ nm_assert_not_reached ();
+ continue;
+ }
+
+ g_hash_table_insert (h,
+ g_steal_pointer (&key),
+ g_variant_take_ref (variant));
+ }
+ for (; i < n_keys; i++)
+ g_free (keys[i]);
+ }
+ } else
+ nm_setting_enumerate_values (setting, read_one_setting_value, info);
+
+ info->setting = NULL;
+
+ if (info->error)
+ return NULL;
+ return g_steal_pointer (&setting);
}
static void
@@ -2998,6 +3070,8 @@ nm_keyfile_write (NMConnection *connection,
GError **error)
{
KeyfileWriterInfo info = { 0 };
+ gs_free NMSetting **settings = NULL;
+ guint i, length = 0;
g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL);
g_return_val_if_fail (!error || !*error, NULL);
@@ -3010,12 +3084,59 @@ nm_keyfile_write (NMConnection *connection,
info.error = NULL;
info.handler = handler;
info.user_data = user_data;
- nm_connection_for_each_setting_value (connection, write_setting_value, &info);
+
+ settings = nm_connection_get_settings (connection, &length);
+ for (i = 0; i < length; i++) {
+ const NMSettInfoSetting *sett_info;
+ NMSetting *setting = settings[i];
+
+ sett_info = _nm_sett_info_setting_get (NM_SETTING_GET_CLASS (setting));
+
+ if (sett_info->detail.gendata_info) {
+ guint k, n_keys;
+ const char *const*keys;
+
+ nm_assert (!nm_keyfile_plugin_get_alias_for_setting_name (sett_info->setting_class->setting_info->setting_name));
+
+ n_keys = _nm_setting_gendata_get_all (setting, &keys, NULL);
+
+ if (n_keys > 0) {
+ const char *setting_name = sett_info->setting_class->setting_info->setting_name;
+ GHashTable *h = _nm_setting_gendata_hash (setting, FALSE);
+
+ for (k = 0; k < n_keys; k++) {
+ const char *key = keys[k];
+ GVariant *v;
+
+ v = g_hash_table_lookup (h, key);
+
+ if (g_variant_is_of_type (v, G_VARIANT_TYPE_BOOLEAN)) {
+ g_key_file_set_boolean (info.keyfile,
+ setting_name,
+ key,
+ g_variant_get_boolean (v));
+ } else {
+ /* BUG: The variant type is not implemented. Since the connection
+ * verifies, this can only mean we either wrongly didn't reject
+ * the connection as invalid, or we didn't properly implement the
+ * variant type. */
+ nm_assert_not_reached ();
+ continue;
+ }
+ }
+ }
+ } else
+ nm_setting_enumerate_values (setting, write_setting_value, &info);
+
+ if (info.error)
+ break;
+ }
if (info.error) {
g_propagate_error (error, info.error);
g_key_file_unref (info.keyfile);
return NULL;
}
+
return info.keyfile;
}
diff --git a/libnm-core/nm-setting-private.h b/libnm-core/nm-setting-private.h
index 99c7b69ccd..1e25226ede 100644
--- a/libnm-core/nm-setting-private.h
+++ b/libnm-core/nm-setting-private.h
@@ -80,6 +80,8 @@ gboolean _nm_setting_clear_secrets_with_flags (NMSetting *setting,
*/
#define NM_SETTING_PARAM_REAPPLY_IMMEDIATELY (1 << (6 + G_PARAM_USER_SHIFT))
+#define NM_SETTING_PARAM_GENDATA_BACKED (1 << (7 + G_PARAM_USER_SHIFT))
+
GVariant *_nm_setting_get_deprecated_virtual_interface_name (NMSetting *setting,
NMConnection *connection,
const char *property);
@@ -127,6 +129,15 @@ _nm_setting_class_commit (NMSettingClass *setting_class,
_nm_setting_class_commit_full (setting_class, meta_type, NULL, NULL);
}
+#define NM_SETT_INFO_SETT_GENDATA(...) \
+ ({ \
+ static const NMSettInfoSettGendata _g = { \
+ __VA_ARGS__ \
+ }; \
+ \
+ &_g; \
+ })
+
#define NM_SETT_INFO_SETT_DETAIL(...) \
(&((const NMSettInfoSettDetail) { \
__VA_ARGS__ \
diff --git a/libnm-core/nm-setting.c b/libnm-core/nm-setting.c
index 2e884de7a0..53a2a22a16 100644
--- a/libnm-core/nm-setting.c
+++ b/libnm-core/nm-setting.c
@@ -56,6 +56,12 @@
/*****************************************************************************/
typedef struct {
+ GHashTable *hash;
+ const char **names;
+ GVariant **values;
+} GenData;
+
+typedef struct {
const char *name;
GType type;
NMSettingPriority priority;
@@ -69,7 +75,7 @@ enum {
};
typedef struct {
- int dummy;
+ GenData *gendata;
} NMSettingPrivate;
G_DEFINE_ABSTRACT_TYPE (NMSetting, nm_setting, G_TYPE_OBJECT)
@@ -78,6 +84,10 @@ G_DEFINE_ABSTRACT_TYPE (NMSetting, nm_setting, G_TYPE_OBJECT)
/*****************************************************************************/
+static GenData *_gendata_hash (NMSetting *setting, gboolean create_if_necessary);
+
+/*****************************************************************************/
+
static NMSettingPriority
_get_base_type_priority (const NMMetaSettingInfo *setting_info,
GType gtype)
@@ -623,15 +633,27 @@ set_property_from_dbus (const NMSettInfoProperty *property,
GVariant *
_nm_setting_to_dbus (NMSetting *setting, NMConnection *connection, NMConnectionSerializationFlags flags)
{
+ NMSettingPrivate *priv;
GVariantBuilder builder;
GVariant *dbus_value;
const NMSettInfoSetting *sett_info;
- guint i;
+ guint n_properties, i;
+ const char *const*gendata_keys;
g_return_val_if_fail (NM_IS_SETTING (setting), NULL);
+ priv = NM_SETTING_GET_PRIVATE (setting);
+
g_variant_builder_init (&builder, NM_VARIANT_TYPE_SETTING);
+ n_properties = _nm_setting_gendata_get_all (setting, &gendata_keys, NULL);
+ for (i = 0; i < n_properties; i++) {
+ g_variant_builder_add (&builder,
+ "{sv}",
+ gendata_keys[i],
+ g_hash_table_lookup (priv->gendata->hash, gendata_keys[i]));
+ }
+
sett_info = _nm_sett_info_setting_get (NM_SETTING_GET_CLASS (setting));
for (i = 0; i < sett_info->property_infos_len; i++) {
const NMSettInfoProperty *property = &sett_info->property_infos[i];
@@ -647,6 +669,9 @@ _nm_setting_to_dbus (NMSetting *setting, NMConnection *connection, NMConnectionS
if (!(prop_spec->flags & G_PARAM_WRITABLE))
continue;
+ if (NM_FLAGS_ANY (prop_spec->flags, NM_SETTING_PARAM_GENDATA_BACKED))
+ continue;
+
if ( (prop_spec->flags & NM_SETTING_PARAM_LEGACY)
&& !_nm_utils_is_manager_process)
continue;
@@ -751,6 +776,26 @@ _nm_setting_new_from_dbus (GType setting_type,
}
sett_info = _nm_sett_info_setting_get (NM_SETTING_GET_CLASS (setting));
+
+ if (sett_info->detail.gendata_info) {
+ GHashTable *hash;
+ GVariantIter iter;
+ char *key;
+ GVariant *val;
+
+ hash = _gendata_hash (setting, TRUE)->hash;
+
+ g_variant_iter_init (&iter, setting_dict);
+ while (g_variant_iter_next (&iter, "{sv}", &key, &val)) {
+ g_hash_table_insert (hash,
+ key,
+ val);
+ }
+
+ _nm_setting_gendata_notify (setting, TRUE);
+ return g_steal_pointer (&setting);
+ }
+
for (i = 0; i < sett_info->property_infos_len; i++) {
const NMSettInfoProperty *property = &sett_info->property_infos[i];
gs_unref_variant GVariant *value = NULL;
@@ -888,14 +933,32 @@ nm_setting_get_dbus_property_type (NMSetting *setting,
gboolean
_nm_setting_get_property (NMSetting *setting, const char *property_name, GValue *value)
{
+ const NMSettInfoSetting *sett_info;
GParamSpec *prop_spec;
g_return_val_if_fail (NM_IS_SETTING (setting), FALSE);
g_return_val_if_fail (property_name, FALSE);
g_return_val_if_fail (value, FALSE);
- prop_spec = g_object_class_find_property (G_OBJECT_GET_CLASS (setting), property_name);
+ sett_info = _nm_sett_info_setting_get (NM_SETTING_GET_CLASS (setting));
+ if (sett_info->detail.gendata_info) {
+ GVariant *variant;
+ GenData *gendata = _gendata_hash (setting, FALSE);
+
+ variant = gendata ? g_hash_table_lookup (gendata->hash, property_name) : NULL;
+
+ if (!variant) {
+ g_value_unset (value);
+ return FALSE;
+ }
+
+ g_value_init (value, G_TYPE_VARIANT);
+ g_value_set_variant (value, variant);
+ return TRUE;
+ }
+
+ prop_spec = g_object_class_find_property (G_OBJECT_GET_CLASS (setting), property_name);
if (!prop_spec) {
g_value_unset (value);
return FALSE;
@@ -929,16 +992,37 @@ duplicate_setting (NMSetting *setting,
NMSetting *
nm_setting_duplicate (NMSetting *setting)
{
+ const NMSettInfoSetting *sett_info;
GObject *dup;
g_return_val_if_fail (NM_IS_SETTING (setting), NULL);
dup = g_object_new (G_OBJECT_TYPE (setting), NULL);
- g_object_freeze_notify (dup);
- nm_setting_enumerate_values (setting, duplicate_setting, dup);
- g_object_thaw_notify (dup);
+ sett_info = _nm_sett_info_setting_get (NM_SETTING_GET_CLASS (setting));
+ if (sett_info->detail.gendata_info) {
+ GenData *gendata = _gendata_hash (setting, FALSE);
+
+ if ( gendata
+ && g_hash_table_size (gendata->hash) > 0) {
+ GHashTableIter iter;
+ GHashTable *h = _gendata_hash (NM_SETTING (dup), TRUE)->hash;
+ const char *key;
+ GVariant *val;
+
+ g_hash_table_iter_init (&iter, gendata->hash);
+ while (g_hash_table_iter_next (&iter, (gpointer *) &key, (gpointer *) &val)) {
+ g_hash_table_insert (h,
+ g_strdup (key),
+ g_variant_ref (val));
+ }
+ }
+ } else {
+ g_object_freeze_notify (dup);
+ nm_setting_enumerate_values (setting, duplicate_setting, dup);
+ g_object_thaw_notify (dup);
+ }
return NM_SETTING (dup);
}
@@ -1118,6 +1202,7 @@ nm_setting_compare (NMSetting *a,
NMSetting *b,
NMSettingCompareFlags flags)
{
+ const NMSettInfoSetting *sett_info;
GParamSpec **property_specs;
guint n_property_specs;
int same = TRUE;
@@ -1130,6 +1215,18 @@ nm_setting_compare (NMSetting *a,
if (G_OBJECT_TYPE (a) != G_OBJECT_TYPE (b))
return FALSE;
+ sett_info = _nm_sett_info_setting_get (NM_SETTING_GET_CLASS (a));
+
+ if (sett_info->detail.gendata_info) {
+ GenData *a_gendata = _gendata_hash (a, FALSE);
+ GenData *b_gendata = _gendata_hash (b, FALSE);
+
+ return nm_utils_hash_table_equal (a_gendata ? a_gendata->hash : NULL,
+ b_gendata ? b_gendata->hash : NULL,
+ TRUE,
+ g_variant_equal);
+ }
+
/* 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 && same; i++) {
@@ -1215,6 +1312,21 @@ should_compare_prop (NMSetting *setting,
return TRUE;
}
+static void
+_setting_diff_add_result (GHashTable *results, const char *prop_name, NMSettingDiffResult r)
+{
+ void *p;
+
+ if (r == NM_SETTING_DIFF_RESULT_UNKNOWN)
+ return;
+
+ if (g_hash_table_lookup_extended (results, prop_name, NULL, &p)) {
+ if (!NM_FLAGS_ALL ((guint) r, GPOINTER_TO_UINT (p)))
+ g_hash_table_insert (results, g_strdup (prop_name), GUINT_TO_POINTER (((guint) r) | GPOINTER_TO_UINT (p)));
+ } else
+ g_hash_table_insert (results, g_strdup (prop_name), GUINT_TO_POINTER (r));
+}
+
/**
* nm_setting_diff:
* @a: a #NMSetting
@@ -1243,8 +1355,7 @@ nm_setting_diff (NMSetting *a,
gboolean invert_results,
GHashTable **results)
{
- GParamSpec **property_specs;
- guint n_property_specs;
+ const NMSettInfoSetting *sett_info;
guint i;
NMSettingDiffResult a_result = NM_SETTING_DIFF_RESULT_IN_A;
NMSettingDiffResult b_result = NM_SETTING_DIFF_RESULT_IN_B;
@@ -1288,78 +1399,117 @@ nm_setting_diff (NMSetting *a,
results_created = TRUE;
}
- /* And now all properties */
- property_specs = g_object_class_list_properties (G_OBJECT_GET_CLASS (a), &n_property_specs);
+ sett_info = _nm_sett_info_setting_get (NM_SETTING_GET_CLASS (a));
- for (i = 0; i < n_property_specs; i++) {
- GParamSpec *prop_spec = property_specs[i];
- NMSettingDiffResult r = NM_SETTING_DIFF_RESULT_UNKNOWN;
+ if (sett_info->detail.gendata_info) {
+ const char *key;
+ GVariant *val, *val2;
+ GHashTableIter iter;
+ GenData *a_gendata = _gendata_hash (a, FALSE);
+ GenData *b_gendata = b ? _gendata_hash (b, FALSE) : NULL;
+
+ if (!a_gendata || !b_gendata) {
+ if (a_gendata || b_gendata) {
+ NMSettingDiffResult one_sided_result;
+
+ one_sided_result = a_gendata ? a_result : b_result;
+ g_hash_table_iter_init (&iter, a_gendata ? a_gendata->hash : b_gendata->hash);
+ while (g_hash_table_iter_next (&iter, (gpointer *) &key, NULL)) {
+ diff_found = TRUE;
+ _setting_diff_add_result (*results, key, one_sided_result);
+ }
+ }
+ } else {
+ g_hash_table_iter_init (&iter, a_gendata->hash);
+ while (g_hash_table_iter_next (&iter, (gpointer *) &key, (gpointer *) &val)) {
+ val2 = b_gendata ? g_hash_table_lookup (b_gendata->hash, key) : NULL;
+ compared_any = TRUE;
+ if ( !val2
+ || !g_variant_equal (val, val2)) {
+ diff_found = TRUE;
+ _setting_diff_add_result (*results, key, a_result);
+ }
+ }
+ g_hash_table_iter_init (&iter, b_gendata->hash);
+ while (g_hash_table_iter_next (&iter, (gpointer *) &key, (gpointer *) &val)) {
+ val2 = a_gendata ? g_hash_table_lookup (a_gendata->hash, key) : NULL;
+ compared_any = TRUE;
+ if ( !val2
+ || !g_variant_equal (val, val2)) {
+ diff_found = TRUE;
+ _setting_diff_add_result (*results, key, b_result);
+ }
+ }
+ }
+ } else {
+ gs_free GParamSpec **property_specs = NULL;
+ guint n_property_specs;
- /* 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;
+ property_specs = g_object_class_list_properties (G_OBJECT_GET_CLASS (a), &n_property_specs);
- compared_any = TRUE;
+ for (i = 0; i < n_property_specs; i++) {
+ GParamSpec *prop_spec = property_specs[i];
+ NMSettingDiffResult r = NM_SETTING_DIFF_RESULT_UNKNOWN;
- if (b) {
- gboolean different;
+ /* 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;
- different = !NM_SETTING_GET_CLASS (a)->compare_property (a, b, prop_spec, flags);
- if (different) {
- gboolean a_is_default, b_is_default;
+ compared_any = TRUE;
+
+ if (b) {
+ gboolean different;
+
+ 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_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 {
+ 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;
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);
+ 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);
- 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 {
- 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;
-
- 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);
- }
-
- if (r != NM_SETTING_DIFF_RESULT_UNKNOWN) {
- void *p;
-
- diff_found = TRUE;
- if (g_hash_table_lookup_extended (*results, prop_spec->name, NULL, &p)) {
- if ((r & GPOINTER_TO_UINT (p)) != r)
- g_hash_table_insert (*results, g_strdup (prop_spec->name), GUINT_TO_POINTER (r | GPOINTER_TO_UINT (p)));
- } else
- g_hash_table_insert (*results, g_strdup (prop_spec->name), GUINT_TO_POINTER (r));
+ if (r != NM_SETTING_DIFF_RESULT_UNKNOWN) {
+ diff_found = TRUE;
+ _setting_diff_add_result (*results, prop_spec->name, r);
+ }
}
}
- g_free (property_specs);
if (!compared_any && !b) {
/* special case: the setting has no properties, and the opposite
@@ -1370,7 +1520,7 @@ nm_setting_diff (NMSetting *a,
if (diff_found) {
/* if there is a difference, we always return FALSE. It also means, we might
- * have allocated a new @results hash, and return if to the caller. */
+ * have allocated a new @results hash, and return it to the caller. */
return FALSE;
} else {
if (results_created) {
@@ -1426,23 +1576,57 @@ nm_setting_enumerate_values (NMSetting *setting,
NMSettingValueIterFn func,
gpointer user_data)
{
+ const NMSettInfoSetting *sett_info;
GParamSpec **property_specs;
- guint n_property_specs;
- int i;
+ guint n_properties;
+ guint i;
GType type;
g_return_if_fail (NM_IS_SETTING (setting));
g_return_if_fail (func != NULL);
- property_specs = g_object_class_list_properties (G_OBJECT_GET_CLASS (setting), &n_property_specs);
+ sett_info = _nm_sett_info_setting_get (NM_SETTING_GET_CLASS (setting));
+
+ if (sett_info->detail.gendata_info) {
+ const char *const*names;
+
+ /* the properties of this setting are not real GObject properties.
+ * Hence, this API makes little sense (or does it?). Still, call
+ * @func with each value. */
+ n_properties = _nm_setting_gendata_get_all (setting, &names, NULL);
+ if (n_properties > 0) {
+ gs_strfreev char **keys = g_strdupv ((char **) names);
+ GHashTable *h = _gendata_hash (setting, FALSE)->hash;
+
+ for (i = 0; i < n_properties; i++) {
+ GValue value = G_VALUE_INIT;
+ GVariant *val = g_hash_table_lookup (h, keys[i]);
+
+ if (!val) {
+ /* was deleted in the meantime? Skip */
+ continue;
+ }
+
+ g_value_init (&value, G_TYPE_VARIANT);
+ g_value_set_variant (&value, val);
+ /* call it will GParamFlags 0. It shall indicate that this
+ * is not a "real" GObject property. */
+ func (setting, keys[i], &value, 0, user_data);
+ g_value_unset (&value);
+ }
+ }
+ return;
+ }
+
+ property_specs = g_object_class_list_properties (G_OBJECT_GET_CLASS (setting), &n_properties);
/* sort the properties. This has an effect on the order in which keyfile
* prints them. */
type = G_OBJECT_TYPE (setting);
- g_qsort_with_data (property_specs, n_property_specs, sizeof (gpointer),
+ g_qsort_with_data (property_specs, n_properties, sizeof (gpointer),
(GCompareDataFunc) _enumerate_values_sort, &type);
- for (i = 0; i < n_property_specs; i++) {
+ for (i = 0; i < n_properties; i++) {
GParamSpec *prop_spec = property_specs[i];
GValue value = G_VALUE_INIT;
@@ -1468,7 +1652,7 @@ nm_setting_enumerate_values (NMSetting *setting,
gboolean
_nm_setting_clear_secrets (NMSetting *setting)
{
- GParamSpec **property_specs;
+ gs_free GParamSpec **property_specs = NULL;
guint n_property_specs;
guint i;
gboolean changed = FALSE;
@@ -1476,7 +1660,6 @@ _nm_setting_clear_secrets (NMSetting *setting)
g_return_val_if_fail (NM_IS_SETTING (setting), FALSE);
property_specs = g_object_class_list_properties (G_OBJECT_GET_CLASS (setting), &n_property_specs);
-
for (i = 0; i < n_property_specs; i++) {
GParamSpec *prop_spec = property_specs[i];
@@ -1493,9 +1676,6 @@ _nm_setting_clear_secrets (NMSetting *setting)
g_value_unset (&value);
}
}
-
- g_free (property_specs);
-
return changed;
}
@@ -1546,7 +1726,7 @@ _nm_setting_clear_secrets_with_flags (NMSetting *setting,
NMSettingClearSecretsWithFlagsFn func,
gpointer user_data)
{
- GParamSpec **property_specs;
+ gs_free GParamSpec **property_specs = NULL;
guint n_property_specs;
guint i;
gboolean changed = FALSE;
@@ -1564,8 +1744,6 @@ _nm_setting_clear_secrets_with_flags (NMSetting *setting,
user_data);
}
}
-
- g_free (property_specs);
return changed;
}
@@ -1870,6 +2048,240 @@ _nm_setting_get_deprecated_virtual_interface_name (NMSetting *setting,
/*****************************************************************************/
+static GenData *
+_gendata_hash (NMSetting *setting, gboolean create_if_necessary)
+{
+ NMSettingPrivate *priv;
+
+ nm_assert (NM_IS_SETTING (setting));
+
+ priv = NM_SETTING_GET_PRIVATE (setting);
+
+ if (G_UNLIKELY (!priv->gendata)) {
+ if (!create_if_necessary)
+ return NULL;
+ priv->gendata = g_slice_new (GenData);
+ priv->gendata->hash = g_hash_table_new_full (nm_str_hash, g_str_equal, g_free, (GDestroyNotify) g_variant_unref);
+ priv->gendata->names = NULL;
+ priv->gendata->values = NULL;
+ }
+
+ return priv->gendata;
+}
+
+GHashTable *
+_nm_setting_gendata_hash (NMSetting *setting, gboolean create_if_necessary)
+{
+ GenData *gendata;
+
+ gendata = _gendata_hash (setting, create_if_necessary);
+ return gendata ? gendata->hash : NULL;
+}
+
+void
+_nm_setting_gendata_notify (NMSetting *setting,
+ gboolean names_changed)
+{
+ GenData *gendata;
+
+ gendata = _gendata_hash (setting, FALSE);
+ if (!gendata)
+ return;
+
+ nm_clear_g_free (&gendata->values);
+
+ if (names_changed) {
+ /* if only the values changed, it's sufficient to invalidate the
+ * values cache. Otherwise, the names cache must be invalidated too. */
+ nm_clear_g_free (&gendata->names);
+ }
+}
+
+GVariant *
+nm_setting_gendata_get (NMSetting *setting,
+ const char *name)
+{
+ GenData *gendata;
+
+ g_return_val_if_fail (NM_IS_SETTING (setting), NULL);
+ g_return_val_if_fail (name, NULL);
+
+ gendata = _gendata_hash (setting, FALSE);
+ return gendata ? g_hash_table_lookup (gendata->hash, name) : NULL;
+}
+
+guint
+_nm_setting_gendata_get_all (NMSetting *setting,
+ const char *const**out_names,
+ GVariant *const**out_values)
+{
+ GenData *gendata;
+ GHashTable *hash;
+ guint i, len;
+
+ nm_assert (NM_IS_SETTING (setting));
+
+ gendata = _gendata_hash (setting, FALSE);
+ if (!gendata)
+ goto out_zero;
+
+ hash = gendata->hash;
+ len = g_hash_table_size (hash);
+ if (len == 0)
+ goto out_zero;
+
+ if (!out_names && !out_values)
+ return len;
+
+ if (G_UNLIKELY (!gendata->names)) {
+ gendata->names = nm_utils_strdict_get_keys (hash,
+ TRUE,
+ NULL);
+ }
+
+ if (out_values) {
+ if (G_UNLIKELY (!gendata->values)) {
+ gendata->values = g_new (GVariant *, len + 1);
+ for (i = 0; i < len; i++)
+ gendata->values[i] = g_hash_table_lookup (hash, gendata->names[i]);
+ gendata->values[i] = NULL;
+ }
+ *out_values = gendata->values;
+ }
+
+ NM_SET_OUT (out_names, (const char *const*) gendata->names);
+ return len;
+
+out_zero:
+ NM_SET_OUT (out_names, NULL);
+ NM_SET_OUT (out_values, NULL);
+ return 0;
+}
+
+/**
+ * nm_setting_gendata_get_all_names:
+ * @setting: the #NMSetting
+ * @out_len: (allow-none): (out):
+ *
+ * Gives the number of generic data elements and optionally returns all their
+ * key names and values. This API is low level access and unless you know what you
+ * are doing, it might not be what you want.
+ *
+ * Returns: (array length=out_len zero-terminated=1) (transfer none):
+ * A %NULL terminated array of key names. If no names are present, this returns
+ * %NULL. The returned array and the names are owned by %NMSetting and might be invalidated
+ * soon.
+ *
+ * Since: 1.14
+ **/
+const char *const*
+nm_setting_gendata_get_all_names (NMSetting *setting,
+ guint *out_len)
+{
+ const char *const*names;
+ guint len;
+
+ g_return_val_if_fail (NM_IS_SETTING (setting), NULL);
+
+ len = _nm_setting_gendata_get_all (setting, &names, NULL);
+ NM_SET_OUT (out_len, len);
+ return names;
+}
+
+/**
+ * nm_setting_gendata_get_all_values:
+ * @setting: the #NMSetting
+ *
+ * Gives the number of generic data elements and optionally returns all their
+ * key names and values. This API is low level access and unless you know what you
+ * are doing, it might not be what you want.
+ *
+ * Returns: (array zero-terminated=1) (transfer none):
+ * A %NULL terminated array of #GVariant. If no data is present, this returns
+ * %NULL. The returned array and the variants are owned by %NMSetting and might be invalidated
+ * soon. The sort order of nm_setting_gendata_get_all_names() and nm_setting_gendata_get_all_values()
+ * is consistent. That means, the nth value has the nth name returned by nm_setting_gendata_get_all_names().
+ *
+ * Since: 1.14
+ **/
+GVariant *const*
+nm_setting_gendata_get_all_values (NMSetting *setting)
+{
+ GVariant *const*values;
+
+ g_return_val_if_fail (NM_IS_SETTING (setting), NULL);
+
+ _nm_setting_gendata_get_all (setting, NULL, &values);
+ return values;
+}
+
+void
+_nm_setting_gendata_to_gvalue (NMSetting *setting,
+ GValue *value)
+{
+ GenData *gendata;
+ GHashTable *new;
+ const char *key;
+ GVariant *val;
+ GHashTableIter iter;
+
+ nm_assert (NM_IS_SETTING (setting));
+ nm_assert (value);
+ nm_assert (G_TYPE_CHECK_VALUE_TYPE ((value), G_TYPE_HASH_TABLE));
+
+ new = g_hash_table_new_full (nm_str_hash, g_str_equal, g_free, (GDestroyNotify) g_variant_unref);
+
+ gendata = _gendata_hash (setting, FALSE);
+ if (gendata) {
+ g_hash_table_iter_init (&iter, gendata->hash);
+ while (g_hash_table_iter_next (&iter, (gpointer *) &key, (gpointer *) &val))
+ g_hash_table_insert (new, g_strdup (key), g_variant_ref (val));
+ }
+
+ g_value_take_boxed (value, new);
+}
+
+gboolean
+_nm_setting_gendata_reset_from_hash (NMSetting *setting,
+ GHashTable *new)
+{
+ GenData *gendata;
+ GHashTableIter iter;
+ const char *key;
+ GVariant *val;
+ guint num;
+
+ nm_assert (NM_IS_SETTING (setting));
+ nm_assert (new);
+
+ num = new ? g_hash_table_size (new) : 0;
+
+ gendata = _gendata_hash (setting, num > 0);
+
+ if (num == 0) {
+ if ( !gendata
+ || g_hash_table_size (gendata->hash) == 0)
+ return FALSE;
+
+ g_hash_table_remove_all (gendata->hash);
+ _nm_setting_gendata_notify (setting, TRUE);
+ return TRUE;
+ }
+
+ /* let's not bother to find out whether the new hash has any different
+ * content the the current gendata. Just replace it. */
+ g_hash_table_remove_all (gendata->hash);
+ if (num > 0) {
+ g_hash_table_iter_init (&iter, new);
+ while (g_hash_table_iter_next (&iter, (gpointer *) &key, (gpointer *) &val))
+ g_hash_table_insert (gendata->hash, g_strdup (key), g_variant_ref (val));
+ }
+ _nm_setting_gendata_notify (setting, TRUE);
+ return TRUE;
+}
+
+/*****************************************************************************/
+
static void
nm_setting_init (NMSetting *setting)
{
@@ -1892,6 +2304,21 @@ get_property (GObject *object, guint prop_id,
}
static void
+finalize (GObject *object)
+{
+ NMSettingPrivate *priv = NM_SETTING_GET_PRIVATE (object);
+
+ if (priv->gendata) {
+ g_free (priv->gendata->names);
+ g_free (priv->gendata->values);
+ g_hash_table_unref (priv->gendata->hash);
+ g_slice_free (GenData, priv->gendata);
+ }
+
+ G_OBJECT_CLASS (nm_setting_parent_class)->finalize (object);
+}
+
+static void
nm_setting_class_init (NMSettingClass *setting_class)
{
GObjectClass *object_class = G_OBJECT_CLASS (setting_class);
@@ -1914,6 +2341,7 @@ nm_setting_class_init (NMSettingClass *setting_class)
g_type_class_add_private (setting_class, sizeof (NMSettingPrivate));
object_class->get_property = get_property;
+ object_class->finalize = finalize;
setting_class->update_one_secret = update_one_secret;
setting_class->get_secret_flags = get_secret_flags;
diff --git a/libnm-core/nm-setting.h b/libnm-core/nm-setting.h
index d06527cdd7..a7a0f81f40 100644
--- a/libnm-core/nm-setting.h
+++ b/libnm-core/nm-setting.h
@@ -287,7 +287,8 @@ void nm_setting_enumerate_values (NMSetting *setting,
char *nm_setting_to_string (NMSetting *setting);
-/* Secrets */
+/*****************************************************************************/
+
gboolean nm_setting_get_secret_flags (NMSetting *setting,
const char *secret_name,
NMSettingSecretFlags *out_flags,
@@ -298,10 +299,13 @@ gboolean nm_setting_set_secret_flags (NMSetting *setting,
NMSettingSecretFlags flags,
GError **error);
-/* Properties */
+/*****************************************************************************/
+
const GVariantType *nm_setting_get_dbus_property_type (NMSetting *setting,
const char *property_name);
+/*****************************************************************************/
+
G_END_DECLS
#endif /* __NM_SETTING_H__ */