[glib/keyfilebackend] keyfile rewrite WIP



commit 77c38cf83d98f55a51f53fcadadf26a67aebc645
Author: Ryan Lortie <desrt desrt ca>
Date:   Tue Jun 22 08:12:04 2010 -0400

    keyfile rewrite WIP

 gio/gkeyfilesettingsbackend.c |  366 +++++++++++++++++++++++++----------------
 1 files changed, 227 insertions(+), 139 deletions(-)
---
diff --git a/gio/gkeyfilesettingsbackend.c b/gio/gkeyfilesettingsbackend.c
index 8d4ae1b..d19706a 100644
--- a/gio/gkeyfilesettingsbackend.c
+++ b/gio/gkeyfilesettingsbackend.c
@@ -23,8 +23,6 @@
 
 #include "config.h"
 
-#include "gkeyfilesettingsbackend.h"
-
 #include <stdio.h>
 #include <string.h>
 #include <errno.h>
@@ -35,176 +33,256 @@
 #include "gfileinfo.h"
 #include "gfilemonitor.h"
 #include "gsimplepermission.h"
+#include "gsettingsbackend.h"
 
 #include "gioalias.h"
 
+#define G_TYPE_KEYFILE_SETTINGS_BACKEND      (g_keyfile_settings_backend_get_type ())
+#define G_KEYFILE_SETTINGS_BACKEND(inst)     (G_TYPE_CHECK_INSTANCE_CAST ((inst),      \
+                                              G_TYPE_KEYFILE_SETTINGS_BACKEND,         \
+                                              GKeyfileSettingsBackend))
+#define G_IS_KEYFILE_SETTINGS_BACKEND(inst)  (G_TYPE_CHECK_INSTANCE_TYPE ((inst),      \
+                                              G_TYPE_KEYFILE_SETTINGS_BACKEND))
+
+
+typedef GSettingsBackendClass GKeyfileSettingsBackendClass;
+
+typedef struct
+{
+  GSettingsBackend   parent_instance;
+
+  GKeyFile          *keyfile;
+  gboolean           writable;
+  gchar             *file_path;
+  gchar             *checksum;
+  gchar             *prefix;
+  gint               prefix_len;
+  GFileMonitor      *monitor;
+} GKeyfileSettingsBackend;
+
 G_DEFINE_TYPE (GKeyfileSettingsBackend,
                g_keyfile_settings_backend,
                G_TYPE_SETTINGS_BACKEND)
 
-struct _GKeyfileSettingsBackendPrivate
+static gboolean
+convert_path (GKeyfileSettingsBackend  *kfsb,
+              const gchar              *key,
+              gchar                   **group,
+              gchar                   **basename)
 {
-  GHashTable   *table;
-  GKeyFile     *keyfile;
-  gboolean      writable;
-  gchar        *file_path;
-  gchar        *checksum;
-  GFileMonitor *monitor;
-};
+  gsize key_len = strlen (key);
+  gsize i;
+
+  if (key_len < kfsb->prefix_len ||
+      memcmp (key, kfsb->prefix, kfsb->prefix_len) != 0)
+    return FALSE;
+
+  key_len -= kfsb->prefix_len;
+  key += kfsb->prefix_len;
+
+  for (i = key_len; i; i--)
+    if (key[i] == '/')
+      break;
+
+  if (i == 0)
+    return FALSE;
+
+  if (basename)
+    *basename = g_memdup (key + i, key_len - i + 1);
+
+  if (group)
+    {
+      *group = g_memdup (key, i + 1);
+      (*group)[i] = '\0';
+    }
+
+  return TRUE;
+}
+
+gboolean
+path_is_valid (GKeyfileSettingsBackend *kfsb,
+               const gchar             *path)
+{
+  return convert_path (kfsb, path, NULL, NULL);
+}
 
 static GVariant *
