645344
From 6edc7e0cfc672fe4c2331ac8131ea1aa82881b63 Mon Sep 17 00:00:00 2001
645344
From: Matthias Clasen <mclasen@redhat.com>
645344
Date: Wed, 19 Dec 2018 19:58:16 -0500
645344
Subject: [PATCH 1/9] settings: Make the keyfile backend parameterless
645344
645344
Make it possible to instantiate a keyfile settings backend
645344
without specifying parameters, by turning the arguments to
645344
the new() function into construct-only properties. If no
645344
filename is specified, default to
645344
$XDG_CONFIG_HOME/glib-2.0/settings/keyfile
645344
---
645344
 gio/gkeyfilesettingsbackend.c  | 252 ++++++++++++++++++++++++++-------
645344
 gio/gsettingsbackendinternal.h |   2 +
645344
 2 files changed, 199 insertions(+), 55 deletions(-)
645344
645344
diff --git a/gio/gkeyfilesettingsbackend.c b/gio/gkeyfilesettingsbackend.c
645344
index a37978e83..e8e9f44a5 100644
645344
--- a/gio/gkeyfilesettingsbackend.c
645344
+++ b/gio/gkeyfilesettingsbackend.c
645344
@@ -21,6 +21,9 @@
645344
 
645344
 #include "config.h"
645344
 
645344
+#include <glib.h>
645344
+#include <glibintl.h>
645344
+
645344
 #include <stdio.h>
645344
 #include <string.h>
645344
 
645344
@@ -28,7 +31,8 @@
645344
 #include "gfileinfo.h"
645344
 #include "gfilemonitor.h"
645344
 #include "gsimplepermission.h"
645344
-#include "gsettingsbackend.h"
645344
+#include "gsettingsbackendinternal.h"
645344
+#include "giomodule.h"
645344
 
645344
 
645344
 #define G_TYPE_KEYFILE_SETTINGS_BACKEND      (g_keyfile_settings_backend_get_type ())
645344
@@ -41,6 +45,12 @@
645344
 
645344
 typedef GSettingsBackendClass GKeyfileSettingsBackendClass;
645344
 
645344
+enum {
645344
+  PROP_FILENAME = 1,
645344
+  PROP_ROOT_PATH,
645344
+  PROP_ROOT_GROUP
645344
+};
645344
+
645344
 typedef struct
645344
 {
645344
   GSettingsBackend   parent_instance;
645344
@@ -61,7 +71,6 @@ typedef struct
645344
   GFileMonitor      *dir_monitor;
645344
 } GKeyfileSettingsBackend;
645344
 
645344
-static GType g_keyfile_settings_backend_get_type (void);
645344
 G_DEFINE_TYPE (GKeyfileSettingsBackend,
645344
                g_keyfile_settings_backend,
645344
                G_TYPE_SETTINGS_BACKEND)
