summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRyan Lortie <desrt@desrt.ca>2011-05-06 12:10:23 +0200
committerRyan Lortie <desrt@desrt.ca>2011-05-06 12:10:23 +0200
commita2c4601f2650e83bff2fec3f1a13dc46cdf3a070 (patch)
tree8e7afddf533c0b3a8ac59113ffd909689fd84b7f
parente7dcf8d6e9e5c184b1302d0c731f632ab8466f1d (diff)
downloaddconf-a2c4601f2650e83bff2fec3f1a13dc46cdf3a070.tar.gz
client-side lockdown support
Support lockdown on the client side for GSettings. For performance reasons only lockdown of specific keys (not entire subpaths) is supported at the moment. This may change in the future if we can find a way to make large numbers of related GVDB lookups sufficiently performant.
-rw-r--r--engine/dconf-engine.c126
-rw-r--r--engine/dconf-engine.h6
-rw-r--r--gsettings/dconfsettingsbackend.c18
3 files changed, 114 insertions, 36 deletions
diff --git a/engine/dconf-engine.c b/engine/dconf-engine.c
index 9181fc2..2878b06 100644
--- a/engine/dconf-engine.c
+++ b/engine/dconf-engine.c
@@ -128,6 +128,7 @@ struct _DConfEngine
guint8 *shm;
GvdbTable **gvdbs;
+ GvdbTable **lock_tables;
gchar **object_paths;
gchar *bus_types;
gchar **names;
@@ -230,6 +231,8 @@ dconf_engine_refresh_system (DConfEngine *engine)
if (engine->gvdbs[i] == NULL)
g_error ("Unable to open '%s', specified in dconf profile\n",
filename);
+ engine->lock_tables[i] = gvdb_table_get_table (engine->gvdbs[i],
+ ".locks");
g_free (filename);
engine->state++;
}
@@ -360,6 +363,7 @@ dconf_engine_new (const gchar *profile)
engine->object_paths = g_new (gchar *, engine->n_dbs);
engine->gvdbs = g_new0 (GvdbTable *, engine->n_dbs);
+ engine->lock_tables = g_new0 (GvdbTable *, engine->n_dbs);
engine->bus_types = g_strdup ("eyyyyyyyyyyyyy");
engine->state = 0;
@@ -390,6 +394,9 @@ dconf_engine_free (DConfEngine *engine)
if (engine->gvdbs[i])
gvdb_table_unref (engine->gvdbs[i]);
+
+ if (engine->lock_tables[i])
+ gvdb_table_unref (engine->lock_tables[i]);
}
if (engine->shm)
@@ -403,67 +410,76 @@ dconf_engine_free (DConfEngine *engine)
g_free (engine->bus_types);
g_free (engine->names);
g_free (engine->gvdbs);
+ g_free (engine->lock_tables);
g_slice_free (DConfEngine, engine);
}
-GVariant *
-dconf_engine_read (DConfEngine *engine,
- const gchar *key)
+static GVariant *
+dconf_engine_read_internal (DConfEngine *engine,
+ const gchar *key,
+ gboolean user,
+ gboolean system)
{
GVariant *value = NULL;
+ gint lowest;
+ gint limit;
gint i;
g_static_mutex_lock (&engine->lock);
dconf_engine_refresh (engine);
- if (engine->gvdbs[0])
- value = gvdb_table_get_value (engine->gvdbs[0], key);
-
- for (i = 1; i < engine->n_dbs && value == NULL; i++)
- value = gvdb_table_get_value (engine->gvdbs[i], key);
+ /* Bound the search space depending on the databases that we are
+ * interested in.
+ */
+ limit = system ? engine->n_dbs : 1;
+ lowest = user ? 0 : 1;
+
+ /* We want i equal to the index of the highest database containing a
+ * lock, or i == lowest if there is no lock. For that reason, we
+ * don't actually check the lowest database for a lock. That makes
+ * sense, because even if it had a lock, it would not change our
+ * search policy (which would be to check the lowest one first).
+ *
+ * Note that we intentionally dishonour 'limit' here -- we want to
+ * ensure that values in the user database are always ignored when
+ * locks are present.
+ */
+ for (i = engine->n_dbs - 1; lowest < i; i--)
+ if (engine->lock_tables[i] != NULL &&
+ gvdb_table_has_value (engine->lock_tables[i], key))
+ break;
+
+ while (i < limit && value == NULL)
+ value = gvdb_table_get_value (engine->gvdbs[i++], key);
g_static_mutex_unlock (&engine->lock);
+ g_print ("you read %s, i say %s\n", key, value ? g_variant_print (value, TRUE) : "(null)");
+
return value;
}
GVariant *
+dconf_engine_read (DConfEngine *engine,
+ const gchar *key)
+{
+ return dconf_engine_read_internal (engine, key, TRUE, TRUE);
+}
+
+GVariant *
dconf_engine_read_default (DConfEngine *engine,
const gchar *key)
{
- GVariant *value = NULL;
- gint i;
-
- g_static_mutex_lock (&engine->lock);
-
- dconf_engine_refresh (engine);
-
- for (i = 1; i < engine->n_dbs && value == NULL; i++)
- value = gvdb_table_get_value (engine->gvdbs[i], key);
-
- g_static_mutex_unlock (&engine->lock);
-
- return value;
+ return dconf_engine_read_internal (engine, key, FALSE, TRUE);
}
GVariant *
dconf_engine_read_no_default (DConfEngine *engine,
const gchar *key)
{
- GVariant *value = NULL;
-
- g_static_mutex_lock (&engine->lock);
-
- dconf_engine_refresh (engine);
-
- if (engine->gvdbs[0])
- value = gvdb_table_get_value (engine->gvdbs[0], key);
-
- g_static_mutex_unlock (&engine->lock);
-
- return value;
+ return dconf_engine_read_internal (engine, key, TRUE, FALSE);
}
static void
@@ -518,10 +534,30 @@ dconf_engine_unwatch (DConfEngine *engine,
}
gboolean
-dconf_engine_is_writable (DConfEngine *engine,
- const gchar *name)
+dconf_engine_is_writable (DConfEngine *engine,
+ const gchar *name)
{
- return TRUE;
+ gboolean writable = TRUE;
+ gint i;
+
+ g_static_mutex_lock (&engine->lock);
+
+ dconf_engine_refresh (engine);
+
+ /* Don't check for locks in the user database.
+ * If there is only a user database then the loop won't run at all.
+ */
+ for (i = engine->n_dbs - 1; 0 < i; i--)
+ if (engine->lock_tables[i] != NULL &&
+ gvdb_table_has_value (engine->lock_tables[i], name))
+ {
+ writable = FALSE;
+ break;
+ }
+
+ g_static_mutex_unlock (&engine->lock);
+
+ return writable;
}
static GVariant *
@@ -672,6 +708,24 @@ dconf_engine_decode_notify (DConfEngine *engine,
}
gboolean
+dconf_engine_decode_writability_notify (const gchar **path,
+ const gchar *iface,
+ const gchar *method,
+ GVariant *body)
+{
+ if (strcmp (iface, "ca.desrt.dconf.Writer") ||
+ strcmp (method, "WritabilityNotify"))
+ return FALSE;
+
+ if (!g_variant_is_of_type (body, G_VARIANT_TYPE ("(s)")))
+ return FALSE;
+
+ g_variant_get_child (body, 0, "&s", path);
+
+ return TRUE;
+}
+
+gboolean
dconf_engine_interpret_reply (DConfEngineMessage *dcem,
const gchar *sender,
GVariant *body,
diff --git a/engine/dconf-engine.h b/engine/dconf-engine.h
index d2058d5..0bde8f0 100644
--- a/engine/dconf-engine.h
+++ b/engine/dconf-engine.h
@@ -144,6 +144,12 @@ gboolean dconf_engine_decode_notify (DConfEn
const gchar *member,
GVariant *body);
G_GNUC_INTERNAL
+gboolean dconf_engine_decode_writability_notify (const gchar **path,
+ const gchar *iface,
+ const gchar *method,
+ GVariant *body);
+
+G_GNUC_INTERNAL
void dconf_engine_set_locked (DConfEngine *engine,
const gchar *path,
gboolean locked,
diff --git a/gsettings/dconfsettingsbackend.c b/gsettings/dconfsettingsbackend.c
index d978646..77d9358 100644
--- a/gsettings/dconfsettingsbackend.c
+++ b/gsettings/dconfsettingsbackend.c
@@ -101,6 +101,24 @@ dconf_settings_backend_signal (GDBusConnection *connection,
g_free (rels);
}
+
+ if (dconf_engine_decode_writability_notify (&path, interface_name,
+ signal_name, parameters))
+ {
+ GSettingsBackend *backend = G_SETTINGS_BACKEND (dcsb);
+
+ if (g_str_has_suffix (path, "/"))
+ {
+ g_settings_backend_path_writable_changed (backend, path);
+ g_settings_backend_path_changed (backend, path, NULL);
+ }
+
+ else
+ {
+ g_settings_backend_writable_changed (backend, path);
+ g_settings_backend_changed (backend, path, NULL);
+ }
+ }
}
static void