-g_keyfile_settings_backend_read (GSettingsBackend   *backend,
-                                 const gchar        *key,
-                                 const GVariantType *expected_type,
-                                 gboolean            default_value)
+get_from_keyfile (GKeyfileSettingsBackend *kfsb,
+                  const GVariantType      *type,
+                  const gchar             *key)
 {
-  GKeyfileSettingsBackend *kf_backend = G_KEYFILE_SETTINGS_BACKEND (backend);
-  GVariant *value;
+  GVariant *return_value = NULL;
+  gchar *group, *name;
 
-  if (default_value)
-    return NULL;
+  if (convert_path (kfsb, key, &group, &name))
+    {
+      gchar *str;
+
+      g_assert (*name);
+
+      str = g_key_file_get_value (kfsb->keyfile, group, name, NULL);
 
-  value = g_hash_table_lookup (kf_backend->priv->table, key);
+      if (str)
+        {
+          return_value = g_variant_parse (type, str, NULL, NULL, NULL);
+          g_free (str);
+        }
 
-  if (value != NULL)
-    g_variant_ref (value);
+      g_free (group);
+      g_free (name);
+    }
 
-  return value;
+  return return_value;
 }
 
 static gboolean
-g_keyfile_settings_backend_write_one (const gchar             *key,
-                                      GVariant                *value,
-                                      GKeyfileSettingsBackend *kf_backend)
+set_to_keyfile (GKeyfileSettingsBackend *kfsb,
+                const gchar             *key,
+                GVariant                *value)
 {
-  const gchar *slash;
-  const gchar *base_key;
-  gchar       *path;
+  gchar *group, *name;
+
+  if (convert_path (kfsb, key, &group, &name))
+    {
+      if (value)
+        {
+          gchar *str = g_variant_print (value, FALSE);
+          g_key_file_set_value (kfsb->keyfile, group, name, str);
+          g_free (str);
+        }
+      else
+        {
+          if (*name == '\0')
+            {
+              gchar **groups;
+              gint i;
 
-  g_hash_table_replace (kf_backend->priv->table,
-                        g_strdup (key), g_variant_ref (value));
+              groups = g_key_file_get_groups (kfsb->keyfile, NULL);
 
-  slash = strrchr (key, '/');
-  g_assert (slash != NULL);
-  base_key = (slash + 1);
-  path = g_strndup (key, slash - key + 1);
+              for (i = 0; groups[i]; i++)
+                {
+                  gint j;
+
+                  for (j = 0; group[j]; j++)
+                    if (group[j] != groups[i][j])
+                      goto no_match;
+
+                  if (groups[i][j] == '\0' || groups[i][j] == '/')
+                    g_key_file_remove_group (kfsb->keyfile, groups[i], NULL);
+                  no_match: continue;
+                }
+
+              g_strfreev (groups);
+            }
+          else
+            g_key_file_remove_key (kfsb->keyfile, group, name, NULL);
+        }
 
-  g_key_file_set_string (kf_backend->priv->keyfile,
-                         path, base_key, g_variant_print (value, TRUE));
+      g_free (group);
+      g_free (name);
 
-  g_free (path);
+      return TRUE;
+    }
 
   return FALSE;
 }
 
-static void
-g_keyfile_settings_backend_keyfile_write (GKeyfileSettingsBackend *kf_backend)
+static GVariant *
+g_keyfile_settings_backend_read (GSettingsBackend   *backend,
+                                 const gchar        *key,
+                                 const GVariantType *expected_type,
+                                 gboolean            default_value)
 {
-  gchar *dirname;
-  gchar *contents;
-  gsize  length;
-  GFile *file;
+  GKeyfileSettingsBackend *kfsb = G_KEYFILE_SETTINGS_BACKEND (backend);
 
-  dirname = g_path_get_dirname (kf_backend->priv->file_path);
-  if (!g_file_test (dirname, G_FILE_TEST_IS_DIR))
-    g_mkdir_with_parents (dirname, 0700);
-  g_free (dirname);
+  if (default_value)
+    return NULL;
 
-  contents = g_key_file_to_data (kf_backend->priv->keyfile, &length, NULL);
+  return get_from_keyfile (kfsb, expected_type, key);
+}
 
-  file = g_file_new_for_path (kf_backend->priv->file_path);
-  g_file_replace_contents (file, contents, length,
-                           NULL, FALSE, G_FILE_CREATE_REPLACE_DESTINATION,
-                           NULL, NULL, NULL);
-  g_object_unref (file);
+typedef struct
+{
+  GKeyfileSettingsBackend *kfsb;
+  gboolean failed;
+} WriteManyData;
 