645344
@@ -287,7 +296,8 @@ g_keyfile_settings_backend_check_one (gpointer key,
645344
 {
645344
   WriteManyData *data = user_data;
645344
 
645344
-  return data->failed = !path_is_valid (data->kfsb, key);
645344
+  return data->failed = g_hash_table_contains (data->kfsb->system_locks, key) ||
645344
+                        !path_is_valid (data->kfsb, key);
645344
 }
645344
 
645344
 static gboolean
645344
@@ -522,25 +532,6 @@ g_keyfile_settings_backend_init (GKeyfileSettingsBackend *kfsb)
645344
 {
645344
 }
645344
 
645344
-static void
645344
-g_keyfile_settings_backend_class_init (GKeyfileSettingsBackendClass *class)
645344
-{
645344
-  GObjectClass *object_class = G_OBJECT_CLASS (class);
645344
-
645344
-  object_class->finalize = g_keyfile_settings_backend_finalize;
645344
-
645344
-  class->read = g_keyfile_settings_backend_read;
645344
-  class->write = g_keyfile_settings_backend_write;
645344
-  class->write_tree = g_keyfile_settings_backend_write_tree;
645344
-  class->reset = g_keyfile_settings_backend_reset;
645344
-  class->get_writable = g_keyfile_settings_backend_get_writable;
645344
-  class->get_permission = g_keyfile_settings_backend_get_permission;
645344
-  /* No need to implement subscribed/unsubscribe: the only point would be to
645344
-   * stop monitoring the file when there's no GSettings anymore, which is no
645344
-   * big win.
645344
-   */
645344
-}
645344
-
645344
 static void
645344
 file_changed (GFileMonitor      *monitor,
645344
               GFile             *file,
645344
@@ -567,6 +558,185 @@ dir_changed (GFileMonitor       *monitor,
645344
   g_keyfile_settings_backend_keyfile_writable (kfsb);
645344
 }
645344
 
645344
+static void
645344
+g_keyfile_settings_backend_constructed (GObject *object)
645344
+{
645344
+  GKeyfileSettingsBackend *kfsb = G_KEYFILE_SETTINGS_BACKEND (object);
645344
+
645344
+  if (kfsb->file == NULL)
645344
+    {
645344
+      char *filename = g_build_filename (g_get_user_config_dir (),
645344
+                                         "glib-2.0", "settings", "keyfile",
645344
+                                         NULL);
645344
+      kfsb->file = g_file_new_for_path (filename);
645344
+      g_free (filename);
645344
+    }
645344
+
645344
+  if (kfsb->prefix == NULL)
645344
+    {
645344
+      kfsb->prefix = g_strdup ("/");
645344
+      kfsb->prefix_len = 1;
645344
+    }
645344
+  
645344
+  kfsb->keyfile = g_key_file_new ();
645344
+  kfsb->permission = g_simple_permission_new (TRUE);
645344
+
645344
+  kfsb->dir = g_file_get_parent (kfsb->file);
645344
+  g_file_make_directory_with_parents (kfsb->dir, NULL, NULL);
645344
+
645344
+  kfsb->file_monitor = g_file_monitor (kfsb->file, G_FILE_MONITOR_NONE, NULL, NULL);
645344
+  kfsb->dir_monitor = g_file_monitor (kfsb->dir, G_FILE_MONITOR_NONE, NULL, NULL);
645344
+
645344
+  compute_checksum (kfsb->digest, NULL, 0);
645344
+
645344
+  g_signal_connect (kfsb->file_monitor, "changed",
645344
+                    G_CALLBACK (file_changed), kfsb);
645344
+  g_signal_connect (kfsb->dir_monitor, "changed",
645344
+                    G_CALLBACK (dir_changed), kfsb);
645344
+
645344
+  g_keyfile_settings_backend_keyfile_writable (kfsb);
645344
+  g_keyfile_settings_backend_keyfile_reload (kfsb);
645344
+}
645344
+
645344
+static void
645344
+g_keyfile_settings_backend_set_property (GObject      *object,
645344
+                                         guint         prop_id,
645344
+                                         const GValue *value,
645344
+                                         GParamSpec   *pspec)
645344
+{
645344
+  GKeyfileSettingsBackend *kfsb = G_KEYFILE_SETTINGS_BACKEND (object);
645344
+
645344
+  switch (prop_id)
645344
+    {
645344
+    case PROP_FILENAME:
645344
+      /* Construct only. */
645344
+      g_assert (kfsb->file == NULL);
645344
+      kfsb->file = g_file_new_for_path (g_value_get_string (value));
645344
+      break;
645344
+
645344
+    case PROP_ROOT_PATH:
645344
+      /* Construct only. */
645344
+      g_assert (kfsb->prefix == NULL);
645344
+      kfsb->prefix = g_value_dup_string (value);
645344
+      if (kfsb->prefix)
645344
+        kfsb->prefix_len = strlen (kfsb->prefix);
645344
+      break;
645344
+
645344
+    case PROP_ROOT_GROUP:
645344
+      /* Construct only. */
645344
+      g_assert (kfsb->root_group == NULL);
645344
+      kfsb->root_group = g_value_dup_string (value);
645344
+      if (kfsb->root_group)
645344
+        kfsb->root_group_len = strlen (kfsb->root_group);
645344
+      break;
645344
+
645344
+    default:
645344
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
645344
+      break;
645344
+    }
645344
+}
645344
+
645344
+static void
645344
+g_keyfile_settings_backend_get_property (GObject    *object,
645344
+                                         guint       prop_id,
645344
+                                         GValue     *value,
645344
+                                         GParamSpec *pspec)
645344
+{
645344
+  GKeyfileSettingsBackend *kfsb = G_KEYFILE_SETTINGS_BACKEND (object);
645344
+
645344
+  switch (prop_id)
645344
+    {
645344
+    case PROP_FILENAME:
645344
+      g_value_set_string (value, g_file_peek_path (kfsb->file));
645344
+      break;
645344
+
645344
+    case PROP_ROOT_PATH:
645344
+      g_value_set_string (value, kfsb->prefix);
645344
+      break;
645344
+
645344
+    case PROP_ROOT_GROUP:
645344
+      g_value_set_string (value, kfsb->root_group);
645344
+      break;
645344
+
645344
+    default:
645344
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
645344
+      break;
645344
+    }
645344
+}
645344
+
645344
+static void
645344
+g_keyfile_settings_backend_class_init (GKeyfileSettingsBackendClass *class)
645344
+{
645344
+  GObjectClass *object_class = G_OBJECT_CLASS (class);
645344
+
645344
+  object_class->finalize = g_keyfile_settings_backend_finalize;
645344
+  object_class->constructed = g_keyfile_settings_backend_constructed;
645344
+  object_class->get_property = g_keyfile_settings_backend_get_property;
645344
+  object_class->set_property = g_keyfile_settings_backend_set_property;
645344
+
645344
+  class->read = g_keyfile_settings_backend_read;
645344
+  class->write = g_keyfile_settings_backend_write;
645344
+  class->write_tree = g_keyfile_settings_backend_write_tree;
645344
+  class->reset = g_keyfile_settings_backend_reset;
645344
+  class->get_writable = g_keyfile_settings_backend_get_writable;
645344
+  class->get_permission = g_keyfile_settings_backend_get_permission;
645344
+  /* No need to implement subscribed/unsubscribe: the only point would be to
645344
+   * stop monitoring the file when there's no GSettings anymore, which is no
645344
+   * big win.
645344
+   */
645344
+
645344
+  /**
645344
+   * GKeyfileSettingsBackend:filename:
645344
+   *
645344
+   * The location where the settings are stored on disk.
645344
+   *
645344
+   * Defaults to `$XDG_CONFIG_HOME/glib-2.0/settings/keyfile`.
645344
+   */
645344
+  g_object_class_install_property (object_class,
645344
+                                   PROP_FILENAME,
645344
+                                   g_param_spec_string ("filename",
645344
+                                                        P_("Filename"),
645344
+                                                        P_("The filename"),
645344
+                                                        NULL,
645344
+                                                        G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
645344
+                                                        G_PARAM_STATIC_STRINGS));
645344
+
645344
+  /**
645344
+   * GKeyfileSettingsBackend:root-path:
645344
+   *
645344
+   * All settings read to or written from the backend must fall under the
645344
+   * path given in @root_path (which must start and end with a slash and
645344
+   * not contain two consecutive slashes).  @root_path may be "/".
645344
+   * 
645344
+   * Defaults to "/".
645344
+   */
645344
+  g_object_class_install_property (object_class,
645344
+                                   PROP_ROOT_PATH,
645344
+                                   g_param_spec_string ("root-path",
645344
+                                                        P_("Root path"),
645344
+                                                        P_("The root path"),
645344
+                                                        NULL,
645344
+                                                        G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
645344
+                                                        G_PARAM_STATIC_STRINGS));
645344
+
645344
+  /**
645344
+   * GKeyfileSettingsBackend:root-group:
645344
+   *
645344
+   * If @root_group is non-%NULL then it specifies the name of the keyfile
645344
+   * group used for keys that are written directly below the root path.
645344
+   *
645344
+   * Defaults to NULL.
645344
+   */
645344
+  g_object_class_install_property (object_class,
645344
+                                   PROP_ROOT_GROUP,
645344
+                                   g_param_spec_string ("root-group",
645344
+                                                        P_("Root group"),
645344
+                                                        P_("The root group"),
645344
+                                                        NULL,
645344
+                                                        G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
645344
+                                                        G_PARAM_STATIC_STRINGS));
645344
+}
645344
+
645344
 /**
645344
  * g_keyfile_settings_backend_new:
645344
  * @filename: the filename of the keyfile
645344
@@ -626,43 +796,15 @@ g_keyfile_settings_backend_new (const gchar *filename,
645344
                                 const gchar *root_path,
645344
                                 const gchar *root_group)
645344
 {
645344
-  GKeyfileSettingsBackend *kfsb;
645344
-
645344
   g_return_val_if_fail (filename != NULL, NULL);
645344
   g_return_val_if_fail (root_path != NULL, NULL);
645344
   g_return_val_if_fail (g_str_has_prefix (root_path, "/"), NULL);
645344
   g_return_val_if_fail (g_str_has_suffix (root_path, "/"), NULL);
645344
   g_return_val_if_fail (strstr (root_path, "//") == NULL, NULL);
645344
 
645344
-  kfsb = g_object_new (G_TYPE_KEYFILE_SETTINGS_BACKEND, NULL);
645344
-  kfsb->keyfile = g_key_file_new ();
645344
-  kfsb->permission = g_simple_permission_new (TRUE);
645344
-
645344
-  kfsb->file = g_file_new_for_path (filename);
645344
-  kfsb->dir = g_file_get_parent (kfsb->file);
645344
-  g_file_make_directory_with_parents (kfsb->dir, NULL, NULL);
645344
-
645344
-  kfsb->file_monitor = g_file_monitor (kfsb->file, 0, NULL, NULL);
645344
-  kfsb->dir_monitor = g_file_monitor (kfsb->dir, 0, NULL, NULL);
645344
-
645344
-  kfsb->prefix_len = strlen (root_path);
645344
-  kfsb->prefix = g_strdup (root_path);
645344
-
645344
-  if (root_group)
645344
-    {
645344
-      kfsb->root_group_len = strlen (root_group);
645344
-      kfsb->root_group = g_strdup (root_group);
645344
-    }
645344
-
645344
-  compute_checksum (kfsb->digest, NULL, 0);
645344
-
645344
-  g_signal_connect (kfsb->file_monitor, "changed",
645344
-                    G_CALLBACK (file_changed), kfsb);
645344
-  g_signal_connect (kfsb->dir_monitor, "changed",
645344
-                    G_CALLBACK (dir_changed), kfsb);
645344
-
645344
-  g_keyfile_settings_backend_keyfile_writable (kfsb);
645344
-  g_keyfile_settings_backend_keyfile_reload (kfsb);
645344
-
645344
-  return G_SETTINGS_BACKEND (kfsb);
645344
+  return G_SETTINGS_BACKEND (g_object_new (G_TYPE_KEYFILE_SETTINGS_BACKEND,
645344
+                                           "filename", filename,
645344
+                                           "root-path", root_path,
645344
+                                           "root-group", root_group,
645344
+                                           NULL));
645344
 }
645344
diff --git a/gio/gsettingsbackendinternal.h b/gio/gsettingsbackendinternal.h
645344
index 2a76a80bc..9e1d51dba 100644
645344
--- a/gio/gsettingsbackendinternal.h
645344
+++ b/gio/gsettingsbackendinternal.h
645344
@@ -87,6 +87,8 @@ GType                   g_null_settings_backend_get_type                (void);
645344
 
645344
 GType                   g_memory_settings_backend_get_type              (void);
645344
 
645344
+GType                   g_keyfile_settings_backend_get_type             (void);
645344
+
645344
 #ifdef HAVE_COCOA
645344
 GType                   g_nextstep_settings_backend_get_type            (void);
645344
 #endif
645344
-- 
645344
2.28.0
645344
645344
645344
From cd448d51f610f1e6a701ac8a1146d3b2048427a0 Mon Sep 17 00:00:00 2001
645344
From: Matthias Clasen <mclasen@redhat.com>
645344
Date: Wed, 19 Dec 2018 20:03:29 -0500
645344
Subject: [PATCH 2/9] settings: Register the keyfile backend as extension
645344
645344
This was not done previously because the backend
645344
could not be instantiated without parameters.
645344
---
645344
 gio/gkeyfilesettingsbackend.c | 11 +++++++----
645344
 1 file changed, 7 insertions(+), 4 deletions(-)
645344
645344
diff --git a/gio/gkeyfilesettingsbackend.c b/gio/gkeyfilesettingsbackend.c
645344
index e8e9f44a5..0e9789cde 100644
645344
--- a/gio/gkeyfilesettingsbackend.c
645344
+++ b/gio/gkeyfilesettingsbackend.c
645344
@@ -32,7 +32,7 @@
645344
 #include "gfilemonitor.h"
645344
 #include "gsimplepermission.h"
645344
 #include "gsettingsbackendinternal.h"
645344
-#include "giomodule.h"
645344
+#include "giomodule-priv.h"
645344
 
645344
 
645344
 #define G_TYPE_KEYFILE_SETTINGS_BACKEND      (g_keyfile_settings_backend_get_type ())
645344
@@ -71,9 +71,12 @@ typedef struct
645344
   GFileMonitor      *dir_monitor;
645344
 } GKeyfileSettingsBackend;
645344
 
645344
-G_DEFINE_TYPE (GKeyfileSettingsBackend,
645344
-               g_keyfile_settings_backend,
645344
-               G_TYPE_SETTINGS_BACKEND)
645344
+G_DEFINE_TYPE_WITH_CODE (GKeyfileSettingsBackend,
645344
+                         g_keyfile_settings_backend,
645344
+                         G_TYPE_SETTINGS_BACKEND,
645344
+                         _g_io_modules_ensure_extension_points_registered ();
645344
+                         g_io_extension_point_implement (G_SETTINGS_BACKEND_EXTENSION_POINT_NAME,
645344
+                                                         g_define_type_id, "keyfile", 10))
645344
 
645344
 static void
645344
 compute_checksum (guint8        *digest,
645344
-- 
645344
2.28.0
645344
645344
645344
From 8cbdb7dd496f6c2361eb46ca4c0848d7210fe27a Mon Sep 17 00:00:00 2001
645344
From: Matthias Clasen <mclasen@redhat.com>
645344
Date: Mon, 5 Nov 2018 16:07:55 -0500
645344
Subject: [PATCH 3/9] settings: Add support for defaults to keyfile backend
645344
645344
Stacked databases and locks are dconf features that allow
645344
management software like Fleet Commander to set system-wide
645344
defaults and overrides centrally for applications.
645344
645344
This patch adds minimal support for the same to the keyfile
645344
backend. We look for a keyfile named 'defaults' and a
645344
lock-list named 'locks'.
645344
645344
Suitable files can be produced from a dconf database with
645344
dconf dump and dconf list-locks, respectively.
645344
645344
The default location for these files is /etc/glib-2.0/settings/.
645344
For test purposes, this can be overwritten with the
645344
GSETTINGS_DEFAULTS_DIR environment variable.
645344
645344
Writes always go to the per-user keyfile.
645344
---
645344
 gio/gkeyfilesettingsbackend.c | 138 ++++++++++++++++++++++++++++++++--
645344
 1 file changed, 132 insertions(+), 6 deletions(-)
645344
645344
diff --git a/gio/gkeyfilesettingsbackend.c b/gio/gkeyfilesettingsbackend.c
645344
index 0e9789cde..0a4e81511 100644
645344
--- a/gio/gkeyfilesettingsbackend.c
645344
+++ b/gio/gkeyfilesettingsbackend.c
645344
@@ -29,6 +29,7 @@
645344
 
645344
 #include "gfile.h"
645344
 #include "gfileinfo.h"
645344
+#include "gfileenumerator.h"
645344
 #include "gfilemonitor.h"
645344
 #include "gsimplepermission.h"
645344
 #include "gsettingsbackendinternal.h"
645344
@@ -45,11 +46,12 @@
645344
 
645344
 typedef GSettingsBackendClass GKeyfileSettingsBackendClass;
645344
 
645344
-enum {
645344
+typedef enum {
645344
   PROP_FILENAME = 1,
645344
   PROP_ROOT_PATH,
645344
-  PROP_ROOT_GROUP
645344
-};
645344
+  PROP_ROOT_GROUP,
645344
+  PROP_DEFAULTS_DIR
645344
+} GKeyfileSettingsBackendProperty;
645344
 
645344
 typedef struct
645344
 {
645344
@@ -58,6 +60,9 @@ typedef struct
645344
   GKeyFile          *keyfile;
645344
   GPermission       *permission;
645344
   gboolean           writable;
645344
+  char              *defaults_dir;
645344
+  GKeyFile          *system_keyfile;
645344
+  GHashTable        *system_locks; /* Used as a set, owning the strings it contains */
645344
 
645344
   gchar             *prefix;
645344
   gint               prefix_len;
645344
@@ -196,10 +201,19 @@ get_from_keyfile (GKeyfileSettingsBackend *kfsb,
645344
   if (convert_path (kfsb, key, &group, &name))
645344
     {
645344
       gchar *str;
645344
+      gchar *sysstr;
645344
 
645344
       g_assert (*name);
645344
 
645344
+      sysstr = g_key_file_get_value (kfsb->system_keyfile, group, name, NULL);
645344
       str = g_key_file_get_value (kfsb->keyfile, group, name, NULL);
645344
+      if (sysstr &&
645344
+          (g_hash_table_contains (kfsb->system_locks, key) ||
645344
+           str == NULL))
645344
+        {
645344
+          g_free (str);
645344
+          str = g_steal_pointer (&sysstr);
645344
+        }
645344
 
645344
       if (str)
645344
         {
645344
@@ -207,6 +221,8 @@ get_from_keyfile (GKeyfileSettingsBackend *kfsb,
645344
           g_free (str);
645344
         }
645344
 
645344
+      g_free (sysstr);
645344
+
645344
       g_free (group);
645344
       g_free (name);
645344
     }
645344
@@ -221,6 +237,9 @@ set_to_keyfile (GKeyfileSettingsBackend *kfsb,
645344
 {
645344
   gchar *group, *name;
645344
 
645344
+  if (g_hash_table_contains (kfsb->system_locks, key))
645344
+    return FALSE;
645344
+
645344
   if (convert_path (kfsb, key, &group, &name))
645344
     {
645344
       if (value)
645344
@@ -368,7 +387,9 @@ g_keyfile_settings_backend_get_writable (GSettingsBackend *backend,
645344
 {
645344
   GKeyfileSettingsBackend *kfsb = G_KEYFILE_SETTINGS_BACKEND (backend);
645344
 
645344
-  return kfsb->writable && path_is_valid (kfsb, name);
645344
+  return kfsb->writable &&
645344
+         !g_hash_table_contains (kfsb->system_locks, name) &&
645344
+         path_is_valid (kfsb, name);
645344
 }
645344
 
645344
 static GPermission *
645344
@@ -514,6 +535,9 @@ g_keyfile_settings_backend_finalize (GObject *object)
645344
 
645344
   g_key_file_free (kfsb->keyfile);
645344
   g_object_unref (kfsb->permission);
645344
+  g_key_file_unref (kfsb->system_keyfile);
645344
+  g_hash_table_unref (kfsb->system_locks);
645344
+  g_free (kfsb->defaults_dir);
645344
 
645344
   g_file_monitor_cancel (kfsb->file_monitor);
645344
   g_object_unref (kfsb->file_monitor);
645344
@@ -561,6 +585,75 @@ dir_changed (GFileMonitor       *monitor,
645344
   g_keyfile_settings_backend_keyfile_writable (kfsb);
645344
 }
645344
 
645344
+static void
645344
+load_system_settings (GKeyfileSettingsBackend *kfsb)
645344
+{
645344
+  GError *error = NULL;
645344
+  const char *dir = "/etc/glib-2.0/settings";
645344
+  char *path;
645344
+  char *contents;
645344
+
645344
+  kfsb->system_keyfile = g_key_file_new ();
645344
+  kfsb->system_locks = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
645344
+
645344
+  if (kfsb->defaults_dir)
645344
+    dir = kfsb->defaults_dir;
645344
+
645344
+  path = g_build_filename (dir, "defaults", NULL);
645344
+
645344
+  /* The defaults are in the same keyfile format that we use for the settings.
645344
+   * It can be produced from a dconf database using: dconf dump
645344
+   */
645344
+  if (!g_key_file_load_from_file (kfsb->system_keyfile, path, G_KEY_FILE_NONE, &error))
645344
+    {
645344
+      if (!g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_NOENT))
645344
+        g_warning ("Failed to read %s: %s", path, error->message);
645344
+      g_clear_error (&error);
645344
+    }
645344
+  else
645344
+    g_debug ("Loading default settings from %s", path);
645344
+
645344
+  g_free (path);
645344
+
645344
+  path = g_build_filename (dir, "locks", NULL);
645344
+
645344
+  /* The locks file is a text file containing a list paths to lock, one per line.
645344
+   * It can be produced from a dconf database using: dconf list-locks
645344
+   */
645344
+  if (!g_file_get_contents (path, &contents, NULL, &error))
645344
+    {
645344
+      if (!g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_NOENT))
645344
+        g_warning ("Failed to read %s: %s", path, error->message);
645344
+      g_clear_error (&error);
645344
+    }
645344
+  else
645344
+    {
645344
+      char **lines;
645344
+      gsize i;
645344
+
645344
+      g_debug ("Loading locks from %s", path);
645344
+
645344
+      lines = g_strsplit (contents, "\n", 0);
645344
+      for (i = 0; lines[i]; i++)
645344
+        {
645344
+          char *line = lines[i];
645344
+          if (line[0] == '#' || line[0] == '\0')
645344
+            {
645344
+              g_free (line);
645344
+              continue;
645344
+            }
645344
+
645344
+          g_debug ("Locking key %s", line);
645344
+          g_hash_table_add (kfsb->system_locks, g_steal_pointer (&line));
645344
+        }
645344
+
645344
+      g_free (lines);
645344
+    }
645344
+  g_free (contents);
645344
+
645344
+  g_free (path);
645344
+}
645344
+
645344
 static void
645344
 g_keyfile_settings_backend_constructed (GObject *object)
645344
 {
645344
@@ -599,6 +692,8 @@ g_keyfile_settings_backend_constructed (GObject *object)
645344
 
645344
   g_keyfile_settings_backend_keyfile_writable (kfsb);
645344
   g_keyfile_settings_backend_keyfile_reload (kfsb);
645344
+
645344
+  load_system_settings (kfsb);
645344
 }
645344
 
645344
 static void
645344
@@ -609,7 +704,7 @@ g_keyfile_settings_backend_set_property (GObject      *object,
645344
 {
645344
   GKeyfileSettingsBackend *kfsb = G_KEYFILE_SETTINGS_BACKEND (object);
645344
 
645344
-  switch (prop_id)
645344
+  switch ((GKeyfileSettingsBackendProperty)prop_id)
645344
     {
645344
     case PROP_FILENAME:
645344
       /* Construct only. */
645344
@@ -633,6 +728,12 @@ g_keyfile_settings_backend_set_property (GObject      *object,
645344
         kfsb->root_group_len = strlen (kfsb->root_group);
645344
       break;
645344
 
645344
+    case PROP_DEFAULTS_DIR:
645344
+      /* Construct only. */
645344
+      g_assert (kfsb->defaults_dir == NULL);
645344
+      kfsb->defaults_dir = g_value_dup_string (value);
645344
+      break;
645344
+
645344
     default:
645344
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
645344
       break;
645344
@@ -647,7 +748,7 @@ g_keyfile_settings_backend_get_property (GObject    *object,
645344
 {
645344
   GKeyfileSettingsBackend *kfsb = G_KEYFILE_SETTINGS_BACKEND (object);
645344
 
645344
-  switch (prop_id)
645344
+  switch ((GKeyfileSettingsBackendProperty)prop_id)
645344
     {
645344
     case PROP_FILENAME:
645344
       g_value_set_string (value, g_file_peek_path (kfsb->file));
645344
@@ -661,6 +762,10 @@ g_keyfile_settings_backend_get_property (GObject    *object,
645344
       g_value_set_string (value, kfsb->root_group);
645344
       break;
645344
 
645344
+    case PROP_DEFAULTS_DIR:
645344
+      g_value_set_string (value, kfsb->defaults_dir);
645344
+      break;
645344
+
645344
     default:
645344
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
645344
       break;
645344
@@ -738,6 +843,22 @@ g_keyfile_settings_backend_class_init (GKeyfileSettingsBackendClass *class)
645344
                                                         NULL,
645344
                                                         G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
645344
                                                         G_PARAM_STATIC_STRINGS));
645344
+
645344
+  /**
645344
+   * GKeyfileSettingsBackend:default-dir:
645344
+   *
645344
+   * The directory where the system defaults and locks are located.
645344
+   *
645344
+   * Defaults to `/etc/glib-2.0/settings`.
645344
+   */
645344
+  g_object_class_install_property (object_class,
645344
+                                   PROP_DEFAULTS_DIR,
645344
+                                   g_param_spec_string ("defaults-dir",
645344
+                                                        P_("Default dir"),
645344
+                                                        P_("Defaults dir"),
645344
+                                                        NULL,
645344
+                                                        G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
645344
+                                                        G_PARAM_STATIC_STRINGS));
645344
 }
645344
 
645344
 /**
645344
@@ -792,6 +913,11 @@ g_keyfile_settings_backend_class_init (GKeyfileSettingsBackendClass *class)
645344
  * characters in your path names or '=' in your key names you may be in
645344
  * trouble.
645344
  *
645344
+ * The backend reads default values from a keyfile called `defaults` in
645344
+ * the directory specified by the #GKeyfileSettingsBackend:defaults-dir property,
645344
+ * and a list of locked keys from a text file with the name `locks` in
645344
+ * the same location.
645344
+ *
645344
  * Returns: (transfer full): a keyfile-backed #GSettingsBackend
645344
  **/
645344
 GSettingsBackend *
645344
-- 
645344
2.28.0
645344
645344
645344
From 93dceb39fe2de23aeffe40ff02c824393c749270 Mon Sep 17 00:00:00 2001
645344
From: Matthias Clasen <mclasen@redhat.com>
645344
Date: Fri, 2 Nov 2018 23:00:49 -0400
645344
Subject: [PATCH 4/9] settings: Prefer the keyfile backend when sandboxed
645344
645344
When we are in a sandboxed situation, bump the priority
645344
of the keyfile settings backend above the dconf one,
645344
so we use a keyfile inside the sandbox instead of requiring
645344
holes in the sandbox for dconf.
645344
---
645344
 gio/gkeyfilesettingsbackend.c | 9 ++++++++-
645344
 1 file changed, 8 insertions(+), 1 deletion(-)
645344
645344
diff --git a/gio/gkeyfilesettingsbackend.c b/gio/gkeyfilesettingsbackend.c
645344
index 0a4e81511..398cb053a 100644
645344
--- a/gio/gkeyfilesettingsbackend.c
645344
+++ b/gio/gkeyfilesettingsbackend.c
645344
@@ -34,6 +34,7 @@
645344
 #include "gsimplepermission.h"
645344
 #include "gsettingsbackendinternal.h"
645344
 #include "giomodule-priv.h"
645344
+#include "gportalsupport.h"
645344
 
645344
 
645344
 #define G_TYPE_KEYFILE_SETTINGS_BACKEND      (g_keyfile_settings_backend_get_type ())
645344
@@ -76,12 +77,18 @@ typedef struct
645344
   GFileMonitor      *dir_monitor;
645344
 } GKeyfileSettingsBackend;
645344
 
645344
+#ifdef G_OS_WIN32
645344
+#define EXTENSION_PRIORITY 10
645344
+#else
645344
+#define EXTENSION_PRIORITY (glib_should_use_portal () ? 110 : 10)
645344
+#endif
645344
+
645344
 G_DEFINE_TYPE_WITH_CODE (GKeyfileSettingsBackend,
645344
                          g_keyfile_settings_backend,
645344
                          G_TYPE_SETTINGS_BACKEND,
645344
                          _g_io_modules_ensure_extension_points_registered ();
645344
                          g_io_extension_point_implement (G_SETTINGS_BACKEND_EXTENSION_POINT_NAME,
645344
-                                                         g_define_type_id, "keyfile", 10))
645344
+                                                         g_define_type_id, "keyfile", EXTENSION_PRIORITY))
645344
 
645344
 static void
645344
 compute_checksum (guint8        *digest,
645344
-- 
645344
2.28.0
645344
645344
645344
From 5d0d49750564aa7fd9e7d0d58c08a08847570921 Mon Sep 17 00:00:00 2001
645344
From: Matthias Clasen <mclasen@redhat.com>
645344
Date: Mon, 21 Jan 2019 22:55:45 -0500
645344
Subject: [PATCH 5/9] keyfile settings: Accept unquoted strings
645344
645344
It is hard for users to remember that strings have to be explicitly
645344
quoted in the keyfile. Be lenient and accept strings that lack those
645344
quotes.
645344
---
645344
 gio/gkeyfilesettingsbackend.c | 19 +++++++++++++++++++
645344
 gio/tests/gsettings.c         | 17 +++++++++++++++++
645344
 2 files changed, 36 insertions(+)
645344
645344
diff --git a/gio/gkeyfilesettingsbackend.c b/gio/gkeyfilesettingsbackend.c
645344
index 398cb053a..d5796b706 100644
645344
--- a/gio/gkeyfilesettingsbackend.c
645344
+++ b/gio/gkeyfilesettingsbackend.c
645344
@@ -225,6 +225,25 @@ get_from_keyfile (GKeyfileSettingsBackend *kfsb,
645344
       if (str)
645344
         {
645344
           return_value = g_variant_parse (type, str, NULL, NULL, NULL);
645344
+          if (return_value == NULL &&
645344
+              g_variant_type_equal (type, G_VARIANT_TYPE_STRING) &&
645344
+              str[0] != '\"')
645344
+            {
645344
+              GString *s = g_string_sized_new (strlen (str) + 2);
645344
+              char *p = str;
645344
+
645344
+              g_string_append_c (s, '\"');
645344
+              while (*p)
645344
+                {
645344
+                  if (*p == '\"')
645344
+                    g_string_append_c (s, '\\');
645344
+                  g_string_append_c (s, *p);
645344
+                  p++;
645344
+                }
645344
+              g_string_append_c (s, '\"');
645344
+              return_value = g_variant_parse (type, s->str, NULL, NULL, NULL);
645344
+              g_string_free (s, TRUE);
645344
+            }
645344
           g_free (str);
645344
         }
645344
 
645344
diff --git a/gio/tests/gsettings.c b/gio/tests/gsettings.c
645344
index 2be4122fe..6eb49f124 100644
645344
--- a/gio/tests/gsettings.c
645344
+++ b/gio/tests/gsettings.c
645344
@@ -1716,6 +1716,23 @@ test_keyfile (void)
645344
   g_assert_cmpstr (str, ==, "howdy");
645344
   g_free (str);
645344
 
645344
+  /* Now check setting a string without quotes */
645344
+  called = FALSE;
645344
+  g_signal_connect (settings, "changed::greeting", G_CALLBACK (key_changed_cb), &called);
645344
+
645344
+  g_key_file_set_string (keyfile, "tests", "greeting", "he\"l🤗uń");
645344
+  g_free (data);
645344
+  data = g_key_file_to_data (keyfile, &len, NULL);
645344
+  g_file_set_contents ("keyfile/gsettings.store", data, len, &error);
645344
+  g_assert_no_error (error);
645344
+  while (!called)
645344
+    g_main_context_iteration (NULL, FALSE);
645344
+  g_signal_handlers_disconnect_by_func (settings, key_changed_cb, &called);
645344
+
645344
+  str = g_settings_get_string (settings, "greeting");
645344
+  g_assert_cmpstr (str, ==, "he\"l🤗uń");
645344
+  g_free (str);
645344
+
645344
   g_settings_set (settings, "farewell", "s", "cheerio");
645344
   
645344
   called = FALSE;
645344
-- 
645344
2.28.0
645344
645344
645344
From 3765e73f9a2dbbc6863bcffdee85ffb18530c89b Mon Sep 17 00:00:00 2001
645344
From: Philip Withnall <withnall@endlessm.com>
645344
Date: Wed, 23 Jan 2019 15:14:58 +0000
645344
Subject: [PATCH 6/9] gkeyfilesettingsbackend: Add a code comment to clarify
645344
 things
645344
645344
Signed-off-by: Philip Withnall <withnall@endlessm.com>
645344
---
645344
 gio/gkeyfilesettingsbackend.c | 4 ++++
645344
 1 file changed, 4 insertions(+)
645344
645344
diff --git a/gio/gkeyfilesettingsbackend.c b/gio/gkeyfilesettingsbackend.c
645344
index d5796b706..5ea632305 100644
645344
--- a/gio/gkeyfilesettingsbackend.c
645344
+++ b/gio/gkeyfilesettingsbackend.c
645344
@@ -225,6 +225,10 @@ get_from_keyfile (GKeyfileSettingsBackend *kfsb,
645344
       if (str)
645344
         {
645344
           return_value = g_variant_parse (type, str, NULL, NULL, NULL);
645344
+
645344
+          /* As a special case, support values of type %G_VARIANT_TYPE_STRING
645344
+           * not being quoted, since users keep forgetting to do it and then
645344
+           * getting confused. */
645344
           if (return_value == NULL &&
645344
               g_variant_type_equal (type, G_VARIANT_TYPE_STRING) &&
645344
               str[0] != '\"')
645344
-- 
645344
2.28.0
645344
645344
645344
From 1df628861afe027e8dce5e27f4249059bad6bc60 Mon Sep 17 00:00:00 2001
645344
From: Matthias Clasen <mclasen@redhat.com>
645344
Date: Wed, 10 Jul 2019 11:14:03 -0400
645344
Subject: [PATCH 7/9] key file: Handle filename being NULL
645344
645344
This happens when we are default-constructed
645344
without explicit arguments.
645344
645344
Closes: https://gitlab.gnome.org/GNOME/glib/issues/1825
645344
---
645344
 gio/gkeyfilesettingsbackend.c | 3 ++-
645344
 1 file changed, 2 insertions(+), 1 deletion(-)
645344
645344
diff --git a/gio/gkeyfilesettingsbackend.c b/gio/gkeyfilesettingsbackend.c
645344
index 5ea632305..a874af287 100644
645344
--- a/gio/gkeyfilesettingsbackend.c
645344
+++ b/gio/gkeyfilesettingsbackend.c
645344
@@ -739,7 +739,8 @@ g_keyfile_settings_backend_set_property (GObject      *object,
645344
     case PROP_FILENAME:
645344
       /* Construct only. */
645344
       g_assert (kfsb->file == NULL);
645344
-      kfsb->file = g_file_new_for_path (g_value_get_string (value));
645344
+      if (g_value_get_string (value))
645344
+        kfsb->file = g_file_new_for_path (g_value_get_string (value));
645344
       break;
645344
 
645344
     case PROP_ROOT_PATH:
645344
-- 
645344
2.28.0
645344
645344
645344
From 9c5d3a6081e5ff419db96d9651bddbfcdb8b1bc6 Mon Sep 17 00:00:00 2001
645344
From: Matthias Clasen <mclasen@redhat.com>
645344
Date: Fri, 12 Jul 2019 11:30:30 -0400
645344
Subject: [PATCH] portal: Add a getter for dconf access
645344
645344
Add method to find whether the sandbox provides
645344
access to dconf. This will be used to tweak
645344
the priorities for the keyfile settings backend.
645344
---
645344
 gio/gportalsupport.c | 18 ++++++++++++++++++
645344
 gio/gportalsupport.h |  1 +
645344
 2 files changed, 19 insertions(+)
645344
645344
diff --git a/gio/gportalsupport.c b/gio/gportalsupport.c
645344
index 2f1e82517..b0a94b360 100644
645344
--- a/gio/gportalsupport.c
645344
+++ b/gio/gportalsupport.c
645344
@@ -23,6 +23,7 @@
645344
 static gboolean flatpak_info_read;
645344
 static gboolean use_portal;
645344
 static gboolean network_available;
645344
+static gboolean dconf_access;
645344
 
645344
 static void
645344
 read_flatpak_info (void)
645344
@@ -40,11 +41,13 @@ read_flatpak_info (void)
645344
 
645344
       use_portal = TRUE;
645344
       network_available = FALSE;
645344
+      dconf_access = FALSE;
645344
 
645344
       keyfile = g_key_file_new ();
645344
       if (g_key_file_load_from_file (keyfile, path, G_KEY_FILE_NONE, NULL))
645344
         {
645344
           char **shared = NULL;
645344
+          char *dconf_policy = NULL;
645344
 
645344
           shared = g_key_file_get_string_list (keyfile, "Context", "shared", NULL, NULL);
645344
           if (shared)
645344
@@ -52,6 +55,14 @@ read_flatpak_info (void)
645344
               network_available = g_strv_contains ((const char * const *)shared, "network");
645344
               g_strfreev (shared);
645344
             }
645344
+
645344
+          dconf_policy = g_key_file_get_string (keyfile, "Session Bus Policy", "ca.desrt.dconf", NULL);
645344
+          if (dconf_policy)
645344
+            {
645344
+              if (strcmp (dconf_policy, "talk") == 0)
645344
+                dconf_access = TRUE;
645344
+              g_free (dconf_policy);
645344
+            }
645344
         }
645344
 
645344
       g_key_file_unref (keyfile);
645344
@@ -64,6 +75,7 @@ read_flatpak_info (void)
645344
       if (var && var[0] == '1')
645344
         use_portal = TRUE;
645344
       network_available = TRUE;
645344
+      dconf_access = TRUE;
645344
     }
645344
 }
645344
 
645344
@@ -81,3 +93,9 @@ glib_network_available_in_sandbox (void)
645344
   return network_available;
645344
 }
645344
 
645344
+gboolean
645344
+glib_has_dconf_access_in_sandbox (void)
645344
+{
645344
+  read_flatpak_info ();
645344
+  return dconf_access;
645344
+}
645344
diff --git a/gio/gportalsupport.h b/gio/gportalsupport.h
645344
index a331f45d3..746f1fd6b 100644
645344
--- a/gio/gportalsupport.h
645344
+++ b/gio/gportalsupport.h
645344
@@ -24,6 +24,7 @@ G_BEGIN_DECLS
645344
 
645344
 gboolean glib_should_use_portal (void);
645344
 gboolean glib_network_available_in_sandbox (void);
645344
+gboolean glib_has_dconf_access_in_sandbox (void);
645344
 
645344
 G_END_DECLS
645344
 
645344
-- 
645344
GitLab
645344
645344
645344
From e6461f208931e27b52d82f7d3b5a7ce4fc26c9d7 Mon Sep 17 00:00:00 2001
645344
From: Matthias Clasen <mclasen@redhat.com>
645344
Date: Fri, 12 Jul 2019 11:31:37 -0400
645344
Subject: [PATCH 8/9] settings: Tweak priorities for keyfile backend
645344
645344
We want to use the keyfile backend in sandboxes,
645344
but we want to avoid people losing their existing
645344
settings that are stored in dconf. Flatpak does
645344
a migration from dconf to keyfile, but only if
645344
the app explictly requests it.
645344
645344
From an app perspective, there are two steps to
645344
the dconf->keyfile migration:
645344
1. Request that flatpak do the migration, by adding
645344
   the migrate-path key to the metadata
645344
2. Stop adding the 'dconf hole' to the sandbox
645344
645344
To keep us from switching to the keyfile backend
645344
prematurely, look at whether the app has stopped
645344
requesting a 'dconf hole' in the sandbox.
645344
---
645344
 gio/gkeyfilesettingsbackend.c | 2 +-
645344
 1 file changed, 1 insertion(+), 1 deletion(-)
645344
645344
diff --git a/gio/gkeyfilesettingsbackend.c b/gio/gkeyfilesettingsbackend.c
645344
index a874af287..f5358818e 100644
645344
--- a/gio/gkeyfilesettingsbackend.c
645344
+++ b/gio/gkeyfilesettingsbackend.c
645344
@@ -80,7 +80,7 @@ typedef struct
645344
 #ifdef G_OS_WIN32
645344
 #define EXTENSION_PRIORITY 10
645344
 #else
645344
-#define EXTENSION_PRIORITY (glib_should_use_portal () ? 110 : 10)
645344
+#define EXTENSION_PRIORITY (glib_should_use_portal () && !glib_has_dconf_access_in_sandbox () ? 110 : 10)
645344
 #endif
645344
 
645344
 G_DEFINE_TYPE_WITH_CODE (GKeyfileSettingsBackend,
645344
-- 
645344
2.28.0
645344
645344
645344
From 5f8d787815dc220fa2e288e03cd0cb9497727753 Mon Sep 17 00:00:00 2001
645344
From: Matthias Clasen <mclasen@redhat.com>
645344
Date: Mon, 8 Jul 2019 10:31:51 -0400
645344
Subject: [PATCH] Ensure that the keyfile settings backend exists
645344
645344
We need to bring the type into existence.
645344
645344
Closes: https://gitlab.gnome.org/GNOME/glib/issues/1822
645344
---
645344
 gio/giomodule.c | 1 +
645344
 1 file changed, 1 insertion(+)
645344
645344
diff --git a/gio/giomodule.c b/gio/giomodule.c
645344
index 9bb28985a..1007abdbf 100644
645344
--- a/gio/giomodule.c
645344
+++ b/gio/giomodule.c
645344
@@ -1211,6 +1211,7 @@ _g_io_modules_ensure_loaded (void)
645344
       /* Initialize types from built-in "modules" */
645344
       g_type_ensure (g_null_settings_backend_get_type ());
645344
       g_type_ensure (g_memory_settings_backend_get_type ());
645344
+      g_type_ensure (g_keyfile_settings_backend_get_type ());
645344
 #if defined(HAVE_INOTIFY_INIT1)
645344
       g_type_ensure (g_inotify_file_monitor_get_type ());
645344
 #endif
645344
-- 
645344
GitLab