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