-  g_free (kf_backend->priv->checksum);
-  kf_backend->priv->checksum = g_compute_checksum_for_string (G_CHECKSUM_SHA256, contents, length);
+static gboolean
+g_keyfile_settings_backend_write_one (gpointer key,
+                                      gpointer value,
+                                      gpointer user_data)
+{
+  WriteManyData *data = user_data;
+  gboolean success;
 
-  g_free (contents);
+  success = set_to_keyfile (data->kfsb, key, value);
+  g_assert (success);
+
+  return FALSE;
 }
 
 static gboolean
-g_keyfile_settings_backend_write (GSettingsBackend *backend,
-                                  const gchar      *key,
-                                  GVariant         *value,
-                                  gpointer          origin_tag)
+g_keyfile_settings_backend_check_one (gpointer key,
+                                      gpointer value,
+                                      gpointer user_data)
 {
-  GKeyfileSettingsBackend *kf_backend = G_KEYFILE_SETTINGS_BACKEND (backend);
+  WriteManyData *data = user_data;
 
-  g_keyfile_settings_backend_write_one (key, value, kf_backend);
-  g_keyfile_settings_backend_keyfile_write (kf_backend);
-
-  g_settings_backend_changed (backend, key, origin_tag);
-
-  return TRUE;
+  return data->failed = !path_is_valid (data->kfsb, key);
 }
 
 static gboolean
-g_keyfile_settings_backend_write_keys (GSettingsBackend *backend,
+g_keyfile_settings_backend_write_many (GSettingsBackend *backend,
                                        GTree            *tree,
                                        gpointer          origin_tag)
 {
-  GKeyfileSettingsBackend *kf_backend = G_KEYFILE_SETTINGS_BACKEND (backend);
+  WriteManyData data = { G_KEYFILE_SETTINGS_BACKEND (backend) };
+
+  if (!data.kfsb->writable)
+    return FALSE;
 
-  g_tree_foreach (tree, (GTraverseFunc) g_keyfile_settings_backend_write_one, backend);
-  g_keyfile_settings_backend_keyfile_write (kf_backend);
+  g_tree_foreach (tree, g_keyfile_settings_backend_check_one, &data);
+
+  if (data.failed)
+    return FALSE;
+
+  g_tree_foreach (tree, g_keyfile_settings_backend_write_one, &data);
 
   g_settings_backend_changed_tree (backend, tree, origin_tag);
 
   return TRUE;
 }
 
+static gboolean
+g_keyfile_settings_backend_write (GSettingsBackend *backend,
+                                  const gchar      *key,
+                                  GVariant         *value,
+                                  gpointer          origin_tag)
+{
+  GKeyfileSettingsBackend *kfsb = G_KEYFILE_SETTINGS_BACKEND (backend);
+  gboolean success;
+
+  if (!kfsb->writable)
+    return FALSE;
+
+  success = set_to_keyfile (kfsb, key, value);
+
+  if (success)
+    g_settings_backend_changed (backend, key, origin_tag);
+
+  return success;
+}
+
 static void
 g_keyfile_settings_backend_reset_path (GSettingsBackend *backend,
                                        const gchar      *path,
-                                       gpointer         origin_tag)
+                                       gpointer          origin_tag)
 {
-  GKeyfileSettingsBackend *kf_backend = G_KEYFILE_SETTINGS_BACKEND (backend);
-  GPtrArray  *reset_array;
-  GList      *hash_keys;
-  GList      *l;
-  gboolean    changed;
-  gchar     **groups = NULL;
-  gsize       groups_nb = 0;
-  int         i;
-
-  reset_array = g_ptr_array_new_with_free_func (g_free);
-
-  hash_keys = g_hash_table_get_keys (kf_backend->priv->table);
-  for (l = hash_keys; l != NULL; l = l->next)
-    {
-      if (g_str_has_prefix (l->data, path))
-        {
-          g_hash_table_remove (kf_backend->priv->table, l->data);
-          g_ptr_array_add (reset_array, g_strdup (l->data));
-        }
-    }
-  g_list_free (hash_keys);
-
-  changed = FALSE;
-  groups = g_key_file_get_groups (kf_backend->priv->keyfile, &groups_nb);
-  for (i = 0; i < groups_nb; i++)
-    {
-      if (g_str_has_prefix (groups[i], path))
-        changed = g_key_file_remove_group (kf_backend->priv->keyfile, groups[i], NULL) || changed;
-    }
-  g_strfreev (groups);
-
-  if (changed)
-    g_keyfile_settings_backend_keyfile_write (kf_backend);
+  GKeyfileSettingsBackend *kfsb = G_KEYFILE_SETTINGS_BACKEND (backend);
 
-  if (reset_array->len > 0)
-    {
-      /* the array has to be NULL-terminated */
-      g_ptr_array_add (reset_array, NULL);
-      g_settings_backend_keys_changed (G_SETTINGS_BACKEND (kf_backend),
-                                       "",
-                                       (const gchar **) reset_array->pdata,
-                                       origin_tag);
-    }
+  set_to_keyfile (kfsb, path, NULL);
 
-  g_ptr_array_free (reset_array, TRUE);
+  g_settings_backend_path_changed (backend, path, origin_tag);
 }
 
 static void
