summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--service/dconf-rebuilder.c240
1 files changed, 98 insertions, 142 deletions
diff --git a/service/dconf-rebuilder.c b/service/dconf-rebuilder.c
index 9cac1a7..3f170d6 100644
--- a/service/dconf-rebuilder.c
+++ b/service/dconf-rebuilder.c
@@ -25,42 +25,34 @@
#include "../gvdb/gvdb-reader.h"
#include "../gvdb/gvdb-builder.h"
-
-typedef struct
-{
- const gchar *prefix;
- gint prefix_len;
-
- GHashTable *table;
- const gchar *const*keys;
- GVariant *const*values;
- gint n_items;
- gint index;
-
- gchar name[4096];
- gint name_len;
-} DConfRebuilderState;
+#include "../common/dconf-paths.h"
static GvdbItem *
-dconf_rebuilder_get_parent (GHashTable *table,
- gchar *key,
- gint length)
+dconf_rebuilder_get_parent (GHashTable *table,
+ const gchar *key)
{
GvdbItem *grandparent, *parent;
+ gchar *parent_name;
+ gint len;
- if (length == 1)
+ if (g_str_equal (key, "/"))
return NULL;
- while (key[--length - 1] != '/');
- key[length] = '\0';
+ len = strlen (key);
+ if (key[len - 1] == '/')
+ len--;
+
+ while (key[len - 1] != '/')
+ len--;
- parent = g_hash_table_lookup (table, key);
+ parent_name = g_strndup (key, len);
+ parent = g_hash_table_lookup (table, parent_name);
if (parent == NULL)
{
- parent = gvdb_hash_table_insert (table, key);
+ parent = gvdb_hash_table_insert (table, parent_name);
- grandparent = dconf_rebuilder_get_parent (table, key, length);
+ grandparent = dconf_rebuilder_get_parent (table, parent_name);
if (grandparent != NULL)
gvdb_item_set_parent (parent, grandparent);
@@ -69,143 +61,107 @@ dconf_rebuilder_get_parent (GHashTable *table,
return parent;
}
-static void
-dconf_rebuilder_insert (GHashTable *table,
- const gchar *key,
- GVariant *value)
+gboolean
+dconf_rebuilder_rebuild (const gchar *filename,
+ const gchar *prefix,
+ const gchar * const *keys,
+ GVariant * const *values,
+ int n_items,
+ GError **error)
{
- GvdbItem *item;
- gchar *mykey;
- gint length;
-
- length = strlen (key);
- mykey = g_alloca (length);
- memcpy (mykey, key, length);
-
- g_assert (g_hash_table_lookup (table, key) == NULL);
- item = gvdb_hash_table_insert (table, key);
-
- gvdb_item_set_parent (item,
- dconf_rebuilder_get_parent (table, mykey, length));
+ GHashTable *table;
+ gboolean success;
+ GHashTable *new;
+ GvdbTable *old;
+ gint i;
- gvdb_item_set_value (item, value);
-}
+ table = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_variant_unref);
-static void
-dconf_rebuilder_put_item (DConfRebuilderState *state)
-{
- if (state->values[state->index] != NULL)
+ /* read in the old values */
+ if ((old = gvdb_table_new (filename, FALSE, NULL)))
{
- gchar *fullname;
+ gchar **names;
+ gint n_names;
+ gint i;
- fullname = g_strconcat (state->prefix, state->keys[state->index], NULL);
- dconf_rebuilder_insert (state->table, fullname, state->values[state->index]);
- g_free (fullname);
- }
+ names = gvdb_table_get_names (old, &n_names);
+ for (i = 0; i < n_names; i++)
+ {
+ if (dconf_is_key (names[i], NULL))
+ {
+ GVariant *value;
- state->index++;
-}
+ value = gvdb_table_get_value (old, names[i]);
-static gboolean
-dconf_rebuilder_walk_name (DConfRebuilderState *state,
- const gchar *name,
- gsize name_len)
-{
- gint cmp;
-
- g_assert (state->name_len + name_len < sizeof state->name - 1);
- memcpy (state->name + state->name_len, name, name_len);
- state->name[state->name_len + name_len] = '\0';
-
- if (state->index == state->n_items)
- return TRUE;
+ if (value != NULL)
+ {
+ g_hash_table_insert (table, names[i], value);
+ names[i] = NULL;
+ }
+ }
- if (state->name_len + name_len < state->prefix_len ||
- memcmp (state->name, state->prefix, state->prefix_len) != 0)
- return TRUE;
-
- while ((cmp = strcmp (state->name + state->prefix_len,
- state->keys[state->index])) > 0)
- {
- dconf_rebuilder_put_item (state);
+ g_free (names[i]);
+ }
- if (state->index == state->n_items)
- return TRUE;
+ gvdb_table_unref (old);
+ g_free (names);
}
- return cmp != 0;
-}
-
-static void
-dconf_rebuilder_walk_value (const gchar *name,
- gsize name_len,
- GVariant *value,
- gpointer user_data)
-{
- DConfRebuilderState *state = user_data;
-
- if (dconf_rebuilder_walk_name (state, name, name_len))
- dconf_rebuilder_insert (state->table, state->name, value);
-
- else
- dconf_rebuilder_put_item (state);
-}
-
-static gboolean
-dconf_rebuilder_walk_open (const gchar *name,
- gsize name_len,
- gpointer user_data)
-{
- DConfRebuilderState *state = user_data;
-
- if (dconf_rebuilder_walk_name (state, name, name_len))
+ /* apply the requested changes */
+ for (i = 0; i < n_items; i++)
{
- state->name_len += name_len;
- return TRUE;
+ gchar *path = g_strconcat (prefix, keys[i], NULL);
+
+ /* Check if we are performing a path reset */
+ if (g_str_has_suffix (path, "/"))
+ {
+ GHashTableIter iter;
+ gpointer key;
+
+ g_assert (values[i] == NULL);
+
+ /* A path reset is really a request to delete all keys that
+ * has a name starting with the reset path.
+ */
+ g_hash_table_iter_init (&iter, table);
+ while (g_hash_table_iter_next (&iter, &key, NULL))
+ if (g_str_has_prefix (key, path))
+ g_hash_table_iter_remove (&iter);
+ }
+
+ if (values[i] != NULL)
+ g_hash_table_insert (table, g_strdup (path), g_variant_ref (values[i]));
+ else
+ g_hash_table_remove (table, path);
+
+ g_free (path);
}
- return FALSE;
-}
+ /* convert back to GVDB format */
+ {
+ GHashTableIter iter;
+ gpointer key, value;
-static void
-dconf_rebuilder_walk_close (gsize name_len,
- gpointer user_data)
-{
- DConfRebuilderState *state = user_data;
+ new = gvdb_hash_table_new (NULL, NULL);
- state->name_len -= name_len;
-}
-
-gboolean
-dconf_rebuilder_rebuild (const gchar *filename,
- const gchar *prefix,
- const gchar *const*keys,
- GVariant *const*values,
- int n_items,
- GError **error)
-{
- DConfRebuilderState state = { prefix, strlen (prefix),
- 0, keys, values, n_items };
- gboolean success;
- GvdbTable *old;
+ g_hash_table_iter_init (&iter, table);
+ while (g_hash_table_iter_next (&iter, &key, &value))
+ {
+ GvdbItem *item;
- state.table = gvdb_hash_table_new (NULL, NULL);
-
- if ((old = gvdb_table_new (filename, FALSE, NULL)))
- {
- gvdb_table_walk (old, "/",
- dconf_rebuilder_walk_open,
- dconf_rebuilder_walk_value,
- dconf_rebuilder_walk_close,
- &state);
- gvdb_table_unref (old);
- }
+ g_assert (g_hash_table_lookup (new, key) == NULL);
+ item = gvdb_hash_table_insert (new, key);
+ gvdb_item_set_parent (item, dconf_rebuilder_get_parent (new, key));
+ gvdb_item_set_value (item, value);
+ }
+ }
- while (state.index != state.n_items)
- dconf_rebuilder_put_item (&state);
+ /* write the new file */
+ success = gvdb_table_write_contents (new, filename, FALSE, error);
- success = gvdb_table_write_contents (state.table, filename, FALSE, error);
- g_hash_table_unref (state.table);
+ /* clean up */
+ g_hash_table_unref (table);
+ g_hash_table_unref (new);
return success;
}