future proofing GConf for backend vtable changes
- From: Mark McLoughlin <mark skynet ie>
- To: Cyrille Moureaux <Cyrille Moureaux Sun COM>
- Cc: gconf-list gnome org
- Subject: future proofing GConf for backend vtable changes
- Date: Tue, 23 Mar 2004 21:27:43 +0000
Hi Cyrille,
In your patch in bug #107692 (allowing notifications from the backend)
you added a new notifier vtable rather than extending the existing
vtable because you were worried about breaking compatibility with
existing backends.
Since the backend API is completely private to GConf right now, we
don't really need to worry about this but I thought it might be nice to
add some future proofing before extending the vtable any further.
The attached patch takes the following approach:
+ The backends are compiled with the vtable's size as the first member
of the structure.
+ When initializing a backend, we create a new vtable instance
according to our knowledge of its size and fill it with whatever the
backend provided us.
+ This means that if the backend was compiled with an older version of
the vtable, the new members are guaranteed to be initialized to NULL
and if it was compiled with a new version of the vtable than the
library, then we just ignore any new methods.
There's some other stuff in the patch too - this part is the only
really relevant bit:
retval = g_new0(GConfBackendVTable, 1);
retval = memcpy(retval, vtable, MIN(vtable->vtable_size, sizeof(GConfBackendVTable)));
So, how does that sound? Havoc?
Cheers,
Mark.
Index: backends/markup-backend.c
===================================================================
RCS file: /cvs/gnome/gconf/backends/markup-backend.c,v
retrieving revision 1.7
diff -u -p -r1.7 markup-backend.c
--- backends/markup-backend.c 27 Oct 2003 18:11:17 -0000 1.7
+++ backends/markup-backend.c 23 Mar 2004 21:22:37 -0000
@@ -132,6 +132,7 @@ static void blow_away_locks (c
static GConfBackendVTable markup_vtable = {
+ sizeof (GConfBackendVTable),
x_shutdown,
resolve_address,
lock,
Index: backends/xml-backend.c
===================================================================
RCS file: /cvs/gnome/gconf/backends/xml-backend.c,v
retrieving revision 1.85
diff -u -p -r1.85 xml-backend.c
--- backends/xml-backend.c 22 Oct 2003 21:03:04 -0000 1.85
+++ backends/xml-backend.c 23 Mar 2004 21:22:37 -0000
@@ -209,6 +209,7 @@ static void clear_cache (GC
static void blow_away_locks (const char *address);
static GConfBackendVTable xml_vtable = {
+ sizeof (GConfBackendVTable),
x_shutdown,
resolve_address,
lock,
Index: gconf/gconf-backend.c
===================================================================
RCS file: /cvs/gnome/gconf/gconf/gconf-backend.c,v
retrieving revision 1.22
diff -u -p -r1.22 gconf-backend.c
--- gconf/gconf-backend.c 27 Mar 2003 01:41:14 -0000 1.22
+++ gconf/gconf-backend.c 23 Mar 2004 21:22:38 -0000
@@ -178,6 +178,63 @@ gconf_backend_file(const gchar* address)
static GHashTable* loaded_backends = NULL;
+static GConfBackendVTable *
+gconf_backend_check_vtable (GConfBackendVTable *vtable,
+ const char *backend_name,
+ GError **err)
+{
+ GConfBackendVTable *retval;
+ int i;
+ struct
+ {
+ char *name;
+ gsize offset;
+ } required_vtable_functions[] = {
+ { "shutdown", G_STRUCT_OFFSET(GConfBackendVTable, shutdown) },
+ { "resolve_address", G_STRUCT_OFFSET(GConfBackendVTable, resolve_address) },
+ { "query_value", G_STRUCT_OFFSET(GConfBackendVTable, query_value) },
+ { "query_metainfo", G_STRUCT_OFFSET(GConfBackendVTable, query_metainfo) },
+ { "set_value", G_STRUCT_OFFSET(GConfBackendVTable, set_value) },
+ { "all_entries", G_STRUCT_OFFSET(GConfBackendVTable, all_entries) },
+ { "all_subdirs", G_STRUCT_OFFSET(GConfBackendVTable, all_subdirs) },
+ { "unset_value", G_STRUCT_OFFSET(GConfBackendVTable, unset_value) },
+ { "dir_exists", G_STRUCT_OFFSET(GConfBackendVTable, dir_exists) },
+ { "remove_dir", G_STRUCT_OFFSET(GConfBackendVTable, remove_dir) },
+ { "set_schema", G_STRUCT_OFFSET(GConfBackendVTable, set_schema) },
+ { "sync_all", G_STRUCT_OFFSET(GConfBackendVTable, sync_all) },
+ { "destroy_source", G_STRUCT_OFFSET(GConfBackendVTable, destroy_source) },
+ { "blow_away_locks", G_STRUCT_OFFSET(GConfBackendVTable, blow_away_locks) }
+ };
+
+ if (!vtable)
+ {
+ gconf_set_error(err,
+ GCONF_ERROR_FAILED, _("Backend `%s' failed return a vtable\n"),
+ backend_name);
+ return NULL;
+ }
+
+ /* Create a copy in case vtable size doesn't match */
+ retval = g_new0(GConfBackendVTable, 1);
+
+ retval = memcpy(retval, vtable, MIN(vtable->vtable_size, sizeof(GConfBackendVTable)));
+
+ for (i = 0; i < G_N_ELEMENTS(required_vtable_functions); i++)
+ {
+ if (G_STRUCT_MEMBER_P(retval, required_vtable_functions[i].offset) == NULL)
+ {
+ gconf_set_error(err,
+ GCONF_ERROR_FAILED, _("Backend `%s' missing required vtable member `%s'\n"),
+ backend_name,
+ required_vtable_functions[i].name);
+ g_free(retval);
+ return NULL;
+ }
+ }
+
+ return retval;
+}
+
GConfBackend*
gconf_get_backend(const gchar* address, GError** err)
{
@@ -225,10 +282,9 @@ gconf_get_backend(const gchar* address,
if (module == NULL)
{
- const gchar* error = g_module_error();
gconf_set_error(err,
GCONF_ERROR_FAILED, _("Error opening module `%s': %s\n"),
- name, error);
+ name, g_module_error());
g_free(name);
return NULL;
}
@@ -237,6 +293,10 @@ gconf_get_backend(const gchar* address,
"gconf_backend_get_vtable",
(gpointer*)&get_vtable))
{
+ gconf_set_error(err,
+ GCONF_ERROR_FAILED, _("Error initializing module `%s': %s\n"),
+ name, g_module_error());
+ g_module_close(module);
g_free(name);
return NULL;
}
@@ -245,7 +305,14 @@ gconf_get_backend(const gchar* address,
backend->module = module;
- backend->vtable = (*get_vtable)();
+ backend->vtable = gconf_backend_check_vtable((*get_vtable)(), name, err);
+ if (!backend->vtable)
+ {
+ g_module_close(module);
+ g_free(name);
+ g_free(backend);
+ return NULL;
+ }
backend->name = name;
@@ -300,6 +367,7 @@ gconf_backend_unref(GConfBackend* backen
g_hash_table_remove(loaded_backends, backend->name);
+ g_free(backend->vtable);
g_free((gchar*)backend->name); /* cast off const */
g_free(backend);
Index: gconf/gconf-backend.h
===================================================================
RCS file: /cvs/gnome/gconf/gconf/gconf-backend.h,v
retrieving revision 1.30
diff -u -p -r1.30 gconf-backend.h
--- gconf/gconf-backend.h 27 Mar 2003 01:41:14 -0000 1.30
+++ gconf/gconf-backend.h 23 Mar 2004 21:22:38 -0000
@@ -33,6 +33,9 @@
typedef struct _GConfBackendVTable GConfBackendVTable;
struct _GConfBackendVTable {
+ /* Set to sizeof (GConfBackendVTable) - used for future proofing */
+ gsize vtable_size;
+
void (* shutdown) (GError** err);
GConfSource* (* resolve_address) (const gchar* address,
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]