summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Meeks <michael.meeks@novell.com>2010-01-08 12:49:29 -0600
committerFederico Mena Quintero <federico@novell.com>2010-01-08 12:49:29 -0600
commita867a03613b7c68523d13b5a7c96636b011692d2 (patch)
tree0fa7e0348d8ede2414eccff7d14b2e8a2319dd8f
parent5c2b93d85c0ec93e4090f7f3b69b0d5d1a219b9b (diff)
downloadgconf-moblin-speed-inherit-bgo571449.tar.gz
bgo#571449 - Inherit attributes from a parent node for mtimemoblin-speed-inherit-bgo571449
-rw-r--r--backends/Makefile.am3
-rw-r--r--backends/markup-backend.c10
-rw-r--r--backends/markup-tree.c348
-rw-r--r--backends/markup-tree.h5
-rw-r--r--backends/xml-test.c13
5 files changed, 345 insertions, 34 deletions
diff --git a/backends/Makefile.am b/backends/Makefile.am
index 3c1bc3b6..61ab03e0 100644
--- a/backends/Makefile.am
+++ b/backends/Makefile.am
@@ -1,5 +1,6 @@
INCLUDES= -I$(top_srcdir) -I$(top_builddir) -I$(top_builddir)/gconf \
$(DEPENDENT_WITH_XML_CFLAGS) \
+ -DGCONF_ETCDIR=\""$(sysgconfdir)"\" \
-DGCONF_ENABLE_INTERNALS=1 -DG_LOG_DOMAIN=\"GConf-Backends\"
backenddir = $(pkglibdir)/$(MAJOR_VERSION)
@@ -36,7 +37,7 @@ xml_test_SOURCES= xml-test.c
xml_test_LDADD = \
$(DEPENDENT_WITH_XML_LIBS) \
$(top_builddir)/gconf/libgconf-$(MAJOR_VERSION).la \
- libgconfbackend-oldxml.la
+ libgconfbackend-xml.la
bin_PROGRAMS = gconf-merge-tree
gconf_merge_tree_SOURCES = gconf-merge-tree.c
diff --git a/backends/markup-backend.c b/backends/markup-backend.c
index 3e653dfb..ce0bb12c 100644
--- a/backends/markup-backend.c
+++ b/backends/markup-backend.c
@@ -489,7 +489,7 @@ query_value (GConfSource *source,
{
retval = markup_entry_get_value (entry, locales);
if (schema_name)
- *schema_name = g_strdup (markup_entry_get_schema_name (entry));
+ *schema_name = markup_entry_get_schema_name (entry);
}
else
{
@@ -521,7 +521,7 @@ query_metainfo (GConfSource *source,
if (entry != NULL)
{
GConfMetaInfo* gcmi;
- const char *schema_name;
+ char *schema_name;
GTime mtime;
const char *mod_user;
@@ -533,6 +533,8 @@ query_metainfo (GConfSource *source,
if (schema_name)
gconf_meta_info_set_schema (gcmi, schema_name);
+
+ g_free (schema_name);
gconf_meta_info_set_mod_time (gcmi, mtime);
@@ -579,7 +581,7 @@ gconf_entry_from_markup_entry (MarkupEntry *entry,
const char **locales)
{
GConfValue *value;
- const char *schema_name;
+ char *schema_name;
GConfEntry *gconf_entry;
value = markup_entry_get_value (entry, locales);
@@ -592,6 +594,8 @@ gconf_entry_from_markup_entry (MarkupEntry *entry,
value);
gconf_entry_set_schema_name (gconf_entry, schema_name);
+ g_free (schema_name);
+
return gconf_entry;
}
diff --git a/backends/markup-tree.c b/backends/markup-tree.c
index c08d6c79..4bb94da9 100644
--- a/backends/markup-tree.c
+++ b/backends/markup-tree.c
@@ -49,7 +49,7 @@ struct _MarkupEntry
GConfValue *value;
/* list of LocalSchemaInfo */
GSList *local_schemas;
- char *schema_name;
+ char *schema_name; /* potentially compressed name */
char *mod_user;
GTime mod_time;
};
@@ -74,6 +74,8 @@ static void markup_dir_setup_as_subtree_root (MarkupDir *dir);
static MarkupEntry* markup_entry_new (MarkupDir *dir,
const char *name);
static void markup_entry_free (MarkupEntry *entry);
+static void markup_entry_set_mod_time (MarkupEntry *entry,
+ GTime mtime);
static void parse_tree (MarkupDir *root,
gboolean parse_subtree,
@@ -96,10 +98,23 @@ struct _MarkupTree
guint refcount;
guint merged : 1;
+ guint inherited : 1;
};
static GHashTable *trees_by_root_dir = NULL;
+/*
+ * To improve interoperability with previous versions of
+ * the XML schema when eg. sharing NFS home directories, we
+ * only use the new compacted / inherited form for
+ * /etc/gconf/... (for now).
+ */
+static gboolean
+enable_inheritance (MarkupTree *tree)
+{
+ return !strncmp (tree->dirname, GCONF_ETCDIR, strlen (GCONF_ETCDIR));
+}
+
MarkupTree*
markup_tree_get (const char *root_dir,
guint dir_mode,
@@ -127,6 +142,7 @@ markup_tree_get (const char *root_dir,
tree->dir_mode = dir_mode;
tree->file_mode = file_mode;
tree->merged = merged != FALSE;
+ tree->inherited = enable_inheritance (tree);
tree->root = markup_dir_new (tree, NULL, "/");
@@ -179,6 +195,7 @@ struct _MarkupDir
MarkupDir *parent;
MarkupDir *subtree_root;
char *name;
+ GTime mod_time;
GSList *entries;
GSList *subdirs;
@@ -230,6 +247,7 @@ markup_dir_new (MarkupTree *tree,
dir->name = g_strdup (name);
dir->tree = tree;
dir->parent = parent;
+ dir->mod_time = parent ? parent->mod_time : 0;
if (parent)
{
@@ -245,6 +263,17 @@ markup_dir_new (MarkupTree *tree,
}
static void
+markup_dir_set_mod_time (MarkupDir *dir, GTime mtime)
+{
+ /* set only if newer for import */
+ while (dir != NULL && dir->mod_time < mtime)
+ {
+ dir->mod_time = mtime;
+ dir = dir->parent;
+ }
+}
+
+static void
markup_dir_free (MarkupDir *dir)
{
GSList *tmp;
@@ -512,6 +541,7 @@ load_subtree (MarkupDir *dir)
markup_dir_list_available_local_descs (dir);
parse_tree (dir, TRUE, NULL, &tmp_err);
+
if (tmp_err)
{
/* note that tmp_err may be a G_MARKUP_ERROR while only
@@ -1335,9 +1365,10 @@ markup_entry_new (MarkupDir *dir,
entry = g_new0 (MarkupEntry, 1);
+ entry->dir = dir;
entry->name = g_strdup (name);
+ entry->mod_time = dir->mod_time;
- entry->dir = dir;
dir->entries = g_slist_prepend (dir->entries, entry);
return entry;
@@ -1596,7 +1627,7 @@ markup_entry_set_value (MarkupEntry *entry,
}
/* Update mod time */
- entry->mod_time = time (NULL);
+ markup_entry_set_mod_time (entry, time (NULL));
/* Need to save to disk */
markup_dir_set_entries_need_save (entry->dir);
@@ -1670,13 +1701,141 @@ markup_entry_unset_value (MarkupEntry *entry,
}
/* Update mod time */
- entry->mod_time = time (NULL);
+ markup_entry_set_mod_time (entry, time (NULL));
/* Need to save to disk */
markup_dir_set_entries_need_save (entry->dir);
markup_dir_queue_sync (entry->dir);
}
+#define VERBOSE_SCHEMA_PREFIX "/schemas"
+#define COMPRESS_CHAR '~'
+
+/*
+ * Sets schema string, and if in inherited mode compresses
+ * it thus, to either "~" (which means the schema is
+ * /schemas + the node path), or to ~/foo (which means
+ * /schemas + the parent path + foo).
+ */
+void
+markup_entry_set_verbose_schema_name (MarkupEntry *entry,
+ const char *verbose)
+{
+ int len;
+ char *cname;
+ const char *elem;
+ GSList *names, *l;
+ MarkupDir *dir;
+
+ g_return_if_fail (entry->dir != NULL);
+
+ /* if we have a ~ - we're perfectly stemmed already... */
+ if (!entry->dir->tree->inherited || !verbose || verbose[0] == '~' ||
+ strncmp (verbose, VERBOSE_SCHEMA_PREFIX,
+ sizeof (VERBOSE_SCHEMA_PREFIX) - 1))
+ {
+ entry->schema_name = g_strdup (verbose);
+ return;
+ }
+
+ /* Not the common case ... compress the schema path */
+
+ /* build list of path elements names */
+ names = g_slist_prepend (NULL, entry->name);
+ for (dir = entry->dir; dir != NULL; dir = dir->parent)
+ names = g_slist_prepend (names, dir->name);
+ /* remove root with name '/' */
+ names = g_slist_delete_link (names, names);
+
+ elem = verbose + sizeof (VERBOSE_SCHEMA_PREFIX);
+ for (l = names; *elem && l != NULL; l = l->next) {
+ const char *frag = l->data;
+ len = strlen (frag);
+ if (strncmp (frag, elem, len) != 0)
+ break;
+
+ if (G_LIKELY (elem[len] == '/')) {
+ elem += len + 1;
+ } else { /* special case "~" means exact path */
+ if (elem[len] == '\0')
+ elem += len;
+ else
+ break;
+ }
+ }
+
+ if (!l) {
+ g_assert (*elem == '\0');
+ cname = g_strdup ("~");
+ } else if (l->next == NULL) { /* just replace the last elem */
+ len = strlen (elem);
+ cname = g_malloc (len + 3);
+ cname[0] = '~';
+ cname[1] = '\0';
+ strcpy (cname + 1, elem - 1);
+ } else {
+ cname = g_strdup (verbose);
+ }
+ g_slist_free (names);
+
+ entry->schema_name = cname;
+}
+
+char*
+markup_entry_get_schema_name (MarkupEntry *entry)
+{
+ int len;
+ char *schema;
+ GSList *names, *l;
+ MarkupDir *dir;
+
+ g_return_val_if_fail (entry->dir != NULL, NULL);
+ g_return_val_if_fail (entry->dir->entries_loaded, NULL);
+
+ /* if we have no ~ - we're not stemmed... */
+ if (!entry->dir->tree->inherited ||
+ entry->schema_name == NULL ||
+ entry->schema_name[0] == '\0' ||
+ entry->schema_name[0] != '~') {
+ return g_strdup (entry->schema_name);
+ }
+
+ /* expand the leading '~' */
+
+ len = sizeof (VERBOSE_SCHEMA_PREFIX) - 1;
+ if (entry->schema_name[1] == '/')
+ {
+ names = g_slist_prepend (NULL, entry->schema_name + 2);
+ }
+ else
+ { /* just ~ special case */
+ g_assert (entry->schema_name[1] == '\0');
+ names = g_slist_prepend (NULL, entry->name);
+ }
+ len += strlen (names->data) + 1;
+
+ /* build list of path elements names */
+ for (dir = entry->dir; dir != NULL; dir = dir->parent)
+ {
+ len += 1 + strlen (dir->name);
+ names = g_slist_prepend (names, dir->name);
+ }
+ /* remove root with name '/' */
+ names = g_slist_delete_link (names, names);
+ len -= 2;
+
+ schema = g_new (char, len + 1);
+ strcpy (schema, VERBOSE_SCHEMA_PREFIX);
+ for (l = names; l != NULL; l = l->next)
+ {
+ strcat (schema, "/");
+ strcat (schema, l->data);
+ }
+ g_assert (strlen (schema) == len);
+
+ return schema;
+}
+
void
markup_entry_set_schema_name (MarkupEntry *entry,
const char *schema_name)
@@ -1691,10 +1850,10 @@ markup_entry_set_schema_name (MarkupEntry *entry,
/* schema_name may be NULL to unset it */
g_free (entry->schema_name);
- entry->schema_name = g_strdup (schema_name);
+ markup_entry_set_verbose_schema_name (entry, schema_name);
/* Update mod time */
- entry->mod_time = time (NULL);
+ markup_entry_set_mod_time (entry, time (NULL));
/* Need to save to disk */
markup_dir_set_entries_need_save (entry->dir);
@@ -1819,15 +1978,6 @@ markup_entry_get_name (MarkupEntry *entry)
}
const char*
-markup_entry_get_schema_name (MarkupEntry *entry)
-{
- g_return_val_if_fail (entry->dir != NULL, NULL);
- g_return_val_if_fail (entry->dir->entries_loaded, NULL);
-
- return entry->schema_name;
-}
-
-const char*
markup_entry_get_mod_user (MarkupEntry *entry)
{
g_return_val_if_fail (entry->dir != NULL, NULL);
@@ -1860,7 +2010,10 @@ static void
markup_entry_set_mod_time (MarkupEntry *entry,
GTime mtime)
{
+ g_return_if_fail (entry->dir != NULL);
+
entry->mod_time = mtime;
+ markup_dir_set_mod_time (entry->dir, mtime);
}
/*
@@ -2756,7 +2909,7 @@ parse_entry_element (GMarkupParseContext *context,
* mess up the modtime
*/
if (schema)
- entry->schema_name = g_strdup (schema);
+ markup_entry_set_verbose_schema_name (entry, schema);
}
else
{
@@ -2815,18 +2968,21 @@ parse_dir_element (GMarkupParseContext *context,
{
MarkupDir *parent;
MarkupDir *dir;
+ const char *mtime;
const char *name;
-
+
g_return_if_fail (peek_state (info) == STATE_GCONF || peek_state (info) == STATE_DIR);
g_return_if_fail (ELEMENT_IS ("dir"));
push_state (info, STATE_DIR);
name = NULL;
+ mtime = NULL;
if (!locate_attributes (context, element_name, attribute_names, attribute_values,
error,
"name", &name,
+ "mtime", &mtime,
NULL))
return;
@@ -2870,6 +3026,9 @@ parse_dir_element (GMarkupParseContext *context,
{
dir = markup_dir_new (info->root->tree, parent, name);
+ if (mtime != NULL)
+ markup_dir_set_mod_time (dir, gconf_string_to_gulong (mtime));
+
/* This is a dummy directory which will be deleted when
* we've finised parsing the contents of this element.
*/
@@ -4159,8 +4318,9 @@ write_entry (MarkupEntry *entry,
if (local_schema_info == NULL)
{
- if (fprintf (f, " mtime=\"%lu\"", (unsigned long) entry->mod_time) < 0)
- goto out;
+ if (!entry->dir->tree->inherited || entry->dir->mod_time != entry->mod_time)
+ if (fprintf (f, " mtime=\"%lu\"", (unsigned long) entry->mod_time) < 0)
+ goto out;
if (entry->schema_name)
{
@@ -4231,9 +4391,17 @@ write_dir (MarkupDir *dir,
g_assert (dir->name != NULL);
- if (fprintf (f, "%s<dir name=\"%s\">\n",
+ if (fprintf (f, "%s<dir name=\"%s\"",
make_whitespace (indent), dir->name) < 0)
goto out;
+ if (dir->tree->inherited &&
+ (dir->parent == dir->tree->root ||
+ dir->parent->mod_time != dir->mod_time))
+ if (fprintf (f, " mtime=\"%lu\"",
+ (unsigned long)dir->mod_time) < 0)
+ goto out;
+ if (fprintf (f, ">\n") < 0)
+ goto out;
tmp = dir->entries;
while (tmp != NULL)
@@ -4634,3 +4802,143 @@ local_schema_info_free (LocalSchemaInfo *info)
gconf_value_free (info->default_value);
g_free (info);
}
+
+#ifndef GCONF_DISABLE_TESTS
+static gboolean
+test_tree (MarkupTree *tree)
+{
+ int i;
+ MarkupDir *dir;
+ MarkupEntry *entry;
+ GError *error = NULL;
+
+ dir = markup_tree_lookup_dir (tree, "/system/smb", &error);
+ if (dir == NULL)
+ g_error ("Failed to lookup directory");
+
+ entry = markup_dir_lookup_entry (dir, "workgroup", &error);
+ if (entry == NULL)
+ g_error ("Failed to lookup entry");
+
+ /* test schema name mangling */
+ struct {
+ char *entry;
+ char *schema_name;
+ char *uncompressed;
+ } tests[] = {
+ { "workgroup", "~", "/schemas/system/smb/workgroup" },
+ { "workgroup_lastelem", "~/workgroup", "/schemas/system/smb/workgroup" },
+ { "workgroup_random", "/schemas/random", "/schemas/random" },
+ { "workgroup_noschema", NULL, NULL },
+ { "workgroup_oddpath", "/foo/system/smb/workgroup", "/foo/system/smb/workgroup" }
+ };
+ for (i = 0; i < G_N_ELEMENTS (tests); i++)
+ {
+ MarkupEntry *entry;
+ entry = markup_dir_lookup_entry (dir, tests[i].entry, &error);
+ if (entry == NULL)
+ g_error ("Failed to lookup '%s'", tests[i].entry);
+ if (!tests[i].schema_name) {
+ if (entry->schema_name)
+ g_error ("expected NULL schema name on '%s'", tests[i].entry);
+ } else {
+ char *name;
+
+ if (!entry->schema_name)
+ g_error ("unexpected NULL schema name on '%s'", tests[i].entry);
+ if (strcmp (tests[i].schema_name, entry->schema_name)) {
+ g_error ("mis-matching compressed schema name '%s' vs. '%s' on key '%s'",
+ entry->schema_name, tests[i].schema_name, tests[i].entry);
+ }
+ name = markup_entry_get_schema_name (entry);
+ if (strcmp (tests[i].uncompressed, name)) {
+ g_error ("mis-matching uncompressed schema name '%s' vs. '%s' on key '%s'",
+ tests[i].uncompressed, name, tests[i].entry);
+ }
+ g_free (name);
+ }
+ }
+ return TRUE;
+}
+#endif
+
+gboolean
+markup_test_tree (void)
+{
+#ifndef GCONF_DISABLE_TESTS
+ const char *xml =
+"<?xml version=\"1.0\"?>\n"
+"<gconf>\n"
+" <dir name=\"system\">\n"
+" <dir name=\"smb\">\n"
+" <entry name=\"workgroup\" mtime=\"1234375446\" schema=\"/schemas/system/smb/workgroup\"/>\n"
+" <entry name=\"workgroup_lastelem\" mtime=\"1234375446\" schema=\"/schemas/system/smb/workgroup\"/>\n"
+" <entry name=\"workgroup_random\" mtime=\"1234375446\" schema=\"/schemas/random\"/>\n"
+" <entry name=\"workgroup_noschema\" mtime=\"1234375446\"/>\n"
+" <entry name=\"workgroup_oddpath\" mtime=\"1234375446\" schema=\"/foo/system/smb/workgroup\"/>\n"
+" </dir>\n"
+" </dir>\n"
+" <dir name=\"schemas\">\n"
+" <dir name=\"system\">\n"
+" <dir name=\"smb\">\n"
+" <entry name=\"workgroup\" mtime=\"1234375446\" type=\"schema\" stype=\"string\" owner=\"gnome-vfs\">\n"
+" <local_schema locale=\"C\" short_desc=\"SMB workgroup\">\n"
+" <default type=\"string\">\n"
+" <stringvalue>WORKGROUP</stringvalue>\n"
+" </default>\n"
+" <longdesc>A Long Desc</longdesc>\n"
+" </local_schema>\n"
+" </entry>\n"
+" </dir>\n"
+" <entry name=\"random\" mtime=\"1234375446\" type=\"schema\" stype=\"string\" owner=\"gnome-vfs\">\n"
+" <local_schema locale=\"C\" short_desc=\"other schema\">\n"
+" <default type=\"string\">\n"
+" <stringvalue>Random</stringvalue>\n"
+" </default>\n"
+" <longdesc>Random Desc</longdesc>\n"
+" </local_schema>\n"
+" </entry>\n"
+" </dir>\n"
+" </dir>\n"
+"</gconf>";
+
+ GMarkupParseContext *context = NULL;
+ GError *error = NULL;
+ ParseInfo info;
+ MarkupTree *tree;
+
+ tree = markup_tree_get ("/home/baa/.gconf/foo.xml", 0, 0, TRUE);
+ g_assert (tree->inherited == FALSE);
+ markup_tree_unref (tree);
+
+ tree = markup_tree_get (GCONF_ETCDIR "/foo.xml", 0, 0, TRUE);
+ g_assert (tree->inherited == TRUE);
+
+ parse_info_init (&info, tree->root, TRUE, NULL);
+
+ /* analog of load_subtree */
+ tree->root->subdirs_loaded = TRUE;
+ tree->root->entries_loaded = TRUE;
+ tree->root->save_as_subtree = TRUE;
+ markup_dir_setup_as_subtree_root (tree->root);
+ markup_dir_list_available_local_descs (tree->root);
+
+ context = g_markup_parse_context_new (&gconf_parser,
+ 0, &info, NULL);
+ if (!g_markup_parse_context_parse (context, xml, strlen (xml), &error))
+ g_error ("Failed to parse gconf xml '%s'", error->message);
+
+ if (!g_markup_parse_context_end_parse (context, &error))
+ g_error ("Failed to end the parsing");
+
+ g_markup_parse_context_free (context);
+
+ parse_info_free (&info);
+
+ test_tree (tree);
+
+ markup_tree_unref (tree);
+ g_message ("All tests passed successfully\n");
+#endif
+ return TRUE;
+}
diff --git a/backends/markup-tree.h b/backends/markup-tree.h
index cda6bd8c..4b31f97b 100644
--- a/backends/markup-tree.h
+++ b/backends/markup-tree.h
@@ -75,9 +75,12 @@ void markup_entry_unset_value (MarkupEntry *entry,
const char *locale);
void markup_entry_set_schema_name (MarkupEntry *entry,
const char *schema_name);
+char* markup_entry_get_schema_name (MarkupEntry *entry);
const char* markup_entry_get_name (MarkupEntry *entry);
-const char* markup_entry_get_schema_name (MarkupEntry *entry);
const char* markup_entry_get_mod_user (MarkupEntry *entry);
GTime markup_entry_get_mod_time (MarkupEntry *entry);
+/* testing hook */
+gboolean markup_tree_test (void);
+
#endif
diff --git a/backends/xml-test.c b/backends/xml-test.c
index 687d558b..4829d961 100644
--- a/backends/xml-test.c
+++ b/backends/xml-test.c
@@ -18,15 +18,11 @@
*/
#include <config.h>
-#include "xml-entry.h"
-#include "xml-dir.h"
-#include "xml-cache.h"
+#include "markup-tree.h"
#include "gconf/gconf-internals.h"
#include "gconf/gconf-backend.h"
#include <stdlib.h>
#include <string.h>
-#include <libxml/entities.h>
-#include <libxml/globals.h>
GConfBackendVTable* gconf_backend_get_vtable (void);
@@ -36,10 +32,9 @@ main (int argc, char **argv)
GConfBackendVTable *vtable;
vtable = gconf_backend_get_vtable ();
-
- xml_test_entry ();
- xml_test_dir ();
- xml_test_cache ();
+
+ if (!markup_test_tree ())
+ return 1;
return 0;
}