@@ -212,37 +290,20 @@ g_keyfile_settings_backend_reset (GSettingsBackend *backend,
                                   const gchar      *key,
                                   gpointer          origin_tag)
 {
-  GKeyfileSettingsBackend *kf_backend = G_KEYFILE_SETTINGS_BACKEND (backend);
-  gboolean     had_key;
-  const gchar *slash;
-  const gchar *base_key;
-  gchar       *path;
-
-  had_key = g_hash_table_lookup_extended (kf_backend->priv->table, key, NULL, NULL);
-  if (had_key)
-    g_hash_table_remove (kf_backend->priv->table, key);
-
-  slash = strrchr (key, '/');
-  g_assert (slash != NULL);
-  base_key = (slash + 1);
-  path = g_strndup (key, slash - key + 1);
+  GKeyfileSettingsBackend *kfsb = G_KEYFILE_SETTINGS_BACKEND (backend);
 
-  if (g_key_file_remove_key (kf_backend->priv->keyfile, path, base_key, NULL))
-    g_keyfile_settings_backend_keyfile_write (kf_backend);
+  set_to_keyfile (kfsb, key, NULL);
 
-  g_free (path);
-
-  if (had_key)
-    g_settings_backend_changed (G_SETTINGS_BACKEND (kf_backend), key, origin_tag);
+  g_settings_backend_changed (backend, key, origin_tag);
 }
 
 static gboolean
 g_keyfile_settings_backend_get_writable (GSettingsBackend *backend,
                                          const gchar      *name)
 {
-  GKeyfileSettingsBackend *kf_backend = G_KEYFILE_SETTINGS_BACKEND (backend);
+  GKeyfileSettingsBackend *kfsb = G_KEYFILE_SETTINGS_BACKEND (backend);
 
-  return kf_backend->priv->writable;
+  return kfsb->writable && path_is_valid (kfsb, name);
 }
 
 static GPermission *
@@ -253,7 +314,34 @@ g_keyfile_settings_backend_get_permission (GSettingsBackend *backend,
 }
 
 static void
-g_keyfile_settings_backend_keyfile_reload (GKeyfileSettingsBackend *kf_backend)
+g_keyfile_settings_backend_keyfile_write (GKeyfileSettingsBackend *kfsb)
+{
+  gchar *dirname;
+  gchar *contents;
+  gsize  length;
+  GFile *file;
+
+  dirname = g_path_get_dirname (kfsb->file_path);
+  if (!g_file_test (dirname, G_FILE_TEST_IS_DIR))
+    g_mkdir_with_parents (dirname, 0700);
+  g_free (dirname);
+
+  contents = g_key_file_to_data (kfsb->keyfile, &length, NULL);
+
+  file = g_file_new_for_path (kfsb->file_path);
+  g_file_replace_contents (file, contents, length,
+                           NULL, FALSE, G_FILE_CREATE_REPLACE_DESTINATION,
+                           NULL, NULL, NULL);
+  g_object_unref (file);
+
+  g_free (kfsb->checksum);
+  kfsb->checksum = g_compute_checksum_for_string (G_CHECKSUM_SHA256, contents, length);
+
+  g_free (contents);
+}
+
+static void
+g_keyfile_settings_backend_keyfile_reload (GKeyfileSettingsBackend *kfsb)
 {
   gchar       *contents = NULL;
   gsize        length = 0;



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]